1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge, 1995 - 2018 */
6 /* Copyright (c) The Exim Maintainers 2020 */
7 /* See the file NOTICE for conditions of use and distribution. */
9 /* Code for DKIM support. Other DKIM relevant code is in
10 receive.c, transport.c and transports/smtp.c */
16 # include "pdkim/pdkim.h"
19 # include "macro_predef.h"
24 builtin_macro_create_var(US"_DKIM_SIGN_HEADERS", US PDKIM_DEFAULT_SIGN_HEADERS);
25 builtin_macro_create_var(US"_DKIM_OVERSIGN_HEADERS", US PDKIM_OVERSIGN_HEADERS);
27 # else /*!MACRO_PREDEF*/
31 pdkim_ctx dkim_sign_ctx;
33 int dkim_verify_oldpool;
34 pdkim_ctx *dkim_verify_ctx = NULL;
35 pdkim_signature *dkim_cur_sig = NULL;
36 static const uschar * dkim_collect_error = NULL;
38 #define DKIM_MAX_SIGNATURES 20
42 /* Look up the DKIM record in DNS for the given hostname.
43 Will use the first found if there are multiple.
44 The return string is tainted, having come from off-site.
48 dkim_exim_query_dns_txt(const uschar * name)
50 dns_answer * dnsa = store_get_dns_answer();
52 rmark reset_point = store_mark();
53 gstring * g = string_get_tainted(256, TRUE);
55 lookup_dnssec_authenticated = NULL;
56 if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
58 store_free_dns_answer(dnsa);
59 return NULL; /*XXX better error detail? logging? */
62 /* Search for TXT record */
64 for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
66 rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
67 if (rr->type == T_TXT)
71 /* Copy record content to the answer buffer */
73 while (rr_offset < rr->size)
75 uschar len = rr->data[rr_offset++];
77 g = string_catn(g, US(rr->data + rr_offset), len);
78 if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
84 /* check if this looks like a DKIM record */
85 if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
87 store_free_dns_answer(dnsa);
88 gstring_release_unused(g);
89 return string_from_gstring(g);
92 if (g) g->ptr = 0; /* overwrite previous record */
96 store_reset(reset_point);
97 store_free_dns_answer(dnsa);
98 return NULL; /*XXX better error detail? logging? */
105 if (f.dkim_init_done) return;
106 f.dkim_init_done = TRUE;
113 dkim_exim_verify_init(BOOL dot_stuffing)
117 /* There is a store-reset between header & body reception for the main pool
118 (actually, after every header line) so cannot use that as we need the data we
119 store per-header, during header processing, at the end of body reception
120 for evaluating the signature. Any allocs done for dkim verify
121 memory-handling must use a different pool. We use a separate one that we
122 can reset per message. */
124 dkim_verify_oldpool = store_pool;
125 store_pool = POOL_MESSAGE;
127 /* Free previous context if there is one */
130 pdkim_free_ctx(dkim_verify_ctx);
132 /* Create new context */
134 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
135 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
136 dkim_collect_error = NULL;
138 /* Start feed up with any cached data */
141 store_pool = dkim_verify_oldpool;
146 dkim_exim_verify_feed(uschar * data, int len)
150 store_pool = POOL_MESSAGE;
151 if ( dkim_collect_input
152 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
154 dkim_collect_error = pdkim_errstr(rc);
155 log_write(0, LOG_MAIN,
156 "DKIM: validation error: %.100s", dkim_collect_error);
157 dkim_collect_input = 0;
159 store_pool = dkim_verify_oldpool;
163 /* Log the result for the given signature */
165 dkim_exim_verify_log_sig(pdkim_signature * sig)
172 /* Remember the domain for the first pass result */
174 if ( !dkim_verify_overall
175 && dkim_verify_status
176 ? Ustrcmp(dkim_verify_status, US"pass") == 0
177 : sig->verify_status == PDKIM_VERIFY_PASS
179 dkim_verify_overall = string_copy(sig->domain);
181 /* Rewrite the sig result if the ACL overrode it. This is only
182 needed because the DMARC code (sigh) peeks at the dkim sigs.
183 Mark the sig for this having been done. */
185 if ( dkim_verify_status
186 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
187 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
189 { /* overridden by ACL */
190 sig->verify_ext_status = -1;
191 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
192 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
193 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
194 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
195 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
196 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
197 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
198 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
200 sig->verify_status = -1;
203 if (!LOGGING(dkim_verbose)) return;
206 logmsg = string_catn(NULL, US"DKIM: ", 6);
207 if (!(s = sig->domain)) s = US"<UNSET>";
208 logmsg = string_append(logmsg, 2, "d=", s);
209 if (!(s = sig->selector)) s = US"<UNSET>";
210 logmsg = string_append(logmsg, 2, " s=", s);
211 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
212 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
213 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
214 dkim_sig_to_a_tag(sig),
215 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
216 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
217 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
219 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
221 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
224 if (sig->verify_status & PDKIM_VERIFY_POLICY)
225 logmsg = string_append(logmsg, 5,
226 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
228 switch (sig->verify_status)
230 case PDKIM_VERIFY_NONE:
231 logmsg = string_cat(logmsg, US" [not verified]");
234 case PDKIM_VERIFY_INVALID:
235 logmsg = string_cat(logmsg, US" [invalid - ");
236 switch (sig->verify_ext_status)
238 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
239 logmsg = string_cat(logmsg,
240 US"public key record (currently?) unavailable]");
243 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
244 logmsg = string_cat(logmsg, US"overlong public key record]");
247 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
248 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
249 logmsg = string_cat(logmsg, US"syntax error in public key record]");
252 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
253 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
256 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
257 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
261 logmsg = string_cat(logmsg, US"unspecified problem]");
265 case PDKIM_VERIFY_FAIL:
266 logmsg = string_cat(logmsg, US" [verification failed - ");
267 switch (sig->verify_ext_status)
269 case PDKIM_VERIFY_FAIL_BODY:
270 logmsg = string_cat(logmsg,
271 US"body hash mismatch (body probably modified in transit)]");
274 case PDKIM_VERIFY_FAIL_MESSAGE:
275 logmsg = string_cat(logmsg,
276 US"signature did not verify "
277 "(headers probably modified in transit)]");
280 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
281 logmsg = string_cat(logmsg,
282 US"signature invalid (key too short)]");
286 logmsg = string_cat(logmsg, US"unspecified reason]");
290 case PDKIM_VERIFY_PASS:
291 logmsg = string_cat(logmsg, US" [verification succeeded]");
295 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
300 /* Log a line for each signature */
302 dkim_exim_verify_log_all(void)
304 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
305 dkim_exim_verify_log_sig(sig);
310 dkim_exim_verify_finish(void)
314 const uschar * errstr = NULL;
316 store_pool = POOL_MESSAGE;
318 /* Delete eventual previous signature chain */
321 dkim_signatures = NULL;
323 if (dkim_collect_error)
325 log_write(0, LOG_MAIN,
326 "DKIM: Error during validation, disabling signature verification: %.100s",
328 f.dkim_disable_verify = TRUE;
332 dkim_collect_input = 0;
334 /* Finish DKIM operation and fetch link to signatures chain */
336 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
338 if (rc != PDKIM_OK && errstr)
339 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
341 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
343 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
345 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
346 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
349 if (g) dkim_signers = g->s;
352 store_pool = dkim_verify_oldpool;
357 /* Args as per dkim_exim_acl_run() below */
359 dkim_acl_call(uschar * id, gstring ** res_ptr,
360 uschar ** user_msgptr, uschar ** log_msgptr)
364 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
366 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
367 dkim_exim_verify_log_sig(dkim_cur_sig);
368 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
374 /* For the given identity, run the DKIM ACL once for each matching signature.
377 id Identity to look for in dkim signatures
378 res_ptr ptr to growable string-list of status results,
379 appended to per ACL run
380 user_msgptr where to put a user error (for SMTP response)
381 log_msgptr where to put a logging message (not for SMTP response)
383 Returns: OK access is granted by an ACCEPT verb
384 DISCARD access is granted by a DISCARD verb
385 FAIL access is denied
386 FAIL_DROP access is denied; drop the connection
387 DEFER can't tell at the moment
392 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
393 uschar ** user_msgptr, uschar ** log_msgptr)
398 dkim_verify_status = US"none";
399 dkim_verify_reason = US"";
400 dkim_cur_signer = id;
402 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
405 /* Find signatures to run ACL on */
407 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
408 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
409 && strcmpic(cmp_val, id) == 0
412 /* The "dkim_domain" and "dkim_selector" expansion variables have
413 related globals, since they are used in the signing code too.
414 Instead of inventing separate names for verification, we set
415 them here. This is easy since a domain and selector is guaranteed
416 to be in a signature. The other dkim_* expansion items are
417 dynamically fetched from dkim_cur_sig at expansion time (see
418 dkim_exim_expand_query() below). */
421 dkim_signing_domain = US sig->domain;
422 dkim_signing_selector = US sig->selector;
423 dkim_key_length = sig->keybits;
425 /* These two return static strings, so we can compare the addr
426 later to see if the ACL overwrote them. Check that when logging */
428 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
429 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
431 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
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 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
631 /* expansion error, do not send message. */
632 { errwhen = US"dkim_domain"; goto expand_bad; }
634 /* Set $dkim_domain expansion variable to each unique domain in list. */
637 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
639 const uschar * dkim_sel;
642 if (dkim_signing_domain[0] == '\0')
645 /* Only sign once for each domain, no matter how often it
646 appears in the expanded list. */
648 dkim_signing_domain = string_copylc(dkim_signing_domain);
649 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
650 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
653 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
655 /* Set $dkim_selector expansion variable to each selector in list,
658 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
659 { errwhen = US"dkim_selector"; goto expand_bad; }
661 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
664 uschar * dkim_canon_expanded;
666 uschar * dkim_sign_headers_expanded = NULL;
667 uschar * dkim_private_key_expanded;
668 uschar * dkim_hash_expanded;
669 uschar * dkim_identity_expanded = NULL;
670 uschar * dkim_timestamps_expanded = NULL;
671 unsigned long tval = 0, xval = 0;
673 /* Get canonicalization to use */
675 dkim_canon_expanded = dkim->dkim_canon
676 ? expand_string(dkim->dkim_canon) : US"relaxed";
677 if (!dkim_canon_expanded) /* expansion error, do not send message. */
678 { errwhen = US"dkim_canon"; goto expand_bad; }
680 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
681 pdkim_canon = PDKIM_CANON_RELAXED;
682 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
683 pdkim_canon = PDKIM_CANON_SIMPLE;
686 log_write(0, LOG_MAIN,
687 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
688 dkim_canon_expanded);
689 pdkim_canon = PDKIM_CANON_RELAXED;
692 if ( dkim->dkim_sign_headers
693 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
694 { errwhen = US"dkim_sign_header"; goto expand_bad; }
695 /* else pass NULL, which means default header list */
697 /* Get private key to use. */
699 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
700 { errwhen = US"dkim_private_key"; goto expand_bad; }
702 if ( Ustrlen(dkim_private_key_expanded) == 0
703 || Ustrcmp(dkim_private_key_expanded, "0") == 0
704 || Ustrcmp(dkim_private_key_expanded, "false") == 0
706 continue; /* don't sign, but no error */
708 if ( dkim_private_key_expanded[0] == '/'
709 && !(dkim_private_key_expanded =
710 expand_file_big_buffer(dkim_private_key_expanded)))
713 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
714 { errwhen = US"dkim_hash"; goto expand_bad; }
716 if (dkim->dkim_identity)
717 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
718 { errwhen = US"dkim_identity"; goto expand_bad; }
719 else if (!*dkim_identity_expanded)
720 dkim_identity_expanded = NULL;
722 if (dkim->dkim_timestamps)
723 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
724 { errwhen = US"dkim_timestamps"; goto expand_bad; }
726 xval = (tval = (unsigned long) time(NULL))
727 + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
729 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
730 dkim_signing_selector,
731 dkim_private_key_expanded,
736 dkim_private_key_expanded[0] = '\0';
738 pdkim_set_optional(sig,
739 CS dkim_sign_headers_expanded,
740 CS dkim_identity_expanded,
742 pdkim_canon, -1, tval, xval);
744 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
747 if (!dkim_sign_ctx.sig) /* link sig to context chain */
748 dkim_sign_ctx.sig = sig;
751 pdkim_signature * n = dkim_sign_ctx.sig;
752 while (n->next) n = n->next;
758 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
759 produce, if some other package (eg. ARC) is signing. */
761 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
763 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
764 sigbuf = string_get(1); /* return a zero-len string */
768 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
771 if (lseek(fd, off, SEEK_SET) < 0)
774 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
775 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
778 /* Handle failed read above. */
781 debug_printf("DKIM: Error reading -K file.\n");
786 /* Build string of headers, one per signature */
788 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
793 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
794 sigbuf = string_get(1); /* return a zero-len string */
796 else for (sigbuf = NULL; sig; sig = sig->next)
797 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
801 (void) string_from_gstring(sigbuf);
802 store_pool = old_pool;
807 log_write(0, LOG_MAIN|LOG_PANIC,
808 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
814 *errstr = string_sprintf("failed to expand %s: %s",
815 errwhen, expand_string_message);
816 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
824 authres_dkim(gstring * g)
826 int start = 0; /* compiler quietening */
828 DEBUG(D_acl) start = g->ptr;
830 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
832 g = string_catn(g, US";\n\tdkim=", 8);
834 if (sig->verify_status & PDKIM_VERIFY_POLICY)
835 g = string_append(g, 5,
836 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
837 else switch(sig->verify_status)
839 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
840 case PDKIM_VERIFY_INVALID:
841 switch (sig->verify_ext_status)
843 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
844 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
845 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
846 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
847 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
848 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
849 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
851 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
852 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
854 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
855 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
858 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
861 case PDKIM_VERIFY_FAIL:
862 switch (sig->verify_ext_status)
864 case PDKIM_VERIFY_FAIL_BODY:
866 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
868 case PDKIM_VERIFY_FAIL_MESSAGE:
870 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
872 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
873 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
876 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
880 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
881 default: g = string_cat(g, US"permerror"); break;
883 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
884 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
885 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
886 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
891 debug_printf("DKIM: no authres\n");
893 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
898 # endif /*!MACRO_PREDEF*/
899 #endif /*!DISABLE_DKIM*/