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);
345 gstring_release_unused(g);
346 dkim_signers = string_from_gstring(g);
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 identity '%s' domain '%s' sel '%s'\n",
362 id, dkim_signing_domain, dkim_signing_selector);
364 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
365 dkim_exim_verify_log_sig(dkim_cur_sig);
366 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
372 /* For the given identity, run the DKIM ACL once for each matching signature.
373 If none match, run it once.
376 id Identity to look for in dkim signatures
377 res_ptr ptr to growable string-list of status results,
378 appended to per ACL run
379 user_msgptr where to put a user error (for SMTP response)
380 log_msgptr where to put a logging message (not for SMTP response)
382 Returns: OK access is granted by an ACCEPT verb
383 DISCARD access is granted by a DISCARD verb
384 FAIL access is denied
385 FAIL_DROP access is denied; drop the connection
386 DEFER can't tell at the moment
391 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
392 uschar ** user_msgptr, uschar ** log_msgptr)
397 dkim_verify_status = US"none";
398 dkim_verify_reason = US"";
399 dkim_cur_signer = id;
401 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
404 /* Find signatures to run ACL on */
406 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
407 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
408 && strcmpic(cmp_val, id) == 0
411 /* The "dkim_domain" and "dkim_selector" expansion variables have
412 related globals, since they are used in the signing code too.
413 Instead of inventing separate names for verification, we set
414 them here. This is easy since a domain and selector is guaranteed
415 to be in a signature. The other dkim_* expansion items are
416 dynamically fetched from dkim_cur_sig at expansion time (see
417 dkim_exim_expand_query() below). */
420 dkim_signing_domain = US sig->domain;
421 dkim_signing_selector = US sig->selector;
422 dkim_key_length = sig->keybits;
424 /* These two return static strings, so we can compare the addr
425 later to see if the ACL overwrote them. Check that when logging */
427 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
428 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
430 if ( (rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK
431 || dkim_verify_minimal && Ustrcmp(dkim_verify_status, "pass") == 0)
438 /* No matching sig found. Call ACL once anyway. */
441 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
446 dkim_exim_expand_defaults(int what)
450 case DKIM_ALGO: return US"";
451 case DKIM_BODYLENGTH: return US"9999999999999";
452 case DKIM_CANON_BODY: return US"";
453 case DKIM_CANON_HEADERS: return US"";
454 case DKIM_COPIEDHEADERS: return US"";
455 case DKIM_CREATED: return US"0";
456 case DKIM_EXPIRES: return US"9999999999999";
457 case DKIM_HEADERNAMES: return US"";
458 case DKIM_IDENTITY: return US"";
459 case DKIM_KEY_GRANULARITY: return US"*";
460 case DKIM_KEY_SRVTYPE: return US"*";
461 case DKIM_KEY_NOTES: return US"";
462 case DKIM_KEY_TESTING: return US"0";
463 case DKIM_NOSUBDOMAINS: return US"0";
464 case DKIM_VERIFY_STATUS: return US"none";
465 case DKIM_VERIFY_REASON: return US"";
466 default: return US"";
472 dkim_exim_expand_query(int what)
474 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
475 return dkim_exim_expand_defaults(what);
480 return dkim_sig_to_a_tag(dkim_cur_sig);
482 case DKIM_BODYLENGTH:
483 return dkim_cur_sig->bodylength >= 0
484 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
485 : dkim_exim_expand_defaults(what);
487 case DKIM_CANON_BODY:
488 switch (dkim_cur_sig->canon_body)
490 case PDKIM_CANON_RELAXED: return US"relaxed";
491 case PDKIM_CANON_SIMPLE:
492 default: return US"simple";
495 case DKIM_CANON_HEADERS:
496 switch (dkim_cur_sig->canon_headers)
498 case PDKIM_CANON_RELAXED: return US"relaxed";
499 case PDKIM_CANON_SIMPLE:
500 default: return US"simple";
503 case DKIM_COPIEDHEADERS:
504 return dkim_cur_sig->copiedheaders
505 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
508 return dkim_cur_sig->created > 0
509 ? string_sprintf("%lu", dkim_cur_sig->created)
510 : dkim_exim_expand_defaults(what);
513 return dkim_cur_sig->expires > 0
514 ? string_sprintf("%lu", dkim_cur_sig->expires)
515 : dkim_exim_expand_defaults(what);
517 case DKIM_HEADERNAMES:
518 return dkim_cur_sig->headernames
519 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
522 return dkim_cur_sig->identity
523 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
525 case DKIM_KEY_GRANULARITY:
526 return dkim_cur_sig->pubkey
527 ? dkim_cur_sig->pubkey->granularity
528 ? US dkim_cur_sig->pubkey->granularity
529 : dkim_exim_expand_defaults(what)
530 : dkim_exim_expand_defaults(what);
532 case DKIM_KEY_SRVTYPE:
533 return dkim_cur_sig->pubkey
534 ? dkim_cur_sig->pubkey->srvtype
535 ? US dkim_cur_sig->pubkey->srvtype
536 : dkim_exim_expand_defaults(what)
537 : dkim_exim_expand_defaults(what);
540 return dkim_cur_sig->pubkey
541 ? dkim_cur_sig->pubkey->notes
542 ? US dkim_cur_sig->pubkey->notes
543 : dkim_exim_expand_defaults(what)
544 : dkim_exim_expand_defaults(what);
546 case DKIM_KEY_TESTING:
547 return dkim_cur_sig->pubkey
548 ? dkim_cur_sig->pubkey->testing
550 : dkim_exim_expand_defaults(what)
551 : dkim_exim_expand_defaults(what);
553 case DKIM_NOSUBDOMAINS:
554 return dkim_cur_sig->pubkey
555 ? dkim_cur_sig->pubkey->no_subdomaining
557 : dkim_exim_expand_defaults(what)
558 : dkim_exim_expand_defaults(what);
560 case DKIM_VERIFY_STATUS:
561 switch (dkim_cur_sig->verify_status)
563 case PDKIM_VERIFY_INVALID: return US"invalid";
564 case PDKIM_VERIFY_FAIL: return US"fail";
565 case PDKIM_VERIFY_PASS: return US"pass";
566 case PDKIM_VERIFY_NONE:
567 default: return US"none";
570 case DKIM_VERIFY_REASON:
571 switch (dkim_cur_sig->verify_ext_status)
573 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
574 return US"pubkey_unavailable";
575 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
576 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
577 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
578 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
579 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
589 dkim_exim_sign_init(void)
591 int old_pool = store_pool;
594 store_pool = POOL_MAIN;
595 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
596 store_pool = old_pool;
600 /* Generate signatures for the given file.
601 If a prefix is given, prepend it to the file for the calculations.
604 NULL: error; error string written
605 string: signature header(s), or a zero-length string (not an error)
609 dkim_exim_sign(int fd, off_t off, uschar * prefix,
610 struct ob_dkim * dkim, const uschar ** errstr)
612 const uschar * dkim_domain = NULL;
614 gstring * seen_doms = NULL;
615 pdkim_signature * sig;
621 int old_pool = store_pool;
625 if (dkim->dot_stuffed)
626 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
628 store_pool = POOL_MAIN;
630 GET_OPTION("dkim_domain");
631 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
632 /* expansion error, do not send message. */
633 { errwhen = US"dkim_domain"; goto expand_bad; }
635 /* Set $dkim_domain expansion variable to each unique domain in list. */
638 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
640 const uschar * dkim_sel;
643 if (dkim_signing_domain[0] == '\0')
646 /* Only sign once for each domain, no matter how often it
647 appears in the expanded list. */
649 dkim_signing_domain = string_copylc(dkim_signing_domain);
650 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
651 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
654 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
656 /* Set $dkim_selector expansion variable to each selector in list,
659 GET_OPTION("dkim_selector");
660 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
661 { errwhen = US"dkim_selector"; goto expand_bad; }
663 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
666 uschar * dkim_canon_expanded;
668 uschar * dkim_sign_headers_expanded = NULL;
669 uschar * dkim_private_key_expanded;
670 uschar * dkim_hash_expanded;
671 uschar * dkim_identity_expanded = NULL;
672 uschar * dkim_timestamps_expanded = NULL;
673 unsigned long tval = 0, xval = 0;
675 /* Get canonicalization to use */
677 GET_OPTION("dkim_canon");
678 dkim_canon_expanded = dkim->dkim_canon
679 ? expand_string(dkim->dkim_canon) : US"relaxed";
680 if (!dkim_canon_expanded) /* expansion error, do not send message. */
681 { errwhen = US"dkim_canon"; goto expand_bad; }
683 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
684 pdkim_canon = PDKIM_CANON_RELAXED;
685 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
686 pdkim_canon = PDKIM_CANON_SIMPLE;
689 log_write(0, LOG_MAIN,
690 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
691 dkim_canon_expanded);
692 pdkim_canon = PDKIM_CANON_RELAXED;
695 GET_OPTION("dkim_sign_headers");
696 if ( dkim->dkim_sign_headers
697 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
698 { errwhen = US"dkim_sign_header"; goto expand_bad; }
699 /* else pass NULL, which means default header list */
701 /* Get private key to use. */
703 GET_OPTION("dkim_private_key");
704 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
705 { errwhen = US"dkim_private_key"; goto expand_bad; }
707 if ( Ustrlen(dkim_private_key_expanded) == 0
708 || Ustrcmp(dkim_private_key_expanded, "0") == 0
709 || Ustrcmp(dkim_private_key_expanded, "false") == 0
711 continue; /* don't sign, but no error */
713 if ( dkim_private_key_expanded[0] == '/'
714 && !(dkim_private_key_expanded =
715 expand_file_big_buffer(dkim_private_key_expanded)))
718 GET_OPTION("dkim_hash");
719 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
720 { errwhen = US"dkim_hash"; goto expand_bad; }
722 GET_OPTION("dkim_identity");
723 if (dkim->dkim_identity)
724 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
725 { errwhen = US"dkim_identity"; goto expand_bad; }
726 else if (!*dkim_identity_expanded)
727 dkim_identity_expanded = NULL;
729 GET_OPTION("dkim_timestamps");
730 if (dkim->dkim_timestamps)
731 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
732 { errwhen = US"dkim_timestamps"; goto expand_bad; }
735 tval = (unsigned long) time(NULL);
736 xval = strtoul(CCS dkim_timestamps_expanded, NULL, 10);
741 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
742 dkim_signing_selector,
743 dkim_private_key_expanded,
748 dkim_private_key_expanded[0] = '\0';
750 pdkim_set_optional(sig,
751 CS dkim_sign_headers_expanded,
752 CS dkim_identity_expanded,
754 pdkim_canon, -1, tval, xval);
756 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
759 dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_domain);
760 dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_selector);
762 if (!dkim_sign_ctx.sig) /* link sig to context chain */
763 dkim_sign_ctx.sig = sig;
766 pdkim_signature * n = dkim_sign_ctx.sig;
767 while (n->next) n = n->next;
773 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
774 produce, if some other package (eg. ARC) is signing. */
776 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
778 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
779 sigbuf = string_get(1); /* return a zero-len string */
783 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
786 if (lseek(fd, off, SEEK_SET) < 0)
789 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
790 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
793 /* Handle failed read above. */
796 debug_printf("DKIM: Error reading -K file.\n");
801 /* Build string of headers, one per signature */
803 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
808 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
809 sigbuf = string_get(1); /* return a zero-len string */
811 else for (sigbuf = NULL; sig; sig = sig->next)
812 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
816 (void) string_from_gstring(sigbuf);
817 store_pool = old_pool;
822 log_write(0, LOG_MAIN|LOG_PANIC,
823 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
829 *errstr = string_sprintf("failed to expand %s: %s",
830 errwhen, expand_string_message);
831 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
839 authres_dkim(gstring * g)
841 int start = 0; /* compiler quietening */
843 DEBUG(D_acl) start = gstring_length(g);
845 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
847 g = string_catn(g, US";\n\tdkim=", 8);
849 if (sig->verify_status & PDKIM_VERIFY_POLICY)
850 g = string_append(g, 5,
851 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
852 else switch(sig->verify_status)
854 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
855 case PDKIM_VERIFY_INVALID:
856 switch (sig->verify_ext_status)
858 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
859 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
860 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
861 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
862 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
863 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
864 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
866 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
867 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
869 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
870 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
873 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
876 case PDKIM_VERIFY_FAIL:
877 switch (sig->verify_ext_status)
879 case PDKIM_VERIFY_FAIL_BODY:
881 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
883 case PDKIM_VERIFY_FAIL_MESSAGE:
885 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
887 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
888 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
891 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
895 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
896 default: g = string_cat(g, US"permerror"); break;
898 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
899 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
900 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
901 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
905 if (gstring_length(g) == start)
906 debug_printf("DKIM:\tno authres\n");
908 debug_printf("DKIM:\tauthres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
913 # endif /*!MACRO_PREDEF*/
914 #endif /*!DISABLE_DKIM*/