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 /* Start feed up with any cached data */
94 store_pool = dkim_verify_oldpool;
99 dkim_exim_verify_feed(uschar * data, int len)
101 store_pool = POOL_PERM;
102 if ( dkim_collect_input
103 && pdkim_feed(dkim_verify_ctx, (char *)data, len) != PDKIM_OK)
104 dkim_collect_input = FALSE;
105 store_pool = dkim_verify_oldpool;
110 dkim_exim_verify_finish(void)
112 pdkim_signature *sig = NULL;
113 int dkim_signers_size = 0;
114 int dkim_signers_ptr = 0;
117 store_pool = POOL_PERM;
119 /* Delete eventual previous signature chain */
121 dkim_signatures = NULL;
123 /* If we have arrived here with dkim_collect_input == FALSE, it
124 means there was a processing error somewhere along the way.
125 Log the incident and disable futher verification. */
127 if (!dkim_collect_input)
129 log_write(0, LOG_MAIN,
130 "DKIM: Error while running this message through validation,"
131 " disabling signature verification.");
132 dkim_disable_verify = TRUE;
136 dkim_collect_input = FALSE;
138 /* Finish DKIM operation and fetch link to signatures chain */
140 if (pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures) != PDKIM_OK)
143 for (sig = dkim_signatures; sig; sig = sig->next)
148 /* Log a line for each signature */
150 uschar *logmsg = string_append(NULL, &size, &ptr, 5,
151 string_sprintf("d=%s s=%s c=%s/%s a=%s b=%d ",
154 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
155 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
156 sig->algo == PDKIM_ALGO_RSA_SHA256
158 : sig->algo == PDKIM_ALGO_RSA_SHA1 ? "rsa-sha1" : "err",
159 (int)sig->sigdata.len > -1 ? sig->sigdata.len * 8 : 0
162 sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
163 sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
164 sig->expires > 0 ? string_sprintf("x=%lu ", sig->expires) : US"",
165 sig->bodylength > -1 ? string_sprintf("l=%lu ", sig->bodylength) : US""
168 switch (sig->verify_status)
170 case PDKIM_VERIFY_NONE:
171 logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
174 case PDKIM_VERIFY_INVALID:
175 logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
176 switch (sig->verify_ext_status)
178 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
179 logmsg = string_append(logmsg, &size, &ptr, 1,
180 "public key record (currently?) unavailable]");
183 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
184 logmsg = string_append(logmsg, &size, &ptr, 1,
185 "overlong public key record]");
188 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
189 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
190 logmsg = string_append(logmsg, &size, &ptr, 1,
191 "syntax error in public key record]");
194 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
195 logmsg = string_append(logmsg, &size, &ptr, 1,
196 "signature tag missing or invalid]");
199 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
200 logmsg = string_append(logmsg, &size, &ptr, 1,
201 "unsupported DKIM version]");
205 logmsg = string_append(logmsg, &size, &ptr, 1,
206 "unspecified problem]");
210 case PDKIM_VERIFY_FAIL:
212 string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
213 switch (sig->verify_ext_status)
215 case PDKIM_VERIFY_FAIL_BODY:
216 logmsg = string_append(logmsg, &size, &ptr, 1,
217 "body hash mismatch (body probably modified in transit)]");
220 case PDKIM_VERIFY_FAIL_MESSAGE:
221 logmsg = string_append(logmsg, &size, &ptr, 1,
222 "signature did not verify (headers probably modified in transit)]");
226 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
230 case PDKIM_VERIFY_PASS:
232 string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
237 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
239 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
241 dkim_signers = string_append(dkim_signers,
243 &dkim_signers_ptr, 2, sig->domain, ":");
246 dkim_signers = string_append(dkim_signers,
248 &dkim_signers_ptr, 2, sig->identity, ":");
250 /* Process next signature */
253 /* NULL-terminate and chop the last colon from the domain list */
257 dkim_signers[dkim_signers_ptr] = '\0';
258 if (Ustrlen(dkim_signers) > 0)
259 dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
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->sigdata.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, uschar * dkim_private_key,
453 const uschar * dkim_domain, uschar * dkim_selector,
454 uschar * dkim_canon, uschar * dkim_sign_headers)
457 uschar *seen_items = NULL;
458 int seen_items_size = 0;
459 int seen_items_offset = 0;
461 uschar *dkim_canon_expanded;
462 uschar *dkim_sign_headers_expanded;
463 uschar *dkim_private_key_expanded;
464 pdkim_ctx *ctx = NULL;
466 uschar *sigbuf = NULL;
469 pdkim_signature *signature;
475 int old_pool = store_pool;
477 store_pool = POOL_MAIN;
479 if (!(dkim_domain = expand_cstring(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);
488 /* Set $dkim_domain expansion variable to each unique domain in list. */
490 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
491 itembuf, sizeof(itembuf))))
493 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
496 /* Only sign once for each domain, no matter how often it
497 appears in the expanded list. */
501 const uschar *seen_items_list = seen_items;
502 if (match_isinlist(dkim_signing_domain,
503 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
508 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
512 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
513 dkim_signing_domain);
514 seen_items[seen_items_offset] = '\0';
516 /* Set up $dkim_selector expansion variable. */
518 if (!(dkim_signing_selector = expand_string(dkim_selector)))
520 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
521 "dkim_selector: %s", expand_string_message);
526 /* Get canonicalization to use */
528 dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
529 if (!dkim_canon_expanded)
531 /* expansion error, do not send message. */
532 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
533 "dkim_canon: %s", expand_string_message);
538 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
539 pdkim_canon = PDKIM_CANON_RELAXED;
540 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
541 pdkim_canon = PDKIM_CANON_SIMPLE;
544 log_write(0, LOG_MAIN,
545 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
546 dkim_canon_expanded);
547 pdkim_canon = PDKIM_CANON_RELAXED;
550 dkim_sign_headers_expanded = NULL;
551 if (dkim_sign_headers)
552 if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
554 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
555 "dkim_sign_headers: %s", expand_string_message);
559 /* else pass NULL, which means default header list */
561 /* Get private key to use. */
563 if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
565 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
566 "dkim_private_key: %s", expand_string_message);
571 if ( Ustrlen(dkim_private_key_expanded) == 0
572 || Ustrcmp(dkim_private_key_expanded, "0") == 0
573 || Ustrcmp(dkim_private_key_expanded, "false") == 0
575 continue; /* don't sign, but no error */
577 if (dkim_private_key_expanded[0] == '/')
581 /* Looks like a filename, load the private key. */
583 memset(big_buffer, 0, big_buffer_size);
584 privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
587 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
588 "private key file for reading: %s",
589 dkim_private_key_expanded);
594 if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
596 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
597 dkim_private_key_expanded);
602 (void) close(privkey_fd);
603 dkim_private_key_expanded = big_buffer;
606 ctx = pdkim_init_sign( (char *) dkim_signing_domain,
607 (char *) dkim_signing_selector,
608 (char *) dkim_private_key_expanded,
609 PDKIM_ALGO_RSA_SHA256);
610 pdkim_set_optional(ctx,
611 (char *) dkim_sign_headers_expanded,
614 pdkim_canon, -1, 0, 0);
616 lseek(dkim_fd, 0, SEEK_SET);
618 while ((sread = read(dkim_fd, &buf, 4096)) > 0)
619 if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
625 /* Handle failed read above. */
628 debug_printf("DKIM: Error reading -K file.\n");
634 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
636 log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
641 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
642 US signature->signature_header, US"\r\n");
650 sigbuf[sigptr] = '\0';
659 store_pool = old_pool;