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"
17 int dkim_verify_oldpool;
18 pdkim_ctx *dkim_verify_ctx = NULL;
19 pdkim_signature *dkim_signatures = NULL;
20 pdkim_signature *dkim_cur_sig = NULL;
21 static const uschar * dkim_collect_error = NULL;
25 /*XXX the caller only uses the first record if we return multiple.
26 Could we hand back an allocated string?
30 dkim_exim_query_dns_txt(char *name, char *answer)
36 lookup_dnssec_authenticated = NULL;
37 if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
38 return PDKIM_FAIL; /*XXX better error detail? logging? */
40 /* Search for TXT record */
42 for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
44 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
45 if (rr->type == T_TXT)
48 int answer_offset = 0;
50 /* Copy record content to the answer buffer */
52 while (rr_offset < rr->size)
54 uschar len = rr->data[rr_offset++];
55 snprintf(answer + answer_offset,
56 PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
57 "%.*s", (int)len, CS (rr->data + rr_offset));
60 if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
61 return PDKIM_FAIL; /*XXX better error detail? logging? */
66 return PDKIM_FAIL; /*XXX better error detail? logging? */
79 dkim_exim_verify_init(BOOL dot_stuffing)
81 /* There is a store-reset between header & body reception
82 so cannot use the main pool. Any allocs done by Exim
83 memory-handling must use the perm pool. */
85 dkim_verify_oldpool = store_pool;
86 store_pool = POOL_PERM;
88 /* Free previous context if there is one */
91 pdkim_free_ctx(dkim_verify_ctx);
93 /* Create new context */
95 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
96 dkim_collect_input = !!dkim_verify_ctx;
97 dkim_collect_error = NULL;
99 /* Start feed up with any cached data */
102 store_pool = dkim_verify_oldpool;
107 dkim_exim_verify_feed(uschar * data, int len)
111 store_pool = POOL_PERM;
112 if ( dkim_collect_input
113 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
115 dkim_collect_error = pdkim_errstr(rc);
116 log_write(0, LOG_MAIN,
117 "DKIM: validation error: %.100s", dkim_collect_error);
118 dkim_collect_input = FALSE;
120 store_pool = dkim_verify_oldpool;
125 dkim_exim_verify_finish(void)
127 pdkim_signature * sig = NULL;
128 int dkim_signers_size = 0, dkim_signers_ptr = 0, rc;
129 const uschar * errstr;
131 store_pool = POOL_PERM;
133 /* Delete eventual previous signature chain */
136 dkim_signatures = NULL;
138 if (dkim_collect_error)
140 log_write(0, LOG_MAIN,
141 "DKIM: Error during validation, disabling signature verification: %.100s",
143 dkim_disable_verify = TRUE;
147 dkim_collect_input = FALSE;
149 /* Finish DKIM operation and fetch link to signatures chain */
151 rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
154 log_write(0, LOG_MAIN, "DKIM: validation error: %.100s%s%s", pdkim_errstr(rc),
155 errstr ? ": " : "", errstr ? errstr : US"");
159 for (sig = dkim_signatures; sig; sig = sig->next)
161 int size = 0, ptr = 0;
162 uschar * logmsg = NULL, * s;
164 /* Log a line for each signature */
166 if (!(s = sig->domain)) s = US"<UNSET>";
167 logmsg = string_append(logmsg, &size, &ptr, 2, "d=", s);
168 if (!(s = sig->selector)) s = US"<UNSET>";
169 logmsg = string_append(logmsg, &size, &ptr, 2, " s=", s);
170 logmsg = string_append(logmsg, &size, &ptr, 7,
171 " c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
172 "/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
173 " a=", dkim_sig_to_a_tag(sig),
174 string_sprintf(" b=%d",
175 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
176 if ((s= sig->identity)) logmsg = string_append(logmsg, &size, &ptr, 2, " i=", s);
177 if (sig->created > 0) logmsg = string_append(logmsg, &size, &ptr, 1,
178 string_sprintf(" t=%lu", sig->created));
179 if (sig->expires > 0) logmsg = string_append(logmsg, &size, &ptr, 1,
180 string_sprintf(" x=%lu", sig->expires));
181 if (sig->bodylength > -1) logmsg = string_append(logmsg, &size, &ptr, 1,
182 string_sprintf(" l=%lu", sig->bodylength));
184 switch (sig->verify_status)
186 case PDKIM_VERIFY_NONE:
187 logmsg = string_append(logmsg, &size, &ptr, 1, " [not verified]");
190 case PDKIM_VERIFY_INVALID:
191 logmsg = string_append(logmsg, &size, &ptr, 1, " [invalid - ");
192 switch (sig->verify_ext_status)
194 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
195 logmsg = string_append(logmsg, &size, &ptr, 1,
196 "public key record (currently?) unavailable]");
199 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
200 logmsg = string_append(logmsg, &size, &ptr, 1,
201 "overlong public key record]");
204 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
205 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
206 logmsg = string_append(logmsg, &size, &ptr, 1,
207 "syntax error in public key record]");
210 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
211 logmsg = string_append(logmsg, &size, &ptr, 1,
212 "signature tag missing or invalid]");
215 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
216 logmsg = string_append(logmsg, &size, &ptr, 1,
217 "unsupported DKIM version]");
221 logmsg = string_append(logmsg, &size, &ptr, 1,
222 "unspecified problem]");
226 case PDKIM_VERIFY_FAIL:
228 string_append(logmsg, &size, &ptr, 1, " [verification failed - ");
229 switch (sig->verify_ext_status)
231 case PDKIM_VERIFY_FAIL_BODY:
232 logmsg = string_append(logmsg, &size, &ptr, 1,
233 "body hash mismatch (body probably modified in transit)]");
236 case PDKIM_VERIFY_FAIL_MESSAGE:
237 logmsg = string_append(logmsg, &size, &ptr, 1,
238 "signature did not verify (headers probably modified in transit)]");
242 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
246 case PDKIM_VERIFY_PASS:
248 string_append(logmsg, &size, &ptr, 1, " [verification succeeded]");
253 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
255 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
258 dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size,
259 &dkim_signers_ptr, ':', sig->domain);
262 dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size,
263 &dkim_signers_ptr, ':', sig->identity);
265 /* Process next signature */
269 store_pool = dkim_verify_oldpool;
274 dkim_exim_acl_setup(uschar * id)
276 pdkim_signature * sig;
280 dkim_cur_signer = id;
282 if (dkim_disable_verify || !id || !dkim_verify_ctx)
285 /* Find signature to run ACL on */
287 for (sig = dkim_signatures; sig; sig = sig->next)
288 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
289 && strcmpic(cmp_val, id) == 0
294 /* The "dkim_domain" and "dkim_selector" expansion variables have
295 related globals, since they are used in the signing code too.
296 Instead of inventing separate names for verification, we set
297 them here. This is easy since a domain and selector is guaranteed
298 to be in a signature. The other dkim_* expansion items are
299 dynamically fetched from dkim_cur_sig at expansion time (see
302 dkim_signing_domain = US sig->domain;
303 dkim_signing_selector = US sig->selector;
304 dkim_key_length = sig->sighash.len * 8;
311 dkim_exim_expand_defaults(int what)
315 case DKIM_ALGO: return US"";
316 case DKIM_BODYLENGTH: return US"9999999999999";
317 case DKIM_CANON_BODY: return US"";
318 case DKIM_CANON_HEADERS: return US"";
319 case DKIM_COPIEDHEADERS: return US"";
320 case DKIM_CREATED: return US"0";
321 case DKIM_EXPIRES: return US"9999999999999";
322 case DKIM_HEADERNAMES: return US"";
323 case DKIM_IDENTITY: return US"";
324 case DKIM_KEY_GRANULARITY: return US"*";
325 case DKIM_KEY_SRVTYPE: return US"*";
326 case DKIM_KEY_NOTES: return US"";
327 case DKIM_KEY_TESTING: return US"0";
328 case DKIM_NOSUBDOMAINS: return US"0";
329 case DKIM_VERIFY_STATUS: return US"none";
330 case DKIM_VERIFY_REASON: return US"";
331 default: return US"";
337 dkim_exim_expand_query(int what)
339 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
340 return dkim_exim_expand_defaults(what);
345 return dkim_sig_to_a_tag(dkim_cur_sig);
347 case DKIM_BODYLENGTH:
348 return dkim_cur_sig->bodylength >= 0
349 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
350 : dkim_exim_expand_defaults(what);
352 case DKIM_CANON_BODY:
353 switch (dkim_cur_sig->canon_body)
355 case PDKIM_CANON_RELAXED: return US"relaxed";
356 case PDKIM_CANON_SIMPLE:
357 default: return US"simple";
360 case DKIM_CANON_HEADERS:
361 switch (dkim_cur_sig->canon_headers)
363 case PDKIM_CANON_RELAXED: return US"relaxed";
364 case PDKIM_CANON_SIMPLE:
365 default: return US"simple";
368 case DKIM_COPIEDHEADERS:
369 return dkim_cur_sig->copiedheaders
370 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
373 return dkim_cur_sig->created > 0
374 ? string_sprintf("%llu", dkim_cur_sig->created)
375 : dkim_exim_expand_defaults(what);
378 return dkim_cur_sig->expires > 0
379 ? string_sprintf("%llu", dkim_cur_sig->expires)
380 : dkim_exim_expand_defaults(what);
382 case DKIM_HEADERNAMES:
383 return dkim_cur_sig->headernames
384 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
387 return dkim_cur_sig->identity
388 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
390 case DKIM_KEY_GRANULARITY:
391 return dkim_cur_sig->pubkey
392 ? dkim_cur_sig->pubkey->granularity
393 ? US dkim_cur_sig->pubkey->granularity
394 : dkim_exim_expand_defaults(what)
395 : dkim_exim_expand_defaults(what);
397 case DKIM_KEY_SRVTYPE:
398 return dkim_cur_sig->pubkey
399 ? dkim_cur_sig->pubkey->srvtype
400 ? US dkim_cur_sig->pubkey->srvtype
401 : dkim_exim_expand_defaults(what)
402 : dkim_exim_expand_defaults(what);
405 return dkim_cur_sig->pubkey
406 ? dkim_cur_sig->pubkey->notes
407 ? US dkim_cur_sig->pubkey->notes
408 : dkim_exim_expand_defaults(what)
409 : dkim_exim_expand_defaults(what);
411 case DKIM_KEY_TESTING:
412 return dkim_cur_sig->pubkey
413 ? dkim_cur_sig->pubkey->testing
415 : dkim_exim_expand_defaults(what)
416 : dkim_exim_expand_defaults(what);
418 case DKIM_NOSUBDOMAINS:
419 return dkim_cur_sig->pubkey
420 ? dkim_cur_sig->pubkey->no_subdomaining
422 : dkim_exim_expand_defaults(what)
423 : dkim_exim_expand_defaults(what);
425 case DKIM_VERIFY_STATUS:
426 switch (dkim_cur_sig->verify_status)
428 case PDKIM_VERIFY_INVALID: return US"invalid";
429 case PDKIM_VERIFY_FAIL: return US"fail";
430 case PDKIM_VERIFY_PASS: return US"pass";
431 case PDKIM_VERIFY_NONE:
432 default: return US"none";
435 case DKIM_VERIFY_REASON:
436 switch (dkim_cur_sig->verify_ext_status)
438 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
439 return US"pubkey_unavailable";
440 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
441 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
442 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
443 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
452 /* Generate signatures for the given file, returning a string.
453 If a prefix is given, prepend it to the file for the calculations.
457 dkim_exim_sign(int fd, off_t off, uschar * prefix,
458 struct ob_dkim * dkim, const uschar ** errstr)
460 const uschar * dkim_domain;
462 uschar * seen_doms = NULL;
463 int seen_doms_size = 0;
464 int seen_doms_offset = 0;
466 pdkim_signature * sig;
467 blob * sigbuf = NULL;
473 int old_pool = store_pool;
475 store_pool = POOL_MAIN;
477 pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
479 if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
481 /* expansion error, do not send message. */
482 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
483 "dkim_domain: %s", expand_string_message);
487 /* Set $dkim_domain expansion variable to each unique domain in list. */
489 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
491 const uschar * dkim_sel;
494 if (dkim_signing_domain[0] == '\0')
497 /* Only sign once for each domain, no matter how often it
498 appears in the expanded list. */
500 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
501 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
504 seen_doms = string_append_listele(seen_doms, &seen_doms_size,
505 &seen_doms_offset, ':', dkim_signing_domain);
507 /* Set $dkim_selector expansion variable to each selector in list,
510 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
511 if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
513 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
514 "dkim_selector: %s", expand_string_message);
518 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
521 uschar * dkim_canon_expanded;
523 uschar * dkim_sign_headers_expanded = NULL;
524 uschar * dkim_private_key_expanded;
525 uschar * dkim_hash_expanded;
527 /* Get canonicalization to use */
529 dkim_canon_expanded = dkim->dkim_canon
530 ? expand_string(dkim->dkim_canon) : US"relaxed";
531 if (!dkim_canon_expanded)
533 /* expansion error, do not send message. */
534 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
535 "dkim_canon: %s", expand_string_message);
539 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
540 pdkim_canon = PDKIM_CANON_RELAXED;
541 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
542 pdkim_canon = PDKIM_CANON_SIMPLE;
545 log_write(0, LOG_MAIN,
546 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
547 dkim_canon_expanded);
548 pdkim_canon = PDKIM_CANON_RELAXED;
551 if (dkim->dkim_sign_headers)
552 if (!(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
554 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
555 "dkim_sign_headers: %s", expand_string_message);
558 /* else pass NULL, which means default header list */
560 /* Get private key to use. */
562 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
564 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
565 "dkim_private_key: %s", expand_string_message);
569 if ( Ustrlen(dkim_private_key_expanded) == 0
570 || Ustrcmp(dkim_private_key_expanded, "0") == 0
571 || Ustrcmp(dkim_private_key_expanded, "false") == 0
573 continue; /* don't sign, but no error */
575 if (dkim_private_key_expanded[0] == '/')
577 int privkey_fd, off = 0, len;
579 /* Looks like a filename, load the private key. */
581 memset(big_buffer, 0, big_buffer_size);
583 if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
585 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
586 "private key file for reading: %s",
587 dkim_private_key_expanded);
593 if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
595 (void) close(privkey_fd);
596 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
597 dkim_private_key_expanded);
604 (void) close(privkey_fd);
605 big_buffer[off] = '\0';
606 dkim_private_key_expanded = big_buffer;
609 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
611 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
612 "dkim_hash: %s", expand_string_message);
616 /*XXX so we currently nail signing to RSA + this hash.
617 Need to extract algo from privkey and check for disallowed combos. */
619 if (!(sig = pdkim_init_sign(&ctx, dkim_signing_domain,
620 dkim_signing_selector,
621 dkim_private_key_expanded,
626 dkim_private_key_expanded[0] = '\0';
628 pdkim_set_optional(sig,
629 CS dkim_sign_headers_expanded,
632 pdkim_canon, -1, 0, 0);
634 if (!ctx.sig) /* link sig to context chain */
638 pdkim_signature * n = ctx.sig;
639 while (n->next) n = n->next;
646 pdkim_feed(&ctx, prefix, Ustrlen(prefix));
648 if (lseek(fd, off, SEEK_SET) < 0)
651 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
652 if ((pdkim_rc = pdkim_feed(&ctx, buf, sread)) != PDKIM_OK)
655 /* Handle failed read above. */
658 debug_printf("DKIM: Error reading -K file.\n");
663 /* Build string of headers, one per signature */
665 if ((pdkim_rc = pdkim_feed_finish(&ctx, &sig, errstr)) != PDKIM_OK)
668 sigbuf = store_get(sizeof(blob));
674 int len = sigbuf->len;
675 sigbuf->data = string_append(sigbuf->data, &sigsize, &len, 2,
676 US sig->signature_header, US"\r\n");
682 sigbuf->data[sigbuf->len] = '\0';
687 store_pool = old_pool;
692 log_write(0, LOG_MAIN|LOG_PANIC,
693 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));