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 /* Module API: Lookup a DNS DKIM record and parse the pubkey.
132 dnsname record to lookup in DNS
133 pubkey_p pointer for return of pubkey
134 hashes_p pointer for return of hashes
136 Return: srvtype, or NULL on error
139 static const uschar *
140 dkim_exim_parse_dns_pubkey(const uschar * dnsname, blob ** pubkey_p,
141 const uschar ** hashes_p)
143 const uschar * dnstxt = dkim_exim_query_dns_txt(dnsname);
148 DEBUG(D_acl) debug_printf_indent("pubkey dns lookup fail\n");
151 if (!(p = pdkim_parse_pubkey_record(dnstxt)))
153 DEBUG(D_acl) debug_printf_indent("pubkey dns record format error\n");
157 *hashes_p = p->hashes;
166 FAIL verify did not pass
167 ERROR problem setting up the pubkey
171 dkim_exim_sig_verify(const blob * sighash, const blob * data_hash,
172 hashmethod hash, const blob * pubkey, const uschar ** errstr_p)
175 const uschar * errstr;
178 if ((errstr = exim_dkim_verify_init(pubkey, KEYFMT_DER, &vctx, NULL)))
180 else if ((errstr = exim_dkim_verify(&vctx, hash, data_hash, sighash)))
189 /****************************************/
192 dkim_exim_init(void * dummy)
194 if (f.dkim_init_done) return TRUE;
195 f.dkim_init_done = TRUE;
202 /* Module API: Set up for verification of a message being received.
207 dkim_exim_verify_init(void)
209 BOOL dot_stuffing = chunking_state <= CHUNKING_OFFERED;
211 if (!smtp_input || smtp_batched_input || f.dkim_disable_verify)
214 dkim_exim_init(NULL);
216 /* There is a store-reset between header & body reception for the main pool
217 (actually, after every header line) so cannot use that as we need the data we
218 store per-header, during header processing, at the end of body reception
219 for evaluating the signature. Any allocs done for dkim verify
220 memory-handling must use a different pool. We use a separate one that we
221 can reset per message. */
223 dkim_verify_oldpool = store_pool;
224 store_pool = POOL_MESSAGE;
226 /* Free previous context if there is one */
229 pdkim_free_ctx(dkim_verify_ctx);
231 /* Create new context */
233 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
234 dkim_exim_verify_pause(FALSE);
235 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
236 dkim_collect_error = NULL;
238 /* Start feed up with any cached data, but limited to message data */
239 receive_get_cache(chunking_state == CHUNKING_LAST
240 ? chunking_data_left : GETC_BUFFER_UNLIMITED);
242 store_pool = dkim_verify_oldpool;
247 /* Module API : Submit a chunk of data for verification input.
248 A NULL data pointer indicates end-of-message.
249 Only use the data when the feed is activated. */
252 dkim_exim_verify_feed(const uschar * data, unsigned len)
256 store_pool = POOL_MESSAGE;
257 if ( (dkim_collect_input || !data)
258 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
260 dkim_collect_error = pdkim_errstr(rc);
261 log_write(0, LOG_MAIN,
262 "DKIM: validation error: %.100s", dkim_collect_error);
263 dkim_collect_input = 0;
265 store_pool = dkim_verify_oldpool;
269 /* Module API: pause/resume the verification data feed */
272 dkim_exim_verify_pause(BOOL pause)
274 static unsigned save = 0;
275 static BOOL paused = FALSE;
280 { dkim_collect_input = save; paused = FALSE; }
284 { save = dkim_collect_input; dkim_collect_input = 0; paused = TRUE; }
287 /* Module API: Finish off the body hashes, calculate sigs and do compares */
290 dkim_exim_verify_finish(void)
294 const uschar * errstr = NULL;
296 store_pool = POOL_MESSAGE;
298 /* Delete eventual previous signature chain */
301 dkim_signatures = NULL;
303 if (dkim_collect_error)
305 log_write(0, LOG_MAIN,
306 "DKIM: Error during validation, disabling signature verification: %.100s",
308 f.dkim_disable_verify = TRUE;
312 dkim_collect_input = 0;
314 /* Finish DKIM operation and fetch link to signatures chain */
316 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
318 if (rc != PDKIM_OK && errstr)
319 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
321 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
323 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
325 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
326 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
328 gstring_release_unused(g);
329 dkim_signers = string_from_gstring(g);
332 store_pool = dkim_verify_oldpool;
337 /* Log the result for the given signature */
339 dkim_exim_verify_log_sig(pdkim_signature * sig)
346 /* Remember the domain for the first pass result */
348 if ( !dkim_vdom_firstpass
349 && dkim_verify_status
350 ? Ustrcmp(dkim_verify_status, US"pass") == 0
351 : sig->verify_status == PDKIM_VERIFY_PASS
353 dkim_vdom_firstpass= string_copy(sig->domain);
355 /* Rewrite the sig result if the ACL overrode it. This is only
356 needed because the DMARC code (sigh) peeks at the dkim sigs.
357 Mark the sig for this having been done. */
359 if ( dkim_verify_status
360 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
361 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
363 { /* overridden by ACL */
364 sig->verify_ext_status = -1;
365 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
366 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
367 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
368 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
369 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
370 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
371 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
372 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
374 sig->verify_status = -1;
377 if (!LOGGING(dkim_verbose)) return;
380 logmsg = string_catn(NULL, US"DKIM: ", 6);
381 if (!(s = sig->domain)) s = US"<UNSET>";
382 logmsg = string_append(logmsg, 2, "d=", s);
383 if (!(s = sig->selector)) s = US"<UNSET>";
384 logmsg = string_append(logmsg, 2, " s=", s);
385 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
386 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
387 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
388 dkim_sig_to_a_tag(sig),
389 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
390 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
391 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
393 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
395 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
398 if (sig->verify_status & PDKIM_VERIFY_POLICY)
399 logmsg = string_append(logmsg, 5,
400 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
402 switch (sig->verify_status)
404 case PDKIM_VERIFY_NONE:
405 logmsg = string_cat(logmsg, US" [not verified]");
408 case PDKIM_VERIFY_INVALID:
409 logmsg = string_cat(logmsg, US" [invalid - ");
410 switch (sig->verify_ext_status)
412 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
413 logmsg = string_cat(logmsg,
414 US"public key record (currently?) unavailable]");
417 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
418 logmsg = string_cat(logmsg, US"overlong public key record]");
421 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
422 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
423 logmsg = string_cat(logmsg, US"syntax error in public key record]");
426 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
427 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
430 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
431 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
435 logmsg = string_cat(logmsg, US"unspecified problem]");
439 case PDKIM_VERIFY_FAIL:
440 logmsg = string_cat(logmsg, US" [verification failed - ");
441 switch (sig->verify_ext_status)
443 case PDKIM_VERIFY_FAIL_BODY:
444 logmsg = string_cat(logmsg,
445 US"body hash mismatch (body probably modified in transit)]");
448 case PDKIM_VERIFY_FAIL_MESSAGE:
449 logmsg = string_cat(logmsg,
450 US"signature did not verify "
451 "(headers probably modified in transit)]");
454 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
455 logmsg = string_cat(logmsg,
456 US"signature invalid (key too short)]");
460 logmsg = string_cat(logmsg, US"unspecified reason]");
464 case PDKIM_VERIFY_PASS:
465 logmsg = string_cat(logmsg, US" [verification succeeded]");
469 log_write(0, LOG_MAIN, "%Y", logmsg);
474 /* Module API: Log a line for each signature */
477 dkim_exim_verify_log_all(void)
479 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
480 dkim_exim_verify_log_sig(sig);
484 /* Module API: append a log element with domain for the first passing sig */
487 dkim_exim_vdom_firstpass(gstring * g)
489 if (dkim_vdom_firstpass)
490 g = string_append(g, 2, US" DKIM=", dkim_vdom_firstpass);
495 /* For one signature, run the DKIM ACL, log the sig result,
496 and append ths sig status to the status list.
498 Args as per dkim_exim_acl_run() below */
501 dkim_acl_call(uschar * id, gstring ** res_ptr,
502 uschar ** user_msgptr, uschar ** log_msgptr)
506 debug_printf("calling acl_smtp_dkim for identity '%s' domain '%s' sel '%s'\n",
507 id, dkim_signing_domain, dkim_signing_selector);
509 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
510 dkim_exim_verify_log_sig(dkim_cur_sig);
511 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
517 /* For the given identity, run the DKIM ACL once for each matching signature.
518 If none match, run it once.
521 id Identity to look for in dkim signatures
522 res_ptr ptr to growable string-list of status results,
523 appended to per ACL run
524 user_msgptr where to put a user error (for SMTP response)
525 log_msgptr where to put a logging message (not for SMTP response)
527 Returns: OK access is granted by an ACCEPT verb
528 DISCARD access is granted by a DISCARD verb
529 FAIL access is denied
530 FAIL_DROP access is denied; drop the connection
531 DEFER can't tell at the moment
536 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
537 uschar ** user_msgptr, uschar ** log_msgptr)
542 dkim_verify_status = US"none";
543 dkim_verify_reason = US"";
544 dkim_cur_signer = id;
546 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
549 /* Find signatures to run ACL on */
551 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
552 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
553 && strcmpic(cmp_val, id) == 0
556 /* The "dkim_domain" and "dkim_selector" expansion variables have
557 related globals, since they are used in the signing code too.
558 Instead of inventing separate names for verification, we set
559 them here. This is easy since a domain and selector is guaranteed
560 to be in a signature. The other dkim_* expansion items are
561 dynamically fetched from dkim_cur_sig at expansion time (see
562 dkim_exim_expand_query() below). */
565 dkim_signing_domain = US sig->domain;
566 dkim_signing_selector = US sig->selector;
567 dkim_key_length = sig->keybits;
569 /* These two return static strings, so we can compare the addr
570 later to see if the ACL overwrote them. Check that when logging */
572 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
573 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
575 if ( (rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK
576 || dkim_verify_minimal && Ustrcmp(dkim_verify_status, "pass") == 0)
583 /* No matching sig found. Call ACL once anyway. */
586 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
591 Loop over dkim_verify_signers option doing ACL calls. If one return any
592 non-OK value stop and return that, else return OK.
596 /*XXX need a user_msgptr */
597 dkim_exim_acl_entry(uschar ** user_msgptr, uschar ** log_msgptr)
601 GET_OPTION("dkim_verify_signers");
602 if (dkim_verify_signers && *dkim_verify_signers)
604 const uschar * dkim_verify_signers_expanded =
605 expand_cstring(dkim_verify_signers);
606 gstring * results = NULL, * seen_items = NULL;
607 int signer_sep = 0, old_pool = store_pool;
609 if (!dkim_verify_signers_expanded)
611 log_write(0, LOG_MAIN|LOG_PANIC,
612 "expansion of dkim_verify_signers option failed: %s",
613 expand_string_message);
617 store_pool = POOL_PERM; /* Allow created variables to live to data ACL */
619 /* Loop over signers we want to verify, calling ACL. Default to OK
620 when no signers are present. Each call from here expands to an ACL
621 call per matching sig in the message. */
624 item = string_nextinlist(&dkim_verify_signers_expanded,
625 &signer_sep, NULL, 0); )
627 /* Prevent running ACL for an empty item */
628 if (!item || !*item) continue;
630 /* Only run ACL once for each domain or identity,
631 no matter how often it appears in the expanded list. */
635 const uschar * seen_items_list = string_from_gstring(seen_items);
637 BOOL seen_this_item = FALSE;
639 while ((seen_item = string_nextinlist(&seen_items_list, &seen_sep,
641 if (Ustrcmp(seen_item, item) == 0)
643 seen_this_item = TRUE;
650 debug_printf("acl_smtp_dkim: skipping signer %s, "
651 "already seen\n", item);
655 seen_items = string_catn(seen_items, US":", 1);
657 seen_items = string_cat(seen_items, item);
659 if ((rc = dkim_exim_acl_run(item, &results, user_msgptr, log_msgptr)) != OK)
662 debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
663 "skipping remaining items\n", rc, item);
666 if (dkim_verify_minimal && Ustrcmp(dkim_verify_status, "pass") == 0)
670 dkim_verify_status = string_from_gstring(results);
671 store_pool = old_pool;
674 dkim_exim_verify_log_all();
679 /******************************************************************************/
684 dkim_exim_signer_isinlist(const uschar * l)
686 return dkim_cur_signer
687 ? match_isinlist(dkim_cur_signer, &l, 0, NULL, NULL, MCL_STRING, TRUE, NULL)
694 dkim_exim_status_listmatch(const uschar * l)
695 { /* return good for any match */
696 const uschar * s = dkim_verify_status ? dkim_verify_status : US"none";
697 int sep = 0, rc = FAIL;
698 for (uschar * ss; ss = string_nextinlist(&s, &sep, NULL, 0); )
699 if ( (rc = match_isinlist(ss, &l, 0, NULL, NULL, MCL_STRING, TRUE, NULL))
704 /* Module API: Overwriteable dkim result variables */
707 dkim_exim_setvar(const uschar * name, void * val)
709 if (Ustrcmp(name, "dkim_verify_status") == 0)
710 dkim_verify_status = val;
711 else if (Ustrcmp(name, "dkim_verify_reason") == 0)
712 dkim_verify_reason = val;
715 /******************************************************************************/
718 dkim_smtp_reset(void)
720 dkim_cur_signer = dkim_signers =
721 dkim_signing_domain = dkim_signing_selector = dkim_signatures = NULL;
722 f.dkim_disable_verify = FALSE;
723 dkim_collect_input = 0;
724 dkim_vdom_firstpass = dkim_verify_status = dkim_verify_reason = NULL;
728 /******************************************************************************/
731 dkim_exim_expand_defaults(int what)
735 case DKIM_ALGO: return US"";
736 case DKIM_BODYLENGTH: return US"9999999999999";
737 case DKIM_CANON_BODY: return US"";
738 case DKIM_CANON_HEADERS: return US"";
739 case DKIM_COPIEDHEADERS: return US"";
740 case DKIM_CREATED: return US"0";
741 case DKIM_EXPIRES: return US"9999999999999";
742 case DKIM_HEADERNAMES: return US"";
743 case DKIM_IDENTITY: return US"";
744 case DKIM_KEY_GRANULARITY: return US"*";
745 case DKIM_KEY_SRVTYPE: return US"*";
746 case DKIM_KEY_NOTES: return US"";
747 case DKIM_KEY_TESTING: return US"0";
748 case DKIM_NOSUBDOMAINS: return US"0";
749 case DKIM_VERIFY_STATUS: return US"none";
750 case DKIM_VERIFY_REASON: return US"";
751 default: return US"";
756 /* Module API: return a computed value for a variable expansion */
759 dkim_exim_expand_query(int what)
761 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
762 return dkim_exim_expand_defaults(what);
767 return dkim_sig_to_a_tag(dkim_cur_sig);
769 case DKIM_BODYLENGTH:
770 return dkim_cur_sig->bodylength >= 0
771 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
772 : dkim_exim_expand_defaults(what);
774 case DKIM_CANON_BODY:
775 switch (dkim_cur_sig->canon_body)
777 case PDKIM_CANON_RELAXED: return US"relaxed";
778 case PDKIM_CANON_SIMPLE:
779 default: return US"simple";
782 case DKIM_CANON_HEADERS:
783 switch (dkim_cur_sig->canon_headers)
785 case PDKIM_CANON_RELAXED: return US"relaxed";
786 case PDKIM_CANON_SIMPLE:
787 default: return US"simple";
790 case DKIM_COPIEDHEADERS:
791 return dkim_cur_sig->copiedheaders
792 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
795 return dkim_cur_sig->created > 0
796 ? string_sprintf("%lu", dkim_cur_sig->created)
797 : dkim_exim_expand_defaults(what);
800 return dkim_cur_sig->expires > 0
801 ? string_sprintf("%lu", dkim_cur_sig->expires)
802 : dkim_exim_expand_defaults(what);
804 case DKIM_HEADERNAMES:
805 return dkim_cur_sig->headernames
806 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
809 return dkim_cur_sig->identity
810 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
812 case DKIM_KEY_GRANULARITY:
813 return dkim_cur_sig->pubkey
814 ? dkim_cur_sig->pubkey->granularity
815 ? US dkim_cur_sig->pubkey->granularity
816 : dkim_exim_expand_defaults(what)
817 : dkim_exim_expand_defaults(what);
819 case DKIM_KEY_SRVTYPE:
820 return dkim_cur_sig->pubkey
821 ? dkim_cur_sig->pubkey->srvtype
822 ? US dkim_cur_sig->pubkey->srvtype
823 : dkim_exim_expand_defaults(what)
824 : dkim_exim_expand_defaults(what);
827 return dkim_cur_sig->pubkey
828 ? dkim_cur_sig->pubkey->notes
829 ? US dkim_cur_sig->pubkey->notes
830 : dkim_exim_expand_defaults(what)
831 : dkim_exim_expand_defaults(what);
833 case DKIM_KEY_TESTING:
834 return dkim_cur_sig->pubkey
835 ? dkim_cur_sig->pubkey->testing
837 : dkim_exim_expand_defaults(what)
838 : dkim_exim_expand_defaults(what);
840 case DKIM_NOSUBDOMAINS:
841 return dkim_cur_sig->pubkey
842 ? dkim_cur_sig->pubkey->no_subdomaining
844 : dkim_exim_expand_defaults(what)
845 : dkim_exim_expand_defaults(what);
847 case DKIM_VERIFY_STATUS:
848 switch (dkim_cur_sig->verify_status)
850 case PDKIM_VERIFY_INVALID: return US"invalid";
851 case PDKIM_VERIFY_FAIL: return US"fail";
852 case PDKIM_VERIFY_PASS: return US"pass";
853 case PDKIM_VERIFY_NONE:
854 default: return US"none";
857 case DKIM_VERIFY_REASON:
858 switch (dkim_cur_sig->verify_ext_status)
860 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
861 return US"pubkey_unavailable";
862 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
863 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
864 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
865 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
866 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
878 dkim_exim_sign_init(void)
880 int old_pool = store_pool;
882 dkim_exim_init(NULL);
883 store_pool = POOL_MAIN;
884 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
885 store_pool = old_pool;
889 /* Generate signatures for the given file.
890 If a prefix is given, prepend it to the file for the calculations.
893 NULL: error; error string written
894 string: signature header(s), or a zero-length string (not an error)
898 dkim_exim_sign(int fd, off_t off, uschar * prefix,
899 struct ob_dkim * dkim, const uschar ** errstr)
901 const uschar * dkim_domain = NULL;
903 gstring * seen_doms = NULL;
904 pdkim_signature * sig;
910 int old_pool = store_pool;
914 if (dkim->dot_stuffed)
915 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
917 store_pool = POOL_MAIN;
919 GET_OPTION("dkim_domain");
920 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
921 /* expansion error, do not send message. */
922 { errwhen = US"dkim_domain"; goto expand_bad; }
924 /* Set $dkim_domain expansion variable to each unique domain in list. */
927 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
929 const uschar * dkim_sel;
932 if (dkim_signing_domain[0] == '\0')
935 /* Only sign once for each domain, no matter how often it
936 appears in the expanded list. */
938 dkim_signing_domain = string_copylc(dkim_signing_domain);
939 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
940 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
943 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
945 /* Set $dkim_selector expansion variable to each selector in list,
948 GET_OPTION("dkim_selector");
949 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
950 { errwhen = US"dkim_selector"; goto expand_bad; }
952 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
955 uschar * dkim_canon_expanded;
957 uschar * dkim_sign_headers_expanded = NULL;
958 uschar * dkim_private_key_expanded;
959 uschar * dkim_hash_expanded;
960 uschar * dkim_identity_expanded = NULL;
961 uschar * dkim_timestamps_expanded = NULL;
962 unsigned long tval = 0, xval = 0;
964 /* Get canonicalization to use */
966 GET_OPTION("dkim_canon");
967 dkim_canon_expanded = dkim->dkim_canon
968 ? expand_string(dkim->dkim_canon) : US"relaxed";
969 if (!dkim_canon_expanded) /* expansion error, do not send message. */
970 { errwhen = US"dkim_canon"; goto expand_bad; }
972 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
973 pdkim_canon = PDKIM_CANON_RELAXED;
974 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
975 pdkim_canon = PDKIM_CANON_SIMPLE;
978 log_write(0, LOG_MAIN,
979 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
980 dkim_canon_expanded);
981 pdkim_canon = PDKIM_CANON_RELAXED;
984 GET_OPTION("dkim_sign_headers");
985 if ( dkim->dkim_sign_headers
986 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
987 { errwhen = US"dkim_sign_header"; goto expand_bad; }
988 /* else pass NULL, which means default header list */
990 /* Get private key to use. */
992 GET_OPTION("dkim_private_key");
993 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
994 { errwhen = US"dkim_private_key"; goto expand_bad; }
996 if ( Ustrlen(dkim_private_key_expanded) == 0
997 || Ustrcmp(dkim_private_key_expanded, "0") == 0
998 || Ustrcmp(dkim_private_key_expanded, "false") == 0
1000 continue; /* don't sign, but no error */
1002 if ( dkim_private_key_expanded[0] == '/'
1003 && !(dkim_private_key_expanded =
1004 expand_file_big_buffer(dkim_private_key_expanded)))
1007 GET_OPTION("dkim_hash");
1008 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
1009 { errwhen = US"dkim_hash"; goto expand_bad; }
1011 GET_OPTION("dkim_identity");
1012 if (dkim->dkim_identity)
1013 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
1014 { errwhen = US"dkim_identity"; goto expand_bad; }
1015 else if (!*dkim_identity_expanded)
1016 dkim_identity_expanded = NULL;
1018 GET_OPTION("dkim_timestamps");
1019 if (dkim->dkim_timestamps)
1020 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
1021 { errwhen = US"dkim_timestamps"; goto expand_bad; }
1024 tval = (unsigned long) time(NULL);
1025 xval = strtoul(CCS dkim_timestamps_expanded, NULL, 10);
1030 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
1031 dkim_signing_selector,
1032 dkim_private_key_expanded,
1037 dkim_private_key_expanded[0] = '\0';
1039 pdkim_set_optional(sig,
1040 CS dkim_sign_headers_expanded,
1041 CS dkim_identity_expanded,
1043 pdkim_canon, -1, tval, xval);
1045 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
1048 dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_domain);
1049 dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_selector);
1051 if (!dkim_sign_ctx.sig) /* link sig to context chain */
1052 dkim_sign_ctx.sig = sig;
1055 pdkim_signature * n = dkim_sign_ctx.sig;
1056 while (n->next) n = n->next;
1062 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
1063 produce, if some other package (eg. ARC) is signing. */
1065 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
1067 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
1068 sigbuf = string_get(1); /* return a zero-len string */
1072 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
1075 if (lseek(fd, off, SEEK_SET) < 0)
1078 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
1079 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
1082 /* Handle failed read above. */
1085 debug_printf("DKIM: Error reading -K file.\n");
1090 /* Build string of headers, one per signature */
1092 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
1097 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
1098 sigbuf = string_get(1); /* return a zero-len string */
1100 else for (sigbuf = NULL; sig; sig = sig->next)
1101 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
1105 (void) string_from_gstring(sigbuf);
1106 store_pool = old_pool;
1111 log_write(0, LOG_MAIN|LOG_PANIC,
1112 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
1118 *errstr = string_sprintf("failed to expand %s: %s",
1119 errwhen, expand_string_message);
1120 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
1126 #ifdef SUPPORT_DMARC
1130 static const pdkim_signature *
1131 dkim_sigs_list(void)
1133 return dkim_signatures;
1137 #ifdef EXPERIMENTAL_ARC
1141 dkim_hashname_to_type(const blob * name)
1143 return pdkim_hashname_to_hashtype(name->data, name->len);
1148 dkim_hashtype_to_method(int hashtype)
1150 return hashtype >= 0 ? pdkim_hashes[hashtype].exim_hashmethod : -1;
1155 dkim_hashname_to_method(const blob * name)
1157 return dkim_hashtype_to_method(dkim_hashname_to_type(name));
1160 /* Module API: Set up a body hashing method on the given signature-context
1161 (creates a new one if needed, or uses an already-present one).
1164 signing TRUE to use dkim's signing context, else dkim_verify_ctx
1165 canon canonicalization spec, text form
1166 hash hash spec, text form
1167 bodylen byte count for message body
1169 Return: pointer to hashing method struct
1172 static pdkim_bodyhash *
1173 dkim_set_bodyhash(BOOL signing,
1174 const blob * canon, const blob * hashname, long bodylen)
1176 int canon_head = -1, canon_body = -1;
1178 pdkim_cstring_to_canons(canon->data, canon->len, &canon_head, &canon_body);
1179 return pdkim_set_bodyhash(signing ? &dkim_sign_ctx: dkim_verify_ctx,
1180 dkim_hashname_to_type(hashname),
1185 /* Module API: Sign a blob of data (which might already be a hash, if
1186 Ed25519 or GCrypt signing).
1190 hm hash to be applied to the data
1191 privkey private key for siging, PEM format
1192 signature pointer for result blob
1194 Return: NULL, or error string on failure
1197 static const uschar *
1198 dkim_sign_blob(const blob * data, hashmethod hm, const uschar * privkey,
1202 const uschar * errstr;
1204 if ((errstr = exim_dkim_signing_init(privkey, &sctx)))
1205 { DEBUG(D_transport) debug_printf("signing key setup: %s\n", errstr); }
1206 else errstr = exim_dkim_sign(&sctx, hm, data, signature);
1211 #endif /*EXPERIMENTAL_ARC*/
1217 authres_dkim(gstring * g)
1219 int start = 0; /* compiler quietening */
1221 DEBUG(D_acl) start = gstring_length(g);
1223 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
1225 g = string_catn(g, US";\n\tdkim=", 8);
1227 if (sig->verify_status & PDKIM_VERIFY_POLICY)
1228 g = string_append(g, 5,
1229 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
1230 else switch(sig->verify_status)
1232 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
1233 case PDKIM_VERIFY_INVALID:
1234 switch (sig->verify_ext_status)
1236 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
1237 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
1238 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
1239 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
1240 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
1241 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
1242 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
1244 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
1245 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
1247 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
1248 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
1251 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
1254 case PDKIM_VERIFY_FAIL:
1255 switch (sig->verify_ext_status)
1257 case PDKIM_VERIFY_FAIL_BODY:
1259 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
1261 case PDKIM_VERIFY_FAIL_MESSAGE:
1263 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
1265 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
1266 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
1269 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
1273 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
1274 default: g = string_cat(g, US"permerror"); break;
1276 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
1277 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
1278 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
1279 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
1283 if (gstring_length(g) == start)
1284 debug_printf("DKIM:\tno authres\n");
1286 debug_printf("DKIM:\tauthres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
1290 /******************************************************************************/
1293 static optionlist dkim_options[] = {
1294 { "acl_smtp_dkim", opt_stringptr, {&acl_smtp_dkim} },
1295 { "dkim_verify_hashes", opt_stringptr, {&dkim_verify_hashes} },
1296 { "dkim_verify_keytypes", opt_stringptr, {&dkim_verify_keytypes} },
1297 { "dkim_verify_min_keysizes", opt_stringptr, {&dkim_verify_min_keysizes} },
1298 { "dkim_verify_minimal", opt_bool, {&dkim_verify_minimal} },
1299 { "dkim_verify_signers", opt_stringptr, {&dkim_verify_signers} },
1302 static void * dkim_functions[] = {
1303 [DKIM_VERIFY_FEED] = dkim_exim_verify_feed,
1304 [DKIM_VERIFY_PAUSE] = dkim_exim_verify_pause,
1305 [DKIM_VERIFY_FINISH] = dkim_exim_verify_finish,
1306 [DKIM_ACL_ENTRY] = dkim_exim_acl_entry,
1307 [DKIM_VERIFY_LOG_ALL] = dkim_exim_verify_log_all,
1308 [DKIM_VDOM_FIRSTPASS] = dkim_exim_vdom_firstpass,
1310 [DKIM_SIGNER_ISINLIST] = dkim_exim_signer_isinlist,
1311 [DKIM_STATUS_LISTMATCH] = dkim_exim_status_listmatch,
1313 [DKIM_SETVAR] = dkim_exim_setvar,
1314 [DKIM_EXPAND_QUERY] = dkim_exim_expand_query,
1316 [DKIM_TRANSPORT_INIT] = dkim_exim_sign_init,
1317 [DKIM_TRANSPORT_WRITE] = dkim_transport_write_message,
1319 #ifdef SUPPORT_DMARC
1320 [DKIM_SIGS_LIST] = dkim_sigs_list,
1322 #ifdef EXPERIMENTAL_ARC
1323 [DKIM_HASHNAME_TO_TYPE] = dkim_hashname_to_type,
1324 [DKIM_HASHTYPE_TO_METHOD] = dkim_hashtype_to_method,
1325 [DKIM_HASHNAME_TO_METHOD] = dkim_hashname_to_method,
1326 [DKIM_SET_BODYHASH] = dkim_set_bodyhash,
1327 [DKIM_DNS_PUBKEY] = dkim_exim_parse_dns_pubkey,
1328 [DKIM_SIG_VERIFY] = dkim_exim_sig_verify,
1329 [DKIM_HEADER_RELAX] = pdkim_relax_header_n,
1330 [DKIM_SIGN_DATA] = dkim_sign_blob,
1334 static var_entry dkim_variables[] = {
1335 { "dkim_algo", vtype_dkim, (void *)DKIM_ALGO },
1336 { "dkim_bodylength", vtype_dkim, (void *)DKIM_BODYLENGTH },
1337 { "dkim_canon_body", vtype_dkim, (void *)DKIM_CANON_BODY },
1338 { "dkim_canon_headers", vtype_dkim, (void *)DKIM_CANON_HEADERS },
1339 { "dkim_copiedheaders", vtype_dkim, (void *)DKIM_COPIEDHEADERS },
1340 { "dkim_created", vtype_dkim, (void *)DKIM_CREATED },
1341 { "dkim_cur_signer", vtype_stringptr, &dkim_cur_signer },
1342 { "dkim_domain", vtype_stringptr, &dkim_signing_domain },
1343 { "dkim_expires", vtype_dkim, (void *)DKIM_EXPIRES },
1344 { "dkim_headernames", vtype_dkim, (void *)DKIM_HEADERNAMES },
1345 { "dkim_identity", vtype_dkim, (void *)DKIM_IDENTITY },
1346 { "dkim_key_granularity",vtype_dkim, (void *)DKIM_KEY_GRANULARITY },
1347 { "dkim_key_length", vtype_int, &dkim_key_length },
1348 { "dkim_key_nosubdomains",vtype_dkim, (void *)DKIM_NOSUBDOMAINS },
1349 { "dkim_key_notes", vtype_dkim, (void *)DKIM_KEY_NOTES },
1350 { "dkim_key_srvtype", vtype_dkim, (void *)DKIM_KEY_SRVTYPE },
1351 { "dkim_key_testing", vtype_dkim, (void *)DKIM_KEY_TESTING },
1352 { "dkim_selector", vtype_stringptr, &dkim_signing_selector },
1353 { "dkim_signers", vtype_stringptr, &dkim_signers },
1354 { "dkim_verify_reason", vtype_stringptr, &dkim_verify_reason },
1355 { "dkim_verify_status", vtype_stringptr, &dkim_verify_status },
1358 misc_module_info dkim_module_info = {
1360 # if SUPPORT_DKIM==2
1361 .dyn_magic = MISC_MODULE_MAGIC,
1363 .init = dkim_exim_init,
1364 .msg_init = dkim_exim_verify_init,
1365 .authres = authres_dkim,
1366 .smtp_reset = dkim_smtp_reset,
1368 .options = dkim_options,
1369 .options_count = nelem(dkim_options),
1371 .functions = dkim_functions,
1372 .functions_count = nelem(dkim_functions),
1374 .variables = dkim_variables,
1375 .variables_count = nelem(dkim_variables),
1378 # endif /*!MACRO_PREDEF*/
1379 #endif /*!DISABLE_DKIM*/