1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge, 1995 - 2017 */
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*/
30 int dkim_verify_oldpool;
31 pdkim_ctx *dkim_verify_ctx = NULL;
32 pdkim_signature *dkim_signatures = NULL;
33 pdkim_signature *dkim_cur_sig = NULL;
34 static const uschar * dkim_collect_error = NULL;
38 /*XXX the caller only uses the first record if we return multiple.
39 Could we hand back an allocated string?
43 dkim_exim_query_dns_txt(char *name, char *answer)
49 lookup_dnssec_authenticated = NULL;
50 if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
51 return PDKIM_FAIL; /*XXX better error detail? logging? */
53 /* Search for TXT record */
55 for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
57 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
58 if (rr->type == T_TXT)
61 int answer_offset = 0;
63 /* Copy record content to the answer buffer */
65 while (rr_offset < rr->size)
67 uschar len = rr->data[rr_offset++];
68 snprintf(answer + answer_offset,
69 PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
70 "%.*s", (int)len, CS (rr->data + rr_offset));
73 if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
74 return PDKIM_FAIL; /*XXX better error detail? logging? */
79 return PDKIM_FAIL; /*XXX better error detail? logging? */
92 dkim_exim_verify_init(BOOL dot_stuffing)
94 /* There is a store-reset between header & body reception
95 so cannot use the main pool. Any allocs done by Exim
96 memory-handling must use the perm pool. */
98 dkim_verify_oldpool = store_pool;
99 store_pool = POOL_PERM;
101 /* Free previous context if there is one */
104 pdkim_free_ctx(dkim_verify_ctx);
106 /* Create new context */
108 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
109 dkim_collect_input = !!dkim_verify_ctx;
110 dkim_collect_error = NULL;
112 /* Start feed up with any cached data */
115 store_pool = dkim_verify_oldpool;
120 dkim_exim_verify_feed(uschar * data, int len)
124 store_pool = POOL_PERM;
125 if ( dkim_collect_input
126 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
128 dkim_collect_error = pdkim_errstr(rc);
129 log_write(0, LOG_MAIN,
130 "DKIM: validation error: %.100s", dkim_collect_error);
131 dkim_collect_input = FALSE;
133 store_pool = dkim_verify_oldpool;
137 /* Log the result for the given signature */
139 dkim_exim_verify_log_sig(pdkim_signature * sig)
146 logmsg = string_catn(NULL, "DKIM: ", 6);
147 if (!(s = sig->domain)) s = US"<UNSET>";
148 logmsg = string_append(logmsg, 2, "d=", s);
149 if (!(s = sig->selector)) s = US"<UNSET>";
150 logmsg = string_append(logmsg, 2, " s=", s);
151 logmsg = string_append(logmsg, 7,
152 " c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
153 "/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
154 " a=", dkim_sig_to_a_tag(sig),
155 string_sprintf(" b=" SIZE_T_FMT,
156 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
157 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
158 if (sig->created > 0) logmsg = string_cat(logmsg,
159 string_sprintf(" t=%lu", sig->created));
160 if (sig->expires > 0) logmsg = string_cat(logmsg,
161 string_sprintf(" x=%lu", sig->expires));
162 if (sig->bodylength > -1) logmsg = string_cat(logmsg,
163 string_sprintf(" l=%lu", sig->bodylength));
165 if ( !dkim_verify_status
166 || ( dkim_verify_status == dkim_exim_expand_query(DKIM_VERIFY_STATUS)
167 && dkim_verify_reason == dkim_exim_expand_query(DKIM_VERIFY_REASON)
169 switch (sig->verify_status)
171 case PDKIM_VERIFY_NONE:
172 logmsg = string_cat(logmsg, " [not verified]");
175 case PDKIM_VERIFY_INVALID:
176 logmsg = string_cat(logmsg, " [invalid - ");
177 switch (sig->verify_ext_status)
179 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
180 logmsg = string_cat(logmsg,
181 "public key record (currently?) unavailable]");
184 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
185 logmsg = string_cat(logmsg, "overlong public key record]");
188 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
189 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
190 logmsg = string_cat(logmsg, "syntax error in public key record]");
193 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
194 logmsg = string_cat(logmsg, "signature tag missing or invalid]");
197 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
198 logmsg = string_cat(logmsg, "unsupported DKIM version]");
202 logmsg = string_cat(logmsg, "unspecified problem]");
206 case PDKIM_VERIFY_FAIL:
207 logmsg = string_cat(logmsg, " [verification failed - ");
208 switch (sig->verify_ext_status)
210 case PDKIM_VERIFY_FAIL_BODY:
211 logmsg = string_cat(logmsg,
212 "body hash mismatch (body probably modified in transit)]");
215 case PDKIM_VERIFY_FAIL_MESSAGE:
216 logmsg = string_cat(logmsg,
217 "signature did not verify (headers probably modified in transit)]");
221 logmsg = string_cat(logmsg, "unspecified reason]");
225 case PDKIM_VERIFY_PASS:
226 logmsg = string_cat(logmsg, " [verification succeeded]");
230 logmsg = string_append(logmsg, 5,
231 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
233 log_write(0, LOG_MAIN, string_from_gstring(logmsg));
238 /* Log a line for "the current" signature */
240 dkim_exim_verify_log_item(void)
242 dkim_exim_verify_log_sig(dkim_cur_sig);
246 /* Log a line for each signature */
248 dkim_exim_verify_log_all(void)
250 pdkim_signature * sig;
251 for (sig = dkim_signatures; sig; sig = sig->next) dkim_exim_verify_log_sig(sig);
256 dkim_exim_verify_finish(void)
258 pdkim_signature * sig;
261 const uschar * errstr;
263 store_pool = POOL_PERM;
265 /* Delete eventual previous signature chain */
268 dkim_signatures = NULL;
270 if (dkim_collect_error)
272 log_write(0, LOG_MAIN,
273 "DKIM: Error during validation, disabling signature verification: %.100s",
275 dkim_disable_verify = TRUE;
279 dkim_collect_input = FALSE;
281 /* Finish DKIM operation and fetch link to signatures chain */
283 rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
286 log_write(0, LOG_MAIN, "DKIM: validation error: %.100s%s%s", pdkim_errstr(rc),
287 errstr ? ": " : "", errstr ? errstr : US"");
291 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
293 for (sig = dkim_signatures; sig; sig = sig->next)
295 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
296 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
299 if (g) dkim_signers = g->s;
302 store_pool = dkim_verify_oldpool;
307 dkim_exim_acl_setup(uschar * id)
309 pdkim_signature * sig;
312 dkim_verify_status = US"none";
313 dkim_verify_reason = US"";
315 dkim_cur_signer = id;
317 if (dkim_disable_verify || !id || !dkim_verify_ctx)
320 /* Find signature to run ACL on */
322 for (sig = dkim_signatures; sig; sig = sig->next)
323 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
324 && strcmpic(cmp_val, id) == 0
329 /* The "dkim_domain" and "dkim_selector" expansion variables have
330 related globals, since they are used in the signing code too.
331 Instead of inventing separate names for verification, we set
332 them here. This is easy since a domain and selector is guaranteed
333 to be in a signature. The other dkim_* expansion items are
334 dynamically fetched from dkim_cur_sig at expansion time (see
337 dkim_signing_domain = US sig->domain;
338 dkim_signing_selector = US sig->selector;
339 dkim_key_length = sig->sighash.len * 8;
341 /* These two return static strings, so we can compare the addr
342 later to see if the ACL overwrote them. Check that when logging */
344 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
345 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
352 dkim_exim_expand_defaults(int what)
356 case DKIM_ALGO: return US"";
357 case DKIM_BODYLENGTH: return US"9999999999999";
358 case DKIM_CANON_BODY: return US"";
359 case DKIM_CANON_HEADERS: return US"";
360 case DKIM_COPIEDHEADERS: return US"";
361 case DKIM_CREATED: return US"0";
362 case DKIM_EXPIRES: return US"9999999999999";
363 case DKIM_HEADERNAMES: return US"";
364 case DKIM_IDENTITY: return US"";
365 case DKIM_KEY_GRANULARITY: return US"*";
366 case DKIM_KEY_SRVTYPE: return US"*";
367 case DKIM_KEY_NOTES: return US"";
368 case DKIM_KEY_TESTING: return US"0";
369 case DKIM_NOSUBDOMAINS: return US"0";
370 case DKIM_VERIFY_STATUS: return US"none";
371 case DKIM_VERIFY_REASON: return US"";
372 default: return US"";
378 dkim_exim_expand_query(int what)
380 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
381 return dkim_exim_expand_defaults(what);
386 return dkim_sig_to_a_tag(dkim_cur_sig);
388 case DKIM_BODYLENGTH:
389 return dkim_cur_sig->bodylength >= 0
390 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
391 : dkim_exim_expand_defaults(what);
393 case DKIM_CANON_BODY:
394 switch (dkim_cur_sig->canon_body)
396 case PDKIM_CANON_RELAXED: return US"relaxed";
397 case PDKIM_CANON_SIMPLE:
398 default: return US"simple";
401 case DKIM_CANON_HEADERS:
402 switch (dkim_cur_sig->canon_headers)
404 case PDKIM_CANON_RELAXED: return US"relaxed";
405 case PDKIM_CANON_SIMPLE:
406 default: return US"simple";
409 case DKIM_COPIEDHEADERS:
410 return dkim_cur_sig->copiedheaders
411 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
414 return dkim_cur_sig->created > 0
415 ? string_sprintf("%lu", dkim_cur_sig->created)
416 : dkim_exim_expand_defaults(what);
419 return dkim_cur_sig->expires > 0
420 ? string_sprintf("%lu", dkim_cur_sig->expires)
421 : dkim_exim_expand_defaults(what);
423 case DKIM_HEADERNAMES:
424 return dkim_cur_sig->headernames
425 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
428 return dkim_cur_sig->identity
429 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
431 case DKIM_KEY_GRANULARITY:
432 return dkim_cur_sig->pubkey
433 ? dkim_cur_sig->pubkey->granularity
434 ? US dkim_cur_sig->pubkey->granularity
435 : dkim_exim_expand_defaults(what)
436 : dkim_exim_expand_defaults(what);
438 case DKIM_KEY_SRVTYPE:
439 return dkim_cur_sig->pubkey
440 ? dkim_cur_sig->pubkey->srvtype
441 ? US dkim_cur_sig->pubkey->srvtype
442 : dkim_exim_expand_defaults(what)
443 : dkim_exim_expand_defaults(what);
446 return dkim_cur_sig->pubkey
447 ? dkim_cur_sig->pubkey->notes
448 ? US dkim_cur_sig->pubkey->notes
449 : dkim_exim_expand_defaults(what)
450 : dkim_exim_expand_defaults(what);
452 case DKIM_KEY_TESTING:
453 return dkim_cur_sig->pubkey
454 ? dkim_cur_sig->pubkey->testing
456 : dkim_exim_expand_defaults(what)
457 : dkim_exim_expand_defaults(what);
459 case DKIM_NOSUBDOMAINS:
460 return dkim_cur_sig->pubkey
461 ? dkim_cur_sig->pubkey->no_subdomaining
463 : dkim_exim_expand_defaults(what)
464 : dkim_exim_expand_defaults(what);
466 case DKIM_VERIFY_STATUS:
467 switch (dkim_cur_sig->verify_status)
469 case PDKIM_VERIFY_INVALID: return US"invalid";
470 case PDKIM_VERIFY_FAIL: return US"fail";
471 case PDKIM_VERIFY_PASS: return US"pass";
472 case PDKIM_VERIFY_NONE:
473 default: return US"none";
476 case DKIM_VERIFY_REASON:
477 switch (dkim_cur_sig->verify_ext_status)
479 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
480 return US"pubkey_unavailable";
481 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
482 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
483 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
484 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
493 /* Generate signatures for the given file, returning a string.
494 If a prefix is given, prepend it to the file for the calculations.
498 dkim_exim_sign(int fd, off_t off, uschar * prefix,
499 struct ob_dkim * dkim, const uschar ** errstr)
501 const uschar * dkim_domain;
503 gstring * seen_doms = NULL;
505 pdkim_signature * sig;
511 int old_pool = store_pool;
514 store_pool = POOL_MAIN;
516 pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
518 if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
519 /* expansion error, do not send message. */
520 { errwhen = US"dkim_domain"; goto expand_bad; }
522 /* Set $dkim_domain expansion variable to each unique domain in list. */
524 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
526 const uschar * dkim_sel;
529 if (dkim_signing_domain[0] == '\0')
532 /* Only sign once for each domain, no matter how often it
533 appears in the expanded list. */
535 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
536 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
539 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
541 /* Set $dkim_selector expansion variable to each selector in list,
544 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
545 if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
546 { errwhen = US"dkim_selector"; goto expand_bad; }
548 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
551 uschar * dkim_canon_expanded;
553 uschar * dkim_sign_headers_expanded = NULL;
554 uschar * dkim_private_key_expanded;
555 uschar * dkim_hash_expanded;
556 uschar * dkim_identity_expanded = NULL;
558 /* Get canonicalization to use */
560 dkim_canon_expanded = dkim->dkim_canon
561 ? expand_string(dkim->dkim_canon) : US"relaxed";
562 if (!dkim_canon_expanded) /* expansion error, do not send message. */
563 { errwhen = US"dkim_canon"; goto expand_bad; }
565 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
566 pdkim_canon = PDKIM_CANON_RELAXED;
567 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
568 pdkim_canon = PDKIM_CANON_SIMPLE;
571 log_write(0, LOG_MAIN,
572 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
573 dkim_canon_expanded);
574 pdkim_canon = PDKIM_CANON_RELAXED;
577 if ( dkim->dkim_sign_headers
578 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
579 { errwhen = US"dkim_sign_header"; goto expand_bad; }
580 /* else pass NULL, which means default header list */
582 /* Get private key to use. */
584 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
585 { errwhen = US"dkim_private_key"; goto expand_bad; }
587 if ( Ustrlen(dkim_private_key_expanded) == 0
588 || Ustrcmp(dkim_private_key_expanded, "0") == 0
589 || Ustrcmp(dkim_private_key_expanded, "false") == 0
591 continue; /* don't sign, but no error */
593 if (dkim_private_key_expanded[0] == '/')
595 int privkey_fd, off = 0, len;
597 /* Looks like a filename, load the private key. */
599 memset(big_buffer, 0, big_buffer_size);
601 if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
603 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
604 "private key file for reading: %s",
605 dkim_private_key_expanded);
611 if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
613 (void) close(privkey_fd);
614 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
615 dkim_private_key_expanded);
622 (void) close(privkey_fd);
623 big_buffer[off] = '\0';
624 dkim_private_key_expanded = big_buffer;
627 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
628 { errwhen = US"dkim_hash"; goto expand_bad; }
630 if (dkim->dkim_identity)
631 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
632 { errwhen = US"dkim_identity"; goto expand_bad; }
633 else if (!*dkim_identity_expanded)
634 dkim_identity_expanded = NULL;
636 /*XXX so we currently nail signing to RSA + this hash.
637 Need to extract algo from privkey and check for disallowed combos. */
639 if (!(sig = pdkim_init_sign(&ctx, dkim_signing_domain,
640 dkim_signing_selector,
641 dkim_private_key_expanded,
646 dkim_private_key_expanded[0] = '\0';
648 pdkim_set_optional(sig,
649 CS dkim_sign_headers_expanded,
650 dkim_identity_expanded,
652 pdkim_canon, -1, 0, 0);
654 if (!ctx.sig) /* link sig to context chain */
658 pdkim_signature * n = ctx.sig;
659 while (n->next) n = n->next;
666 pdkim_feed(&ctx, prefix, Ustrlen(prefix));
668 if (lseek(fd, off, SEEK_SET) < 0)
671 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
672 if ((pdkim_rc = pdkim_feed(&ctx, buf, sread)) != PDKIM_OK)
675 /* Handle failed read above. */
678 debug_printf("DKIM: Error reading -K file.\n");
683 /* Build string of headers, one per signature */
685 if ((pdkim_rc = pdkim_feed_finish(&ctx, &sig, errstr)) != PDKIM_OK)
688 for (sigbuf = NULL; sig; sig = sig->next)
689 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
691 (void) string_from_gstring(sigbuf);
694 store_pool = old_pool;
699 log_write(0, LOG_MAIN|LOG_PANIC,
700 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
706 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
707 errwhen, expand_string_message);
711 # endif /*!MACRO_PREDEF*/
712 #endif /*!DISABLE_DKIM*/