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 */
21 # include "../macro_predef.h"
26 builtin_macro_create_var(US"_DKIM_SIGN_HEADERS", US PDKIM_DEFAULT_SIGN_HEADERS);
27 builtin_macro_create_var(US"_DKIM_OVERSIGN_HEADERS", US PDKIM_OVERSIGN_HEADERS);
29 # else /*!MACRO_PREDEF*/
33 uschar *dkim_verify_hashes = US"sha256:sha512";
34 uschar *dkim_verify_keytypes = US"ed25519:rsa";
35 uschar *dkim_verify_min_keysizes = US"rsa=1024 ed25519=250";
36 BOOL dkim_verify_minimal = FALSE;
37 uschar *dkim_verify_signers = US"$dkim_signers";
41 uschar *dkim_cur_signer = NULL;
42 int dkim_key_length = 0;
43 uschar *dkim_signers = NULL;
44 uschar *dkim_signing_domain = NULL;
45 uschar *dkim_signing_selector = NULL;
46 uschar *dkim_verify_reason = NULL;
47 uschar *dkim_verify_status = NULL;
49 /* Working variables */
51 unsigned dkim_collect_input = 0;
52 void *dkim_signatures = NULL;
53 gstring *dkim_signing_record = NULL;
54 uschar *dkim_vdom_firstpass = NULL;
57 extern BOOL dkim_transport_write_message(transport_ctx *,
58 struct ob_dkim *, const uschar ** errstr);
60 /****************************************/
62 pdkim_ctx dkim_sign_ctx;
64 int dkim_verify_oldpool;
65 pdkim_ctx * dkim_verify_ctx = NULL;
66 pdkim_signature *dkim_cur_sig = NULL;
67 static const uschar * dkim_collect_error = NULL;
69 #define DKIM_MAX_SIGNATURES 20
70 static void dkim_exim_verify_pause(BOOL pause);
73 /****************************************/
75 /* Look up the DKIM record in DNS for the given hostname.
76 Will use the first found if there are multiple.
77 The return string is tainted, having come from off-site.
81 dkim_exim_query_dns_txt(const uschar * name)
83 dns_answer * dnsa = store_get_dns_answer();
85 rmark reset_point = store_mark();
86 gstring * g = string_get_tainted(256, GET_TAINTED);
88 lookup_dnssec_authenticated = NULL;
89 if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
92 /* Search for TXT record */
94 for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
96 rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
97 if (rr->type == T_TXT)
98 { /* Copy record content to the answer buffer */
99 for (int rr_offset = 0; rr_offset < rr->size; )
101 uschar len = rr->data[rr_offset++];
103 g = string_catn(g, US(rr->data + rr_offset), len);
104 if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
110 /* Check if this looks like a DKIM record */
111 if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
113 store_free_dns_answer(dnsa);
114 gstring_release_unused(g);
115 return string_from_gstring(g);
118 gstring_reset(g); /* overwrite previous record */
122 store_reset(reset_point);
123 store_free_dns_answer(dnsa);
124 return NULL; /*XXX better error detail? logging? */
129 #ifdef EXPERIMENTAL_ARC
130 /* Module API: Lookup a DNS DKIM record and parse the pubkey.
133 dnsname record to lookup in DNS
134 pubkey_p pointer for return of pubkey
135 hashes_p pointer for return of hashes
137 Return: srvtype, or NULL on error
140 static const uschar *
141 dkim_exim_parse_dns_pubkey(const uschar * dnsname, blob ** pubkey_p,
142 const uschar ** hashes_p)
144 const uschar * dnstxt = dkim_exim_query_dns_txt(dnsname);
149 DEBUG(D_acl) debug_printf_indent("pubkey dns lookup fail\n");
152 if (!(p = pdkim_parse_pubkey_record(dnstxt)))
154 DEBUG(D_acl) debug_printf_indent("pubkey dns record format error\n");
158 *hashes_p = p->hashes;
167 FAIL verify did not pass
168 ERROR problem setting up the pubkey
172 dkim_exim_sig_verify(const blob * sighash, const blob * data_hash,
173 hashmethod hash, const blob * pubkey, const uschar ** errstr_p)
176 const uschar * errstr;
179 if ((errstr = exim_dkim_verify_init(pubkey, KEYFMT_DER, &vctx, NULL)))
181 else if ((errstr = exim_dkim_verify(&vctx, hash, data_hash, sighash)))
191 /****************************************/
194 dkim_exim_init(void * dummy)
196 if (f.dkim_init_done) return TRUE;
197 f.dkim_init_done = TRUE;
204 /* Module API: Set up for verification of a message being received.
209 dkim_exim_verify_init(void)
211 BOOL dot_stuffing = chunking_state <= CHUNKING_OFFERED;
213 if (!smtp_input || smtp_batched_input || f.dkim_disable_verify)
216 dkim_exim_init(NULL);
218 /* There is a store-reset between header & body reception for the main pool
219 (actually, after every header line) so cannot use that as we need the data we
220 store per-header, during header processing, at the end of body reception
221 for evaluating the signature. Any allocs done for dkim verify
222 memory-handling must use a different pool. We use a separate one that we
223 can reset per message. */
225 dkim_verify_oldpool = store_pool;
226 store_pool = POOL_MESSAGE;
228 /* Free previous context if there is one */
231 pdkim_free_ctx(dkim_verify_ctx);
233 /* Create new context */
235 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
236 dkim_exim_verify_pause(FALSE);
237 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
238 dkim_collect_error = NULL;
240 /* Start feed up with any cached data, but limited to message data */
241 receive_get_cache(chunking_state == CHUNKING_LAST
242 ? chunking_data_left : GETC_BUFFER_UNLIMITED);
244 store_pool = dkim_verify_oldpool;
249 /* Module API : Submit a chunk of data for verification input.
250 A NULL data pointer indicates end-of-message.
251 Only use the data when the feed is activated. */
254 dkim_exim_verify_feed(const uschar * data, unsigned len)
258 store_pool = POOL_MESSAGE;
259 if ( (dkim_collect_input || !data)
260 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
262 dkim_collect_error = pdkim_errstr(rc);
263 log_write(0, LOG_MAIN,
264 "DKIM: validation error: %.100s", dkim_collect_error);
265 dkim_collect_input = 0;
267 store_pool = dkim_verify_oldpool;
271 /* Module API: pause/resume the verification data feed */
274 dkim_exim_verify_pause(BOOL pause)
276 static unsigned save = 0;
277 static BOOL paused = FALSE;
282 { dkim_collect_input = save; paused = FALSE; }
286 { save = dkim_collect_input; dkim_collect_input = 0; paused = TRUE; }
289 /* Module API: Finish off the body hashes, calculate sigs and do compares */
292 dkim_exim_verify_finish(void)
296 const uschar * errstr = NULL;
298 store_pool = POOL_MESSAGE;
300 /* Delete eventual previous signature chain */
303 dkim_signatures = NULL;
305 if (dkim_collect_error)
307 log_write(0, LOG_MAIN,
308 "DKIM: Error during validation, disabling signature verification: %.100s",
310 f.dkim_disable_verify = TRUE;
314 dkim_collect_input = 0;
316 /* Finish DKIM operation and fetch link to signatures chain */
318 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
320 if (rc != PDKIM_OK && errstr)
321 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
323 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
325 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
327 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
328 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
330 gstring_release_unused(g);
331 dkim_signers = string_from_gstring(g);
334 store_pool = dkim_verify_oldpool;
339 /* Log the result for the given signature */
341 dkim_exim_verify_log_sig(pdkim_signature * sig)
348 /* Remember the domain for the first pass result */
350 if ( !dkim_vdom_firstpass
351 && dkim_verify_status
352 ? Ustrcmp(dkim_verify_status, US"pass") == 0
353 : sig->verify_status == PDKIM_VERIFY_PASS
355 dkim_vdom_firstpass= string_copy(sig->domain);
357 /* Rewrite the sig result if the ACL overrode it. This is only
358 needed because the DMARC code (sigh) peeks at the dkim sigs.
359 Mark the sig for this having been done. */
361 if ( dkim_verify_status
362 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
363 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
365 { /* overridden by ACL */
366 sig->verify_ext_status = -1;
367 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
368 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
369 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
370 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
371 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
372 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
373 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
374 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
376 sig->verify_status = -1;
379 if (!LOGGING(dkim_verbose)) return;
382 logmsg = string_catn(NULL, US"DKIM: ", 6);
383 if (!(s = sig->domain)) s = US"<UNSET>";
384 logmsg = string_append(logmsg, 2, "d=", s);
385 if (!(s = sig->selector)) s = US"<UNSET>";
386 logmsg = string_append(logmsg, 2, " s=", s);
387 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
388 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
389 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
390 dkim_sig_to_a_tag(sig),
391 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
392 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
393 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
395 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
397 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
400 if (sig->verify_status & PDKIM_VERIFY_POLICY)
401 logmsg = string_append(logmsg, 5,
402 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
404 switch (sig->verify_status)
406 case PDKIM_VERIFY_NONE:
407 logmsg = string_cat(logmsg, US" [not verified]");
410 case PDKIM_VERIFY_INVALID:
411 logmsg = string_cat(logmsg, US" [invalid - ");
412 switch (sig->verify_ext_status)
414 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
415 logmsg = string_cat(logmsg,
416 US"public key record (currently?) unavailable]");
419 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
420 logmsg = string_cat(logmsg, US"overlong public key record]");
423 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
424 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
425 logmsg = string_cat(logmsg, US"syntax error in public key record]");
428 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
429 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
432 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
433 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
437 logmsg = string_cat(logmsg, US"unspecified problem]");
441 case PDKIM_VERIFY_FAIL:
442 logmsg = string_cat(logmsg, US" [verification failed - ");
443 switch (sig->verify_ext_status)
445 case PDKIM_VERIFY_FAIL_BODY:
446 logmsg = string_cat(logmsg,
447 US"body hash mismatch (body probably modified in transit)]");
450 case PDKIM_VERIFY_FAIL_MESSAGE:
451 logmsg = string_cat(logmsg,
452 US"signature did not verify "
453 "(headers probably modified in transit)]");
456 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
457 logmsg = string_cat(logmsg,
458 US"signature invalid (key too short)]");
462 logmsg = string_cat(logmsg, US"unspecified reason]");
466 case PDKIM_VERIFY_PASS:
467 logmsg = string_cat(logmsg, US" [verification succeeded]");
471 log_write(0, LOG_MAIN, "%Y", logmsg);
476 /* Module API: Log a line for each signature */
479 dkim_exim_verify_log_all(void)
481 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
482 dkim_exim_verify_log_sig(sig);
486 /* Module API: append a log element with domain for the first passing sig */
489 dkim_exim_vdom_firstpass(gstring * g)
491 if (dkim_vdom_firstpass)
492 g = string_append(g, 2, US" DKIM=", dkim_vdom_firstpass);
497 /* For one signature, run the DKIM ACL, log the sig result,
498 and append ths sig status to the status list.
500 Args as per dkim_exim_acl_run() below */
503 dkim_acl_call(uschar * id, gstring ** res_ptr,
504 uschar ** user_msgptr, uschar ** log_msgptr)
508 debug_printf("calling acl_smtp_dkim for identity '%s' domain '%s' sel '%s'\n",
509 id, dkim_signing_domain, dkim_signing_selector);
511 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
512 dkim_exim_verify_log_sig(dkim_cur_sig);
513 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
519 /* For the given identity, run the DKIM ACL once for each matching signature.
520 If none match, run it once.
523 id Identity to look for in dkim signatures
524 res_ptr ptr to growable string-list of status results,
525 appended to per ACL run
526 user_msgptr where to put a user error (for SMTP response)
527 log_msgptr where to put a logging message (not for SMTP response)
529 Returns: OK access is granted by an ACCEPT verb
530 DISCARD access is granted by a DISCARD verb
531 FAIL access is denied
532 FAIL_DROP access is denied; drop the connection
533 DEFER can't tell at the moment
538 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
539 uschar ** user_msgptr, uschar ** log_msgptr)
544 dkim_verify_status = US"none";
545 dkim_verify_reason = US"";
546 dkim_cur_signer = id;
548 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
551 /* Find signatures to run ACL on */
553 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
554 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
555 && strcmpic(cmp_val, id) == 0
558 /* The "dkim_domain" and "dkim_selector" expansion variables have
559 related globals, since they are used in the signing code too.
560 Instead of inventing separate names for verification, we set
561 them here. This is easy since a domain and selector is guaranteed
562 to be in a signature. The other dkim_* expansion items are
563 dynamically fetched from dkim_cur_sig at expansion time (see
564 dkim_exim_expand_query() below). */
567 dkim_signing_domain = US sig->domain;
568 dkim_signing_selector = US sig->selector;
569 dkim_key_length = sig->keybits;
571 /* These two return static strings, so we can compare the addr
572 later to see if the ACL overwrote them. Check that when logging */
574 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
575 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
577 if ( (rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK
578 || dkim_verify_minimal && Ustrcmp(dkim_verify_status, "pass") == 0)
585 /* No matching sig found. Call ACL once anyway. */
588 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
593 Loop over dkim_verify_signers option doing ACL calls. If one return any
594 non-OK value stop and return that, else return OK.
598 /*XXX need a user_msgptr */
599 dkim_exim_acl_entry(uschar ** user_msgptr, uschar ** log_msgptr)
603 GET_OPTION("dkim_verify_signers");
604 if (dkim_verify_signers && *dkim_verify_signers)
606 const uschar * dkim_verify_signers_expanded =
607 expand_cstring(dkim_verify_signers);
608 gstring * results = NULL, * seen_items = NULL;
609 int signer_sep = 0, old_pool = store_pool;
611 if (!dkim_verify_signers_expanded)
613 log_write(0, LOG_MAIN|LOG_PANIC,
614 "expansion of dkim_verify_signers option failed: %s",
615 expand_string_message);
619 store_pool = POOL_PERM; /* Allow created variables to live to data ACL */
621 /* Loop over signers we want to verify, calling ACL. Default to OK
622 when no signers are present. Each call from here expands to an ACL
623 call per matching sig in the message. */
626 item = string_nextinlist(&dkim_verify_signers_expanded,
627 &signer_sep, NULL, 0); )
629 /* Prevent running ACL for an empty item */
630 if (!item || !*item) continue;
632 /* Only run ACL once for each domain or identity,
633 no matter how often it appears in the expanded list. */
637 const uschar * seen_items_list = string_from_gstring(seen_items);
639 BOOL seen_this_item = FALSE;
641 while ((seen_item = string_nextinlist(&seen_items_list, &seen_sep,
643 if (Ustrcmp(seen_item, item) == 0)
645 seen_this_item = TRUE;
652 debug_printf("acl_smtp_dkim: skipping signer %s, "
653 "already seen\n", item);
657 seen_items = string_catn(seen_items, US":", 1);
659 seen_items = string_cat(seen_items, item);
661 if ((rc = dkim_exim_acl_run(item, &results, user_msgptr, log_msgptr)) != OK)
664 debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
665 "skipping remaining items\n", rc, item);
668 if (dkim_verify_minimal && Ustrcmp(dkim_verify_status, "pass") == 0)
672 dkim_verify_status = string_from_gstring(results);
673 store_pool = old_pool;
676 dkim_exim_verify_log_all();
681 /******************************************************************************/
686 dkim_exim_signer_isinlist(const uschar * l)
688 return dkim_cur_signer
689 ? match_isinlist(dkim_cur_signer, &l, 0, NULL, NULL, MCL_STRING, TRUE, NULL)
696 dkim_exim_status_listmatch(const uschar * l)
697 { /* return good for any match */
698 const uschar * s = dkim_verify_status ? dkim_verify_status : US"none";
699 int sep = 0, rc = FAIL;
700 for (uschar * ss; ss = string_nextinlist(&s, &sep, NULL, 0); )
701 if ( (rc = match_isinlist(ss, &l, 0, NULL, NULL, MCL_STRING, TRUE, NULL))
706 /* Module API: Overwriteable dkim result variables */
709 dkim_exim_setvar(const uschar * name, void * val)
711 if (Ustrcmp(name, "dkim_verify_status") == 0)
712 dkim_verify_status = val;
713 else if (Ustrcmp(name, "dkim_verify_reason") == 0)
714 dkim_verify_reason = val;
717 /******************************************************************************/
720 dkim_smtp_reset(void)
722 dkim_cur_signer = dkim_signers =
723 dkim_signing_domain = dkim_signing_selector = dkim_signatures = NULL;
724 f.dkim_disable_verify = FALSE;
725 dkim_collect_input = 0;
726 dkim_vdom_firstpass = dkim_verify_status = dkim_verify_reason = NULL;
730 /******************************************************************************/
733 dkim_exim_expand_defaults(int what)
737 case DKIM_ALGO: return US"";
738 case DKIM_BODYLENGTH: return US"9999999999999";
739 case DKIM_CANON_BODY: return US"";
740 case DKIM_CANON_HEADERS: return US"";
741 case DKIM_COPIEDHEADERS: return US"";
742 case DKIM_CREATED: return US"0";
743 case DKIM_EXPIRES: return US"9999999999999";
744 case DKIM_HEADERNAMES: return US"";
745 case DKIM_IDENTITY: return US"";
746 case DKIM_KEY_GRANULARITY: return US"*";
747 case DKIM_KEY_SRVTYPE: return US"*";
748 case DKIM_KEY_NOTES: return US"";
749 case DKIM_KEY_TESTING: return US"0";
750 case DKIM_NOSUBDOMAINS: return US"0";
751 case DKIM_VERIFY_STATUS: return US"none";
752 case DKIM_VERIFY_REASON: return US"";
753 default: return US"";
758 /* Module API: return a computed value for a variable expansion */
761 dkim_exim_expand_query(int what)
763 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
764 return dkim_exim_expand_defaults(what);
769 return dkim_sig_to_a_tag(dkim_cur_sig);
771 case DKIM_BODYLENGTH:
772 return dkim_cur_sig->bodylength >= 0
773 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
774 : dkim_exim_expand_defaults(what);
776 case DKIM_CANON_BODY:
777 switch (dkim_cur_sig->canon_body)
779 case PDKIM_CANON_RELAXED: return US"relaxed";
780 case PDKIM_CANON_SIMPLE:
781 default: return US"simple";
784 case DKIM_CANON_HEADERS:
785 switch (dkim_cur_sig->canon_headers)
787 case PDKIM_CANON_RELAXED: return US"relaxed";
788 case PDKIM_CANON_SIMPLE:
789 default: return US"simple";
792 case DKIM_COPIEDHEADERS:
793 return dkim_cur_sig->copiedheaders
794 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
797 return dkim_cur_sig->created > 0
798 ? string_sprintf("%lu", dkim_cur_sig->created)
799 : dkim_exim_expand_defaults(what);
802 return dkim_cur_sig->expires > 0
803 ? string_sprintf("%lu", dkim_cur_sig->expires)
804 : dkim_exim_expand_defaults(what);
806 case DKIM_HEADERNAMES:
807 return dkim_cur_sig->headernames
808 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
811 return dkim_cur_sig->identity
812 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
814 case DKIM_KEY_GRANULARITY:
815 return dkim_cur_sig->pubkey
816 ? dkim_cur_sig->pubkey->granularity
817 ? US dkim_cur_sig->pubkey->granularity
818 : dkim_exim_expand_defaults(what)
819 : dkim_exim_expand_defaults(what);
821 case DKIM_KEY_SRVTYPE:
822 return dkim_cur_sig->pubkey
823 ? dkim_cur_sig->pubkey->srvtype
824 ? US dkim_cur_sig->pubkey->srvtype
825 : dkim_exim_expand_defaults(what)
826 : dkim_exim_expand_defaults(what);
829 return dkim_cur_sig->pubkey
830 ? dkim_cur_sig->pubkey->notes
831 ? US dkim_cur_sig->pubkey->notes
832 : dkim_exim_expand_defaults(what)
833 : dkim_exim_expand_defaults(what);
835 case DKIM_KEY_TESTING:
836 return dkim_cur_sig->pubkey
837 ? dkim_cur_sig->pubkey->testing
839 : dkim_exim_expand_defaults(what)
840 : dkim_exim_expand_defaults(what);
842 case DKIM_NOSUBDOMAINS:
843 return dkim_cur_sig->pubkey
844 ? dkim_cur_sig->pubkey->no_subdomaining
846 : dkim_exim_expand_defaults(what)
847 : dkim_exim_expand_defaults(what);
849 case DKIM_VERIFY_STATUS:
850 switch (dkim_cur_sig->verify_status)
852 case PDKIM_VERIFY_INVALID: return US"invalid";
853 case PDKIM_VERIFY_FAIL: return US"fail";
854 case PDKIM_VERIFY_PASS: return US"pass";
855 case PDKIM_VERIFY_NONE:
856 default: return US"none";
859 case DKIM_VERIFY_REASON:
860 switch (dkim_cur_sig->verify_ext_status)
862 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
863 return US"pubkey_unavailable";
864 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
865 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
866 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
867 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
868 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
880 dkim_exim_sign_init(void)
882 int old_pool = store_pool;
884 dkim_exim_init(NULL);
885 store_pool = POOL_MAIN;
886 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
887 store_pool = old_pool;
891 /* Generate signatures for the given file.
892 If a prefix is given, prepend it to the file for the calculations.
895 NULL: error; error string written
896 string: signature header(s), or a zero-length string (not an error)
900 dkim_exim_sign(int fd, off_t off, uschar * prefix,
901 struct ob_dkim * dkim, const uschar ** errstr)
903 const uschar * dkim_domain = NULL;
905 gstring * seen_doms = NULL;
906 pdkim_signature * sig;
912 int old_pool = store_pool;
916 if (dkim->dot_stuffed)
917 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
919 store_pool = POOL_MAIN;
921 GET_OPTION("dkim_domain");
922 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
923 /* expansion error, do not send message. */
924 { errwhen = US"dkim_domain"; goto expand_bad; }
926 /* Set $dkim_domain expansion variable to each unique domain in list. */
929 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
931 const uschar * dkim_sel;
934 if (dkim_signing_domain[0] == '\0')
937 /* Only sign once for each domain, no matter how often it
938 appears in the expanded list. */
940 dkim_signing_domain = string_copylc(dkim_signing_domain);
941 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
942 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
945 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
947 /* Set $dkim_selector expansion variable to each selector in list,
950 GET_OPTION("dkim_selector");
951 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
952 { errwhen = US"dkim_selector"; goto expand_bad; }
954 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
957 uschar * dkim_canon_expanded;
959 uschar * dkim_sign_headers_expanded = NULL;
960 uschar * dkim_private_key_expanded;
961 uschar * dkim_hash_expanded;
962 uschar * dkim_identity_expanded = NULL;
963 uschar * dkim_timestamps_expanded = NULL;
964 unsigned long tval = 0, xval = 0;
966 /* Get canonicalization to use */
968 GET_OPTION("dkim_canon");
969 dkim_canon_expanded = dkim->dkim_canon
970 ? expand_string(dkim->dkim_canon) : US"relaxed";
971 if (!dkim_canon_expanded) /* expansion error, do not send message. */
972 { errwhen = US"dkim_canon"; goto expand_bad; }
974 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
975 pdkim_canon = PDKIM_CANON_RELAXED;
976 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
977 pdkim_canon = PDKIM_CANON_SIMPLE;
980 log_write(0, LOG_MAIN,
981 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
982 dkim_canon_expanded);
983 pdkim_canon = PDKIM_CANON_RELAXED;
986 GET_OPTION("dkim_sign_headers");
987 if ( dkim->dkim_sign_headers
988 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
989 { errwhen = US"dkim_sign_header"; goto expand_bad; }
990 /* else pass NULL, which means default header list */
992 /* Get private key to use. */
994 GET_OPTION("dkim_private_key");
995 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
996 { errwhen = US"dkim_private_key"; goto expand_bad; }
998 if ( Ustrlen(dkim_private_key_expanded) == 0
999 || Ustrcmp(dkim_private_key_expanded, "0") == 0
1000 || Ustrcmp(dkim_private_key_expanded, "false") == 0
1002 continue; /* don't sign, but no error */
1004 if ( dkim_private_key_expanded[0] == '/'
1005 && !(dkim_private_key_expanded =
1006 expand_file_big_buffer(dkim_private_key_expanded)))
1009 GET_OPTION("dkim_hash");
1010 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
1011 { errwhen = US"dkim_hash"; goto expand_bad; }
1013 GET_OPTION("dkim_identity");
1014 if (dkim->dkim_identity)
1015 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
1016 { errwhen = US"dkim_identity"; goto expand_bad; }
1017 else if (!*dkim_identity_expanded)
1018 dkim_identity_expanded = NULL;
1020 GET_OPTION("dkim_timestamps");
1021 if (dkim->dkim_timestamps)
1022 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
1023 { errwhen = US"dkim_timestamps"; goto expand_bad; }
1026 tval = (unsigned long) time(NULL);
1027 xval = strtoul(CCS dkim_timestamps_expanded, NULL, 10);
1032 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
1033 dkim_signing_selector,
1034 dkim_private_key_expanded,
1039 dkim_private_key_expanded[0] = '\0';
1041 pdkim_set_optional(sig,
1042 CS dkim_sign_headers_expanded,
1043 CS dkim_identity_expanded,
1045 pdkim_canon, -1, tval, xval);
1047 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
1050 dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_domain);
1051 dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_selector);
1053 if (!dkim_sign_ctx.sig) /* link sig to context chain */
1054 dkim_sign_ctx.sig = sig;
1057 pdkim_signature * n = dkim_sign_ctx.sig;
1058 while (n->next) n = n->next;
1064 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
1065 produce, if some other package (eg. ARC) is signing. */
1067 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
1069 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
1070 sigbuf = string_get(1); /* return a zero-len string */
1074 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
1077 if (lseek(fd, off, SEEK_SET) < 0)
1080 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
1081 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
1084 /* Handle failed read above. */
1087 debug_printf("DKIM: Error reading -K file.\n");
1092 /* Build string of headers, one per signature */
1094 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
1099 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
1100 sigbuf = string_get(1); /* return a zero-len string */
1102 else for (sigbuf = NULL; sig; sig = sig->next)
1103 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
1107 (void) string_from_gstring(sigbuf);
1108 store_pool = old_pool;
1113 log_write(0, LOG_MAIN|LOG_PANIC,
1114 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
1120 *errstr = string_sprintf("failed to expand %s: %s",
1121 errwhen, expand_string_message);
1122 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
1128 #ifdef SUPPORT_DMARC
1132 static const pdkim_signature *
1133 dkim_sigs_list(void)
1135 return dkim_signatures;
1139 #ifdef EXPERIMENTAL_ARC
1143 dkim_hashname_to_type(const blob * name)
1145 return pdkim_hashname_to_hashtype(name->data, name->len);
1150 dkim_hashtype_to_method(int hashtype)
1152 return hashtype >= 0 ? pdkim_hashes[hashtype].exim_hashmethod : -1;
1157 dkim_hashname_to_method(const blob * name)
1159 return dkim_hashtype_to_method(dkim_hashname_to_type(name));
1162 /* Module API: Set up a body hashing method on the given signature-context
1163 (creates a new one if needed, or uses an already-present one).
1166 signing TRUE to use dkim's signing context, else dkim_verify_ctx
1167 canon canonicalization spec, text form
1168 hash hash spec, text form
1169 bodylen byte count for message body
1171 Return: pointer to hashing method struct
1174 static pdkim_bodyhash *
1175 dkim_set_bodyhash(BOOL signing,
1176 const blob * canon, const blob * hashname, long bodylen)
1178 int canon_head = -1, canon_body = -1;
1180 pdkim_cstring_to_canons(canon->data, canon->len, &canon_head, &canon_body);
1181 return pdkim_set_bodyhash(signing ? &dkim_sign_ctx: dkim_verify_ctx,
1182 dkim_hashname_to_type(hashname),
1187 /* Module API: Sign a blob of data (which might already be a hash, if
1188 Ed25519 or GCrypt signing).
1192 hm hash to be applied to the data
1193 privkey private key for siging, PEM format
1194 signature pointer for result blob
1196 Return: NULL, or error string on failure
1199 static const uschar *
1200 dkim_sign_blob(const blob * data, hashmethod hm, const uschar * privkey,
1204 const uschar * errstr;
1206 if ((errstr = exim_dkim_signing_init(privkey, &sctx)))
1207 { DEBUG(D_transport) debug_printf("signing key setup: %s\n", errstr); }
1208 else errstr = exim_dkim_sign(&sctx, hm, data, signature);
1213 #endif /*EXPERIMENTAL_ARC*/
1219 authres_dkim(gstring * g)
1221 int start = 0; /* compiler quietening */
1223 DEBUG(D_acl) start = gstring_length(g);
1225 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
1227 g = string_catn(g, US";\n\tdkim=", 8);
1229 if (sig->verify_status & PDKIM_VERIFY_POLICY)
1230 g = string_append(g, 5,
1231 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
1232 else switch(sig->verify_status)
1234 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
1235 case PDKIM_VERIFY_INVALID:
1236 switch (sig->verify_ext_status)
1238 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
1239 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
1240 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
1241 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
1242 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
1243 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
1244 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
1246 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
1247 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
1249 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
1250 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
1253 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
1256 case PDKIM_VERIFY_FAIL:
1257 switch (sig->verify_ext_status)
1259 case PDKIM_VERIFY_FAIL_BODY:
1261 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
1263 case PDKIM_VERIFY_FAIL_MESSAGE:
1265 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
1267 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
1268 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
1271 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
1275 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
1276 default: g = string_cat(g, US"permerror"); break;
1278 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
1279 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
1280 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
1281 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
1285 if (gstring_length(g) == start)
1286 debug_printf("DKIM:\tno authres\n");
1288 debug_printf("DKIM:\tauthres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
1292 /******************************************************************************/
1295 static optionlist dkim_options[] = {
1296 { "acl_smtp_dkim", opt_stringptr, {&acl_smtp_dkim} },
1297 { "dkim_verify_hashes", opt_stringptr, {&dkim_verify_hashes} },
1298 { "dkim_verify_keytypes", opt_stringptr, {&dkim_verify_keytypes} },
1299 { "dkim_verify_min_keysizes", opt_stringptr, {&dkim_verify_min_keysizes} },
1300 { "dkim_verify_minimal", opt_bool, {&dkim_verify_minimal} },
1301 { "dkim_verify_signers", opt_stringptr, {&dkim_verify_signers} },
1304 static void * dkim_functions[] = {
1305 [DKIM_VERIFY_FEED] = (void *) dkim_exim_verify_feed,
1306 [DKIM_VERIFY_PAUSE] = (void *) dkim_exim_verify_pause,
1307 [DKIM_VERIFY_FINISH] = (void *) dkim_exim_verify_finish,
1308 [DKIM_ACL_ENTRY] = (void *) dkim_exim_acl_entry,
1309 [DKIM_VERIFY_LOG_ALL] = (void *) dkim_exim_verify_log_all,
1310 [DKIM_VDOM_FIRSTPASS] = (void *) dkim_exim_vdom_firstpass,
1312 [DKIM_SIGNER_ISINLIST] = (void *) dkim_exim_signer_isinlist,
1313 [DKIM_STATUS_LISTMATCH] = (void *) dkim_exim_status_listmatch,
1315 [DKIM_SETVAR] = (void *) dkim_exim_setvar,
1316 [DKIM_EXPAND_QUERY] = (void *) dkim_exim_expand_query,
1318 [DKIM_TRANSPORT_INIT] = (void *) dkim_exim_sign_init,
1319 [DKIM_TRANSPORT_WRITE] = (void *) dkim_transport_write_message,
1321 #ifdef SUPPORT_DMARC
1322 [DKIM_SIGS_LIST] = (void *) dkim_sigs_list,
1324 #ifdef EXPERIMENTAL_ARC
1325 [DKIM_HASHNAME_TO_TYPE] = (void *) dkim_hashname_to_type,
1326 [DKIM_HASHTYPE_TO_METHOD] = (void *) dkim_hashtype_to_method,
1327 [DKIM_HASHNAME_TO_METHOD] = (void *) dkim_hashname_to_method,
1328 [DKIM_SET_BODYHASH] = (void *) dkim_set_bodyhash,
1329 [DKIM_DNS_PUBKEY] = (void *) dkim_exim_parse_dns_pubkey,
1330 [DKIM_SIG_VERIFY] = (void *) dkim_exim_sig_verify,
1331 [DKIM_HEADER_RELAX] = (void *) pdkim_relax_header_n,
1332 [DKIM_SIGN_DATA] = (void *) dkim_sign_blob,
1336 static var_entry dkim_variables[] = {
1337 { "dkim_algo", vtype_dkim, (void *)DKIM_ALGO },
1338 { "dkim_bodylength", vtype_dkim, (void *)DKIM_BODYLENGTH },
1339 { "dkim_canon_body", vtype_dkim, (void *)DKIM_CANON_BODY },
1340 { "dkim_canon_headers", vtype_dkim, (void *)DKIM_CANON_HEADERS },
1341 { "dkim_copiedheaders", vtype_dkim, (void *)DKIM_COPIEDHEADERS },
1342 { "dkim_created", vtype_dkim, (void *)DKIM_CREATED },
1343 { "dkim_cur_signer", vtype_stringptr, &dkim_cur_signer },
1344 { "dkim_domain", vtype_stringptr, &dkim_signing_domain },
1345 { "dkim_expires", vtype_dkim, (void *)DKIM_EXPIRES },
1346 { "dkim_headernames", vtype_dkim, (void *)DKIM_HEADERNAMES },
1347 { "dkim_identity", vtype_dkim, (void *)DKIM_IDENTITY },
1348 { "dkim_key_granularity",vtype_dkim, (void *)DKIM_KEY_GRANULARITY },
1349 { "dkim_key_length", vtype_int, &dkim_key_length },
1350 { "dkim_key_nosubdomains",vtype_dkim, (void *)DKIM_NOSUBDOMAINS },
1351 { "dkim_key_notes", vtype_dkim, (void *)DKIM_KEY_NOTES },
1352 { "dkim_key_srvtype", vtype_dkim, (void *)DKIM_KEY_SRVTYPE },
1353 { "dkim_key_testing", vtype_dkim, (void *)DKIM_KEY_TESTING },
1354 { "dkim_selector", vtype_stringptr, &dkim_signing_selector },
1355 { "dkim_signers", vtype_stringptr, &dkim_signers },
1356 { "dkim_verify_reason", vtype_stringptr, &dkim_verify_reason },
1357 { "dkim_verify_status", vtype_stringptr, &dkim_verify_status },
1360 misc_module_info dkim_module_info = {
1363 .dyn_magic = MISC_MODULE_MAGIC,
1365 .init = dkim_exim_init,
1366 .msg_init = dkim_exim_verify_init,
1367 .authres = authres_dkim,
1368 .smtp_reset = dkim_smtp_reset,
1370 .options = dkim_options,
1371 .options_count = nelem(dkim_options),
1373 .functions = dkim_functions,
1374 .functions_count = nelem(dkim_functions),
1376 .variables = dkim_variables,
1377 .variables_count = nelem(dkim_variables),
1380 # endif /*!MACRO_PREDEF*/
1381 #endif /*!DISABLE_DKIM*/