1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge, 1995 - 2016 */
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;
23 dkim_exim_query_dns_txt(char *name, char *answer)
29 lookup_dnssec_authenticated = NULL;
30 if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
33 /* Search for TXT record */
35 for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
37 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
38 if (rr->type == T_TXT)
41 int answer_offset = 0;
43 /* Copy record content to the answer buffer */
45 while (rr_offset < rr->size)
47 uschar len = rr->data[rr_offset++];
48 snprintf(answer + answer_offset,
49 PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
50 "%.*s", (int)len, (char *) (rr->data + rr_offset));
53 if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
72 dkim_exim_verify_init(void)
74 /* There is a store-reset between header & body reception
75 so cannot use the main pool. Any allocs done by Exim
76 memory-handling must use the perm pool. */
78 dkim_verify_oldpool = store_pool;
79 store_pool = POOL_PERM;
81 /* Free previous context if there is one */
84 pdkim_free_ctx(dkim_verify_ctx);
86 /* Create new context */
88 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt);
89 dkim_collect_input = !!dkim_verify_ctx;
91 store_pool = dkim_verify_oldpool;
96 dkim_exim_verify_feed(uschar * data, int len)
98 store_pool = POOL_PERM;
99 if ( dkim_collect_input
100 && pdkim_feed(dkim_verify_ctx, (char *)data, len) != PDKIM_OK)
101 dkim_collect_input = FALSE;
102 store_pool = dkim_verify_oldpool;
107 dkim_exim_verify_finish(void)
109 pdkim_signature *sig = NULL;
110 int dkim_signers_size = 0;
111 int dkim_signers_ptr = 0;
114 store_pool = POOL_PERM;
116 /* Delete eventual previous signature chain */
118 dkim_signatures = NULL;
120 /* If we have arrived here with dkim_collect_input == FALSE, it
121 means there was a processing error somewhere along the way.
122 Log the incident and disable futher verification. */
124 if (!dkim_collect_input)
126 log_write(0, LOG_MAIN,
127 "DKIM: Error while running this message through validation,"
128 " disabling signature verification.");
129 dkim_disable_verify = TRUE;
133 dkim_collect_input = FALSE;
135 /* Finish DKIM operation and fetch link to signatures chain */
137 if (pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures) != PDKIM_OK)
140 for (sig = dkim_signatures; sig; sig = sig->next)
145 /* Log a line for each signature */
147 uschar *logmsg = string_append(NULL, &size, &ptr, 5,
148 string_sprintf("d=%s s=%s c=%s/%s a=%s b=%d ",
151 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
152 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
153 sig->algo == PDKIM_ALGO_RSA_SHA256
155 : sig->algo == PDKIM_ALGO_RSA_SHA1 ? "rsa-sha1" : "err",
156 (int)sig->sigdata.len > -1 ? sig->sigdata.len * 8 : 0
159 sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
160 sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
161 sig->expires > 0 ? string_sprintf("x=%lu ", sig->expires) : US"",
162 sig->bodylength > -1 ? string_sprintf("l=%lu ", sig->bodylength) : US""
165 switch (sig->verify_status)
167 case PDKIM_VERIFY_NONE:
168 logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
171 case PDKIM_VERIFY_INVALID:
172 logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
173 switch (sig->verify_ext_status)
175 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
176 logmsg = string_append(logmsg, &size, &ptr, 1,
177 "public key record (currently?) unavailable]");
180 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
181 logmsg = string_append(logmsg, &size, &ptr, 1,
182 "overlong public key record]");
185 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
186 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
187 logmsg = string_append(logmsg, &size, &ptr, 1,
188 "syntax error in public key record]");
191 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
192 logmsg = string_append(logmsg, &size, &ptr, 1,
193 "signature tag missing or invalid]");
196 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
197 logmsg = string_append(logmsg, &size, &ptr, 1,
198 "unsupported DKIM version]");
202 logmsg = string_append(logmsg, &size, &ptr, 1,
203 "unspecified problem]");
207 case PDKIM_VERIFY_FAIL:
209 string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
210 switch (sig->verify_ext_status)
212 case PDKIM_VERIFY_FAIL_BODY:
213 logmsg = string_append(logmsg, &size, &ptr, 1,
214 "body hash mismatch (body probably modified in transit)]");
217 case PDKIM_VERIFY_FAIL_MESSAGE:
218 logmsg = string_append(logmsg, &size, &ptr, 1,
219 "signature did not verify (headers probably modified in transit)]");
223 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
227 case PDKIM_VERIFY_PASS:
229 string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
234 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
236 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
238 dkim_signers = string_append(dkim_signers,
240 &dkim_signers_ptr, 2, sig->domain, ":");
243 dkim_signers = string_append(dkim_signers,
245 &dkim_signers_ptr, 2, sig->identity, ":");
247 /* Process next signature */
250 /* NULL-terminate and chop the last colon from the domain list */
254 dkim_signers[dkim_signers_ptr] = '\0';
255 if (Ustrlen(dkim_signers) > 0)
256 dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
260 store_pool = dkim_verify_oldpool;
265 dkim_exim_acl_setup(uschar * id)
267 pdkim_signature * sig;
271 dkim_cur_signer = id;
273 if (dkim_disable_verify || !id || !dkim_verify_ctx)
276 /* Find signature to run ACL on */
278 for (sig = dkim_signatures; sig; sig = sig->next)
279 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
280 && strcmpic(cmp_val, id) == 0
285 /* The "dkim_domain" and "dkim_selector" expansion variables have
286 related globals, since they are used in the signing code too.
287 Instead of inventing separate names for verification, we set
288 them here. This is easy since a domain and selector is guaranteed
289 to be in a signature. The other dkim_* expansion items are
290 dynamically fetched from dkim_cur_sig at expansion time (see
293 dkim_signing_domain = US sig->domain;
294 dkim_signing_selector = US sig->selector;
295 dkim_key_length = sig->sigdata.len * 8;
302 dkim_exim_expand_defaults(int what)
306 case DKIM_ALGO: return US"";
307 case DKIM_BODYLENGTH: return US"9999999999999";
308 case DKIM_CANON_BODY: return US"";
309 case DKIM_CANON_HEADERS: return US"";
310 case DKIM_COPIEDHEADERS: return US"";
311 case DKIM_CREATED: return US"0";
312 case DKIM_EXPIRES: return US"9999999999999";
313 case DKIM_HEADERNAMES: return US"";
314 case DKIM_IDENTITY: return US"";
315 case DKIM_KEY_GRANULARITY: return US"*";
316 case DKIM_KEY_SRVTYPE: return US"*";
317 case DKIM_KEY_NOTES: return US"";
318 case DKIM_KEY_TESTING: return US"0";
319 case DKIM_NOSUBDOMAINS: return US"0";
320 case DKIM_VERIFY_STATUS: return US"none";
321 case DKIM_VERIFY_REASON: return US"";
322 default: return US"";
328 dkim_exim_expand_query(int what)
330 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
331 return dkim_exim_expand_defaults(what);
336 switch (dkim_cur_sig->algo)
338 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
339 case PDKIM_ALGO_RSA_SHA256:
340 default: return US"rsa-sha256";
343 case DKIM_BODYLENGTH:
344 return dkim_cur_sig->bodylength >= 0
345 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
346 : dkim_exim_expand_defaults(what);
348 case DKIM_CANON_BODY:
349 switch (dkim_cur_sig->canon_body)
351 case PDKIM_CANON_RELAXED: return US"relaxed";
352 case PDKIM_CANON_SIMPLE:
353 default: return US"simple";
356 case DKIM_CANON_HEADERS:
357 switch (dkim_cur_sig->canon_headers)
359 case PDKIM_CANON_RELAXED: return US"relaxed";
360 case PDKIM_CANON_SIMPLE:
361 default: return US"simple";
364 case DKIM_COPIEDHEADERS:
365 return dkim_cur_sig->copiedheaders
366 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
369 return dkim_cur_sig->created > 0
370 ? string_sprintf("%llu", dkim_cur_sig->created)
371 : dkim_exim_expand_defaults(what);
374 return dkim_cur_sig->expires > 0
375 ? string_sprintf("%llu", dkim_cur_sig->expires)
376 : dkim_exim_expand_defaults(what);
378 case DKIM_HEADERNAMES:
379 return dkim_cur_sig->headernames
380 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
383 return dkim_cur_sig->identity
384 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
386 case DKIM_KEY_GRANULARITY:
387 return dkim_cur_sig->pubkey
388 ? dkim_cur_sig->pubkey->granularity
389 ? US dkim_cur_sig->pubkey->granularity
390 : dkim_exim_expand_defaults(what)
391 : dkim_exim_expand_defaults(what);
393 case DKIM_KEY_SRVTYPE:
394 return dkim_cur_sig->pubkey
395 ? dkim_cur_sig->pubkey->srvtype
396 ? US dkim_cur_sig->pubkey->srvtype
397 : dkim_exim_expand_defaults(what)
398 : dkim_exim_expand_defaults(what);
401 return dkim_cur_sig->pubkey
402 ? dkim_cur_sig->pubkey->notes
403 ? US dkim_cur_sig->pubkey->notes
404 : dkim_exim_expand_defaults(what)
405 : dkim_exim_expand_defaults(what);
407 case DKIM_KEY_TESTING:
408 return dkim_cur_sig->pubkey
409 ? dkim_cur_sig->pubkey->testing
411 : dkim_exim_expand_defaults(what)
412 : dkim_exim_expand_defaults(what);
414 case DKIM_NOSUBDOMAINS:
415 return dkim_cur_sig->pubkey
416 ? dkim_cur_sig->pubkey->no_subdomaining
418 : dkim_exim_expand_defaults(what)
419 : dkim_exim_expand_defaults(what);
421 case DKIM_VERIFY_STATUS:
422 switch (dkim_cur_sig->verify_status)
424 case PDKIM_VERIFY_INVALID: return US"invalid";
425 case PDKIM_VERIFY_FAIL: return US"fail";
426 case PDKIM_VERIFY_PASS: return US"pass";
427 case PDKIM_VERIFY_NONE:
428 default: return US"none";
431 case DKIM_VERIFY_REASON:
432 switch (dkim_cur_sig->verify_ext_status)
434 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
435 return US"pubkey_unavailable";
436 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
437 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
438 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
439 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
449 dkim_exim_sign(int dkim_fd, uschar * dkim_private_key,
450 const uschar * dkim_domain, uschar * dkim_selector,
451 uschar * dkim_canon, uschar * dkim_sign_headers)
454 uschar *seen_items = NULL;
455 int seen_items_size = 0;
456 int seen_items_offset = 0;
458 uschar *dkim_canon_expanded;
459 uschar *dkim_sign_headers_expanded;
460 uschar *dkim_private_key_expanded;
461 pdkim_ctx *ctx = NULL;
463 uschar *sigbuf = NULL;
466 pdkim_signature *signature;
472 int old_pool = store_pool;
474 store_pool = POOL_MAIN;
476 if (!(dkim_domain = expand_cstring(dkim_domain)))
478 /* expansion error, do not send message. */
479 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
480 "dkim_domain: %s", expand_string_message);
485 /* Set $dkim_domain expansion variable to each unique domain in list. */
487 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
488 itembuf, sizeof(itembuf))))
490 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
493 /* Only sign once for each domain, no matter how often it
494 appears in the expanded list. */
498 const uschar *seen_items_list = seen_items;
499 if (match_isinlist(dkim_signing_domain,
500 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
505 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
509 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
510 dkim_signing_domain);
511 seen_items[seen_items_offset] = '\0';
513 /* Set up $dkim_selector expansion variable. */
515 if (!(dkim_signing_selector = expand_string(dkim_selector)))
517 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
518 "dkim_selector: %s", expand_string_message);
523 /* Get canonicalization to use */
525 dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
526 if (!dkim_canon_expanded)
528 /* expansion error, do not send message. */
529 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
530 "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_sign_headers)
549 if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
551 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
552 "dkim_sign_headers: %s", expand_string_message);
556 /* else pass NULL, which means default header list */
558 /* Get private key to use. */
560 if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
562 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
563 "dkim_private_key: %s", expand_string_message);
568 if ( Ustrlen(dkim_private_key_expanded) == 0
569 || Ustrcmp(dkim_private_key_expanded, "0") == 0
570 || Ustrcmp(dkim_private_key_expanded, "false") == 0
572 continue; /* don't sign, but no error */
574 if (dkim_private_key_expanded[0] == '/')
578 /* Looks like a filename, load the private key. */
580 memset(big_buffer, 0, big_buffer_size);
581 privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
584 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
585 "private key file for reading: %s",
586 dkim_private_key_expanded);
591 if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
593 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
594 dkim_private_key_expanded);
599 (void) close(privkey_fd);
600 dkim_private_key_expanded = big_buffer;
603 ctx = pdkim_init_sign( (char *) dkim_signing_domain,
604 (char *) dkim_signing_selector,
605 (char *) dkim_private_key_expanded,
606 PDKIM_ALGO_RSA_SHA256);
607 pdkim_set_optional(ctx,
608 (char *) dkim_sign_headers_expanded,
611 pdkim_canon, -1, 0, 0);
613 lseek(dkim_fd, 0, SEEK_SET);
615 while ((sread = read(dkim_fd, &buf, 4096)) > 0)
616 if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
622 /* Handle failed read above. */
625 debug_printf("DKIM: Error reading -K file.\n");
631 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
633 log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
638 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
639 US signature->signature_header, US"\r\n");
647 sigbuf[sigptr] = '\0';
656 store_pool = old_pool;