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)
51 lookup_dnssec_authenticated = NULL;
52 if (dns_lookup(&dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
53 return NULL; /*XXX better error detail? logging? */
55 /* Search for TXT record */
57 for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
59 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
60 if (rr->type == T_TXT)
64 /* Copy record content to the answer buffer */
66 while (rr_offset < rr->size)
68 uschar len = rr->data[rr_offset++];
70 g = string_catn(g, US(rr->data + rr_offset), len);
71 if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
77 /* check if this looks like a DKIM record */
78 if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
80 gstring_reset_unused(g);
81 return string_from_gstring(g);
84 if (g) g->ptr = 0; /* overwrite previous record */
88 if (g) store_reset(g);
89 return NULL; /*XXX better error detail? logging? */
102 dkim_exim_verify_init(BOOL dot_stuffing)
104 /* There is a store-reset between header & body reception
105 so cannot use the main pool. Any allocs done by Exim
106 memory-handling must use the perm pool. */
108 dkim_verify_oldpool = store_pool;
109 store_pool = POOL_PERM;
111 /* Free previous context if there is one */
114 pdkim_free_ctx(dkim_verify_ctx);
116 /* Create new context */
118 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
119 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
120 dkim_collect_error = NULL;
122 /* Start feed up with any cached data */
125 store_pool = dkim_verify_oldpool;
130 dkim_exim_verify_feed(uschar * data, int len)
134 store_pool = POOL_PERM;
135 if ( dkim_collect_input
136 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
138 dkim_collect_error = pdkim_errstr(rc);
139 log_write(0, LOG_MAIN,
140 "DKIM: validation error: %.100s", dkim_collect_error);
141 dkim_collect_input = 0;
143 store_pool = dkim_verify_oldpool;
147 /* Log the result for the given signature */
149 dkim_exim_verify_log_sig(pdkim_signature * sig)
156 /* Remember the domain for the first pass result */
158 if ( !dkim_verify_overall
159 && dkim_verify_status
160 ? Ustrcmp(dkim_verify_status, US"pass") == 0
161 : sig->verify_status == PDKIM_VERIFY_PASS
163 dkim_verify_overall = string_copy(sig->domain);
165 /* Rewrite the sig result if the ACL overrode it. This is only
166 needed because the DMARC code (sigh) peeks at the dkim sigs.
167 Mark the sig for this having been done. */
169 if ( dkim_verify_status
170 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
171 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
173 { /* overridden by ACL */
174 sig->verify_ext_status = -1;
175 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
176 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
177 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
178 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
179 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
180 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
181 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
182 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
184 sig->verify_status = -1;
187 if (!LOGGING(dkim_verbose)) return;
190 logmsg = string_catn(NULL, US"DKIM: ", 6);
191 if (!(s = sig->domain)) s = US"<UNSET>";
192 logmsg = string_append(logmsg, 2, "d=", s);
193 if (!(s = sig->selector)) s = US"<UNSET>";
194 logmsg = string_append(logmsg, 2, " s=", s);
195 logmsg = string_append(logmsg, 7,
196 " c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
197 "/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
198 " a=", dkim_sig_to_a_tag(sig),
199 string_sprintf(" b=" SIZE_T_FMT,
200 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
201 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
202 if (sig->created > 0) logmsg = string_cat(logmsg,
203 string_sprintf(" t=%lu", sig->created));
204 if (sig->expires > 0) logmsg = string_cat(logmsg,
205 string_sprintf(" x=%lu", sig->expires));
206 if (sig->bodylength > -1) logmsg = string_cat(logmsg,
207 string_sprintf(" l=%lu", sig->bodylength));
209 if (sig->verify_status & PDKIM_VERIFY_POLICY)
210 logmsg = string_append(logmsg, 5,
211 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
213 switch (sig->verify_status)
215 case PDKIM_VERIFY_NONE:
216 logmsg = string_cat(logmsg, US" [not verified]");
219 case PDKIM_VERIFY_INVALID:
220 logmsg = string_cat(logmsg, US" [invalid - ");
221 switch (sig->verify_ext_status)
223 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
224 logmsg = string_cat(logmsg,
225 US"public key record (currently?) unavailable]");
228 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
229 logmsg = string_cat(logmsg, US"overlong public key record]");
232 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
233 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
234 logmsg = string_cat(logmsg, US"syntax error in public key record]");
237 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
238 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
241 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
242 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
246 logmsg = string_cat(logmsg, US"unspecified problem]");
250 case PDKIM_VERIFY_FAIL:
251 logmsg = string_cat(logmsg, US" [verification failed - ");
252 switch (sig->verify_ext_status)
254 case PDKIM_VERIFY_FAIL_BODY:
255 logmsg = string_cat(logmsg,
256 US"body hash mismatch (body probably modified in transit)]");
259 case PDKIM_VERIFY_FAIL_MESSAGE:
260 logmsg = string_cat(logmsg,
261 US"signature did not verify "
262 "(headers probably modified in transit)]");
266 logmsg = string_cat(logmsg, US"unspecified reason]");
270 case PDKIM_VERIFY_PASS:
271 logmsg = string_cat(logmsg, US" [verification succeeded]");
275 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
280 /* Log a line for each signature */
282 dkim_exim_verify_log_all(void)
284 pdkim_signature * sig;
285 for (sig = dkim_signatures; sig; sig = sig->next) dkim_exim_verify_log_sig(sig);
290 dkim_exim_verify_finish(void)
292 pdkim_signature * sig;
295 const uschar * errstr = NULL;
297 store_pool = POOL_PERM;
299 /* Delete eventual previous signature chain */
302 dkim_signatures = NULL;
304 if (dkim_collect_error)
306 log_write(0, LOG_MAIN,
307 "DKIM: Error during validation, disabling signature verification: %.100s",
309 dkim_disable_verify = TRUE;
313 dkim_collect_input = 0;
315 /* Finish DKIM operation and fetch link to signatures chain */
317 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
319 if (rc != PDKIM_OK && errstr)
320 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
322 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
324 for (sig = dkim_signatures; sig; sig = sig->next)
326 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
327 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
330 if (g) dkim_signers = g->s;
333 store_pool = dkim_verify_oldpool;
338 /* Args as per dkim_exim_acl_run() below */
340 dkim_acl_call(uschar * id, gstring ** res_ptr,
341 uschar ** user_msgptr, uschar ** log_msgptr)
345 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
347 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
348 dkim_exim_verify_log_sig(dkim_cur_sig);
349 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
355 /* For the given identity, run the DKIM ACL once for each matching signature.
358 id Identity to look for in dkim signatures
359 res_ptr ptr to growable string-list of status results,
360 appended to per ACL run
361 user_msgptr where to put a user error (for SMTP response)
362 log_msgptr where to put a logging message (not for SMTP response)
364 Returns: OK access is granted by an ACCEPT verb
365 DISCARD access is granted by a DISCARD verb
366 FAIL access is denied
367 FAIL_DROP access is denied; drop the connection
368 DEFER can't tell at the moment
373 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
374 uschar ** user_msgptr, uschar ** log_msgptr)
376 pdkim_signature * sig;
380 dkim_verify_status = US"none";
381 dkim_verify_reason = US"";
382 dkim_cur_signer = id;
384 if (dkim_disable_verify || !id || !dkim_verify_ctx)
387 /* Find signatures to run ACL on */
389 for (sig = dkim_signatures; sig; sig = sig->next)
390 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
391 && strcmpic(cmp_val, id) == 0
394 /* The "dkim_domain" and "dkim_selector" expansion variables have
395 related globals, since they are used in the signing code too.
396 Instead of inventing separate names for verification, we set
397 them here. This is easy since a domain and selector is guaranteed
398 to be in a signature. The other dkim_* expansion items are
399 dynamically fetched from dkim_cur_sig at expansion time (see
400 dkim_exim_expand_query() below). */
403 dkim_signing_domain = US sig->domain;
404 dkim_signing_selector = US sig->selector;
405 dkim_key_length = sig->sighash.len * 8;
407 /* These two return static strings, so we can compare the addr
408 later to see if the ACL overwrote them. Check that when logging */
410 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
411 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
413 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
420 /* No matching sig found. Call ACL once anyway. */
423 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
428 dkim_exim_expand_defaults(int what)
432 case DKIM_ALGO: return US"";
433 case DKIM_BODYLENGTH: return US"9999999999999";
434 case DKIM_CANON_BODY: return US"";
435 case DKIM_CANON_HEADERS: return US"";
436 case DKIM_COPIEDHEADERS: return US"";
437 case DKIM_CREATED: return US"0";
438 case DKIM_EXPIRES: return US"9999999999999";
439 case DKIM_HEADERNAMES: return US"";
440 case DKIM_IDENTITY: return US"";
441 case DKIM_KEY_GRANULARITY: return US"*";
442 case DKIM_KEY_SRVTYPE: return US"*";
443 case DKIM_KEY_NOTES: return US"";
444 case DKIM_KEY_TESTING: return US"0";
445 case DKIM_NOSUBDOMAINS: return US"0";
446 case DKIM_VERIFY_STATUS: return US"none";
447 case DKIM_VERIFY_REASON: return US"";
448 default: return US"";
454 dkim_exim_expand_query(int what)
456 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
457 return dkim_exim_expand_defaults(what);
462 return dkim_sig_to_a_tag(dkim_cur_sig);
464 case DKIM_BODYLENGTH:
465 return dkim_cur_sig->bodylength >= 0
466 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
467 : dkim_exim_expand_defaults(what);
469 case DKIM_CANON_BODY:
470 switch (dkim_cur_sig->canon_body)
472 case PDKIM_CANON_RELAXED: return US"relaxed";
473 case PDKIM_CANON_SIMPLE:
474 default: return US"simple";
477 case DKIM_CANON_HEADERS:
478 switch (dkim_cur_sig->canon_headers)
480 case PDKIM_CANON_RELAXED: return US"relaxed";
481 case PDKIM_CANON_SIMPLE:
482 default: return US"simple";
485 case DKIM_COPIEDHEADERS:
486 return dkim_cur_sig->copiedheaders
487 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
490 return dkim_cur_sig->created > 0
491 ? string_sprintf("%lu", dkim_cur_sig->created)
492 : dkim_exim_expand_defaults(what);
495 return dkim_cur_sig->expires > 0
496 ? string_sprintf("%lu", dkim_cur_sig->expires)
497 : dkim_exim_expand_defaults(what);
499 case DKIM_HEADERNAMES:
500 return dkim_cur_sig->headernames
501 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
504 return dkim_cur_sig->identity
505 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
507 case DKIM_KEY_GRANULARITY:
508 return dkim_cur_sig->pubkey
509 ? dkim_cur_sig->pubkey->granularity
510 ? US dkim_cur_sig->pubkey->granularity
511 : dkim_exim_expand_defaults(what)
512 : dkim_exim_expand_defaults(what);
514 case DKIM_KEY_SRVTYPE:
515 return dkim_cur_sig->pubkey
516 ? dkim_cur_sig->pubkey->srvtype
517 ? US dkim_cur_sig->pubkey->srvtype
518 : dkim_exim_expand_defaults(what)
519 : dkim_exim_expand_defaults(what);
522 return dkim_cur_sig->pubkey
523 ? dkim_cur_sig->pubkey->notes
524 ? US dkim_cur_sig->pubkey->notes
525 : dkim_exim_expand_defaults(what)
526 : dkim_exim_expand_defaults(what);
528 case DKIM_KEY_TESTING:
529 return dkim_cur_sig->pubkey
530 ? dkim_cur_sig->pubkey->testing
532 : dkim_exim_expand_defaults(what)
533 : dkim_exim_expand_defaults(what);
535 case DKIM_NOSUBDOMAINS:
536 return dkim_cur_sig->pubkey
537 ? dkim_cur_sig->pubkey->no_subdomaining
539 : dkim_exim_expand_defaults(what)
540 : dkim_exim_expand_defaults(what);
542 case DKIM_VERIFY_STATUS:
543 switch (dkim_cur_sig->verify_status)
545 case PDKIM_VERIFY_INVALID: return US"invalid";
546 case PDKIM_VERIFY_FAIL: return US"fail";
547 case PDKIM_VERIFY_PASS: return US"pass";
548 case PDKIM_VERIFY_NONE:
549 default: return US"none";
552 case DKIM_VERIFY_REASON:
553 switch (dkim_cur_sig->verify_ext_status)
555 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
556 return US"pubkey_unavailable";
557 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
558 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
559 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
560 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
570 dkim_exim_sign_init(void)
572 int old_pool = store_pool;
573 store_pool = POOL_MAIN;
574 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
575 store_pool = old_pool;
579 /* Generate signatures for the given file.
580 If a prefix is given, prepend it to the file for the calculations.
583 NULL: error; error string written
584 string: signature header(s), or a zero-length string (not an error)
588 dkim_exim_sign(int fd, off_t off, uschar * prefix,
589 struct ob_dkim * dkim, const uschar ** errstr)
591 const uschar * dkim_domain = NULL;
593 gstring * seen_doms = NULL;
594 pdkim_signature * sig;
600 int old_pool = store_pool;
604 if (dkim->dot_stuffed)
605 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
607 store_pool = POOL_MAIN;
609 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
610 /* expansion error, do not send message. */
611 { errwhen = US"dkim_domain"; goto expand_bad; }
613 /* Set $dkim_domain expansion variable to each unique domain in list. */
616 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
618 const uschar * dkim_sel;
621 if (dkim_signing_domain[0] == '\0')
624 /* Only sign once for each domain, no matter how often it
625 appears in the expanded list. */
627 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
628 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
631 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
633 /* Set $dkim_selector expansion variable to each selector in list,
636 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
637 { errwhen = US"dkim_selector"; goto expand_bad; }
639 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
642 uschar * dkim_canon_expanded;
644 uschar * dkim_sign_headers_expanded = NULL;
645 uschar * dkim_private_key_expanded;
646 uschar * dkim_hash_expanded;
647 uschar * dkim_identity_expanded = NULL;
649 /* Get canonicalization to use */
651 dkim_canon_expanded = dkim->dkim_canon
652 ? expand_string(dkim->dkim_canon) : US"relaxed";
653 if (!dkim_canon_expanded) /* expansion error, do not send message. */
654 { errwhen = US"dkim_canon"; goto expand_bad; }
656 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
657 pdkim_canon = PDKIM_CANON_RELAXED;
658 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
659 pdkim_canon = PDKIM_CANON_SIMPLE;
662 log_write(0, LOG_MAIN,
663 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
664 dkim_canon_expanded);
665 pdkim_canon = PDKIM_CANON_RELAXED;
668 if ( dkim->dkim_sign_headers
669 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
670 { errwhen = US"dkim_sign_header"; goto expand_bad; }
671 /* else pass NULL, which means default header list */
673 /* Get private key to use. */
675 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
676 { errwhen = US"dkim_private_key"; goto expand_bad; }
678 if ( Ustrlen(dkim_private_key_expanded) == 0
679 || Ustrcmp(dkim_private_key_expanded, "0") == 0
680 || Ustrcmp(dkim_private_key_expanded, "false") == 0
682 continue; /* don't sign, but no error */
684 if ( dkim_private_key_expanded[0] == '/'
685 && !(dkim_private_key_expanded =
686 expand_file_big_buffer(dkim_private_key_expanded)))
689 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
690 { errwhen = US"dkim_hash"; goto expand_bad; }
692 if (dkim->dkim_identity)
693 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
694 { errwhen = US"dkim_identity"; goto expand_bad; }
695 else if (!*dkim_identity_expanded)
696 dkim_identity_expanded = NULL;
698 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
699 dkim_signing_selector,
700 dkim_private_key_expanded,
705 dkim_private_key_expanded[0] = '\0';
707 pdkim_set_optional(sig,
708 CS dkim_sign_headers_expanded,
709 CS dkim_identity_expanded,
711 pdkim_canon, -1, 0, 0);
713 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
716 if (!dkim_sign_ctx.sig) /* link sig to context chain */
717 dkim_sign_ctx.sig = sig;
720 pdkim_signature * n = dkim_sign_ctx.sig;
721 while (n->next) n = n->next;
727 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
728 produce, if some other package (eg. ARC) is signing. */
730 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
732 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
733 sigbuf = string_get(1); /* return a zero-len string */
737 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
740 if (lseek(fd, off, SEEK_SET) < 0)
743 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
744 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
747 /* Handle failed read above. */
750 debug_printf("DKIM: Error reading -K file.\n");
755 /* Build string of headers, one per signature */
757 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
762 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
763 sigbuf = string_get(1); /* return a zero-len string */
765 else for (sigbuf = NULL; sig; sig = sig->next)
766 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
770 (void) string_from_gstring(sigbuf);
771 store_pool = old_pool;
776 log_write(0, LOG_MAIN|LOG_PANIC,
777 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
783 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
784 errwhen, expand_string_message);
792 authres_dkim(gstring * g)
794 pdkim_signature * sig;
795 int start = 0; /* compiler quietening */
797 DEBUG(D_acl) start = g->ptr;
799 for (sig = dkim_signatures; sig; sig = sig->next)
801 g = string_catn(g, US";\n\tdkim=", 8);
803 if (sig->verify_status & PDKIM_VERIFY_POLICY)
804 g = string_append(g, 5,
805 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
806 else switch(sig->verify_status)
808 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
809 case PDKIM_VERIFY_INVALID:
810 switch (sig->verify_ext_status)
812 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
813 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
814 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
815 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
816 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
817 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
818 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
820 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
821 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
823 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
824 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
827 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
830 case PDKIM_VERIFY_FAIL:
831 switch (sig->verify_ext_status)
833 case PDKIM_VERIFY_FAIL_BODY:
835 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
837 case PDKIM_VERIFY_FAIL_MESSAGE:
839 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
842 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
846 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
847 default: g = string_cat(g, US"permerror"); break;
849 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
850 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
851 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
852 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
857 debug_printf("DKIM: no authres\n");
859 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
864 # endif /*!MACRO_PREDEF*/
865 #endif /*!DISABLE_DKIM*/