1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
6 /* Copyright (c) University of Cambridge, 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
10 /* Code for DKIM support. Other DKIM relevant code is in
11 receive.c, transport.c and transports/smtp.c */
17 # include "pdkim/pdkim.h"
20 # include "macro_predef.h"
25 builtin_macro_create_var(US"_DKIM_SIGN_HEADERS", US PDKIM_DEFAULT_SIGN_HEADERS);
26 builtin_macro_create_var(US"_DKIM_OVERSIGN_HEADERS", US PDKIM_OVERSIGN_HEADERS);
28 # else /*!MACRO_PREDEF*/
32 pdkim_ctx dkim_sign_ctx;
34 int dkim_verify_oldpool;
35 pdkim_ctx *dkim_verify_ctx = NULL;
36 pdkim_signature *dkim_cur_sig = NULL;
37 static const uschar * dkim_collect_error = NULL;
39 #define DKIM_MAX_SIGNATURES 20
43 /* Look up the DKIM record in DNS for the given hostname.
44 Will use the first found if there are multiple.
45 The return string is tainted, having come from off-site.
49 dkim_exim_query_dns_txt(const uschar * name)
51 dns_answer * dnsa = store_get_dns_answer();
53 rmark reset_point = store_mark();
54 gstring * g = string_get_tainted(256, GET_TAINTED);
56 lookup_dnssec_authenticated = NULL;
57 if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
60 /* Search for TXT record */
62 for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
64 rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
65 if (rr->type == T_TXT)
66 { /* Copy record content to the answer buffer */
67 for (int rr_offset = 0; rr_offset < rr->size; )
69 uschar len = rr->data[rr_offset++];
71 g = string_catn(g, US(rr->data + rr_offset), len);
72 if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
78 /* Check if this looks like a DKIM record */
79 if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
81 store_free_dns_answer(dnsa);
82 gstring_release_unused(g);
83 return string_from_gstring(g);
86 gstring_reset(g); /* overwrite previous record */
90 store_reset(reset_point);
91 store_free_dns_answer(dnsa);
92 return NULL; /*XXX better error detail? logging? */
99 if (f.dkim_init_done) return;
100 f.dkim_init_done = TRUE;
107 dkim_exim_verify_init(BOOL dot_stuffing)
111 /* There is a store-reset between header & body reception for the main pool
112 (actually, after every header line) so cannot use that as we need the data we
113 store per-header, during header processing, at the end of body reception
114 for evaluating the signature. Any allocs done for dkim verify
115 memory-handling must use a different pool. We use a separate one that we
116 can reset per message. */
118 dkim_verify_oldpool = store_pool;
119 store_pool = POOL_MESSAGE;
121 /* Free previous context if there is one */
124 pdkim_free_ctx(dkim_verify_ctx);
126 /* Create new context */
128 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
129 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
130 dkim_collect_error = NULL;
132 /* Start feed up with any cached data, but limited to message data */
133 receive_get_cache(chunking_state == CHUNKING_LAST
134 ? chunking_data_left : GETC_BUFFER_UNLIMITED);
136 store_pool = dkim_verify_oldpool;
140 /* Submit a chunk of data for verification input.
141 Only use the data when the feed is activated. */
143 dkim_exim_verify_feed(uschar * data, int len)
147 store_pool = POOL_MESSAGE;
148 if ( dkim_collect_input
149 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
151 dkim_collect_error = pdkim_errstr(rc);
152 log_write(0, LOG_MAIN,
153 "DKIM: validation error: %.100s", dkim_collect_error);
154 dkim_collect_input = 0;
156 store_pool = dkim_verify_oldpool;
160 /* Log the result for the given signature */
162 dkim_exim_verify_log_sig(pdkim_signature * sig)
169 /* Remember the domain for the first pass result */
171 if ( !dkim_verify_overall
172 && dkim_verify_status
173 ? Ustrcmp(dkim_verify_status, US"pass") == 0
174 : sig->verify_status == PDKIM_VERIFY_PASS
176 dkim_verify_overall = string_copy(sig->domain);
178 /* Rewrite the sig result if the ACL overrode it. This is only
179 needed because the DMARC code (sigh) peeks at the dkim sigs.
180 Mark the sig for this having been done. */
182 if ( dkim_verify_status
183 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
184 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
186 { /* overridden by ACL */
187 sig->verify_ext_status = -1;
188 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
189 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
190 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
191 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
192 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
193 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
194 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
195 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
197 sig->verify_status = -1;
200 if (!LOGGING(dkim_verbose)) return;
203 logmsg = string_catn(NULL, US"DKIM: ", 6);
204 if (!(s = sig->domain)) s = US"<UNSET>";
205 logmsg = string_append(logmsg, 2, "d=", s);
206 if (!(s = sig->selector)) s = US"<UNSET>";
207 logmsg = string_append(logmsg, 2, " s=", s);
208 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
209 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
210 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
211 dkim_sig_to_a_tag(sig),
212 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
213 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
214 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
216 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
218 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
221 if (sig->verify_status & PDKIM_VERIFY_POLICY)
222 logmsg = string_append(logmsg, 5,
223 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
225 switch (sig->verify_status)
227 case PDKIM_VERIFY_NONE:
228 logmsg = string_cat(logmsg, US" [not verified]");
231 case PDKIM_VERIFY_INVALID:
232 logmsg = string_cat(logmsg, US" [invalid - ");
233 switch (sig->verify_ext_status)
235 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
236 logmsg = string_cat(logmsg,
237 US"public key record (currently?) unavailable]");
240 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
241 logmsg = string_cat(logmsg, US"overlong public key record]");
244 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
245 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
246 logmsg = string_cat(logmsg, US"syntax error in public key record]");
249 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
250 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
253 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
254 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
258 logmsg = string_cat(logmsg, US"unspecified problem]");
262 case PDKIM_VERIFY_FAIL:
263 logmsg = string_cat(logmsg, US" [verification failed - ");
264 switch (sig->verify_ext_status)
266 case PDKIM_VERIFY_FAIL_BODY:
267 logmsg = string_cat(logmsg,
268 US"body hash mismatch (body probably modified in transit)]");
271 case PDKIM_VERIFY_FAIL_MESSAGE:
272 logmsg = string_cat(logmsg,
273 US"signature did not verify "
274 "(headers probably modified in transit)]");
277 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
278 logmsg = string_cat(logmsg,
279 US"signature invalid (key too short)]");
283 logmsg = string_cat(logmsg, US"unspecified reason]");
287 case PDKIM_VERIFY_PASS:
288 logmsg = string_cat(logmsg, US" [verification succeeded]");
292 log_write(0, LOG_MAIN, "%Y", logmsg);
297 /* Log a line for each signature */
299 dkim_exim_verify_log_all(void)
301 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
302 dkim_exim_verify_log_sig(sig);
307 dkim_exim_verify_finish(void)
311 const uschar * errstr = NULL;
313 store_pool = POOL_MESSAGE;
315 /* Delete eventual previous signature chain */
318 dkim_signatures = NULL;
320 if (dkim_collect_error)
322 log_write(0, LOG_MAIN,
323 "DKIM: Error during validation, disabling signature verification: %.100s",
325 f.dkim_disable_verify = TRUE;
329 dkim_collect_input = 0;
331 /* Finish DKIM operation and fetch link to signatures chain */
333 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
335 if (rc != PDKIM_OK && errstr)
336 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
338 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
340 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
342 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
343 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
346 if (g) dkim_signers = g->s;
349 store_pool = dkim_verify_oldpool;
354 /* Args as per dkim_exim_acl_run() below */
356 dkim_acl_call(uschar * id, gstring ** res_ptr,
357 uschar ** user_msgptr, uschar ** log_msgptr)
361 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
363 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
364 dkim_exim_verify_log_sig(dkim_cur_sig);
365 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
371 /* For the given identity, run the DKIM ACL once for each matching signature.
374 id Identity to look for in dkim signatures
375 res_ptr ptr to growable string-list of status results,
376 appended to per ACL run
377 user_msgptr where to put a user error (for SMTP response)
378 log_msgptr where to put a logging message (not for SMTP response)
380 Returns: OK access is granted by an ACCEPT verb
381 DISCARD access is granted by a DISCARD verb
382 FAIL access is denied
383 FAIL_DROP access is denied; drop the connection
384 DEFER can't tell at the moment
389 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
390 uschar ** user_msgptr, uschar ** log_msgptr)
395 dkim_verify_status = US"none";
396 dkim_verify_reason = US"";
397 dkim_cur_signer = id;
399 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
402 /* Find signatures to run ACL on */
404 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
405 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
406 && strcmpic(cmp_val, id) == 0
409 /* The "dkim_domain" and "dkim_selector" expansion variables have
410 related globals, since they are used in the signing code too.
411 Instead of inventing separate names for verification, we set
412 them here. This is easy since a domain and selector is guaranteed
413 to be in a signature. The other dkim_* expansion items are
414 dynamically fetched from dkim_cur_sig at expansion time (see
415 dkim_exim_expand_query() below). */
418 dkim_signing_domain = US sig->domain;
419 dkim_signing_selector = US sig->selector;
420 dkim_key_length = sig->keybits;
422 /* These two return static strings, so we can compare the addr
423 later to see if the ACL overwrote them. Check that when logging */
425 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
426 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
428 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
435 /* No matching sig found. Call ACL once anyway. */
438 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
443 dkim_exim_expand_defaults(int what)
447 case DKIM_ALGO: return US"";
448 case DKIM_BODYLENGTH: return US"9999999999999";
449 case DKIM_CANON_BODY: return US"";
450 case DKIM_CANON_HEADERS: return US"";
451 case DKIM_COPIEDHEADERS: return US"";
452 case DKIM_CREATED: return US"0";
453 case DKIM_EXPIRES: return US"9999999999999";
454 case DKIM_HEADERNAMES: return US"";
455 case DKIM_IDENTITY: return US"";
456 case DKIM_KEY_GRANULARITY: return US"*";
457 case DKIM_KEY_SRVTYPE: return US"*";
458 case DKIM_KEY_NOTES: return US"";
459 case DKIM_KEY_TESTING: return US"0";
460 case DKIM_NOSUBDOMAINS: return US"0";
461 case DKIM_VERIFY_STATUS: return US"none";
462 case DKIM_VERIFY_REASON: return US"";
463 default: return US"";
469 dkim_exim_expand_query(int what)
471 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
472 return dkim_exim_expand_defaults(what);
477 return dkim_sig_to_a_tag(dkim_cur_sig);
479 case DKIM_BODYLENGTH:
480 return dkim_cur_sig->bodylength >= 0
481 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
482 : dkim_exim_expand_defaults(what);
484 case DKIM_CANON_BODY:
485 switch (dkim_cur_sig->canon_body)
487 case PDKIM_CANON_RELAXED: return US"relaxed";
488 case PDKIM_CANON_SIMPLE:
489 default: return US"simple";
492 case DKIM_CANON_HEADERS:
493 switch (dkim_cur_sig->canon_headers)
495 case PDKIM_CANON_RELAXED: return US"relaxed";
496 case PDKIM_CANON_SIMPLE:
497 default: return US"simple";
500 case DKIM_COPIEDHEADERS:
501 return dkim_cur_sig->copiedheaders
502 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
505 return dkim_cur_sig->created > 0
506 ? string_sprintf("%lu", dkim_cur_sig->created)
507 : dkim_exim_expand_defaults(what);
510 return dkim_cur_sig->expires > 0
511 ? string_sprintf("%lu", dkim_cur_sig->expires)
512 : dkim_exim_expand_defaults(what);
514 case DKIM_HEADERNAMES:
515 return dkim_cur_sig->headernames
516 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
519 return dkim_cur_sig->identity
520 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
522 case DKIM_KEY_GRANULARITY:
523 return dkim_cur_sig->pubkey
524 ? dkim_cur_sig->pubkey->granularity
525 ? US dkim_cur_sig->pubkey->granularity
526 : dkim_exim_expand_defaults(what)
527 : dkim_exim_expand_defaults(what);
529 case DKIM_KEY_SRVTYPE:
530 return dkim_cur_sig->pubkey
531 ? dkim_cur_sig->pubkey->srvtype
532 ? US dkim_cur_sig->pubkey->srvtype
533 : dkim_exim_expand_defaults(what)
534 : dkim_exim_expand_defaults(what);
537 return dkim_cur_sig->pubkey
538 ? dkim_cur_sig->pubkey->notes
539 ? US dkim_cur_sig->pubkey->notes
540 : dkim_exim_expand_defaults(what)
541 : dkim_exim_expand_defaults(what);
543 case DKIM_KEY_TESTING:
544 return dkim_cur_sig->pubkey
545 ? dkim_cur_sig->pubkey->testing
547 : dkim_exim_expand_defaults(what)
548 : dkim_exim_expand_defaults(what);
550 case DKIM_NOSUBDOMAINS:
551 return dkim_cur_sig->pubkey
552 ? dkim_cur_sig->pubkey->no_subdomaining
554 : dkim_exim_expand_defaults(what)
555 : dkim_exim_expand_defaults(what);
557 case DKIM_VERIFY_STATUS:
558 switch (dkim_cur_sig->verify_status)
560 case PDKIM_VERIFY_INVALID: return US"invalid";
561 case PDKIM_VERIFY_FAIL: return US"fail";
562 case PDKIM_VERIFY_PASS: return US"pass";
563 case PDKIM_VERIFY_NONE:
564 default: return US"none";
567 case DKIM_VERIFY_REASON:
568 switch (dkim_cur_sig->verify_ext_status)
570 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
571 return US"pubkey_unavailable";
572 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
573 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
574 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
575 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
576 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
586 dkim_exim_sign_init(void)
588 int old_pool = store_pool;
591 store_pool = POOL_MAIN;
592 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
593 store_pool = old_pool;
597 /* Generate signatures for the given file.
598 If a prefix is given, prepend it to the file for the calculations.
601 NULL: error; error string written
602 string: signature header(s), or a zero-length string (not an error)
606 dkim_exim_sign(int fd, off_t off, uschar * prefix,
607 struct ob_dkim * dkim, const uschar ** errstr)
609 const uschar * dkim_domain = NULL;
611 gstring * seen_doms = NULL;
612 pdkim_signature * sig;
618 int old_pool = store_pool;
622 if (dkim->dot_stuffed)
623 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
625 store_pool = POOL_MAIN;
627 GET_OPTION("dkim_domain");
628 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
629 /* expansion error, do not send message. */
630 { errwhen = US"dkim_domain"; goto expand_bad; }
632 /* Set $dkim_domain expansion variable to each unique domain in list. */
635 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
637 const uschar * dkim_sel;
640 if (dkim_signing_domain[0] == '\0')
643 /* Only sign once for each domain, no matter how often it
644 appears in the expanded list. */
646 dkim_signing_domain = string_copylc(dkim_signing_domain);
647 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
648 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
651 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
653 /* Set $dkim_selector expansion variable to each selector in list,
656 GET_OPTION("dkim_selector");
657 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
658 { errwhen = US"dkim_selector"; goto expand_bad; }
660 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
663 uschar * dkim_canon_expanded;
665 uschar * dkim_sign_headers_expanded = NULL;
666 uschar * dkim_private_key_expanded;
667 uschar * dkim_hash_expanded;
668 uschar * dkim_identity_expanded = NULL;
669 uschar * dkim_timestamps_expanded = NULL;
670 unsigned long tval = 0, xval = 0;
672 /* Get canonicalization to use */
674 GET_OPTION("dkim_canon");
675 dkim_canon_expanded = dkim->dkim_canon
676 ? expand_string(dkim->dkim_canon) : US"relaxed";
677 if (!dkim_canon_expanded) /* expansion error, do not send message. */
678 { errwhen = US"dkim_canon"; goto expand_bad; }
680 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
681 pdkim_canon = PDKIM_CANON_RELAXED;
682 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
683 pdkim_canon = PDKIM_CANON_SIMPLE;
686 log_write(0, LOG_MAIN,
687 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
688 dkim_canon_expanded);
689 pdkim_canon = PDKIM_CANON_RELAXED;
692 GET_OPTION("dkim_sign_headers");
693 if ( dkim->dkim_sign_headers
694 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
695 { errwhen = US"dkim_sign_header"; goto expand_bad; }
696 /* else pass NULL, which means default header list */
698 /* Get private key to use. */
700 GET_OPTION("dkim_private_key");
701 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
702 { errwhen = US"dkim_private_key"; goto expand_bad; }
704 if ( Ustrlen(dkim_private_key_expanded) == 0
705 || Ustrcmp(dkim_private_key_expanded, "0") == 0
706 || Ustrcmp(dkim_private_key_expanded, "false") == 0
708 continue; /* don't sign, but no error */
710 if ( dkim_private_key_expanded[0] == '/'
711 && !(dkim_private_key_expanded =
712 expand_file_big_buffer(dkim_private_key_expanded)))
715 GET_OPTION("dkim_hash");
716 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
717 { errwhen = US"dkim_hash"; goto expand_bad; }
719 GET_OPTION("dkim_identity");
720 if (dkim->dkim_identity)
721 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
722 { errwhen = US"dkim_identity"; goto expand_bad; }
723 else if (!*dkim_identity_expanded)
724 dkim_identity_expanded = NULL;
726 GET_OPTION("dkim_timestamps");
727 if (dkim->dkim_timestamps)
728 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
729 { errwhen = US"dkim_timestamps"; goto expand_bad; }
732 tval = (unsigned long) time(NULL);
733 xval = strtoul(CCS dkim_timestamps_expanded, NULL, 10);
738 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
739 dkim_signing_selector,
740 dkim_private_key_expanded,
745 dkim_private_key_expanded[0] = '\0';
747 pdkim_set_optional(sig,
748 CS dkim_sign_headers_expanded,
749 CS dkim_identity_expanded,
751 pdkim_canon, -1, tval, xval);
753 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
756 dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_domain);
757 dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_selector);
759 if (!dkim_sign_ctx.sig) /* link sig to context chain */
760 dkim_sign_ctx.sig = sig;
763 pdkim_signature * n = dkim_sign_ctx.sig;
764 while (n->next) n = n->next;
770 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
771 produce, if some other package (eg. ARC) is signing. */
773 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
775 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
776 sigbuf = string_get(1); /* return a zero-len string */
780 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
783 if (lseek(fd, off, SEEK_SET) < 0)
786 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
787 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
790 /* Handle failed read above. */
793 debug_printf("DKIM: Error reading -K file.\n");
798 /* Build string of headers, one per signature */
800 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
805 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
806 sigbuf = string_get(1); /* return a zero-len string */
808 else for (sigbuf = NULL; sig; sig = sig->next)
809 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
813 (void) string_from_gstring(sigbuf);
814 store_pool = old_pool;
819 log_write(0, LOG_MAIN|LOG_PANIC,
820 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
826 *errstr = string_sprintf("failed to expand %s: %s",
827 errwhen, expand_string_message);
828 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
836 authres_dkim(gstring * g)
838 int start = 0; /* compiler quietening */
840 DEBUG(D_acl) start = gstring_length(g);
842 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
844 g = string_catn(g, US";\n\tdkim=", 8);
846 if (sig->verify_status & PDKIM_VERIFY_POLICY)
847 g = string_append(g, 5,
848 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
849 else switch(sig->verify_status)
851 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
852 case PDKIM_VERIFY_INVALID:
853 switch (sig->verify_ext_status)
855 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
856 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
857 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
858 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
859 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
860 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
861 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
863 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
864 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
866 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
867 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
870 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
873 case PDKIM_VERIFY_FAIL:
874 switch (sig->verify_ext_status)
876 case PDKIM_VERIFY_FAIL_BODY:
878 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
880 case PDKIM_VERIFY_FAIL_MESSAGE:
882 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
884 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
885 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
888 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
892 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
893 default: g = string_cat(g, US"permerror"); break;
895 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
896 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
897 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
898 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
902 if (gstring_length(g) == start)
903 debug_printf("DKIM:\tno authres\n");
905 debug_printf("DKIM:\tauthres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
910 # endif /*!MACRO_PREDEF*/
911 #endif /*!DISABLE_DKIM*/