DKIM: permit dkim_private_key to override dkim_strict on signing. Bug 2220
[exim.git] / src / src / dkim.c
CommitLineData
80a47a2c
TK
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
d4e5e70b 5/* Copyright (c) University of Cambridge, 1995 - 2017 */
80a47a2c
TK
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* Code for DKIM support. Other DKIM relevant code is in
9 receive.c, transport.c and transports/smtp.c */
10
11#include "exim.h"
12
13#ifndef DISABLE_DKIM
14
970424a5
JH
15# include "pdkim/pdkim.h"
16
17# ifdef MACRO_PREDEF
5f69a529 18# include "macro_predef.h"
970424a5
JH
19
20void
a2701501 21params_dkim(void)
970424a5
JH
22{
23builtin_macro_create_var(US"_DKIM_SIGN_HEADERS", US PDKIM_DEFAULT_SIGN_HEADERS);
24}
25# else /*!MACRO_PREDEF*/
26
27
28
80a47a2c 29
ca9cb170 30int dkim_verify_oldpool;
1cfe5c1c 31pdkim_ctx *dkim_verify_ctx = NULL;
80a47a2c 32pdkim_signature *dkim_signatures = NULL;
1cfe5c1c 33pdkim_signature *dkim_cur_sig = NULL;
b9df1829 34static const uschar * dkim_collect_error = NULL;
80a47a2c 35
d73e45df
JH
36
37
38/*XXX the caller only uses the first record if we return multiple.
39Could we hand back an allocated string?
40*/
41
1cfe5c1c
JH
42static int
43dkim_exim_query_dns_txt(char *name, char *answer)
44{
45dns_answer dnsa;
46dns_scan dnss;
47dns_record *rr;
80a47a2c 48
1cfe5c1c
JH
49lookup_dnssec_authenticated = NULL;
50if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
f7302073 51 return PDKIM_FAIL; /*XXX better error detail? logging? */
80a47a2c 52
1cfe5c1c 53/* Search for TXT record */
80a47a2c 54
1cfe5c1c
JH
55for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
56 rr;
57 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
58 if (rr->type == T_TXT)
59 {
80a47a2c
TK
60 int rr_offset = 0;
61 int answer_offset = 0;
1cfe5c1c
JH
62
63 /* Copy record content to the answer buffer */
64
65 while (rr_offset < rr->size)
66 {
67 uschar len = rr->data[rr_offset++];
68 snprintf(answer + answer_offset,
69 PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
5903c6ff 70 "%.*s", (int)len, CS (rr->data + rr_offset));
1cfe5c1c
JH
71 rr_offset += len;
72 answer_offset += len;
73 if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
f7302073 74 return PDKIM_FAIL; /*XXX better error detail? logging? */
4263f395 75 }
dd33c4e6
HSHR
76
77 /* check if this looks like a DKIM record */
78 if (strncasecmp(answer, "v=dkim", 6) != 0) continue;
1cfe5c1c 79 return PDKIM_OK;
80a47a2c 80 }
80a47a2c 81
f7302073 82return PDKIM_FAIL; /*XXX better error detail? logging? */
80a47a2c
TK
83}
84
85
2592e6c0
JH
86void
87dkim_exim_init(void)
88{
89pdkim_init();
90}
91
92
ca9cb170 93
1cfe5c1c 94void
e983e85a 95dkim_exim_verify_init(BOOL dot_stuffing)
1cfe5c1c 96{
ca9cb170
JH
97/* There is a store-reset between header & body reception
98so cannot use the main pool. Any allocs done by Exim
99memory-handling must use the perm pool. */
100
101dkim_verify_oldpool = store_pool;
102store_pool = POOL_PERM;
103
1cfe5c1c 104/* Free previous context if there is one */
80a47a2c 105
1cfe5c1c
JH
106if (dkim_verify_ctx)
107 pdkim_free_ctx(dkim_verify_ctx);
80a47a2c 108
1cfe5c1c 109/* Create new context */
80a47a2c 110
e983e85a 111dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
3b957582 112dkim_collect_input = !!dkim_verify_ctx;
b9df1829 113dkim_collect_error = NULL;
ca9cb170 114
584e96c6
JH
115/* Start feed up with any cached data */
116receive_get_cache();
117
ca9cb170 118store_pool = dkim_verify_oldpool;
80a47a2c
TK
119}
120
121
1cfe5c1c
JH
122void
123dkim_exim_verify_feed(uschar * data, int len)
124{
f7302073
JH
125int rc;
126
ca9cb170 127store_pool = POOL_PERM;
1cfe5c1c 128if ( dkim_collect_input
ef698bf6 129 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
f7302073 130 {
b9df1829 131 dkim_collect_error = pdkim_errstr(rc);
f7302073 132 log_write(0, LOG_MAIN,
b9df1829 133 "DKIM: validation error: %.100s", dkim_collect_error);
1cfe5c1c 134 dkim_collect_input = FALSE;
f7302073 135 }
ca9cb170 136store_pool = dkim_verify_oldpool;
80a47a2c
TK
137}
138
139
a79d8834
JH
140/* Log the result for the given signature */
141static void
142dkim_exim_verify_log_sig(pdkim_signature * sig)
1cfe5c1c 143{
cc55f420 144gstring * logmsg;
a79d8834
JH
145uschar * s;
146
cc55f420
JH
147if (!sig) return;
148
2c47372f
JH
149if ( !dkim_verify_overall
150 && dkim_verify_status
151 ? Ustrcmp(dkim_verify_status, US"pass") == 0
152 : sig->verify_status == PDKIM_VERIFY_PASS
153 )
154 dkim_verify_overall = string_copy(sig->domain);
155
156if (!LOGGING(dkim_verbose)) return;
157
aaaa94ea 158logmsg = string_catn(NULL, US"DKIM: ", 6);
a79d8834
JH
159if (!(s = sig->domain)) s = US"<UNSET>";
160logmsg = string_append(logmsg, 2, "d=", s);
161if (!(s = sig->selector)) s = US"<UNSET>";
162logmsg = string_append(logmsg, 2, " s=", s);
dd33c4e6 163logmsg = string_append(logmsg, 7,
a79d8834
JH
164" c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
165"/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
166" a=", dkim_sig_to_a_tag(sig),
167string_sprintf(" b=" SIZE_T_FMT,
168 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
169if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
170if (sig->created > 0) logmsg = string_cat(logmsg,
171 string_sprintf(" t=%lu", sig->created));
172if (sig->expires > 0) logmsg = string_cat(logmsg,
173 string_sprintf(" x=%lu", sig->expires));
174if (sig->bodylength > -1) logmsg = string_cat(logmsg,
175 string_sprintf(" l=%lu", sig->bodylength));
176
177if ( !dkim_verify_status
178 || ( dkim_verify_status == dkim_exim_expand_query(DKIM_VERIFY_STATUS)
179 && dkim_verify_reason == dkim_exim_expand_query(DKIM_VERIFY_REASON)
180 ) )
1cfe5c1c
JH
181 switch (sig->verify_status)
182 {
183 case PDKIM_VERIFY_NONE:
aaaa94ea 184 logmsg = string_cat(logmsg, US" [not verified]");
80a47a2c 185 break;
1cfe5c1c
JH
186
187 case PDKIM_VERIFY_INVALID:
aaaa94ea 188 logmsg = string_cat(logmsg, US" [invalid - ");
1cfe5c1c
JH
189 switch (sig->verify_ext_status)
190 {
191 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
acec9514 192 logmsg = string_cat(logmsg,
aaaa94ea 193 US"public key record (currently?) unavailable]");
1cfe5c1c
JH
194 break;
195
196 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
aaaa94ea 197 logmsg = string_cat(logmsg, US"overlong public key record]");
1cfe5c1c
JH
198 break;
199
df3def24
JH
200 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
201 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
aaaa94ea 202 logmsg = string_cat(logmsg, US"syntax error in public key record]");
1cfe5c1c 203 break;
07eeb4df 204
a79d8834 205 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
aaaa94ea 206 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
a79d8834 207 break;
07eeb4df 208
a79d8834 209 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
aaaa94ea 210 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
a79d8834 211 break;
1cfe5c1c
JH
212
213 default:
aaaa94ea 214 logmsg = string_cat(logmsg, US"unspecified problem]");
1cfe5c1c 215 }
80a47a2c 216 break;
1cfe5c1c
JH
217
218 case PDKIM_VERIFY_FAIL:
aaaa94ea 219 logmsg = string_cat(logmsg, US" [verification failed - ");
1cfe5c1c
JH
220 switch (sig->verify_ext_status)
221 {
222 case PDKIM_VERIFY_FAIL_BODY:
acec9514 223 logmsg = string_cat(logmsg,
aaaa94ea 224 US"body hash mismatch (body probably modified in transit)]");
1cfe5c1c
JH
225 break;
226
227 case PDKIM_VERIFY_FAIL_MESSAGE:
acec9514 228 logmsg = string_cat(logmsg,
aaaa94ea
JH
229 US"signature did not verify "
230 "(headers probably modified in transit)]");
1cfe5c1c
JH
231 break;
232
233 default:
aaaa94ea 234 logmsg = string_cat(logmsg, US"unspecified reason]");
1cfe5c1c 235 }
80a47a2c 236 break;
1cfe5c1c
JH
237
238 case PDKIM_VERIFY_PASS:
aaaa94ea 239 logmsg = string_cat(logmsg, US" [verification succeeded]");
80a47a2c
TK
240 break;
241 }
a79d8834
JH
242else
243 logmsg = string_append(logmsg, 5,
244 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
245
aaaa94ea 246log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
a79d8834
JH
247return;
248}
249
80a47a2c 250
a79d8834
JH
251/* Log a line for each signature */
252void
253dkim_exim_verify_log_all(void)
254{
255pdkim_signature * sig;
256for (sig = dkim_signatures; sig; sig = sig->next) dkim_exim_verify_log_sig(sig);
257}
1cfe5c1c 258
80a47a2c 259
a79d8834
JH
260void
261dkim_exim_verify_finish(void)
262{
263pdkim_signature * sig;
264int rc;
265gstring * g = NULL;
266const uschar * errstr;
267
268store_pool = POOL_PERM;
269
270/* Delete eventual previous signature chain */
271
272dkim_signers = NULL;
273dkim_signatures = NULL;
274
275if (dkim_collect_error)
276 {
277 log_write(0, LOG_MAIN,
278 "DKIM: Error during validation, disabling signature verification: %.100s",
279 dkim_collect_error);
280 dkim_disable_verify = TRUE;
281 goto out;
282 }
283
284dkim_collect_input = FALSE;
285
286/* Finish DKIM operation and fetch link to signatures chain */
287
288rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
289if (rc != PDKIM_OK)
290 {
291 log_write(0, LOG_MAIN, "DKIM: validation error: %.100s%s%s", pdkim_errstr(rc),
292 errstr ? ": " : "", errstr ? errstr : US"");
293 goto out;
294 }
295
296/* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
297
298for (sig = dkim_signatures; sig; sig = sig->next)
299 {
300 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
301 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
80a47a2c
TK
302 }
303
acec9514
JH
304if (g) dkim_signers = g->s;
305
ca9cb170
JH
306out:
307store_pool = dkim_verify_oldpool;
80a47a2c
TK
308}
309
310
18067c75
JH
311
312/* Args as per dkim_exim_acl_run() below */
313static int
314dkim_acl_call(uschar * id, gstring ** res_ptr,
315 uschar ** user_msgptr, uschar ** log_msgptr)
316{
317int rc;
318DEBUG(D_receive)
319 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
320
321rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
322dkim_exim_verify_log_sig(dkim_cur_sig);
323*res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
324return rc;
325}
326
327
328
329/* For the given identity, run the DKIM ACL once for each matching signature.
330
331Arguments
332 id Identity to look for in dkim signatures
333 res_ptr ptr to growable string-list of status results,
334 appended to per ACL run
335 user_msgptr where to put a user error (for SMTP response)
336 log_msgptr where to put a logging message (not for SMTP response)
337
338Returns: OK access is granted by an ACCEPT verb
339 DISCARD access is granted by a DISCARD verb
340 FAIL access is denied
341 FAIL_DROP access is denied; drop the connection
342 DEFER can't tell at the moment
343 ERROR disaster
344*/
345
346int
347dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
348 uschar ** user_msgptr, uschar ** log_msgptr)
1cfe5c1c
JH
349{
350pdkim_signature * sig;
351uschar * cmp_val;
18067c75 352int rc = -1;
1cfe5c1c 353
cc55f420
JH
354dkim_verify_status = US"none";
355dkim_verify_reason = US"";
1cfe5c1c
JH
356dkim_cur_signer = id;
357
358if (dkim_disable_verify || !id || !dkim_verify_ctx)
18067c75 359 return OK;
1cfe5c1c 360
18067c75 361/* Find signatures to run ACL on */
1cfe5c1c
JH
362
363for (sig = dkim_signatures; sig; sig = sig->next)
364 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
365 && strcmpic(cmp_val, id) == 0
366 )
367 {
1cfe5c1c 368 /* The "dkim_domain" and "dkim_selector" expansion variables have
18067c75
JH
369 related globals, since they are used in the signing code too.
370 Instead of inventing separate names for verification, we set
371 them here. This is easy since a domain and selector is guaranteed
372 to be in a signature. The other dkim_* expansion items are
373 dynamically fetched from dkim_cur_sig at expansion time (see
374 function below). */
1cfe5c1c 375
18067c75 376 dkim_cur_sig = sig;
1cfe5c1c
JH
377 dkim_signing_domain = US sig->domain;
378 dkim_signing_selector = US sig->selector;
dcd03763 379 dkim_key_length = sig->sighash.len * 8;
a79d8834
JH
380
381 /* These two return static strings, so we can compare the addr
382 later to see if the ACL overwrote them. Check that when logging */
383
384 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
385 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
dd33c4e6 386
18067c75
JH
387 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
388 return rc;
80a47a2c 389 }
18067c75
JH
390
391if (rc != -1)
392 return rc;
393
394/* No matching sig found. Call ACL once anyway. */
395
396dkim_cur_sig = NULL;
397return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
80a47a2c
TK
398}
399
400
1cfe5c1c
JH
401static uschar *
402dkim_exim_expand_defaults(int what)
403{
404switch (what)
405 {
406 case DKIM_ALGO: return US"";
407 case DKIM_BODYLENGTH: return US"9999999999999";
408 case DKIM_CANON_BODY: return US"";
409 case DKIM_CANON_HEADERS: return US"";
410 case DKIM_COPIEDHEADERS: return US"";
411 case DKIM_CREATED: return US"0";
412 case DKIM_EXPIRES: return US"9999999999999";
413 case DKIM_HEADERNAMES: return US"";
414 case DKIM_IDENTITY: return US"";
415 case DKIM_KEY_GRANULARITY: return US"*";
416 case DKIM_KEY_SRVTYPE: return US"*";
417 case DKIM_KEY_NOTES: return US"";
418 case DKIM_KEY_TESTING: return US"0";
419 case DKIM_NOSUBDOMAINS: return US"0";
420 case DKIM_VERIFY_STATUS: return US"none";
421 case DKIM_VERIFY_REASON: return US"";
422 default: return US"";
423 }
424}
80a47a2c 425
80a47a2c 426
1cfe5c1c
JH
427uschar *
428dkim_exim_expand_query(int what)
429{
430if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
431 return dkim_exim_expand_defaults(what);
432
433switch (what)
434 {
435 case DKIM_ALGO:
d73e45df 436 return dkim_sig_to_a_tag(dkim_cur_sig);
1cfe5c1c
JH
437
438 case DKIM_BODYLENGTH:
439 return dkim_cur_sig->bodylength >= 0
bb07bcd3 440 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
1cfe5c1c
JH
441 : dkim_exim_expand_defaults(what);
442
443 case DKIM_CANON_BODY:
444 switch (dkim_cur_sig->canon_body)
445 {
446 case PDKIM_CANON_RELAXED: return US"relaxed";
447 case PDKIM_CANON_SIMPLE:
448 default: return US"simple";
80a47a2c 449 }
1cfe5c1c
JH
450
451 case DKIM_CANON_HEADERS:
a79d8834
JH
452 switch (dkim_cur_sig->canon_headers)
453 {
454 case PDKIM_CANON_RELAXED: return US"relaxed";
455 case PDKIM_CANON_SIMPLE:
456 default: return US"simple";
457 }
1cfe5c1c
JH
458
459 case DKIM_COPIEDHEADERS:
460 return dkim_cur_sig->copiedheaders
461 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
462
463 case DKIM_CREATED:
464 return dkim_cur_sig->created > 0
bb07bcd3 465 ? string_sprintf("%lu", dkim_cur_sig->created)
1cfe5c1c
JH
466 : dkim_exim_expand_defaults(what);
467
468 case DKIM_EXPIRES:
469 return dkim_cur_sig->expires > 0
bb07bcd3 470 ? string_sprintf("%lu", dkim_cur_sig->expires)
1cfe5c1c
JH
471 : dkim_exim_expand_defaults(what);
472
473 case DKIM_HEADERNAMES:
474 return dkim_cur_sig->headernames
2592e6c0 475 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
1cfe5c1c
JH
476
477 case DKIM_IDENTITY:
478 return dkim_cur_sig->identity
479 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
480
481 case DKIM_KEY_GRANULARITY:
482 return dkim_cur_sig->pubkey
483 ? dkim_cur_sig->pubkey->granularity
484 ? US dkim_cur_sig->pubkey->granularity
485 : dkim_exim_expand_defaults(what)
486 : dkim_exim_expand_defaults(what);
487
488 case DKIM_KEY_SRVTYPE:
489 return dkim_cur_sig->pubkey
490 ? dkim_cur_sig->pubkey->srvtype
491 ? US dkim_cur_sig->pubkey->srvtype
492 : dkim_exim_expand_defaults(what)
493 : dkim_exim_expand_defaults(what);
494
495 case DKIM_KEY_NOTES:
496 return dkim_cur_sig->pubkey
497 ? dkim_cur_sig->pubkey->notes
498 ? US dkim_cur_sig->pubkey->notes
499 : dkim_exim_expand_defaults(what)
500 : dkim_exim_expand_defaults(what);
501
502 case DKIM_KEY_TESTING:
503 return dkim_cur_sig->pubkey
504 ? dkim_cur_sig->pubkey->testing
505 ? US"1"
506 : dkim_exim_expand_defaults(what)
507 : dkim_exim_expand_defaults(what);
508
509 case DKIM_NOSUBDOMAINS:
510 return dkim_cur_sig->pubkey
511 ? dkim_cur_sig->pubkey->no_subdomaining
512 ? US"1"
513 : dkim_exim_expand_defaults(what)
514 : dkim_exim_expand_defaults(what);
515
516 case DKIM_VERIFY_STATUS:
517 switch (dkim_cur_sig->verify_status)
518 {
519 case PDKIM_VERIFY_INVALID: return US"invalid";
520 case PDKIM_VERIFY_FAIL: return US"fail";
521 case PDKIM_VERIFY_PASS: return US"pass";
522 case PDKIM_VERIFY_NONE:
523 default: return US"none";
80a47a2c 524 }
80a47a2c 525
1cfe5c1c
JH
526 case DKIM_VERIFY_REASON:
527 switch (dkim_cur_sig->verify_ext_status)
528 {
529 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
530 return US"pubkey_unavailable";
df3def24
JH
531 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
532 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
1cfe5c1c
JH
533 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
534 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
535 }
80a47a2c 536
1cfe5c1c
JH
537 default:
538 return US"";
80a47a2c
TK
539 }
540}
541
542
0b8f4f1a 543/* Generate signatures for the given file.
42055a33 544If a prefix is given, prepend it to the file for the calculations.
0b8f4f1a
JH
545
546Return:
547 NULL: error; error string written
548 string: signature header(s), or a zero-length string (not an error)
42055a33
JH
549*/
550
acec9514 551gstring *
42055a33
JH
552dkim_exim_sign(int fd, off_t off, uschar * prefix,
553 struct ob_dkim * dkim, const uschar ** errstr)
55414b25 554{
e983e85a 555const uschar * dkim_domain;
1cfe5c1c 556int sep = 0;
acec9514 557gstring * seen_doms = NULL;
9e70917d
JH
558pdkim_ctx ctx;
559pdkim_signature * sig;
acec9514 560gstring * sigbuf;
1cfe5c1c
JH
561int pdkim_rc;
562int sread;
ef698bf6 563uschar buf[4096];
1cfe5c1c
JH
564int save_errno = 0;
565int old_pool = store_pool;
7c6ec81b 566uschar * errwhen;
1cfe5c1c
JH
567
568store_pool = POOL_MAIN;
569
9e70917d
JH
570pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
571
e983e85a 572if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
1cfe5c1c 573 /* expansion error, do not send message. */
7c6ec81b 574 { errwhen = US"dkim_domain"; goto expand_bad; }
1cfe5c1c
JH
575
576/* Set $dkim_domain expansion variable to each unique domain in list. */
577
42055a33 578while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
1cfe5c1c 579 {
9e70917d
JH
580 const uschar * dkim_sel;
581 int sel_sep = 0;
582
42055a33 583 if (dkim_signing_domain[0] == '\0')
1cfe5c1c
JH
584 continue;
585
586 /* Only sign once for each domain, no matter how often it
587 appears in the expanded list. */
588
9e70917d
JH
589 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
590 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
591 continue;
1cfe5c1c 592
acec9514 593 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
1cfe5c1c 594
9e70917d
JH
595 /* Set $dkim_selector expansion variable to each selector in list,
596 for this domain. */
1cfe5c1c 597
9e70917d 598 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
e983e85a 599 if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
7c6ec81b 600 { errwhen = US"dkim_selector"; goto expand_bad; }
1cfe5c1c 601
9e70917d
JH
602 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
603 NULL, 0)))
1cfe5c1c 604 {
9e70917d
JH
605 uschar * dkim_canon_expanded;
606 int pdkim_canon;
607 uschar * dkim_sign_headers_expanded = NULL;
608 uschar * dkim_private_key_expanded;
609 uschar * dkim_hash_expanded;
7c6ec81b 610 uschar * dkim_identity_expanded = NULL;
80a47a2c 611
9e70917d 612 /* Get canonicalization to use */
1cfe5c1c 613
9e70917d
JH
614 dkim_canon_expanded = dkim->dkim_canon
615 ? expand_string(dkim->dkim_canon) : US"relaxed";
7c6ec81b
JH
616 if (!dkim_canon_expanded) /* expansion error, do not send message. */
617 { errwhen = US"dkim_canon"; goto expand_bad; }
1cfe5c1c 618
9e70917d
JH
619 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
620 pdkim_canon = PDKIM_CANON_RELAXED;
621 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
622 pdkim_canon = PDKIM_CANON_SIMPLE;
623 else
624 {
625 log_write(0, LOG_MAIN,
626 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
627 dkim_canon_expanded);
628 pdkim_canon = PDKIM_CANON_RELAXED;
629 }
1cfe5c1c 630
7c6ec81b
JH
631 if ( dkim->dkim_sign_headers
632 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
633 { errwhen = US"dkim_sign_header"; goto expand_bad; }
634 /* else pass NULL, which means default header list */
1cfe5c1c 635
9e70917d 636 /* Get private key to use. */
e983e85a 637
9e70917d 638 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
7c6ec81b 639 { errwhen = US"dkim_private_key"; goto expand_bad; }
80a47a2c 640
9e70917d
JH
641 if ( Ustrlen(dkim_private_key_expanded) == 0
642 || Ustrcmp(dkim_private_key_expanded, "0") == 0
643 || Ustrcmp(dkim_private_key_expanded, "false") == 0
644 )
645 continue; /* don't sign, but no error */
646
647 if (dkim_private_key_expanded[0] == '/')
1cfe5c1c 648 {
9e70917d
JH
649 int privkey_fd, off = 0, len;
650
651 /* Looks like a filename, load the private key. */
652
653 memset(big_buffer, 0, big_buffer_size);
654
655 if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
59d98039 656 {
9e70917d
JH
657 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
658 "private key file for reading: %s",
59d98039
JH
659 dkim_private_key_expanded);
660 goto bad;
661 }
9e70917d
JH
662
663 do
664 {
665 if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
666 {
667 (void) close(privkey_fd);
668 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
669 dkim_private_key_expanded);
670 goto bad;
671 }
672 off += len;
673 }
674 while (len > 0);
675
676 (void) close(privkey_fd);
677 big_buffer[off] = '\0';
678 dkim_private_key_expanded = big_buffer;
1ac6b2e7 679 }
80a47a2c 680
9e70917d 681 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
7c6ec81b
JH
682 { errwhen = US"dkim_hash"; goto expand_bad; }
683
684 if (dkim->dkim_identity)
685 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
686 { errwhen = US"dkim_identity"; goto expand_bad; }
687 else if (!*dkim_identity_expanded)
688 dkim_identity_expanded = NULL;
1cfe5c1c 689
9e70917d
JH
690 /*XXX so we currently nail signing to RSA + this hash.
691 Need to extract algo from privkey and check for disallowed combos. */
d73e45df 692
9e70917d
JH
693 if (!(sig = pdkim_init_sign(&ctx, dkim_signing_domain,
694 dkim_signing_selector,
695 dkim_private_key_expanded,
696 dkim_hash_expanded,
697 errstr
698 )))
699 goto bad;
700 dkim_private_key_expanded[0] = '\0';
701
702 pdkim_set_optional(sig,
703 CS dkim_sign_headers_expanded,
27fd1318 704 CS dkim_identity_expanded,
9e70917d
JH
705 pdkim_canon,
706 pdkim_canon, -1, 0, 0);
707
708 if (!ctx.sig) /* link sig to context chain */
709 ctx.sig = sig;
710 else
711 {
712 pdkim_signature * n = ctx.sig;
713 while (n->next) n = n->next;
714 n->next = sig;
715 }
80a47a2c 716 }
9e70917d 717 }
0b8f4f1a
JH
718if (!ctx.sig)
719 {
720 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
721 sigbuf = string_get(1); /* return a zero-len string */
722 goto CLEANUP;
723 }
80a47a2c 724
0b8f4f1a
JH
725if (prefix && (pdkim_feed(&ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
726 goto pk_bad;
80a47a2c 727
9e70917d
JH
728if (lseek(fd, off, SEEK_SET) < 0)
729 sread = -1;
730else
731 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
732 if ((pdkim_rc = pdkim_feed(&ctx, buf, sread)) != PDKIM_OK)
733 goto pk_bad;
80a47a2c 734
9e70917d
JH
735/* Handle failed read above. */
736if (sread == -1)
737 {
738 debug_printf("DKIM: Error reading -K file.\n");
739 save_errno = errno;
740 goto bad;
80a47a2c 741 }
a8e1eeba 742
9e70917d
JH
743/* Build string of headers, one per signature */
744
745if ((pdkim_rc = pdkim_feed_finish(&ctx, &sig, errstr)) != PDKIM_OK)
746 goto pk_bad;
747
acec9514
JH
748for (sigbuf = NULL; sig; sig = sig->next)
749 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
9e70917d 750
1cfe5c1c 751CLEANUP:
0b8f4f1a 752 (void) string_from_gstring(sigbuf);
f7302073
JH
753 store_pool = old_pool;
754 errno = save_errno;
9e70917d 755 return sigbuf;
f7302073
JH
756
757pk_bad:
758 log_write(0, LOG_MAIN|LOG_PANIC,
759 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
760bad:
9e70917d 761 sigbuf = NULL;
f7302073 762 goto CLEANUP;
7c6ec81b
JH
763
764expand_bad:
765 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
766 errwhen, expand_string_message);
767 goto bad;
93f2d376 768}
80a47a2c 769
970424a5
JH
770# endif /*!MACRO_PREDEF*/
771#endif /*!DISABLE_DKIM*/