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);
25 # else /*!MACRO_PREDEF*/
29 pdkim_ctx dkim_sign_ctx;
31 int dkim_verify_oldpool;
32 pdkim_ctx *dkim_verify_ctx = NULL;
33 pdkim_signature *dkim_cur_sig = NULL;
34 static const uschar * dkim_collect_error = NULL;
36 #define DKIM_MAX_SIGNATURES 20
40 /*XXX the caller only uses the first record if we return multiple.
44 dkim_exim_query_dns_txt(uschar * name)
50 lookup_dnssec_authenticated = NULL;
51 if (dns_lookup(&dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
52 return NULL; /*XXX better error detail? logging? */
54 /* Search for TXT record */
56 for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
58 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
59 if (rr->type == T_TXT)
63 /* Copy record content to the answer buffer */
65 while (rr_offset < rr->size)
67 uschar len = rr->data[rr_offset++];
69 g = string_catn(g, US(rr->data + rr_offset), len);
70 if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
76 /* check if this looks like a DKIM record */
77 if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
79 gstring_reset_unused(g);
80 return string_from_gstring(g);
83 if (g) g->ptr = 0; /* overwrite previous record */
87 if (g) store_reset(g);
88 return NULL; /*XXX better error detail? logging? */
101 dkim_exim_verify_init(BOOL dot_stuffing)
103 /* There is a store-reset between header & body reception
104 so cannot use the main pool. Any allocs done by Exim
105 memory-handling must use the perm pool. */
107 dkim_verify_oldpool = store_pool;
108 store_pool = POOL_PERM;
110 /* Free previous context if there is one */
113 pdkim_free_ctx(dkim_verify_ctx);
115 /* Create new context */
117 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
118 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
119 dkim_collect_error = NULL;
121 /* Start feed up with any cached data */
124 store_pool = dkim_verify_oldpool;
129 dkim_exim_verify_feed(uschar * data, int len)
133 store_pool = POOL_PERM;
134 if ( dkim_collect_input
135 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
137 dkim_collect_error = pdkim_errstr(rc);
138 log_write(0, LOG_MAIN,
139 "DKIM: validation error: %.100s", dkim_collect_error);
140 dkim_collect_input = 0;
142 store_pool = dkim_verify_oldpool;
146 /* Log the result for the given signature */
148 dkim_exim_verify_log_sig(pdkim_signature * sig)
155 /* Remember the domain for the first pass result */
157 if ( !dkim_verify_overall
158 && dkim_verify_status
159 ? Ustrcmp(dkim_verify_status, US"pass") == 0
160 : sig->verify_status == PDKIM_VERIFY_PASS
162 dkim_verify_overall = string_copy(sig->domain);
164 /* Rewrite the sig result if the ACL overrode it. This is only
165 needed because the DMARC code (sigh) peeks at the dkim sigs.
166 Mark the sig for this having been done. */
168 if ( dkim_verify_status
169 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
170 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
172 { /* overridden by ACL */
173 sig->verify_ext_status = -1;
174 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
175 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
176 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
177 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
178 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
179 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
180 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
181 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
183 sig->verify_status = -1;
186 if (!LOGGING(dkim_verbose)) return;
189 logmsg = string_catn(NULL, US"DKIM: ", 6);
190 if (!(s = sig->domain)) s = US"<UNSET>";
191 logmsg = string_append(logmsg, 2, "d=", s);
192 if (!(s = sig->selector)) s = US"<UNSET>";
193 logmsg = string_append(logmsg, 2, " s=", s);
194 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
195 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
196 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
197 dkim_sig_to_a_tag(sig),
198 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
199 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
200 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
202 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
204 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
207 if (sig->verify_status & PDKIM_VERIFY_POLICY)
208 logmsg = string_append(logmsg, 5,
209 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
211 switch (sig->verify_status)
213 case PDKIM_VERIFY_NONE:
214 logmsg = string_cat(logmsg, US" [not verified]");
217 case PDKIM_VERIFY_INVALID:
218 logmsg = string_cat(logmsg, US" [invalid - ");
219 switch (sig->verify_ext_status)
221 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
222 logmsg = string_cat(logmsg,
223 US"public key record (currently?) unavailable]");
226 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
227 logmsg = string_cat(logmsg, US"overlong public key record]");
230 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
231 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
232 logmsg = string_cat(logmsg, US"syntax error in public key record]");
235 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
236 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
239 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
240 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
244 logmsg = string_cat(logmsg, US"unspecified problem]");
248 case PDKIM_VERIFY_FAIL:
249 logmsg = string_cat(logmsg, US" [verification failed - ");
250 switch (sig->verify_ext_status)
252 case PDKIM_VERIFY_FAIL_BODY:
253 logmsg = string_cat(logmsg,
254 US"body hash mismatch (body probably modified in transit)]");
257 case PDKIM_VERIFY_FAIL_MESSAGE:
258 logmsg = string_cat(logmsg,
259 US"signature did not verify "
260 "(headers probably modified in transit)]");
264 logmsg = string_cat(logmsg, US"unspecified reason]");
268 case PDKIM_VERIFY_PASS:
269 logmsg = string_cat(logmsg, US" [verification succeeded]");
273 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
278 /* Log a line for each signature */
280 dkim_exim_verify_log_all(void)
282 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
283 dkim_exim_verify_log_sig(sig);
288 dkim_exim_verify_finish(void)
292 const uschar * errstr = NULL;
294 store_pool = POOL_PERM;
296 /* Delete eventual previous signature chain */
299 dkim_signatures = NULL;
301 if (dkim_collect_error)
303 log_write(0, LOG_MAIN,
304 "DKIM: Error during validation, disabling signature verification: %.100s",
306 f.dkim_disable_verify = TRUE;
310 dkim_collect_input = 0;
312 /* Finish DKIM operation and fetch link to signatures chain */
314 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
316 if (rc != PDKIM_OK && errstr)
317 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
319 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
321 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
323 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
324 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
327 if (g) dkim_signers = g->s;
330 store_pool = dkim_verify_oldpool;
335 /* Args as per dkim_exim_acl_run() below */
337 dkim_acl_call(uschar * id, gstring ** res_ptr,
338 uschar ** user_msgptr, uschar ** log_msgptr)
342 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
344 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
345 dkim_exim_verify_log_sig(dkim_cur_sig);
346 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
352 /* For the given identity, run the DKIM ACL once for each matching signature.
355 id Identity to look for in dkim signatures
356 res_ptr ptr to growable string-list of status results,
357 appended to per ACL run
358 user_msgptr where to put a user error (for SMTP response)
359 log_msgptr where to put a logging message (not for SMTP response)
361 Returns: OK access is granted by an ACCEPT verb
362 DISCARD access is granted by a DISCARD verb
363 FAIL access is denied
364 FAIL_DROP access is denied; drop the connection
365 DEFER can't tell at the moment
370 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
371 uschar ** user_msgptr, uschar ** log_msgptr)
376 dkim_verify_status = US"none";
377 dkim_verify_reason = US"";
378 dkim_cur_signer = id;
380 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
383 /* Find signatures to run ACL on */
385 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
386 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
387 && strcmpic(cmp_val, id) == 0
390 /* The "dkim_domain" and "dkim_selector" expansion variables have
391 related globals, since they are used in the signing code too.
392 Instead of inventing separate names for verification, we set
393 them here. This is easy since a domain and selector is guaranteed
394 to be in a signature. The other dkim_* expansion items are
395 dynamically fetched from dkim_cur_sig at expansion time (see
396 dkim_exim_expand_query() below). */
399 dkim_signing_domain = US sig->domain;
400 dkim_signing_selector = US sig->selector;
401 dkim_key_length = sig->sighash.len * 8;
403 /* These two return static strings, so we can compare the addr
404 later to see if the ACL overwrote them. Check that when logging */
406 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
407 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
409 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
416 /* No matching sig found. Call ACL once anyway. */
419 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
424 dkim_exim_expand_defaults(int what)
428 case DKIM_ALGO: return US"";
429 case DKIM_BODYLENGTH: return US"9999999999999";
430 case DKIM_CANON_BODY: return US"";
431 case DKIM_CANON_HEADERS: return US"";
432 case DKIM_COPIEDHEADERS: return US"";
433 case DKIM_CREATED: return US"0";
434 case DKIM_EXPIRES: return US"9999999999999";
435 case DKIM_HEADERNAMES: return US"";
436 case DKIM_IDENTITY: return US"";
437 case DKIM_KEY_GRANULARITY: return US"*";
438 case DKIM_KEY_SRVTYPE: return US"*";
439 case DKIM_KEY_NOTES: return US"";
440 case DKIM_KEY_TESTING: return US"0";
441 case DKIM_NOSUBDOMAINS: return US"0";
442 case DKIM_VERIFY_STATUS: return US"none";
443 case DKIM_VERIFY_REASON: return US"";
444 default: return US"";
450 dkim_exim_expand_query(int what)
452 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
453 return dkim_exim_expand_defaults(what);
458 return dkim_sig_to_a_tag(dkim_cur_sig);
460 case DKIM_BODYLENGTH:
461 return dkim_cur_sig->bodylength >= 0
462 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
463 : dkim_exim_expand_defaults(what);
465 case DKIM_CANON_BODY:
466 switch (dkim_cur_sig->canon_body)
468 case PDKIM_CANON_RELAXED: return US"relaxed";
469 case PDKIM_CANON_SIMPLE:
470 default: return US"simple";
473 case DKIM_CANON_HEADERS:
474 switch (dkim_cur_sig->canon_headers)
476 case PDKIM_CANON_RELAXED: return US"relaxed";
477 case PDKIM_CANON_SIMPLE:
478 default: return US"simple";
481 case DKIM_COPIEDHEADERS:
482 return dkim_cur_sig->copiedheaders
483 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
486 return dkim_cur_sig->created > 0
487 ? string_sprintf("%lu", dkim_cur_sig->created)
488 : dkim_exim_expand_defaults(what);
491 return dkim_cur_sig->expires > 0
492 ? string_sprintf("%lu", dkim_cur_sig->expires)
493 : dkim_exim_expand_defaults(what);
495 case DKIM_HEADERNAMES:
496 return dkim_cur_sig->headernames
497 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
500 return dkim_cur_sig->identity
501 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
503 case DKIM_KEY_GRANULARITY:
504 return dkim_cur_sig->pubkey
505 ? dkim_cur_sig->pubkey->granularity
506 ? US dkim_cur_sig->pubkey->granularity
507 : dkim_exim_expand_defaults(what)
508 : dkim_exim_expand_defaults(what);
510 case DKIM_KEY_SRVTYPE:
511 return dkim_cur_sig->pubkey
512 ? dkim_cur_sig->pubkey->srvtype
513 ? US dkim_cur_sig->pubkey->srvtype
514 : dkim_exim_expand_defaults(what)
515 : dkim_exim_expand_defaults(what);
518 return dkim_cur_sig->pubkey
519 ? dkim_cur_sig->pubkey->notes
520 ? US dkim_cur_sig->pubkey->notes
521 : dkim_exim_expand_defaults(what)
522 : dkim_exim_expand_defaults(what);
524 case DKIM_KEY_TESTING:
525 return dkim_cur_sig->pubkey
526 ? dkim_cur_sig->pubkey->testing
528 : dkim_exim_expand_defaults(what)
529 : dkim_exim_expand_defaults(what);
531 case DKIM_NOSUBDOMAINS:
532 return dkim_cur_sig->pubkey
533 ? dkim_cur_sig->pubkey->no_subdomaining
535 : dkim_exim_expand_defaults(what)
536 : dkim_exim_expand_defaults(what);
538 case DKIM_VERIFY_STATUS:
539 switch (dkim_cur_sig->verify_status)
541 case PDKIM_VERIFY_INVALID: return US"invalid";
542 case PDKIM_VERIFY_FAIL: return US"fail";
543 case PDKIM_VERIFY_PASS: return US"pass";
544 case PDKIM_VERIFY_NONE:
545 default: return US"none";
548 case DKIM_VERIFY_REASON:
549 switch (dkim_cur_sig->verify_ext_status)
551 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
552 return US"pubkey_unavailable";
553 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
554 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
555 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
556 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
566 dkim_exim_sign_init(void)
568 int old_pool = store_pool;
569 store_pool = POOL_MAIN;
570 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
571 store_pool = old_pool;
575 /* Generate signatures for the given file.
576 If a prefix is given, prepend it to the file for the calculations.
579 NULL: error; error string written
580 string: signature header(s), or a zero-length string (not an error)
584 dkim_exim_sign(int fd, off_t off, uschar * prefix,
585 struct ob_dkim * dkim, const uschar ** errstr)
587 const uschar * dkim_domain = NULL;
589 gstring * seen_doms = NULL;
590 pdkim_signature * sig;
596 int old_pool = store_pool;
600 if (dkim->dot_stuffed)
601 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
603 store_pool = POOL_MAIN;
605 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
606 /* expansion error, do not send message. */
607 { errwhen = US"dkim_domain"; goto expand_bad; }
609 /* Set $dkim_domain expansion variable to each unique domain in list. */
612 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
614 const uschar * dkim_sel;
617 if (dkim_signing_domain[0] == '\0')
620 /* Only sign once for each domain, no matter how often it
621 appears in the expanded list. */
623 dkim_signing_domain = string_copylc(dkim_signing_domain);
624 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
625 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
628 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
630 /* Set $dkim_selector expansion variable to each selector in list,
633 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
634 { errwhen = US"dkim_selector"; goto expand_bad; }
636 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
639 uschar * dkim_canon_expanded;
641 uschar * dkim_sign_headers_expanded = NULL;
642 uschar * dkim_private_key_expanded;
643 uschar * dkim_hash_expanded;
644 uschar * dkim_identity_expanded = NULL;
645 uschar * dkim_timestamps_expanded = NULL;
646 unsigned long tval = 0, xval = 0;
648 /* Get canonicalization to use */
650 dkim_canon_expanded = dkim->dkim_canon
651 ? expand_string(dkim->dkim_canon) : US"relaxed";
652 if (!dkim_canon_expanded) /* expansion error, do not send message. */
653 { errwhen = US"dkim_canon"; goto expand_bad; }
655 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
656 pdkim_canon = PDKIM_CANON_RELAXED;
657 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
658 pdkim_canon = PDKIM_CANON_SIMPLE;
661 log_write(0, LOG_MAIN,
662 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
663 dkim_canon_expanded);
664 pdkim_canon = PDKIM_CANON_RELAXED;
667 if ( dkim->dkim_sign_headers
668 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
669 { errwhen = US"dkim_sign_header"; goto expand_bad; }
670 /* else pass NULL, which means default header list */
672 /* Get private key to use. */
674 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
675 { errwhen = US"dkim_private_key"; goto expand_bad; }
677 if ( Ustrlen(dkim_private_key_expanded) == 0
678 || Ustrcmp(dkim_private_key_expanded, "0") == 0
679 || Ustrcmp(dkim_private_key_expanded, "false") == 0
681 continue; /* don't sign, but no error */
683 if ( dkim_private_key_expanded[0] == '/'
684 && !(dkim_private_key_expanded =
685 expand_file_big_buffer(dkim_private_key_expanded)))
688 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
689 { errwhen = US"dkim_hash"; goto expand_bad; }
691 if (dkim->dkim_identity)
692 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
693 { errwhen = US"dkim_identity"; goto expand_bad; }
694 else if (!*dkim_identity_expanded)
695 dkim_identity_expanded = NULL;
697 if (dkim->dkim_timestamps)
698 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
699 { errwhen = US"dkim_timestamps"; goto expand_bad; }
701 xval = (tval = (unsigned long) time(NULL))
702 + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
704 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
705 dkim_signing_selector,
706 dkim_private_key_expanded,
711 dkim_private_key_expanded[0] = '\0';
713 pdkim_set_optional(sig,
714 CS dkim_sign_headers_expanded,
715 CS dkim_identity_expanded,
717 pdkim_canon, -1, tval, xval);
719 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
722 if (!dkim_sign_ctx.sig) /* link sig to context chain */
723 dkim_sign_ctx.sig = sig;
726 pdkim_signature * n = dkim_sign_ctx.sig;
727 while (n->next) n = n->next;
733 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
734 produce, if some other package (eg. ARC) is signing. */
736 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
738 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
739 sigbuf = string_get(1); /* return a zero-len string */
743 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
746 if (lseek(fd, off, SEEK_SET) < 0)
749 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
750 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
753 /* Handle failed read above. */
756 debug_printf("DKIM: Error reading -K file.\n");
761 /* Build string of headers, one per signature */
763 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
768 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
769 sigbuf = string_get(1); /* return a zero-len string */
771 else for (sigbuf = NULL; sig; sig = sig->next)
772 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
776 (void) string_from_gstring(sigbuf);
777 store_pool = old_pool;
782 log_write(0, LOG_MAIN|LOG_PANIC,
783 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
789 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
790 errwhen, expand_string_message);
798 authres_dkim(gstring * g)
800 int start = 0; /* compiler quietening */
802 DEBUG(D_acl) start = g->ptr;
804 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
806 g = string_catn(g, US";\n\tdkim=", 8);
808 if (sig->verify_status & PDKIM_VERIFY_POLICY)
809 g = string_append(g, 5,
810 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
811 else switch(sig->verify_status)
813 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
814 case PDKIM_VERIFY_INVALID:
815 switch (sig->verify_ext_status)
817 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
818 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
819 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
820 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
821 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
822 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
823 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
825 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
826 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
828 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
829 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
832 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
835 case PDKIM_VERIFY_FAIL:
836 switch (sig->verify_ext_status)
838 case PDKIM_VERIFY_FAIL_BODY:
840 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
842 case PDKIM_VERIFY_FAIL_MESSAGE:
844 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
847 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
851 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
852 default: g = string_cat(g, US"permerror"); break;
854 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
855 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
856 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
857 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
862 debug_printf("DKIM: no authres\n");
864 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
869 # endif /*!MACRO_PREDEF*/
870 #endif /*!DISABLE_DKIM*/