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)
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)
65 { /* Copy record content to the answer buffer */
66 for (int rr_offset = 0; 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 store_free_dns_answer(dnsa);
81 gstring_release_unused(g);
82 return string_from_gstring(g);
85 g->ptr = 0; /* overwrite previous record */
89 store_reset(reset_point);
90 store_free_dns_answer(dnsa);
91 return NULL; /*XXX better error detail? logging? */
98 if (f.dkim_init_done) return;
99 f.dkim_init_done = TRUE;
106 dkim_exim_verify_init(BOOL dot_stuffing)
110 /* There is a store-reset between header & body reception for the main pool
111 (actually, after every header line) so cannot use that as we need the data we
112 store per-header, during header processing, at the end of body reception
113 for evaluating the signature. Any allocs done for dkim verify
114 memory-handling must use a different pool. We use a separate one that we
115 can reset per message. */
117 dkim_verify_oldpool = store_pool;
118 store_pool = POOL_MESSAGE;
120 /* Free previous context if there is one */
123 pdkim_free_ctx(dkim_verify_ctx);
125 /* Create new context */
127 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
128 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
129 dkim_collect_error = NULL;
131 /* Start feed up with any cached data, but limited to message data */
132 receive_get_cache(chunking_state == CHUNKING_LAST
133 ? chunking_data_left : GETC_BUFFER_UNLIMITED);
135 store_pool = dkim_verify_oldpool;
139 /* Submit a chunk of data for verification input.
140 Only use the data when the feed is activated. */
142 dkim_exim_verify_feed(uschar * data, int len)
146 store_pool = POOL_MESSAGE;
147 if ( dkim_collect_input
148 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
150 dkim_collect_error = pdkim_errstr(rc);
151 log_write(0, LOG_MAIN,
152 "DKIM: validation error: %.100s", dkim_collect_error);
153 dkim_collect_input = 0;
155 store_pool = dkim_verify_oldpool;
159 /* Log the result for the given signature */
161 dkim_exim_verify_log_sig(pdkim_signature * sig)
168 /* Remember the domain for the first pass result */
170 if ( !dkim_verify_overall
171 && dkim_verify_status
172 ? Ustrcmp(dkim_verify_status, US"pass") == 0
173 : sig->verify_status == PDKIM_VERIFY_PASS
175 dkim_verify_overall = string_copy(sig->domain);
177 /* Rewrite the sig result if the ACL overrode it. This is only
178 needed because the DMARC code (sigh) peeks at the dkim sigs.
179 Mark the sig for this having been done. */
181 if ( dkim_verify_status
182 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
183 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
185 { /* overridden by ACL */
186 sig->verify_ext_status = -1;
187 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
188 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
189 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
190 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
191 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
192 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
193 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
194 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
196 sig->verify_status = -1;
199 if (!LOGGING(dkim_verbose)) return;
202 logmsg = string_catn(NULL, US"DKIM: ", 6);
203 if (!(s = sig->domain)) s = US"<UNSET>";
204 logmsg = string_append(logmsg, 2, "d=", s);
205 if (!(s = sig->selector)) s = US"<UNSET>";
206 logmsg = string_append(logmsg, 2, " s=", s);
207 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
208 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
209 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
210 dkim_sig_to_a_tag(sig),
211 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
212 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
213 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
215 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
217 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
220 if (sig->verify_status & PDKIM_VERIFY_POLICY)
221 logmsg = string_append(logmsg, 5,
222 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
224 switch (sig->verify_status)
226 case PDKIM_VERIFY_NONE:
227 logmsg = string_cat(logmsg, US" [not verified]");
230 case PDKIM_VERIFY_INVALID:
231 logmsg = string_cat(logmsg, US" [invalid - ");
232 switch (sig->verify_ext_status)
234 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
235 logmsg = string_cat(logmsg,
236 US"public key record (currently?) unavailable]");
239 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
240 logmsg = string_cat(logmsg, US"overlong public key record]");
243 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
244 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
245 logmsg = string_cat(logmsg, US"syntax error in public key record]");
248 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
249 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
252 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
253 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
257 logmsg = string_cat(logmsg, US"unspecified problem]");
261 case PDKIM_VERIFY_FAIL:
262 logmsg = string_cat(logmsg, US" [verification failed - ");
263 switch (sig->verify_ext_status)
265 case PDKIM_VERIFY_FAIL_BODY:
266 logmsg = string_cat(logmsg,
267 US"body hash mismatch (body probably modified in transit)]");
270 case PDKIM_VERIFY_FAIL_MESSAGE:
271 logmsg = string_cat(logmsg,
272 US"signature did not verify "
273 "(headers probably modified in transit)]");
276 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
277 logmsg = string_cat(logmsg,
278 US"signature invalid (key too short)]");
282 logmsg = string_cat(logmsg, US"unspecified reason]");
286 case PDKIM_VERIFY_PASS:
287 logmsg = string_cat(logmsg, US" [verification succeeded]");
291 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
296 /* Log a line for each signature */
298 dkim_exim_verify_log_all(void)
300 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
301 dkim_exim_verify_log_sig(sig);
306 dkim_exim_verify_finish(void)
310 const uschar * errstr = NULL;
312 store_pool = POOL_MESSAGE;
314 /* Delete eventual previous signature chain */
317 dkim_signatures = NULL;
319 if (dkim_collect_error)
321 log_write(0, LOG_MAIN,
322 "DKIM: Error during validation, disabling signature verification: %.100s",
324 f.dkim_disable_verify = TRUE;
328 dkim_collect_input = 0;
330 /* Finish DKIM operation and fetch link to signatures chain */
332 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
334 if (rc != PDKIM_OK && errstr)
335 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
337 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
339 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
341 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
342 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
345 if (g) dkim_signers = g->s;
348 store_pool = dkim_verify_oldpool;
353 /* Args as per dkim_exim_acl_run() below */
355 dkim_acl_call(uschar * id, gstring ** res_ptr,
356 uschar ** user_msgptr, uschar ** log_msgptr)
360 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
362 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
363 dkim_exim_verify_log_sig(dkim_cur_sig);
364 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
370 /* For the given identity, run the DKIM ACL once for each matching signature.
373 id Identity to look for in dkim signatures
374 res_ptr ptr to growable string-list of status results,
375 appended to per ACL run
376 user_msgptr where to put a user error (for SMTP response)
377 log_msgptr where to put a logging message (not for SMTP response)
379 Returns: OK access is granted by an ACCEPT verb
380 DISCARD access is granted by a DISCARD verb
381 FAIL access is denied
382 FAIL_DROP access is denied; drop the connection
383 DEFER can't tell at the moment
388 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
389 uschar ** user_msgptr, uschar ** log_msgptr)
394 dkim_verify_status = US"none";
395 dkim_verify_reason = US"";
396 dkim_cur_signer = id;
398 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
401 /* Find signatures to run ACL on */
403 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
404 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
405 && strcmpic(cmp_val, id) == 0
408 /* The "dkim_domain" and "dkim_selector" expansion variables have
409 related globals, since they are used in the signing code too.
410 Instead of inventing separate names for verification, we set
411 them here. This is easy since a domain and selector is guaranteed
412 to be in a signature. The other dkim_* expansion items are
413 dynamically fetched from dkim_cur_sig at expansion time (see
414 dkim_exim_expand_query() below). */
417 dkim_signing_domain = US sig->domain;
418 dkim_signing_selector = US sig->selector;
419 dkim_key_length = sig->keybits;
421 /* These two return static strings, so we can compare the addr
422 later to see if the ACL overwrote them. Check that when logging */
424 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
425 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
427 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
434 /* No matching sig found. Call ACL once anyway. */
437 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
442 dkim_exim_expand_defaults(int what)
446 case DKIM_ALGO: return US"";
447 case DKIM_BODYLENGTH: return US"9999999999999";
448 case DKIM_CANON_BODY: return US"";
449 case DKIM_CANON_HEADERS: return US"";
450 case DKIM_COPIEDHEADERS: return US"";
451 case DKIM_CREATED: return US"0";
452 case DKIM_EXPIRES: return US"9999999999999";
453 case DKIM_HEADERNAMES: return US"";
454 case DKIM_IDENTITY: return US"";
455 case DKIM_KEY_GRANULARITY: return US"*";
456 case DKIM_KEY_SRVTYPE: return US"*";
457 case DKIM_KEY_NOTES: return US"";
458 case DKIM_KEY_TESTING: return US"0";
459 case DKIM_NOSUBDOMAINS: return US"0";
460 case DKIM_VERIFY_STATUS: return US"none";
461 case DKIM_VERIFY_REASON: return US"";
462 default: return US"";
468 dkim_exim_expand_query(int what)
470 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
471 return dkim_exim_expand_defaults(what);
476 return dkim_sig_to_a_tag(dkim_cur_sig);
478 case DKIM_BODYLENGTH:
479 return dkim_cur_sig->bodylength >= 0
480 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
481 : dkim_exim_expand_defaults(what);
483 case DKIM_CANON_BODY:
484 switch (dkim_cur_sig->canon_body)
486 case PDKIM_CANON_RELAXED: return US"relaxed";
487 case PDKIM_CANON_SIMPLE:
488 default: return US"simple";
491 case DKIM_CANON_HEADERS:
492 switch (dkim_cur_sig->canon_headers)
494 case PDKIM_CANON_RELAXED: return US"relaxed";
495 case PDKIM_CANON_SIMPLE:
496 default: return US"simple";
499 case DKIM_COPIEDHEADERS:
500 return dkim_cur_sig->copiedheaders
501 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
504 return dkim_cur_sig->created > 0
505 ? string_sprintf("%lu", dkim_cur_sig->created)
506 : dkim_exim_expand_defaults(what);
509 return dkim_cur_sig->expires > 0
510 ? string_sprintf("%lu", dkim_cur_sig->expires)
511 : dkim_exim_expand_defaults(what);
513 case DKIM_HEADERNAMES:
514 return dkim_cur_sig->headernames
515 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
518 return dkim_cur_sig->identity
519 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
521 case DKIM_KEY_GRANULARITY:
522 return dkim_cur_sig->pubkey
523 ? dkim_cur_sig->pubkey->granularity
524 ? US dkim_cur_sig->pubkey->granularity
525 : dkim_exim_expand_defaults(what)
526 : dkim_exim_expand_defaults(what);
528 case DKIM_KEY_SRVTYPE:
529 return dkim_cur_sig->pubkey
530 ? dkim_cur_sig->pubkey->srvtype
531 ? US dkim_cur_sig->pubkey->srvtype
532 : dkim_exim_expand_defaults(what)
533 : dkim_exim_expand_defaults(what);
536 return dkim_cur_sig->pubkey
537 ? dkim_cur_sig->pubkey->notes
538 ? US dkim_cur_sig->pubkey->notes
539 : dkim_exim_expand_defaults(what)
540 : dkim_exim_expand_defaults(what);
542 case DKIM_KEY_TESTING:
543 return dkim_cur_sig->pubkey
544 ? dkim_cur_sig->pubkey->testing
546 : dkim_exim_expand_defaults(what)
547 : dkim_exim_expand_defaults(what);
549 case DKIM_NOSUBDOMAINS:
550 return dkim_cur_sig->pubkey
551 ? dkim_cur_sig->pubkey->no_subdomaining
553 : dkim_exim_expand_defaults(what)
554 : dkim_exim_expand_defaults(what);
556 case DKIM_VERIFY_STATUS:
557 switch (dkim_cur_sig->verify_status)
559 case PDKIM_VERIFY_INVALID: return US"invalid";
560 case PDKIM_VERIFY_FAIL: return US"fail";
561 case PDKIM_VERIFY_PASS: return US"pass";
562 case PDKIM_VERIFY_NONE:
563 default: return US"none";
566 case DKIM_VERIFY_REASON:
567 switch (dkim_cur_sig->verify_ext_status)
569 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
570 return US"pubkey_unavailable";
571 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
572 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
573 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
574 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
575 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
585 dkim_exim_sign_init(void)
587 int old_pool = store_pool;
590 store_pool = POOL_MAIN;
591 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
592 store_pool = old_pool;
596 /* Generate signatures for the given file.
597 If a prefix is given, prepend it to the file for the calculations.
600 NULL: error; error string written
601 string: signature header(s), or a zero-length string (not an error)
605 dkim_exim_sign(int fd, off_t off, uschar * prefix,
606 struct ob_dkim * dkim, const uschar ** errstr)
608 const uschar * dkim_domain = NULL;
610 gstring * seen_doms = NULL;
611 pdkim_signature * sig;
617 int old_pool = store_pool;
621 if (dkim->dot_stuffed)
622 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
624 store_pool = POOL_MAIN;
626 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
627 /* expansion error, do not send message. */
628 { errwhen = US"dkim_domain"; goto expand_bad; }
630 /* Set $dkim_domain expansion variable to each unique domain in list. */
633 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
635 const uschar * dkim_sel;
638 if (dkim_signing_domain[0] == '\0')
641 /* Only sign once for each domain, no matter how often it
642 appears in the expanded list. */
644 dkim_signing_domain = string_copylc(dkim_signing_domain);
645 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
646 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
649 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
651 /* Set $dkim_selector expansion variable to each selector in list,
654 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
655 { errwhen = US"dkim_selector"; goto expand_bad; }
657 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
660 uschar * dkim_canon_expanded;
662 uschar * dkim_sign_headers_expanded = NULL;
663 uschar * dkim_private_key_expanded;
664 uschar * dkim_hash_expanded;
665 uschar * dkim_identity_expanded = NULL;
666 uschar * dkim_timestamps_expanded = NULL;
667 unsigned long tval = 0, xval = 0;
669 /* Get canonicalization to use */
671 dkim_canon_expanded = dkim->dkim_canon
672 ? expand_string(dkim->dkim_canon) : US"relaxed";
673 if (!dkim_canon_expanded) /* expansion error, do not send message. */
674 { errwhen = US"dkim_canon"; goto expand_bad; }
676 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
677 pdkim_canon = PDKIM_CANON_RELAXED;
678 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
679 pdkim_canon = PDKIM_CANON_SIMPLE;
682 log_write(0, LOG_MAIN,
683 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
684 dkim_canon_expanded);
685 pdkim_canon = PDKIM_CANON_RELAXED;
688 if ( dkim->dkim_sign_headers
689 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
690 { errwhen = US"dkim_sign_header"; goto expand_bad; }
691 /* else pass NULL, which means default header list */
693 /* Get private key to use. */
695 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
696 { errwhen = US"dkim_private_key"; goto expand_bad; }
698 if ( Ustrlen(dkim_private_key_expanded) == 0
699 || Ustrcmp(dkim_private_key_expanded, "0") == 0
700 || Ustrcmp(dkim_private_key_expanded, "false") == 0
702 continue; /* don't sign, but no error */
704 if ( dkim_private_key_expanded[0] == '/'
705 && !(dkim_private_key_expanded =
706 expand_file_big_buffer(dkim_private_key_expanded)))
709 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
710 { errwhen = US"dkim_hash"; goto expand_bad; }
712 if (dkim->dkim_identity)
713 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
714 { errwhen = US"dkim_identity"; goto expand_bad; }
715 else if (!*dkim_identity_expanded)
716 dkim_identity_expanded = NULL;
718 if (dkim->dkim_timestamps)
719 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
720 { errwhen = US"dkim_timestamps"; goto expand_bad; }
722 xval = (tval = (unsigned long) time(NULL))
723 + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
725 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
726 dkim_signing_selector,
727 dkim_private_key_expanded,
732 dkim_private_key_expanded[0] = '\0';
734 pdkim_set_optional(sig,
735 CS dkim_sign_headers_expanded,
736 CS dkim_identity_expanded,
738 pdkim_canon, -1, tval, xval);
740 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
743 if (!dkim_sign_ctx.sig) /* link sig to context chain */
744 dkim_sign_ctx.sig = sig;
747 pdkim_signature * n = dkim_sign_ctx.sig;
748 while (n->next) n = n->next;
754 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
755 produce, if some other package (eg. ARC) is signing. */
757 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
759 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
760 sigbuf = string_get(1); /* return a zero-len string */
764 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
767 if (lseek(fd, off, SEEK_SET) < 0)
770 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
771 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
774 /* Handle failed read above. */
777 debug_printf("DKIM: Error reading -K file.\n");
782 /* Build string of headers, one per signature */
784 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
789 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
790 sigbuf = string_get(1); /* return a zero-len string */
792 else for (sigbuf = NULL; sig; sig = sig->next)
793 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
797 (void) string_from_gstring(sigbuf);
798 store_pool = old_pool;
803 log_write(0, LOG_MAIN|LOG_PANIC,
804 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
810 *errstr = string_sprintf("failed to expand %s: %s",
811 errwhen, expand_string_message);
812 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
820 authres_dkim(gstring * g)
822 int start = 0; /* compiler quietening */
824 DEBUG(D_acl) start = g->ptr;
826 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
828 g = string_catn(g, US";\n\tdkim=", 8);
830 if (sig->verify_status & PDKIM_VERIFY_POLICY)
831 g = string_append(g, 5,
832 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
833 else switch(sig->verify_status)
835 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
836 case PDKIM_VERIFY_INVALID:
837 switch (sig->verify_ext_status)
839 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
840 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
841 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
842 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
843 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
844 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
845 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
847 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
848 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
850 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
851 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
854 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
857 case PDKIM_VERIFY_FAIL:
858 switch (sig->verify_ext_status)
860 case PDKIM_VERIFY_FAIL_BODY:
862 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
864 case PDKIM_VERIFY_FAIL_MESSAGE:
866 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
868 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
869 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
872 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
876 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
877 default: g = string_cat(g, US"permerror"); break;
879 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
880 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
881 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
882 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
887 debug_printf("DKIM: no authres\n");
889 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
894 # endif /*!MACRO_PREDEF*/
895 #endif /*!DISABLE_DKIM*/