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