1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge, 1995 - 2018 */
6 /* See the file NOTICE for conditions of use and distribution. */
8 /* Code for DKIM support. Other DKIM relevant code is in
9 receive.c, transport.c and transports/smtp.c */
15 # include "pdkim/pdkim.h"
18 # include "macro_predef.h"
23 builtin_macro_create_var(US"_DKIM_SIGN_HEADERS", US PDKIM_DEFAULT_SIGN_HEADERS);
24 builtin_macro_create_var(US"_DKIM_OVERSIGN_HEADERS", US PDKIM_OVERSIGN_HEADERS);
26 # else /*!MACRO_PREDEF*/
30 pdkim_ctx dkim_sign_ctx;
32 int dkim_verify_oldpool;
33 pdkim_ctx *dkim_verify_ctx = NULL;
34 pdkim_signature *dkim_cur_sig = NULL;
35 static const uschar * dkim_collect_error = NULL;
37 #define DKIM_MAX_SIGNATURES 20
41 /* Look up the DKIM record in DNS for the given hostname.
42 Will use the first found if there are multiple.
43 The return string is tainted, having come from off-site.
47 dkim_exim_query_dns_txt(const uschar * name)
49 dns_answer * dnsa = store_get_dns_answer();
51 rmark reset_point = store_mark();
54 lookup_dnssec_authenticated = NULL;
55 if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
56 return NULL; /*XXX better error detail? logging? */
58 /* Search for TXT record */
60 for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
62 rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
63 if (rr->type == T_TXT)
67 /* Copy record content to the answer buffer */
69 while (rr_offset < rr->size)
71 uschar len = rr->data[rr_offset++];
73 g = string_catn(g, US(rr->data + rr_offset), len);
74 if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
80 /* check if this looks like a DKIM record */
81 if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
83 gstring_release_unused(g);
84 return string_from_gstring(g);
87 if (g) g->ptr = 0; /* overwrite previous record */
91 store_reset(reset_point);
92 return NULL; /*XXX better error detail? logging? */
99 if (f.dkim_init_done) return;
100 f.dkim_init_done = TRUE;
107 dkim_exim_verify_init(BOOL dot_stuffing)
111 /* There is a store-reset between header & body reception
112 so cannot use the main pool. Any allocs done by Exim
113 memory-handling must use the perm pool. */
115 dkim_verify_oldpool = store_pool;
116 store_pool = POOL_PERM;
118 /* Free previous context if there is one */
121 pdkim_free_ctx(dkim_verify_ctx);
123 /* Create new context */
125 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
126 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
127 dkim_collect_error = NULL;
129 /* Start feed up with any cached data */
132 store_pool = dkim_verify_oldpool;
137 dkim_exim_verify_feed(uschar * data, int len)
141 store_pool = POOL_PERM;
142 if ( dkim_collect_input
143 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
145 dkim_collect_error = pdkim_errstr(rc);
146 log_write(0, LOG_MAIN,
147 "DKIM: validation error: %.100s", dkim_collect_error);
148 dkim_collect_input = 0;
150 store_pool = dkim_verify_oldpool;
154 /* Log the result for the given signature */
156 dkim_exim_verify_log_sig(pdkim_signature * sig)
163 /* Remember the domain for the first pass result */
165 if ( !dkim_verify_overall
166 && dkim_verify_status
167 ? Ustrcmp(dkim_verify_status, US"pass") == 0
168 : sig->verify_status == PDKIM_VERIFY_PASS
170 dkim_verify_overall = string_copy(sig->domain);
172 /* Rewrite the sig result if the ACL overrode it. This is only
173 needed because the DMARC code (sigh) peeks at the dkim sigs.
174 Mark the sig for this having been done. */
176 if ( dkim_verify_status
177 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
178 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
180 { /* overridden by ACL */
181 sig->verify_ext_status = -1;
182 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
183 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
184 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
185 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
186 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
187 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
188 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
189 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
191 sig->verify_status = -1;
194 if (!LOGGING(dkim_verbose)) return;
197 logmsg = string_catn(NULL, US"DKIM: ", 6);
198 if (!(s = sig->domain)) s = US"<UNSET>";
199 logmsg = string_append(logmsg, 2, "d=", s);
200 if (!(s = sig->selector)) s = US"<UNSET>";
201 logmsg = string_append(logmsg, 2, " s=", s);
202 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
203 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
204 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
205 dkim_sig_to_a_tag(sig),
206 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
207 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
208 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
210 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
212 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
215 if (sig->verify_status & PDKIM_VERIFY_POLICY)
216 logmsg = string_append(logmsg, 5,
217 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
219 switch (sig->verify_status)
221 case PDKIM_VERIFY_NONE:
222 logmsg = string_cat(logmsg, US" [not verified]");
225 case PDKIM_VERIFY_INVALID:
226 logmsg = string_cat(logmsg, US" [invalid - ");
227 switch (sig->verify_ext_status)
229 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
230 logmsg = string_cat(logmsg,
231 US"public key record (currently?) unavailable]");
234 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
235 logmsg = string_cat(logmsg, US"overlong public key record]");
238 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
239 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
240 logmsg = string_cat(logmsg, US"syntax error in public key record]");
243 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
244 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
247 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
248 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
252 logmsg = string_cat(logmsg, US"unspecified problem]");
256 case PDKIM_VERIFY_FAIL:
257 logmsg = string_cat(logmsg, US" [verification failed - ");
258 switch (sig->verify_ext_status)
260 case PDKIM_VERIFY_FAIL_BODY:
261 logmsg = string_cat(logmsg,
262 US"body hash mismatch (body probably modified in transit)]");
265 case PDKIM_VERIFY_FAIL_MESSAGE:
266 logmsg = string_cat(logmsg,
267 US"signature did not verify "
268 "(headers probably modified in transit)]");
271 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
272 logmsg = string_cat(logmsg,
273 US"signature invalid (key too short)]");
277 logmsg = string_cat(logmsg, US"unspecified reason]");
281 case PDKIM_VERIFY_PASS:
282 logmsg = string_cat(logmsg, US" [verification succeeded]");
286 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
291 /* Log a line for each signature */
293 dkim_exim_verify_log_all(void)
295 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
296 dkim_exim_verify_log_sig(sig);
301 dkim_exim_verify_finish(void)
305 const uschar * errstr = NULL;
307 store_pool = POOL_PERM;
309 /* Delete eventual previous signature chain */
312 dkim_signatures = NULL;
314 if (dkim_collect_error)
316 log_write(0, LOG_MAIN,
317 "DKIM: Error during validation, disabling signature verification: %.100s",
319 f.dkim_disable_verify = TRUE;
323 dkim_collect_input = 0;
325 /* Finish DKIM operation and fetch link to signatures chain */
327 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
329 if (rc != PDKIM_OK && errstr)
330 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
332 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
334 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
336 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
337 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
340 if (g) dkim_signers = g->s;
343 store_pool = dkim_verify_oldpool;
348 /* Args as per dkim_exim_acl_run() below */
350 dkim_acl_call(uschar * id, gstring ** res_ptr,
351 uschar ** user_msgptr, uschar ** log_msgptr)
355 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
357 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
358 dkim_exim_verify_log_sig(dkim_cur_sig);
359 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
365 /* For the given identity, run the DKIM ACL once for each matching signature.
368 id Identity to look for in dkim signatures
369 res_ptr ptr to growable string-list of status results,
370 appended to per ACL run
371 user_msgptr where to put a user error (for SMTP response)
372 log_msgptr where to put a logging message (not for SMTP response)
374 Returns: OK access is granted by an ACCEPT verb
375 DISCARD access is granted by a DISCARD verb
376 FAIL access is denied
377 FAIL_DROP access is denied; drop the connection
378 DEFER can't tell at the moment
383 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
384 uschar ** user_msgptr, uschar ** log_msgptr)
389 dkim_verify_status = US"none";
390 dkim_verify_reason = US"";
391 dkim_cur_signer = id;
393 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
396 /* Find signatures to run ACL on */
398 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
399 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
400 && strcmpic(cmp_val, id) == 0
403 /* The "dkim_domain" and "dkim_selector" expansion variables have
404 related globals, since they are used in the signing code too.
405 Instead of inventing separate names for verification, we set
406 them here. This is easy since a domain and selector is guaranteed
407 to be in a signature. The other dkim_* expansion items are
408 dynamically fetched from dkim_cur_sig at expansion time (see
409 dkim_exim_expand_query() below). */
412 dkim_signing_domain = US sig->domain;
413 dkim_signing_selector = US sig->selector;
414 dkim_key_length = sig->keybits;
416 /* These two return static strings, so we can compare the addr
417 later to see if the ACL overwrote them. Check that when logging */
419 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
420 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
422 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
429 /* No matching sig found. Call ACL once anyway. */
432 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
437 dkim_exim_expand_defaults(int what)
441 case DKIM_ALGO: return US"";
442 case DKIM_BODYLENGTH: return US"9999999999999";
443 case DKIM_CANON_BODY: return US"";
444 case DKIM_CANON_HEADERS: return US"";
445 case DKIM_COPIEDHEADERS: return US"";
446 case DKIM_CREATED: return US"0";
447 case DKIM_EXPIRES: return US"9999999999999";
448 case DKIM_HEADERNAMES: return US"";
449 case DKIM_IDENTITY: return US"";
450 case DKIM_KEY_GRANULARITY: return US"*";
451 case DKIM_KEY_SRVTYPE: return US"*";
452 case DKIM_KEY_NOTES: return US"";
453 case DKIM_KEY_TESTING: return US"0";
454 case DKIM_NOSUBDOMAINS: return US"0";
455 case DKIM_VERIFY_STATUS: return US"none";
456 case DKIM_VERIFY_REASON: return US"";
457 default: return US"";
463 dkim_exim_expand_query(int what)
465 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
466 return dkim_exim_expand_defaults(what);
471 return dkim_sig_to_a_tag(dkim_cur_sig);
473 case DKIM_BODYLENGTH:
474 return dkim_cur_sig->bodylength >= 0
475 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
476 : dkim_exim_expand_defaults(what);
478 case DKIM_CANON_BODY:
479 switch (dkim_cur_sig->canon_body)
481 case PDKIM_CANON_RELAXED: return US"relaxed";
482 case PDKIM_CANON_SIMPLE:
483 default: return US"simple";
486 case DKIM_CANON_HEADERS:
487 switch (dkim_cur_sig->canon_headers)
489 case PDKIM_CANON_RELAXED: return US"relaxed";
490 case PDKIM_CANON_SIMPLE:
491 default: return US"simple";
494 case DKIM_COPIEDHEADERS:
495 return dkim_cur_sig->copiedheaders
496 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
499 return dkim_cur_sig->created > 0
500 ? string_sprintf("%lu", dkim_cur_sig->created)
501 : dkim_exim_expand_defaults(what);
504 return dkim_cur_sig->expires > 0
505 ? string_sprintf("%lu", dkim_cur_sig->expires)
506 : dkim_exim_expand_defaults(what);
508 case DKIM_HEADERNAMES:
509 return dkim_cur_sig->headernames
510 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
513 return dkim_cur_sig->identity
514 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
516 case DKIM_KEY_GRANULARITY:
517 return dkim_cur_sig->pubkey
518 ? dkim_cur_sig->pubkey->granularity
519 ? US dkim_cur_sig->pubkey->granularity
520 : dkim_exim_expand_defaults(what)
521 : dkim_exim_expand_defaults(what);
523 case DKIM_KEY_SRVTYPE:
524 return dkim_cur_sig->pubkey
525 ? dkim_cur_sig->pubkey->srvtype
526 ? US dkim_cur_sig->pubkey->srvtype
527 : dkim_exim_expand_defaults(what)
528 : dkim_exim_expand_defaults(what);
531 return dkim_cur_sig->pubkey
532 ? dkim_cur_sig->pubkey->notes
533 ? US dkim_cur_sig->pubkey->notes
534 : dkim_exim_expand_defaults(what)
535 : dkim_exim_expand_defaults(what);
537 case DKIM_KEY_TESTING:
538 return dkim_cur_sig->pubkey
539 ? dkim_cur_sig->pubkey->testing
541 : dkim_exim_expand_defaults(what)
542 : dkim_exim_expand_defaults(what);
544 case DKIM_NOSUBDOMAINS:
545 return dkim_cur_sig->pubkey
546 ? dkim_cur_sig->pubkey->no_subdomaining
548 : dkim_exim_expand_defaults(what)
549 : dkim_exim_expand_defaults(what);
551 case DKIM_VERIFY_STATUS:
552 switch (dkim_cur_sig->verify_status)
554 case PDKIM_VERIFY_INVALID: return US"invalid";
555 case PDKIM_VERIFY_FAIL: return US"fail";
556 case PDKIM_VERIFY_PASS: return US"pass";
557 case PDKIM_VERIFY_NONE:
558 default: return US"none";
561 case DKIM_VERIFY_REASON:
562 switch (dkim_cur_sig->verify_ext_status)
564 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
565 return US"pubkey_unavailable";
566 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
567 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
568 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
569 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
570 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
580 dkim_exim_sign_init(void)
582 int old_pool = store_pool;
585 store_pool = POOL_MAIN;
586 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
587 store_pool = old_pool;
591 /* Generate signatures for the given file.
592 If a prefix is given, prepend it to the file for the calculations.
595 NULL: error; error string written
596 string: signature header(s), or a zero-length string (not an error)
600 dkim_exim_sign(int fd, off_t off, uschar * prefix,
601 struct ob_dkim * dkim, const uschar ** errstr)
603 const uschar * dkim_domain = NULL;
605 gstring * seen_doms = NULL;
606 pdkim_signature * sig;
612 int old_pool = store_pool;
616 if (dkim->dot_stuffed)
617 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
619 store_pool = POOL_MAIN;
621 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
622 /* expansion error, do not send message. */
623 { errwhen = US"dkim_domain"; goto expand_bad; }
625 /* Set $dkim_domain expansion variable to each unique domain in list. */
628 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
630 const uschar * dkim_sel;
633 if (dkim_signing_domain[0] == '\0')
636 /* Only sign once for each domain, no matter how often it
637 appears in the expanded list. */
639 dkim_signing_domain = string_copylc(dkim_signing_domain);
640 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
641 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
644 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
646 /* Set $dkim_selector expansion variable to each selector in list,
649 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
650 { errwhen = US"dkim_selector"; goto expand_bad; }
652 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
655 uschar * dkim_canon_expanded;
657 uschar * dkim_sign_headers_expanded = NULL;
658 uschar * dkim_private_key_expanded;
659 uschar * dkim_hash_expanded;
660 uschar * dkim_identity_expanded = NULL;
661 uschar * dkim_timestamps_expanded = NULL;
662 unsigned long tval = 0, xval = 0;
664 /* Get canonicalization to use */
666 dkim_canon_expanded = dkim->dkim_canon
667 ? expand_string(dkim->dkim_canon) : US"relaxed";
668 if (!dkim_canon_expanded) /* expansion error, do not send message. */
669 { errwhen = US"dkim_canon"; goto expand_bad; }
671 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
672 pdkim_canon = PDKIM_CANON_RELAXED;
673 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
674 pdkim_canon = PDKIM_CANON_SIMPLE;
677 log_write(0, LOG_MAIN,
678 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
679 dkim_canon_expanded);
680 pdkim_canon = PDKIM_CANON_RELAXED;
683 if ( dkim->dkim_sign_headers
684 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
685 { errwhen = US"dkim_sign_header"; goto expand_bad; }
686 /* else pass NULL, which means default header list */
688 /* Get private key to use. */
690 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
691 { errwhen = US"dkim_private_key"; goto expand_bad; }
693 if ( Ustrlen(dkim_private_key_expanded) == 0
694 || Ustrcmp(dkim_private_key_expanded, "0") == 0
695 || Ustrcmp(dkim_private_key_expanded, "false") == 0
697 continue; /* don't sign, but no error */
699 if ( dkim_private_key_expanded[0] == '/'
700 && !(dkim_private_key_expanded =
701 expand_file_big_buffer(dkim_private_key_expanded)))
704 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
705 { errwhen = US"dkim_hash"; goto expand_bad; }
707 if (dkim->dkim_identity)
708 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
709 { errwhen = US"dkim_identity"; goto expand_bad; }
710 else if (!*dkim_identity_expanded)
711 dkim_identity_expanded = NULL;
713 if (dkim->dkim_timestamps)
714 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
715 { errwhen = US"dkim_timestamps"; goto expand_bad; }
717 xval = (tval = (unsigned long) time(NULL))
718 + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
720 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
721 dkim_signing_selector,
722 dkim_private_key_expanded,
727 dkim_private_key_expanded[0] = '\0';
729 pdkim_set_optional(sig,
730 CS dkim_sign_headers_expanded,
731 CS dkim_identity_expanded,
733 pdkim_canon, -1, tval, xval);
735 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
738 if (!dkim_sign_ctx.sig) /* link sig to context chain */
739 dkim_sign_ctx.sig = sig;
742 pdkim_signature * n = dkim_sign_ctx.sig;
743 while (n->next) n = n->next;
749 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
750 produce, if some other package (eg. ARC) is signing. */
752 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
754 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
755 sigbuf = string_get(1); /* return a zero-len string */
759 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
762 if (lseek(fd, off, SEEK_SET) < 0)
765 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
766 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
769 /* Handle failed read above. */
772 debug_printf("DKIM: Error reading -K file.\n");
777 /* Build string of headers, one per signature */
779 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
784 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
785 sigbuf = string_get(1); /* return a zero-len string */
787 else for (sigbuf = NULL; sig; sig = sig->next)
788 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
792 (void) string_from_gstring(sigbuf);
793 store_pool = old_pool;
798 log_write(0, LOG_MAIN|LOG_PANIC,
799 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
805 *errstr = string_sprintf("failed to expand %s: %s",
806 errwhen, expand_string_message);
807 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
815 authres_dkim(gstring * g)
817 int start = 0; /* compiler quietening */
819 DEBUG(D_acl) start = g->ptr;
821 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
823 g = string_catn(g, US";\n\tdkim=", 8);
825 if (sig->verify_status & PDKIM_VERIFY_POLICY)
826 g = string_append(g, 5,
827 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
828 else switch(sig->verify_status)
830 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
831 case PDKIM_VERIFY_INVALID:
832 switch (sig->verify_ext_status)
834 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
835 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
836 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
837 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
838 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
839 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
840 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
842 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
843 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
845 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
846 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
849 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
852 case PDKIM_VERIFY_FAIL:
853 switch (sig->verify_ext_status)
855 case PDKIM_VERIFY_FAIL_BODY:
857 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
859 case PDKIM_VERIFY_FAIL_MESSAGE:
861 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
863 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
864 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
867 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
871 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
872 default: g = string_cat(g, US"permerror"); break;
874 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
875 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
876 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
877 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
882 debug_printf("DKIM: no authres\n");
884 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
889 # endif /*!MACRO_PREDEF*/
890 #endif /*!DISABLE_DKIM*/