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();
55 lookup_dnssec_authenticated = NULL;
56 if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
57 return NULL; /*XXX better error detail? logging? */
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)
68 /* Copy record content to the answer buffer */
70 while (rr_offset < rr->size)
72 uschar len = rr->data[rr_offset++];
74 g = string_catn(g, US(rr->data + rr_offset), len);
75 if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
81 /* check if this looks like a DKIM record */
82 if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
84 gstring_release_unused(g);
85 return string_from_gstring(g);
88 if (g) g->ptr = 0; /* overwrite previous record */
92 store_reset(reset_point);
93 return NULL; /*XXX better error detail? logging? */
100 if (f.dkim_init_done) return;
101 f.dkim_init_done = TRUE;
108 dkim_exim_verify_init(BOOL dot_stuffing)
112 /* There is a store-reset between header & body reception for the main pool
113 (actually, after every header line) so cannot use that as we need the data we
114 store per-header, during header processing, at the end of body reception
115 for evaluating the signature. Any allocs done for dkim verify
116 memory-handling must use a different pool. We use a separate one that we
117 can reset per message. */
119 dkim_verify_oldpool = store_pool;
120 store_pool = POOL_MESSAGE;
122 /* Free previous context if there is one */
125 pdkim_free_ctx(dkim_verify_ctx);
127 /* Create new context */
129 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
130 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
131 dkim_collect_error = NULL;
133 /* Start feed up with any cached data */
136 store_pool = dkim_verify_oldpool;
141 dkim_exim_verify_feed(uschar * data, int len)
145 store_pool = POOL_MESSAGE;
146 if ( dkim_collect_input
147 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
149 dkim_collect_error = pdkim_errstr(rc);
150 log_write(0, LOG_MAIN,
151 "DKIM: validation error: %.100s", dkim_collect_error);
152 dkim_collect_input = 0;
154 store_pool = dkim_verify_oldpool;
158 /* Log the result for the given signature */
160 dkim_exim_verify_log_sig(pdkim_signature * sig)
167 /* Remember the domain for the first pass result */
169 if ( !dkim_verify_overall
170 && dkim_verify_status
171 ? Ustrcmp(dkim_verify_status, US"pass") == 0
172 : sig->verify_status == PDKIM_VERIFY_PASS
174 dkim_verify_overall = string_copy(sig->domain);
176 /* Rewrite the sig result if the ACL overrode it. This is only
177 needed because the DMARC code (sigh) peeks at the dkim sigs.
178 Mark the sig for this having been done. */
180 if ( dkim_verify_status
181 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
182 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
184 { /* overridden by ACL */
185 sig->verify_ext_status = -1;
186 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
187 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
188 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
189 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
190 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
191 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
192 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
193 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
195 sig->verify_status = -1;
198 if (!LOGGING(dkim_verbose)) return;
201 logmsg = string_catn(NULL, US"DKIM: ", 6);
202 if (!(s = sig->domain)) s = US"<UNSET>";
203 logmsg = string_append(logmsg, 2, "d=", s);
204 if (!(s = sig->selector)) s = US"<UNSET>";
205 logmsg = string_append(logmsg, 2, " s=", s);
206 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
207 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
208 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
209 dkim_sig_to_a_tag(sig),
210 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
211 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
212 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
214 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
216 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
219 if (sig->verify_status & PDKIM_VERIFY_POLICY)
220 logmsg = string_append(logmsg, 5,
221 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
223 switch (sig->verify_status)
225 case PDKIM_VERIFY_NONE:
226 logmsg = string_cat(logmsg, US" [not verified]");
229 case PDKIM_VERIFY_INVALID:
230 logmsg = string_cat(logmsg, US" [invalid - ");
231 switch (sig->verify_ext_status)
233 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
234 logmsg = string_cat(logmsg,
235 US"public key record (currently?) unavailable]");
238 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
239 logmsg = string_cat(logmsg, US"overlong public key record]");
242 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
243 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
244 logmsg = string_cat(logmsg, US"syntax error in public key record]");
247 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
248 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
251 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
252 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
256 logmsg = string_cat(logmsg, US"unspecified problem]");
260 case PDKIM_VERIFY_FAIL:
261 logmsg = string_cat(logmsg, US" [verification failed - ");
262 switch (sig->verify_ext_status)
264 case PDKIM_VERIFY_FAIL_BODY:
265 logmsg = string_cat(logmsg,
266 US"body hash mismatch (body probably modified in transit)]");
269 case PDKIM_VERIFY_FAIL_MESSAGE:
270 logmsg = string_cat(logmsg,
271 US"signature did not verify "
272 "(headers probably modified in transit)]");
275 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
276 logmsg = string_cat(logmsg,
277 US"signature invalid (key too short)]");
281 logmsg = string_cat(logmsg, US"unspecified reason]");
285 case PDKIM_VERIFY_PASS:
286 logmsg = string_cat(logmsg, US" [verification succeeded]");
290 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
295 /* Log a line for each signature */
297 dkim_exim_verify_log_all(void)
299 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
300 dkim_exim_verify_log_sig(sig);
305 dkim_exim_verify_finish(void)
309 const uschar * errstr = NULL;
311 store_pool = POOL_MESSAGE;
313 /* Delete eventual previous signature chain */
316 dkim_signatures = NULL;
318 if (dkim_collect_error)
320 log_write(0, LOG_MAIN,
321 "DKIM: Error during validation, disabling signature verification: %.100s",
323 f.dkim_disable_verify = TRUE;
327 dkim_collect_input = 0;
329 /* Finish DKIM operation and fetch link to signatures chain */
331 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
333 if (rc != PDKIM_OK && errstr)
334 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
336 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
338 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
340 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
341 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
344 if (g) dkim_signers = g->s;
347 store_pool = dkim_verify_oldpool;
352 /* Args as per dkim_exim_acl_run() below */
354 dkim_acl_call(uschar * id, gstring ** res_ptr,
355 uschar ** user_msgptr, uschar ** log_msgptr)
359 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
361 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
362 dkim_exim_verify_log_sig(dkim_cur_sig);
363 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
369 /* For the given identity, run the DKIM ACL once for each matching signature.
372 id Identity to look for in dkim signatures
373 res_ptr ptr to growable string-list of status results,
374 appended to per ACL run
375 user_msgptr where to put a user error (for SMTP response)
376 log_msgptr where to put a logging message (not for SMTP response)
378 Returns: OK access is granted by an ACCEPT verb
379 DISCARD access is granted by a DISCARD verb
380 FAIL access is denied
381 FAIL_DROP access is denied; drop the connection
382 DEFER can't tell at the moment
387 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
388 uschar ** user_msgptr, uschar ** log_msgptr)
393 dkim_verify_status = US"none";
394 dkim_verify_reason = US"";
395 dkim_cur_signer = id;
397 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
400 /* Find signatures to run ACL on */
402 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
403 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
404 && strcmpic(cmp_val, id) == 0
407 /* The "dkim_domain" and "dkim_selector" expansion variables have
408 related globals, since they are used in the signing code too.
409 Instead of inventing separate names for verification, we set
410 them here. This is easy since a domain and selector is guaranteed
411 to be in a signature. The other dkim_* expansion items are
412 dynamically fetched from dkim_cur_sig at expansion time (see
413 dkim_exim_expand_query() below). */
416 dkim_signing_domain = US sig->domain;
417 dkim_signing_selector = US sig->selector;
418 dkim_key_length = sig->keybits;
420 /* These two return static strings, so we can compare the addr
421 later to see if the ACL overwrote them. Check that when logging */
423 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
424 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
426 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
433 /* No matching sig found. Call ACL once anyway. */
436 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
441 dkim_exim_expand_defaults(int what)
445 case DKIM_ALGO: return US"";
446 case DKIM_BODYLENGTH: return US"9999999999999";
447 case DKIM_CANON_BODY: return US"";
448 case DKIM_CANON_HEADERS: return US"";
449 case DKIM_COPIEDHEADERS: return US"";
450 case DKIM_CREATED: return US"0";
451 case DKIM_EXPIRES: return US"9999999999999";
452 case DKIM_HEADERNAMES: return US"";
453 case DKIM_IDENTITY: return US"";
454 case DKIM_KEY_GRANULARITY: return US"*";
455 case DKIM_KEY_SRVTYPE: return US"*";
456 case DKIM_KEY_NOTES: return US"";
457 case DKIM_KEY_TESTING: return US"0";
458 case DKIM_NOSUBDOMAINS: return US"0";
459 case DKIM_VERIFY_STATUS: return US"none";
460 case DKIM_VERIFY_REASON: return US"";
461 default: return US"";
467 dkim_exim_expand_query(int what)
469 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
470 return dkim_exim_expand_defaults(what);
475 return dkim_sig_to_a_tag(dkim_cur_sig);
477 case DKIM_BODYLENGTH:
478 return dkim_cur_sig->bodylength >= 0
479 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
480 : dkim_exim_expand_defaults(what);
482 case DKIM_CANON_BODY:
483 switch (dkim_cur_sig->canon_body)
485 case PDKIM_CANON_RELAXED: return US"relaxed";
486 case PDKIM_CANON_SIMPLE:
487 default: return US"simple";
490 case DKIM_CANON_HEADERS:
491 switch (dkim_cur_sig->canon_headers)
493 case PDKIM_CANON_RELAXED: return US"relaxed";
494 case PDKIM_CANON_SIMPLE:
495 default: return US"simple";
498 case DKIM_COPIEDHEADERS:
499 return dkim_cur_sig->copiedheaders
500 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
503 return dkim_cur_sig->created > 0
504 ? string_sprintf("%lu", dkim_cur_sig->created)
505 : dkim_exim_expand_defaults(what);
508 return dkim_cur_sig->expires > 0
509 ? string_sprintf("%lu", dkim_cur_sig->expires)
510 : dkim_exim_expand_defaults(what);
512 case DKIM_HEADERNAMES:
513 return dkim_cur_sig->headernames
514 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
517 return dkim_cur_sig->identity
518 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
520 case DKIM_KEY_GRANULARITY:
521 return dkim_cur_sig->pubkey
522 ? dkim_cur_sig->pubkey->granularity
523 ? US dkim_cur_sig->pubkey->granularity
524 : dkim_exim_expand_defaults(what)
525 : dkim_exim_expand_defaults(what);
527 case DKIM_KEY_SRVTYPE:
528 return dkim_cur_sig->pubkey
529 ? dkim_cur_sig->pubkey->srvtype
530 ? US dkim_cur_sig->pubkey->srvtype
531 : dkim_exim_expand_defaults(what)
532 : dkim_exim_expand_defaults(what);
535 return dkim_cur_sig->pubkey
536 ? dkim_cur_sig->pubkey->notes
537 ? US dkim_cur_sig->pubkey->notes
538 : dkim_exim_expand_defaults(what)
539 : dkim_exim_expand_defaults(what);
541 case DKIM_KEY_TESTING:
542 return dkim_cur_sig->pubkey
543 ? dkim_cur_sig->pubkey->testing
545 : dkim_exim_expand_defaults(what)
546 : dkim_exim_expand_defaults(what);
548 case DKIM_NOSUBDOMAINS:
549 return dkim_cur_sig->pubkey
550 ? dkim_cur_sig->pubkey->no_subdomaining
552 : dkim_exim_expand_defaults(what)
553 : dkim_exim_expand_defaults(what);
555 case DKIM_VERIFY_STATUS:
556 switch (dkim_cur_sig->verify_status)
558 case PDKIM_VERIFY_INVALID: return US"invalid";
559 case PDKIM_VERIFY_FAIL: return US"fail";
560 case PDKIM_VERIFY_PASS: return US"pass";
561 case PDKIM_VERIFY_NONE:
562 default: return US"none";
565 case DKIM_VERIFY_REASON:
566 switch (dkim_cur_sig->verify_ext_status)
568 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
569 return US"pubkey_unavailable";
570 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
571 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
572 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
573 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
574 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
584 dkim_exim_sign_init(void)
586 int old_pool = store_pool;
589 store_pool = POOL_MAIN;
590 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
591 store_pool = old_pool;
595 /* Generate signatures for the given file.
596 If a prefix is given, prepend it to the file for the calculations.
599 NULL: error; error string written
600 string: signature header(s), or a zero-length string (not an error)
604 dkim_exim_sign(int fd, off_t off, uschar * prefix,
605 struct ob_dkim * dkim, const uschar ** errstr)
607 const uschar * dkim_domain = NULL;
609 gstring * seen_doms = NULL;
610 pdkim_signature * sig;
616 int old_pool = store_pool;
620 if (dkim->dot_stuffed)
621 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
623 store_pool = POOL_MAIN;
625 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
626 /* expansion error, do not send message. */
627 { errwhen = US"dkim_domain"; goto expand_bad; }
629 /* Set $dkim_domain expansion variable to each unique domain in list. */
632 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
634 const uschar * dkim_sel;
637 if (dkim_signing_domain[0] == '\0')
640 /* Only sign once for each domain, no matter how often it
641 appears in the expanded list. */
643 dkim_signing_domain = string_copylc(dkim_signing_domain);
644 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
645 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
648 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
650 /* Set $dkim_selector expansion variable to each selector in list,
653 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
654 { errwhen = US"dkim_selector"; goto expand_bad; }
656 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
659 uschar * dkim_canon_expanded;
661 uschar * dkim_sign_headers_expanded = NULL;
662 uschar * dkim_private_key_expanded;
663 uschar * dkim_hash_expanded;
664 uschar * dkim_identity_expanded = NULL;
665 uschar * dkim_timestamps_expanded = NULL;
666 unsigned long tval = 0, xval = 0;
668 /* Get canonicalization to use */
670 dkim_canon_expanded = dkim->dkim_canon
671 ? expand_string(dkim->dkim_canon) : US"relaxed";
672 if (!dkim_canon_expanded) /* expansion error, do not send message. */
673 { errwhen = US"dkim_canon"; goto expand_bad; }
675 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
676 pdkim_canon = PDKIM_CANON_RELAXED;
677 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
678 pdkim_canon = PDKIM_CANON_SIMPLE;
681 log_write(0, LOG_MAIN,
682 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
683 dkim_canon_expanded);
684 pdkim_canon = PDKIM_CANON_RELAXED;
687 if ( dkim->dkim_sign_headers
688 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
689 { errwhen = US"dkim_sign_header"; goto expand_bad; }
690 /* else pass NULL, which means default header list */
692 /* Get private key to use. */
694 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
695 { errwhen = US"dkim_private_key"; goto expand_bad; }
697 if ( Ustrlen(dkim_private_key_expanded) == 0
698 || Ustrcmp(dkim_private_key_expanded, "0") == 0
699 || Ustrcmp(dkim_private_key_expanded, "false") == 0
701 continue; /* don't sign, but no error */
703 if ( dkim_private_key_expanded[0] == '/'
704 && !(dkim_private_key_expanded =
705 expand_file_big_buffer(dkim_private_key_expanded)))
708 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
709 { errwhen = US"dkim_hash"; goto expand_bad; }
711 if (dkim->dkim_identity)
712 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
713 { errwhen = US"dkim_identity"; goto expand_bad; }
714 else if (!*dkim_identity_expanded)
715 dkim_identity_expanded = NULL;
717 if (dkim->dkim_timestamps)
718 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
719 { errwhen = US"dkim_timestamps"; goto expand_bad; }
721 xval = (tval = (unsigned long) time(NULL))
722 + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
724 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
725 dkim_signing_selector,
726 dkim_private_key_expanded,
731 dkim_private_key_expanded[0] = '\0';
733 pdkim_set_optional(sig,
734 CS dkim_sign_headers_expanded,
735 CS dkim_identity_expanded,
737 pdkim_canon, -1, tval, xval);
739 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
742 if (!dkim_sign_ctx.sig) /* link sig to context chain */
743 dkim_sign_ctx.sig = sig;
746 pdkim_signature * n = dkim_sign_ctx.sig;
747 while (n->next) n = n->next;
753 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
754 produce, if some other package (eg. ARC) is signing. */
756 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
758 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
759 sigbuf = string_get(1); /* return a zero-len string */
763 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
766 if (lseek(fd, off, SEEK_SET) < 0)
769 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
770 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
773 /* Handle failed read above. */
776 debug_printf("DKIM: Error reading -K file.\n");
781 /* Build string of headers, one per signature */
783 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
788 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
789 sigbuf = string_get(1); /* return a zero-len string */
791 else for (sigbuf = NULL; sig; sig = sig->next)
792 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
796 (void) string_from_gstring(sigbuf);
797 store_pool = old_pool;
802 log_write(0, LOG_MAIN|LOG_PANIC,
803 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
809 *errstr = string_sprintf("failed to expand %s: %s",
810 errwhen, expand_string_message);
811 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
819 authres_dkim(gstring * g)
821 int start = 0; /* compiler quietening */
823 DEBUG(D_acl) start = g->ptr;
825 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
827 g = string_catn(g, US";\n\tdkim=", 8);
829 if (sig->verify_status & PDKIM_VERIFY_POLICY)
830 g = string_append(g, 5,
831 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
832 else switch(sig->verify_status)
834 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
835 case PDKIM_VERIFY_INVALID:
836 switch (sig->verify_ext_status)
838 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
839 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
840 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
841 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
842 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
843 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
844 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
846 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
847 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
849 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
850 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
853 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
856 case PDKIM_VERIFY_FAIL:
857 switch (sig->verify_ext_status)
859 case PDKIM_VERIFY_FAIL_BODY:
861 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
863 case PDKIM_VERIFY_FAIL_MESSAGE:
865 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
867 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
868 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
871 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
875 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
876 default: g = string_cat(g, US"permerror"); break;
878 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
879 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
880 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
881 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
886 debug_printf("DKIM: no authres\n");
888 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
893 # endif /*!MACRO_PREDEF*/
894 #endif /*!DISABLE_DKIM*/