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;
24 dkim_exim_query_dns_txt(char *name, char *answer)
30 lookup_dnssec_authenticated = NULL;
31 if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
32 return PDKIM_FAIL; /*XXX better error detail? logging? */
34 /* Search for TXT record */
36 for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
38 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
39 if (rr->type == T_TXT)
42 int answer_offset = 0;
44 /* Copy record content to the answer buffer */
46 while (rr_offset < rr->size)
48 uschar len = rr->data[rr_offset++];
49 snprintf(answer + answer_offset,
50 PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
51 "%.*s", (int)len, (char *) (rr->data + rr_offset));
54 if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
55 return PDKIM_FAIL; /*XXX better error detail? logging? */
60 return PDKIM_FAIL; /*XXX better error detail? logging? */
73 dkim_exim_verify_init(BOOL dot_stuffing)
75 /* There is a store-reset between header & body reception
76 so cannot use the main pool. Any allocs done by Exim
77 memory-handling must use the perm pool. */
79 dkim_verify_oldpool = store_pool;
80 store_pool = POOL_PERM;
82 /* Free previous context if there is one */
85 pdkim_free_ctx(dkim_verify_ctx);
87 /* Create new context */
89 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
90 dkim_collect_input = !!dkim_verify_ctx;
91 dkim_collect_error = NULL;
93 /* Start feed up with any cached data */
96 store_pool = dkim_verify_oldpool;
101 dkim_exim_verify_feed(uschar * data, int len)
105 store_pool = POOL_PERM;
106 if ( dkim_collect_input
107 && (rc = pdkim_feed(dkim_verify_ctx, CS data, len)) != PDKIM_OK)
109 dkim_collect_error = pdkim_errstr(rc);
110 log_write(0, LOG_MAIN,
111 "DKIM: validation error: %.100s", dkim_collect_error);
112 dkim_collect_input = FALSE;
114 store_pool = dkim_verify_oldpool;
119 dkim_exim_verify_finish(void)
121 pdkim_signature * sig = NULL;
122 int dkim_signers_size = 0, dkim_signers_ptr = 0, rc;
123 const uschar * errstr;
125 store_pool = POOL_PERM;
127 /* Delete eventual previous signature chain */
130 dkim_signatures = NULL;
132 if (dkim_collect_error)
134 log_write(0, LOG_MAIN,
135 "DKIM: Error during validation, disabling signature verification: %.100s",
137 dkim_disable_verify = TRUE;
141 dkim_collect_input = FALSE;
143 /* Finish DKIM operation and fetch link to signatures chain */
145 rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
148 log_write(0, LOG_MAIN, "DKIM: validation error: %.100s%s%s", pdkim_errstr(rc),
149 errstr ? ": " : "", errstr ? errstr : US"");
153 for (sig = dkim_signatures; sig; sig = sig->next)
155 int size = 0, ptr = 0;
156 uschar * logmsg = NULL, * s;
158 /* Log a line for each signature */
160 if (!(s = sig->domain)) s = US"<UNSET>";
161 logmsg = string_append(logmsg, &size, &ptr, 2, "d=", s);
162 if (!(s = sig->selector)) s = US"<UNSET>";
163 logmsg = string_append(logmsg, &size, &ptr, 2, " s=", s);
164 logmsg = string_append(logmsg, &size, &ptr, 7,
165 " c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
166 "/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
167 " a=", sig->algo == PDKIM_ALGO_RSA_SHA256
169 : sig->algo == PDKIM_ALGO_RSA_SHA1 ? "rsa-sha1" : "err",
170 string_sprintf(" b=%d",
171 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
172 if ((s= sig->identity)) string_append(logmsg, &size, &ptr, 2, " i=", s);
173 if (sig->created > 0) string_append(logmsg, &size, &ptr, 1,
174 string_sprintf(" t=%lu", sig->created));
175 if (sig->expires > 0) string_append(logmsg, &size, &ptr, 1,
176 string_sprintf(" x=%lu", sig->expires));
177 if (sig->bodylength > -1) string_append(logmsg, &size, &ptr, 1,
178 string_sprintf(" l=%lu", sig->bodylength));
180 switch (sig->verify_status)
182 case PDKIM_VERIFY_NONE:
183 logmsg = string_append(logmsg, &size, &ptr, 1, " [not verified]");
186 case PDKIM_VERIFY_INVALID:
187 logmsg = string_append(logmsg, &size, &ptr, 1, " [invalid - ");
188 switch (sig->verify_ext_status)
190 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
191 logmsg = string_append(logmsg, &size, &ptr, 1,
192 "public key record (currently?) unavailable]");
195 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
196 logmsg = string_append(logmsg, &size, &ptr, 1,
197 "overlong public key record]");
200 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
201 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
202 logmsg = string_append(logmsg, &size, &ptr, 1,
203 "syntax error in public key record]");
206 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
207 logmsg = string_append(logmsg, &size, &ptr, 1,
208 "signature tag missing or invalid]");
211 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
212 logmsg = string_append(logmsg, &size, &ptr, 1,
213 "unsupported DKIM version]");
217 logmsg = string_append(logmsg, &size, &ptr, 1,
218 "unspecified problem]");
222 case PDKIM_VERIFY_FAIL:
224 string_append(logmsg, &size, &ptr, 1, " [verification failed - ");
225 switch (sig->verify_ext_status)
227 case PDKIM_VERIFY_FAIL_BODY:
228 logmsg = string_append(logmsg, &size, &ptr, 1,
229 "body hash mismatch (body probably modified in transit)]");
232 case PDKIM_VERIFY_FAIL_MESSAGE:
233 logmsg = string_append(logmsg, &size, &ptr, 1,
234 "signature did not verify (headers probably modified in transit)]");
238 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
242 case PDKIM_VERIFY_PASS:
244 string_append(logmsg, &size, &ptr, 1, " [verification succeeded]");
249 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
251 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
254 dkim_signers = string_append_listele(dkim_signers, ':', sig->domain);
257 dkim_signers = string_append_listele(dkim_signers, ':', sig->identity);
259 /* Process next signature */
263 store_pool = dkim_verify_oldpool;
268 dkim_exim_acl_setup(uschar * id)
270 pdkim_signature * sig;
274 dkim_cur_signer = id;
276 if (dkim_disable_verify || !id || !dkim_verify_ctx)
279 /* Find signature to run ACL on */
281 for (sig = dkim_signatures; sig; sig = sig->next)
282 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
283 && strcmpic(cmp_val, id) == 0
288 /* The "dkim_domain" and "dkim_selector" expansion variables have
289 related globals, since they are used in the signing code too.
290 Instead of inventing separate names for verification, we set
291 them here. This is easy since a domain and selector is guaranteed
292 to be in a signature. The other dkim_* expansion items are
293 dynamically fetched from dkim_cur_sig at expansion time (see
296 dkim_signing_domain = US sig->domain;
297 dkim_signing_selector = US sig->selector;
298 dkim_key_length = sig->sighash.len * 8;
305 dkim_exim_expand_defaults(int what)
309 case DKIM_ALGO: return US"";
310 case DKIM_BODYLENGTH: return US"9999999999999";
311 case DKIM_CANON_BODY: return US"";
312 case DKIM_CANON_HEADERS: return US"";
313 case DKIM_COPIEDHEADERS: return US"";
314 case DKIM_CREATED: return US"0";
315 case DKIM_EXPIRES: return US"9999999999999";
316 case DKIM_HEADERNAMES: return US"";
317 case DKIM_IDENTITY: return US"";
318 case DKIM_KEY_GRANULARITY: return US"*";
319 case DKIM_KEY_SRVTYPE: return US"*";
320 case DKIM_KEY_NOTES: return US"";
321 case DKIM_KEY_TESTING: return US"0";
322 case DKIM_NOSUBDOMAINS: return US"0";
323 case DKIM_VERIFY_STATUS: return US"none";
324 case DKIM_VERIFY_REASON: return US"";
325 default: return US"";
331 dkim_exim_expand_query(int what)
333 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
334 return dkim_exim_expand_defaults(what);
339 switch (dkim_cur_sig->algo)
341 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
342 case PDKIM_ALGO_RSA_SHA256:
343 default: return US"rsa-sha256";
346 case DKIM_BODYLENGTH:
347 return dkim_cur_sig->bodylength >= 0
348 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
349 : dkim_exim_expand_defaults(what);
351 case DKIM_CANON_BODY:
352 switch (dkim_cur_sig->canon_body)
354 case PDKIM_CANON_RELAXED: return US"relaxed";
355 case PDKIM_CANON_SIMPLE:
356 default: return US"simple";
359 case DKIM_CANON_HEADERS:
360 switch (dkim_cur_sig->canon_headers)
362 case PDKIM_CANON_RELAXED: return US"relaxed";
363 case PDKIM_CANON_SIMPLE:
364 default: return US"simple";
367 case DKIM_COPIEDHEADERS:
368 return dkim_cur_sig->copiedheaders
369 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
372 return dkim_cur_sig->created > 0
373 ? string_sprintf("%llu", dkim_cur_sig->created)
374 : dkim_exim_expand_defaults(what);
377 return dkim_cur_sig->expires > 0
378 ? string_sprintf("%llu", dkim_cur_sig->expires)
379 : dkim_exim_expand_defaults(what);
381 case DKIM_HEADERNAMES:
382 return dkim_cur_sig->headernames
383 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
386 return dkim_cur_sig->identity
387 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
389 case DKIM_KEY_GRANULARITY:
390 return dkim_cur_sig->pubkey
391 ? dkim_cur_sig->pubkey->granularity
392 ? US dkim_cur_sig->pubkey->granularity
393 : dkim_exim_expand_defaults(what)
394 : dkim_exim_expand_defaults(what);
396 case DKIM_KEY_SRVTYPE:
397 return dkim_cur_sig->pubkey
398 ? dkim_cur_sig->pubkey->srvtype
399 ? US dkim_cur_sig->pubkey->srvtype
400 : dkim_exim_expand_defaults(what)
401 : dkim_exim_expand_defaults(what);
404 return dkim_cur_sig->pubkey
405 ? dkim_cur_sig->pubkey->notes
406 ? US dkim_cur_sig->pubkey->notes
407 : dkim_exim_expand_defaults(what)
408 : dkim_exim_expand_defaults(what);
410 case DKIM_KEY_TESTING:
411 return dkim_cur_sig->pubkey
412 ? dkim_cur_sig->pubkey->testing
414 : dkim_exim_expand_defaults(what)
415 : dkim_exim_expand_defaults(what);
417 case DKIM_NOSUBDOMAINS:
418 return dkim_cur_sig->pubkey
419 ? dkim_cur_sig->pubkey->no_subdomaining
421 : dkim_exim_expand_defaults(what)
422 : dkim_exim_expand_defaults(what);
424 case DKIM_VERIFY_STATUS:
425 switch (dkim_cur_sig->verify_status)
427 case PDKIM_VERIFY_INVALID: return US"invalid";
428 case PDKIM_VERIFY_FAIL: return US"fail";
429 case PDKIM_VERIFY_PASS: return US"pass";
430 case PDKIM_VERIFY_NONE:
431 default: return US"none";
434 case DKIM_VERIFY_REASON:
435 switch (dkim_cur_sig->verify_ext_status)
437 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
438 return US"pubkey_unavailable";
439 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
440 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
441 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
442 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
452 dkim_exim_sign(int dkim_fd, struct ob_dkim * dkim, const uschar ** errstr)
454 const uschar * dkim_domain;
456 uschar *seen_items = NULL;
457 int seen_items_size = 0;
458 int seen_items_offset = 0;
460 uschar *dkim_canon_expanded;
461 uschar *dkim_sign_headers_expanded;
462 uschar *dkim_private_key_expanded;
463 pdkim_ctx *ctx = NULL;
465 uschar *sigbuf = NULL;
468 pdkim_signature *signature;
474 int old_pool = store_pool;
476 store_pool = POOL_MAIN;
478 if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
480 /* expansion error, do not send message. */
481 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
482 "dkim_domain: %s", expand_string_message);
486 /* Set $dkim_domain expansion variable to each unique domain in list. */
488 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
489 itembuf, sizeof(itembuf))))
491 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
494 /* Only sign once for each domain, no matter how often it
495 appears in the expanded list. */
499 const uschar *seen_items_list = seen_items;
500 if (match_isinlist(dkim_signing_domain,
501 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
506 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
510 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
511 dkim_signing_domain);
512 seen_items[seen_items_offset] = '\0';
514 /* Set up $dkim_selector expansion variable. */
516 if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
518 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
519 "dkim_selector: %s", expand_string_message);
523 /* Get canonicalization to use */
525 dkim_canon_expanded = dkim->dkim_canon
526 ? expand_string(dkim->dkim_canon) : US"relaxed";
527 if (!dkim_canon_expanded)
529 /* expansion error, do not send message. */
530 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
531 "dkim_canon: %s", expand_string_message);
535 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
536 pdkim_canon = PDKIM_CANON_RELAXED;
537 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
538 pdkim_canon = PDKIM_CANON_SIMPLE;
541 log_write(0, LOG_MAIN,
542 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
543 dkim_canon_expanded);
544 pdkim_canon = PDKIM_CANON_RELAXED;
547 dkim_sign_headers_expanded = NULL;
548 if (dkim->dkim_sign_headers)
549 if (!(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
551 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
552 "dkim_sign_headers: %s", expand_string_message);
555 /* else pass NULL, which means default header list */
557 /* Get private key to use. */
559 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
561 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
562 "dkim_private_key: %s", expand_string_message);
566 if ( Ustrlen(dkim_private_key_expanded) == 0
567 || Ustrcmp(dkim_private_key_expanded, "0") == 0
568 || Ustrcmp(dkim_private_key_expanded, "false") == 0
570 continue; /* don't sign, but no error */
572 if (dkim_private_key_expanded[0] == '/')
574 int privkey_fd, off = 0, len;
576 /* Looks like a filename, load the private key. */
578 memset(big_buffer, 0, big_buffer_size);
580 if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
582 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
583 "private key file for reading: %s",
584 dkim_private_key_expanded);
590 if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
592 (void) close(privkey_fd);
593 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
594 dkim_private_key_expanded);
601 (void) close(privkey_fd);
602 big_buffer[off] = '\0';
603 dkim_private_key_expanded = big_buffer;
606 if (!(ctx = pdkim_init_sign(CS dkim_signing_domain,
607 CS dkim_signing_selector,
608 CS dkim_private_key_expanded,
609 PDKIM_ALGO_RSA_SHA256,
611 &dkim_exim_query_dns_txt,
615 dkim_private_key_expanded[0] = '\0';
616 pdkim_set_optional(ctx,
617 CS dkim_sign_headers_expanded,
620 pdkim_canon, -1, 0, 0);
622 lseek(dkim_fd, 0, SEEK_SET);
624 while ((sread = read(dkim_fd, &buf, sizeof(buf))) > 0)
625 if ((pdkim_rc = pdkim_feed(ctx, buf, sread)) != PDKIM_OK)
628 /* Handle failed read above. */
631 debug_printf("DKIM: Error reading -K file.\n");
636 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature, errstr)) != PDKIM_OK)
639 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
640 US signature->signature_header, US"\r\n");
648 sigbuf[sigptr] = '\0';
657 store_pool = old_pool;
662 log_write(0, LOG_MAIN|LOG_PANIC,
663 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));