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();
55 lookup_dnssec_authenticated = NULL;
56 if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
57 return NULL; /*XXX better error detail? logging? */
59 /* Search for TXT record */
61 for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
63 rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
64 if (rr->type == T_TXT)
68 /* Copy record content to the answer buffer */
70 while (rr_offset < rr->size)
72 uschar len = rr->data[rr_offset++];
74 g = string_catn(g, US(rr->data + rr_offset), len);
75 if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
81 /* check if this looks like a DKIM record */
82 if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
84 gstring_release_unused(g);
85 return string_from_gstring(g);
88 if (g) g->ptr = 0; /* overwrite previous record */
92 store_reset(reset_point);
93 return NULL; /*XXX better error detail? logging? */
100 if (f.dkim_init_done) return;
101 f.dkim_init_done = TRUE;
108 dkim_exim_verify_init(BOOL dot_stuffing)
112 /* There is a store-reset between header & body reception
113 so cannot use the main pool. Any allocs done by Exim
114 memory-handling must use the perm pool. */
116 dkim_verify_oldpool = store_pool;
117 store_pool = POOL_PERM;
119 /* Free previous context if there is one */
122 pdkim_free_ctx(dkim_verify_ctx);
124 /* Create new context */
126 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
127 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
128 dkim_collect_error = NULL;
130 /* Start feed up with any cached data */
133 store_pool = dkim_verify_oldpool;
138 dkim_exim_verify_feed(uschar * data, int len)
142 store_pool = POOL_PERM;
143 if ( dkim_collect_input
144 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
146 dkim_collect_error = pdkim_errstr(rc);
147 log_write(0, LOG_MAIN,
148 "DKIM: validation error: %.100s", dkim_collect_error);
149 dkim_collect_input = 0;
151 store_pool = dkim_verify_oldpool;
155 /* Log the result for the given signature */
157 dkim_exim_verify_log_sig(pdkim_signature * sig)
164 /* Remember the domain for the first pass result */
166 if ( !dkim_verify_overall
167 && dkim_verify_status
168 ? Ustrcmp(dkim_verify_status, US"pass") == 0
169 : sig->verify_status == PDKIM_VERIFY_PASS
171 dkim_verify_overall = string_copy(sig->domain);
173 /* Rewrite the sig result if the ACL overrode it. This is only
174 needed because the DMARC code (sigh) peeks at the dkim sigs.
175 Mark the sig for this having been done. */
177 if ( dkim_verify_status
178 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
179 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
181 { /* overridden by ACL */
182 sig->verify_ext_status = -1;
183 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
184 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
185 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
186 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
187 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
188 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
189 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
190 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
192 sig->verify_status = -1;
195 if (!LOGGING(dkim_verbose)) return;
198 logmsg = string_catn(NULL, US"DKIM: ", 6);
199 if (!(s = sig->domain)) s = US"<UNSET>";
200 logmsg = string_append(logmsg, 2, "d=", s);
201 if (!(s = sig->selector)) s = US"<UNSET>";
202 logmsg = string_append(logmsg, 2, " s=", s);
203 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
204 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
205 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
206 dkim_sig_to_a_tag(sig),
207 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
208 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
209 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
211 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
213 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
216 if (sig->verify_status & PDKIM_VERIFY_POLICY)
217 logmsg = string_append(logmsg, 5,
218 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
220 switch (sig->verify_status)
222 case PDKIM_VERIFY_NONE:
223 logmsg = string_cat(logmsg, US" [not verified]");
226 case PDKIM_VERIFY_INVALID:
227 logmsg = string_cat(logmsg, US" [invalid - ");
228 switch (sig->verify_ext_status)
230 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
231 logmsg = string_cat(logmsg,
232 US"public key record (currently?) unavailable]");
235 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
236 logmsg = string_cat(logmsg, US"overlong public key record]");
239 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
240 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
241 logmsg = string_cat(logmsg, US"syntax error in public key record]");
244 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
245 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
248 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
249 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
253 logmsg = string_cat(logmsg, US"unspecified problem]");
257 case PDKIM_VERIFY_FAIL:
258 logmsg = string_cat(logmsg, US" [verification failed - ");
259 switch (sig->verify_ext_status)
261 case PDKIM_VERIFY_FAIL_BODY:
262 logmsg = string_cat(logmsg,
263 US"body hash mismatch (body probably modified in transit)]");
266 case PDKIM_VERIFY_FAIL_MESSAGE:
267 logmsg = string_cat(logmsg,
268 US"signature did not verify "
269 "(headers probably modified in transit)]");
272 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
273 logmsg = string_cat(logmsg,
274 US"signature invalid (key too short)]");
278 logmsg = string_cat(logmsg, US"unspecified reason]");
282 case PDKIM_VERIFY_PASS:
283 logmsg = string_cat(logmsg, US" [verification succeeded]");
287 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
292 /* Log a line for each signature */
294 dkim_exim_verify_log_all(void)
296 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
297 dkim_exim_verify_log_sig(sig);
302 dkim_exim_verify_finish(void)
306 const uschar * errstr = NULL;
308 store_pool = POOL_PERM;
310 /* Delete eventual previous signature chain */
313 dkim_signatures = NULL;
315 if (dkim_collect_error)
317 log_write(0, LOG_MAIN,
318 "DKIM: Error during validation, disabling signature verification: %.100s",
320 f.dkim_disable_verify = TRUE;
324 dkim_collect_input = 0;
326 /* Finish DKIM operation and fetch link to signatures chain */
328 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
330 if (rc != PDKIM_OK && errstr)
331 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
333 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
335 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
337 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
338 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
341 if (g) dkim_signers = g->s;
344 store_pool = dkim_verify_oldpool;
349 /* Args as per dkim_exim_acl_run() below */
351 dkim_acl_call(uschar * id, gstring ** res_ptr,
352 uschar ** user_msgptr, uschar ** log_msgptr)
356 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
358 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
359 dkim_exim_verify_log_sig(dkim_cur_sig);
360 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
366 /* For the given identity, run the DKIM ACL once for each matching signature.
369 id Identity to look for in dkim signatures
370 res_ptr ptr to growable string-list of status results,
371 appended to per ACL run
372 user_msgptr where to put a user error (for SMTP response)
373 log_msgptr where to put a logging message (not for SMTP response)
375 Returns: OK access is granted by an ACCEPT verb
376 DISCARD access is granted by a DISCARD verb
377 FAIL access is denied
378 FAIL_DROP access is denied; drop the connection
379 DEFER can't tell at the moment
384 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
385 uschar ** user_msgptr, uschar ** log_msgptr)
390 dkim_verify_status = US"none";
391 dkim_verify_reason = US"";
392 dkim_cur_signer = id;
394 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
397 /* Find signatures to run ACL on */
399 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
400 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
401 && strcmpic(cmp_val, id) == 0
404 /* The "dkim_domain" and "dkim_selector" expansion variables have
405 related globals, since they are used in the signing code too.
406 Instead of inventing separate names for verification, we set
407 them here. This is easy since a domain and selector is guaranteed
408 to be in a signature. The other dkim_* expansion items are
409 dynamically fetched from dkim_cur_sig at expansion time (see
410 dkim_exim_expand_query() below). */
413 dkim_signing_domain = US sig->domain;
414 dkim_signing_selector = US sig->selector;
415 dkim_key_length = sig->keybits;
417 /* These two return static strings, so we can compare the addr
418 later to see if the ACL overwrote them. Check that when logging */
420 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
421 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
423 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
430 /* No matching sig found. Call ACL once anyway. */
433 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
438 dkim_exim_expand_defaults(int what)
442 case DKIM_ALGO: return US"";
443 case DKIM_BODYLENGTH: return US"9999999999999";
444 case DKIM_CANON_BODY: return US"";
445 case DKIM_CANON_HEADERS: return US"";
446 case DKIM_COPIEDHEADERS: return US"";
447 case DKIM_CREATED: return US"0";
448 case DKIM_EXPIRES: return US"9999999999999";
449 case DKIM_HEADERNAMES: return US"";
450 case DKIM_IDENTITY: return US"";
451 case DKIM_KEY_GRANULARITY: return US"*";
452 case DKIM_KEY_SRVTYPE: return US"*";
453 case DKIM_KEY_NOTES: return US"";
454 case DKIM_KEY_TESTING: return US"0";
455 case DKIM_NOSUBDOMAINS: return US"0";
456 case DKIM_VERIFY_STATUS: return US"none";
457 case DKIM_VERIFY_REASON: return US"";
458 default: return US"";
464 dkim_exim_expand_query(int what)
466 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
467 return dkim_exim_expand_defaults(what);
472 return dkim_sig_to_a_tag(dkim_cur_sig);
474 case DKIM_BODYLENGTH:
475 return dkim_cur_sig->bodylength >= 0
476 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
477 : dkim_exim_expand_defaults(what);
479 case DKIM_CANON_BODY:
480 switch (dkim_cur_sig->canon_body)
482 case PDKIM_CANON_RELAXED: return US"relaxed";
483 case PDKIM_CANON_SIMPLE:
484 default: return US"simple";
487 case DKIM_CANON_HEADERS:
488 switch (dkim_cur_sig->canon_headers)
490 case PDKIM_CANON_RELAXED: return US"relaxed";
491 case PDKIM_CANON_SIMPLE:
492 default: return US"simple";
495 case DKIM_COPIEDHEADERS:
496 return dkim_cur_sig->copiedheaders
497 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
500 return dkim_cur_sig->created > 0
501 ? string_sprintf("%lu", dkim_cur_sig->created)
502 : dkim_exim_expand_defaults(what);
505 return dkim_cur_sig->expires > 0
506 ? string_sprintf("%lu", dkim_cur_sig->expires)
507 : dkim_exim_expand_defaults(what);
509 case DKIM_HEADERNAMES:
510 return dkim_cur_sig->headernames
511 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
514 return dkim_cur_sig->identity
515 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
517 case DKIM_KEY_GRANULARITY:
518 return dkim_cur_sig->pubkey
519 ? dkim_cur_sig->pubkey->granularity
520 ? US dkim_cur_sig->pubkey->granularity
521 : dkim_exim_expand_defaults(what)
522 : dkim_exim_expand_defaults(what);
524 case DKIM_KEY_SRVTYPE:
525 return dkim_cur_sig->pubkey
526 ? dkim_cur_sig->pubkey->srvtype
527 ? US dkim_cur_sig->pubkey->srvtype
528 : dkim_exim_expand_defaults(what)
529 : dkim_exim_expand_defaults(what);
532 return dkim_cur_sig->pubkey
533 ? dkim_cur_sig->pubkey->notes
534 ? US dkim_cur_sig->pubkey->notes
535 : dkim_exim_expand_defaults(what)
536 : dkim_exim_expand_defaults(what);
538 case DKIM_KEY_TESTING:
539 return dkim_cur_sig->pubkey
540 ? dkim_cur_sig->pubkey->testing
542 : dkim_exim_expand_defaults(what)
543 : dkim_exim_expand_defaults(what);
545 case DKIM_NOSUBDOMAINS:
546 return dkim_cur_sig->pubkey
547 ? dkim_cur_sig->pubkey->no_subdomaining
549 : dkim_exim_expand_defaults(what)
550 : dkim_exim_expand_defaults(what);
552 case DKIM_VERIFY_STATUS:
553 switch (dkim_cur_sig->verify_status)
555 case PDKIM_VERIFY_INVALID: return US"invalid";
556 case PDKIM_VERIFY_FAIL: return US"fail";
557 case PDKIM_VERIFY_PASS: return US"pass";
558 case PDKIM_VERIFY_NONE:
559 default: return US"none";
562 case DKIM_VERIFY_REASON:
563 switch (dkim_cur_sig->verify_ext_status)
565 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
566 return US"pubkey_unavailable";
567 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
568 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
569 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
570 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
571 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
581 dkim_exim_sign_init(void)
583 int old_pool = store_pool;
586 store_pool = POOL_MAIN;
587 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
588 store_pool = old_pool;
592 /* Generate signatures for the given file.
593 If a prefix is given, prepend it to the file for the calculations.
596 NULL: error; error string written
597 string: signature header(s), or a zero-length string (not an error)
601 dkim_exim_sign(int fd, off_t off, uschar * prefix,
602 struct ob_dkim * dkim, const uschar ** errstr)
604 const uschar * dkim_domain = NULL;
606 gstring * seen_doms = NULL;
607 pdkim_signature * sig;
613 int old_pool = store_pool;
617 if (dkim->dot_stuffed)
618 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
620 store_pool = POOL_MAIN;
622 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
623 /* expansion error, do not send message. */
624 { errwhen = US"dkim_domain"; goto expand_bad; }
626 /* Set $dkim_domain expansion variable to each unique domain in list. */
629 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
631 const uschar * dkim_sel;
634 if (dkim_signing_domain[0] == '\0')
637 /* Only sign once for each domain, no matter how often it
638 appears in the expanded list. */
640 dkim_signing_domain = string_copylc(dkim_signing_domain);
641 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
642 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
645 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
647 /* Set $dkim_selector expansion variable to each selector in list,
650 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
651 { errwhen = US"dkim_selector"; goto expand_bad; }
653 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
656 uschar * dkim_canon_expanded;
658 uschar * dkim_sign_headers_expanded = NULL;
659 uschar * dkim_private_key_expanded;
660 uschar * dkim_hash_expanded;
661 uschar * dkim_identity_expanded = NULL;
662 uschar * dkim_timestamps_expanded = NULL;
663 unsigned long tval = 0, xval = 0;
665 /* Get canonicalization to use */
667 dkim_canon_expanded = dkim->dkim_canon
668 ? expand_string(dkim->dkim_canon) : US"relaxed";
669 if (!dkim_canon_expanded) /* expansion error, do not send message. */
670 { errwhen = US"dkim_canon"; goto expand_bad; }
672 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
673 pdkim_canon = PDKIM_CANON_RELAXED;
674 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
675 pdkim_canon = PDKIM_CANON_SIMPLE;
678 log_write(0, LOG_MAIN,
679 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
680 dkim_canon_expanded);
681 pdkim_canon = PDKIM_CANON_RELAXED;
684 if ( dkim->dkim_sign_headers
685 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
686 { errwhen = US"dkim_sign_header"; goto expand_bad; }
687 /* else pass NULL, which means default header list */
689 /* Get private key to use. */
691 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
692 { errwhen = US"dkim_private_key"; goto expand_bad; }
694 if ( Ustrlen(dkim_private_key_expanded) == 0
695 || Ustrcmp(dkim_private_key_expanded, "0") == 0
696 || Ustrcmp(dkim_private_key_expanded, "false") == 0
698 continue; /* don't sign, but no error */
700 if ( dkim_private_key_expanded[0] == '/'
701 && !(dkim_private_key_expanded =
702 expand_file_big_buffer(dkim_private_key_expanded)))
705 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
706 { errwhen = US"dkim_hash"; goto expand_bad; }
708 if (dkim->dkim_identity)
709 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
710 { errwhen = US"dkim_identity"; goto expand_bad; }
711 else if (!*dkim_identity_expanded)
712 dkim_identity_expanded = NULL;
714 if (dkim->dkim_timestamps)
715 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
716 { errwhen = US"dkim_timestamps"; goto expand_bad; }
718 xval = (tval = (unsigned long) time(NULL))
719 + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
721 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
722 dkim_signing_selector,
723 dkim_private_key_expanded,
728 dkim_private_key_expanded[0] = '\0';
730 pdkim_set_optional(sig,
731 CS dkim_sign_headers_expanded,
732 CS dkim_identity_expanded,
734 pdkim_canon, -1, tval, xval);
736 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
739 if (!dkim_sign_ctx.sig) /* link sig to context chain */
740 dkim_sign_ctx.sig = sig;
743 pdkim_signature * n = dkim_sign_ctx.sig;
744 while (n->next) n = n->next;
750 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
751 produce, if some other package (eg. ARC) is signing. */
753 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
755 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
756 sigbuf = string_get(1); /* return a zero-len string */
760 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
763 if (lseek(fd, off, SEEK_SET) < 0)
766 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
767 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
770 /* Handle failed read above. */
773 debug_printf("DKIM: Error reading -K file.\n");
778 /* Build string of headers, one per signature */
780 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
785 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
786 sigbuf = string_get(1); /* return a zero-len string */
788 else for (sigbuf = NULL; sig; sig = sig->next)
789 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
793 (void) string_from_gstring(sigbuf);
794 store_pool = old_pool;
799 log_write(0, LOG_MAIN|LOG_PANIC,
800 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
806 *errstr = string_sprintf("failed to expand %s: %s",
807 errwhen, expand_string_message);
808 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
816 authres_dkim(gstring * g)
818 int start = 0; /* compiler quietening */
820 DEBUG(D_acl) start = g->ptr;
822 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
824 g = string_catn(g, US";\n\tdkim=", 8);
826 if (sig->verify_status & PDKIM_VERIFY_POLICY)
827 g = string_append(g, 5,
828 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
829 else switch(sig->verify_status)
831 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
832 case PDKIM_VERIFY_INVALID:
833 switch (sig->verify_ext_status)
835 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
836 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
837 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
838 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
839 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
840 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
841 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
843 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
844 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
846 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
847 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
850 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
853 case PDKIM_VERIFY_FAIL:
854 switch (sig->verify_ext_status)
856 case PDKIM_VERIFY_FAIL_BODY:
858 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
860 case PDKIM_VERIFY_FAIL_MESSAGE:
862 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
864 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
865 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
868 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
872 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
873 default: g = string_cat(g, US"permerror"); break;
875 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
876 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
877 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
878 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
883 debug_printf("DKIM: no authres\n");
885 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
890 # endif /*!MACRO_PREDEF*/
891 #endif /*!DISABLE_DKIM*/