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 */
134 store_pool = dkim_verify_oldpool;
139 dkim_exim_verify_feed(uschar * data, int len)
143 store_pool = POOL_MESSAGE;
144 if ( dkim_collect_input
145 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
147 dkim_collect_error = pdkim_errstr(rc);
148 log_write(0, LOG_MAIN,
149 "DKIM: validation error: %.100s", dkim_collect_error);
150 dkim_collect_input = 0;
152 store_pool = dkim_verify_oldpool;
156 /* Log the result for the given signature */
158 dkim_exim_verify_log_sig(pdkim_signature * sig)
165 /* Remember the domain for the first pass result */
167 if ( !dkim_verify_overall
168 && dkim_verify_status
169 ? Ustrcmp(dkim_verify_status, US"pass") == 0
170 : sig->verify_status == PDKIM_VERIFY_PASS
172 dkim_verify_overall = string_copy(sig->domain);
174 /* Rewrite the sig result if the ACL overrode it. This is only
175 needed because the DMARC code (sigh) peeks at the dkim sigs.
176 Mark the sig for this having been done. */
178 if ( dkim_verify_status
179 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
180 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
182 { /* overridden by ACL */
183 sig->verify_ext_status = -1;
184 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
185 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
186 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
187 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
188 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
189 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
190 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
191 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
193 sig->verify_status = -1;
196 if (!LOGGING(dkim_verbose)) return;
199 logmsg = string_catn(NULL, US"DKIM: ", 6);
200 if (!(s = sig->domain)) s = US"<UNSET>";
201 logmsg = string_append(logmsg, 2, "d=", s);
202 if (!(s = sig->selector)) s = US"<UNSET>";
203 logmsg = string_append(logmsg, 2, " s=", s);
204 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
205 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
206 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
207 dkim_sig_to_a_tag(sig),
208 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
209 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
210 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
212 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
214 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
217 if (sig->verify_status & PDKIM_VERIFY_POLICY)
218 logmsg = string_append(logmsg, 5,
219 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
221 switch (sig->verify_status)
223 case PDKIM_VERIFY_NONE:
224 logmsg = string_cat(logmsg, US" [not verified]");
227 case PDKIM_VERIFY_INVALID:
228 logmsg = string_cat(logmsg, US" [invalid - ");
229 switch (sig->verify_ext_status)
231 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
232 logmsg = string_cat(logmsg,
233 US"public key record (currently?) unavailable]");
236 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
237 logmsg = string_cat(logmsg, US"overlong public key record]");
240 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
241 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
242 logmsg = string_cat(logmsg, US"syntax error in public key record]");
245 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
246 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
249 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
250 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
254 logmsg = string_cat(logmsg, US"unspecified problem]");
258 case PDKIM_VERIFY_FAIL:
259 logmsg = string_cat(logmsg, US" [verification failed - ");
260 switch (sig->verify_ext_status)
262 case PDKIM_VERIFY_FAIL_BODY:
263 logmsg = string_cat(logmsg,
264 US"body hash mismatch (body probably modified in transit)]");
267 case PDKIM_VERIFY_FAIL_MESSAGE:
268 logmsg = string_cat(logmsg,
269 US"signature did not verify "
270 "(headers probably modified in transit)]");
273 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
274 logmsg = string_cat(logmsg,
275 US"signature invalid (key too short)]");
279 logmsg = string_cat(logmsg, US"unspecified reason]");
283 case PDKIM_VERIFY_PASS:
284 logmsg = string_cat(logmsg, US" [verification succeeded]");
288 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
293 /* Log a line for each signature */
295 dkim_exim_verify_log_all(void)
297 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
298 dkim_exim_verify_log_sig(sig);
303 dkim_exim_verify_finish(void)
307 const uschar * errstr = NULL;
309 store_pool = POOL_MESSAGE;
311 /* Delete eventual previous signature chain */
314 dkim_signatures = NULL;
316 if (dkim_collect_error)
318 log_write(0, LOG_MAIN,
319 "DKIM: Error during validation, disabling signature verification: %.100s",
321 f.dkim_disable_verify = TRUE;
325 dkim_collect_input = 0;
327 /* Finish DKIM operation and fetch link to signatures chain */
329 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
331 if (rc != PDKIM_OK && errstr)
332 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
334 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
336 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
338 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
339 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
342 if (g) dkim_signers = g->s;
345 store_pool = dkim_verify_oldpool;
350 /* Args as per dkim_exim_acl_run() below */
352 dkim_acl_call(uschar * id, gstring ** res_ptr,
353 uschar ** user_msgptr, uschar ** log_msgptr)
357 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
359 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
360 dkim_exim_verify_log_sig(dkim_cur_sig);
361 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
367 /* For the given identity, run the DKIM ACL once for each matching signature.
370 id Identity to look for in dkim signatures
371 res_ptr ptr to growable string-list of status results,
372 appended to per ACL run
373 user_msgptr where to put a user error (for SMTP response)
374 log_msgptr where to put a logging message (not for SMTP response)
376 Returns: OK access is granted by an ACCEPT verb
377 DISCARD access is granted by a DISCARD verb
378 FAIL access is denied
379 FAIL_DROP access is denied; drop the connection
380 DEFER can't tell at the moment
385 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
386 uschar ** user_msgptr, uschar ** log_msgptr)
391 dkim_verify_status = US"none";
392 dkim_verify_reason = US"";
393 dkim_cur_signer = id;
395 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
398 /* Find signatures to run ACL on */
400 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
401 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
402 && strcmpic(cmp_val, id) == 0
405 /* The "dkim_domain" and "dkim_selector" expansion variables have
406 related globals, since they are used in the signing code too.
407 Instead of inventing separate names for verification, we set
408 them here. This is easy since a domain and selector is guaranteed
409 to be in a signature. The other dkim_* expansion items are
410 dynamically fetched from dkim_cur_sig at expansion time (see
411 dkim_exim_expand_query() below). */
414 dkim_signing_domain = US sig->domain;
415 dkim_signing_selector = US sig->selector;
416 dkim_key_length = sig->keybits;
418 /* These two return static strings, so we can compare the addr
419 later to see if the ACL overwrote them. Check that when logging */
421 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
422 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
424 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
431 /* No matching sig found. Call ACL once anyway. */
434 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
439 dkim_exim_expand_defaults(int what)
443 case DKIM_ALGO: return US"";
444 case DKIM_BODYLENGTH: return US"9999999999999";
445 case DKIM_CANON_BODY: return US"";
446 case DKIM_CANON_HEADERS: return US"";
447 case DKIM_COPIEDHEADERS: return US"";
448 case DKIM_CREATED: return US"0";
449 case DKIM_EXPIRES: return US"9999999999999";
450 case DKIM_HEADERNAMES: return US"";
451 case DKIM_IDENTITY: return US"";
452 case DKIM_KEY_GRANULARITY: return US"*";
453 case DKIM_KEY_SRVTYPE: return US"*";
454 case DKIM_KEY_NOTES: return US"";
455 case DKIM_KEY_TESTING: return US"0";
456 case DKIM_NOSUBDOMAINS: return US"0";
457 case DKIM_VERIFY_STATUS: return US"none";
458 case DKIM_VERIFY_REASON: return US"";
459 default: return US"";
465 dkim_exim_expand_query(int what)
467 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
468 return dkim_exim_expand_defaults(what);
473 return dkim_sig_to_a_tag(dkim_cur_sig);
475 case DKIM_BODYLENGTH:
476 return dkim_cur_sig->bodylength >= 0
477 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
478 : dkim_exim_expand_defaults(what);
480 case DKIM_CANON_BODY:
481 switch (dkim_cur_sig->canon_body)
483 case PDKIM_CANON_RELAXED: return US"relaxed";
484 case PDKIM_CANON_SIMPLE:
485 default: return US"simple";
488 case DKIM_CANON_HEADERS:
489 switch (dkim_cur_sig->canon_headers)
491 case PDKIM_CANON_RELAXED: return US"relaxed";
492 case PDKIM_CANON_SIMPLE:
493 default: return US"simple";
496 case DKIM_COPIEDHEADERS:
497 return dkim_cur_sig->copiedheaders
498 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
501 return dkim_cur_sig->created > 0
502 ? string_sprintf("%lu", dkim_cur_sig->created)
503 : dkim_exim_expand_defaults(what);
506 return dkim_cur_sig->expires > 0
507 ? string_sprintf("%lu", dkim_cur_sig->expires)
508 : dkim_exim_expand_defaults(what);
510 case DKIM_HEADERNAMES:
511 return dkim_cur_sig->headernames
512 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
515 return dkim_cur_sig->identity
516 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
518 case DKIM_KEY_GRANULARITY:
519 return dkim_cur_sig->pubkey
520 ? dkim_cur_sig->pubkey->granularity
521 ? US dkim_cur_sig->pubkey->granularity
522 : dkim_exim_expand_defaults(what)
523 : dkim_exim_expand_defaults(what);
525 case DKIM_KEY_SRVTYPE:
526 return dkim_cur_sig->pubkey
527 ? dkim_cur_sig->pubkey->srvtype
528 ? US dkim_cur_sig->pubkey->srvtype
529 : dkim_exim_expand_defaults(what)
530 : dkim_exim_expand_defaults(what);
533 return dkim_cur_sig->pubkey
534 ? dkim_cur_sig->pubkey->notes
535 ? US dkim_cur_sig->pubkey->notes
536 : dkim_exim_expand_defaults(what)
537 : dkim_exim_expand_defaults(what);
539 case DKIM_KEY_TESTING:
540 return dkim_cur_sig->pubkey
541 ? dkim_cur_sig->pubkey->testing
543 : dkim_exim_expand_defaults(what)
544 : dkim_exim_expand_defaults(what);
546 case DKIM_NOSUBDOMAINS:
547 return dkim_cur_sig->pubkey
548 ? dkim_cur_sig->pubkey->no_subdomaining
550 : dkim_exim_expand_defaults(what)
551 : dkim_exim_expand_defaults(what);
553 case DKIM_VERIFY_STATUS:
554 switch (dkim_cur_sig->verify_status)
556 case PDKIM_VERIFY_INVALID: return US"invalid";
557 case PDKIM_VERIFY_FAIL: return US"fail";
558 case PDKIM_VERIFY_PASS: return US"pass";
559 case PDKIM_VERIFY_NONE:
560 default: return US"none";
563 case DKIM_VERIFY_REASON:
564 switch (dkim_cur_sig->verify_ext_status)
566 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
567 return US"pubkey_unavailable";
568 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
569 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
570 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
571 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
572 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
582 dkim_exim_sign_init(void)
584 int old_pool = store_pool;
587 store_pool = POOL_MAIN;
588 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
589 store_pool = old_pool;
593 /* Generate signatures for the given file.
594 If a prefix is given, prepend it to the file for the calculations.
597 NULL: error; error string written
598 string: signature header(s), or a zero-length string (not an error)
602 dkim_exim_sign(int fd, off_t off, uschar * prefix,
603 struct ob_dkim * dkim, const uschar ** errstr)
605 const uschar * dkim_domain = NULL;
607 gstring * seen_doms = NULL;
608 pdkim_signature * sig;
614 int old_pool = store_pool;
618 if (dkim->dot_stuffed)
619 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
621 store_pool = POOL_MAIN;
623 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
624 /* expansion error, do not send message. */
625 { errwhen = US"dkim_domain"; goto expand_bad; }
627 /* Set $dkim_domain expansion variable to each unique domain in list. */
630 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
632 const uschar * dkim_sel;
635 if (dkim_signing_domain[0] == '\0')
638 /* Only sign once for each domain, no matter how often it
639 appears in the expanded list. */
641 dkim_signing_domain = string_copylc(dkim_signing_domain);
642 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
643 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
646 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
648 /* Set $dkim_selector expansion variable to each selector in list,
651 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
652 { errwhen = US"dkim_selector"; goto expand_bad; }
654 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
657 uschar * dkim_canon_expanded;
659 uschar * dkim_sign_headers_expanded = NULL;
660 uschar * dkim_private_key_expanded;
661 uschar * dkim_hash_expanded;
662 uschar * dkim_identity_expanded = NULL;
663 uschar * dkim_timestamps_expanded = NULL;
664 unsigned long tval = 0, xval = 0;
666 /* Get canonicalization to use */
668 dkim_canon_expanded = dkim->dkim_canon
669 ? expand_string(dkim->dkim_canon) : US"relaxed";
670 if (!dkim_canon_expanded) /* expansion error, do not send message. */
671 { errwhen = US"dkim_canon"; goto expand_bad; }
673 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
674 pdkim_canon = PDKIM_CANON_RELAXED;
675 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
676 pdkim_canon = PDKIM_CANON_SIMPLE;
679 log_write(0, LOG_MAIN,
680 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
681 dkim_canon_expanded);
682 pdkim_canon = PDKIM_CANON_RELAXED;
685 if ( dkim->dkim_sign_headers
686 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
687 { errwhen = US"dkim_sign_header"; goto expand_bad; }
688 /* else pass NULL, which means default header list */
690 /* Get private key to use. */
692 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
693 { errwhen = US"dkim_private_key"; goto expand_bad; }
695 if ( Ustrlen(dkim_private_key_expanded) == 0
696 || Ustrcmp(dkim_private_key_expanded, "0") == 0
697 || Ustrcmp(dkim_private_key_expanded, "false") == 0
699 continue; /* don't sign, but no error */
701 if ( dkim_private_key_expanded[0] == '/'
702 && !(dkim_private_key_expanded =
703 expand_file_big_buffer(dkim_private_key_expanded)))
706 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
707 { errwhen = US"dkim_hash"; goto expand_bad; }
709 if (dkim->dkim_identity)
710 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
711 { errwhen = US"dkim_identity"; goto expand_bad; }
712 else if (!*dkim_identity_expanded)
713 dkim_identity_expanded = NULL;
715 if (dkim->dkim_timestamps)
716 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
717 { errwhen = US"dkim_timestamps"; goto expand_bad; }
719 xval = (tval = (unsigned long) time(NULL))
720 + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
722 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
723 dkim_signing_selector,
724 dkim_private_key_expanded,
729 dkim_private_key_expanded[0] = '\0';
731 pdkim_set_optional(sig,
732 CS dkim_sign_headers_expanded,
733 CS dkim_identity_expanded,
735 pdkim_canon, -1, tval, xval);
737 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
740 if (!dkim_sign_ctx.sig) /* link sig to context chain */
741 dkim_sign_ctx.sig = sig;
744 pdkim_signature * n = dkim_sign_ctx.sig;
745 while (n->next) n = n->next;
751 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
752 produce, if some other package (eg. ARC) is signing. */
754 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
756 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
757 sigbuf = string_get(1); /* return a zero-len string */
761 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
764 if (lseek(fd, off, SEEK_SET) < 0)
767 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
768 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
771 /* Handle failed read above. */
774 debug_printf("DKIM: Error reading -K file.\n");
779 /* Build string of headers, one per signature */
781 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
786 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
787 sigbuf = string_get(1); /* return a zero-len string */
789 else for (sigbuf = NULL; sig; sig = sig->next)
790 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
794 (void) string_from_gstring(sigbuf);
795 store_pool = old_pool;
800 log_write(0, LOG_MAIN|LOG_PANIC,
801 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
807 *errstr = string_sprintf("failed to expand %s: %s",
808 errwhen, expand_string_message);
809 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
817 authres_dkim(gstring * g)
819 int start = 0; /* compiler quietening */
821 DEBUG(D_acl) start = g->ptr;
823 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
825 g = string_catn(g, US";\n\tdkim=", 8);
827 if (sig->verify_status & PDKIM_VERIFY_POLICY)
828 g = string_append(g, 5,
829 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
830 else switch(sig->verify_status)
832 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
833 case PDKIM_VERIFY_INVALID:
834 switch (sig->verify_ext_status)
836 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
837 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
838 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
839 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
840 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
841 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
842 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
844 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
845 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
847 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
848 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
851 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
854 case PDKIM_VERIFY_FAIL:
855 switch (sig->verify_ext_status)
857 case PDKIM_VERIFY_FAIL_BODY:
859 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
861 case PDKIM_VERIFY_FAIL_MESSAGE:
863 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
865 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
866 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
869 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
873 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
874 default: g = string_cat(g, US"permerror"); break;
876 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
877 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
878 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
879 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
884 debug_printf("DKIM: no authres\n");
886 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
891 # endif /*!MACRO_PREDEF*/
892 #endif /*!DISABLE_DKIM*/