1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge, 1995 - 2015 */
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 pdkim_ctx *dkim_verify_ctx = NULL;
18 pdkim_signature *dkim_signatures = NULL;
19 pdkim_signature *dkim_cur_sig = NULL;
22 dkim_exim_query_dns_txt(char *name, char *answer)
28 lookup_dnssec_authenticated = NULL;
29 if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
32 /* Search for TXT record */
34 for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
36 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
37 if (rr->type == T_TXT)
40 int answer_offset = 0;
42 /* Copy record content to the answer buffer */
44 while (rr_offset < rr->size)
46 uschar len = rr->data[rr_offset++];
47 snprintf(answer + answer_offset,
48 PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
49 "%.*s", (int)len, (char *) (rr->data + rr_offset));
52 if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
70 dkim_exim_verify_init(void)
72 /* Free previous context if there is one */
75 pdkim_free_ctx(dkim_verify_ctx);
77 /* Create new context */
79 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt);
80 dkim_collect_input = !!dkim_verify_ctx;
85 dkim_exim_verify_feed(uschar * data, int len)
87 if ( dkim_collect_input
88 && pdkim_feed(dkim_verify_ctx, (char *)data, len) != PDKIM_OK)
89 dkim_collect_input = FALSE;
94 dkim_exim_verify_finish(void)
96 pdkim_signature *sig = NULL;
97 int dkim_signers_size = 0;
98 int dkim_signers_ptr = 0;
101 /* Delete eventual previous signature chain */
103 dkim_signatures = NULL;
105 /* If we have arrived here with dkim_collect_input == FALSE, it
106 means there was a processing error somewhere along the way.
107 Log the incident and disable futher verification. */
109 if (!dkim_collect_input)
111 log_write(0, LOG_MAIN,
112 "DKIM: Error while running this message through validation,"
113 " disabling signature verification.");
114 dkim_disable_verify = TRUE;
118 dkim_collect_input = FALSE;
120 /* Finish DKIM operation and fetch link to signatures chain */
122 if (pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures) != PDKIM_OK)
125 for (sig = dkim_signatures; sig; sig = sig->next)
130 /* Log a line for each signature */
132 uschar *logmsg = string_append(NULL, &size, &ptr, 5,
133 string_sprintf("d=%s s=%s c=%s/%s a=%s b=%d ",
136 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
137 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
138 sig->algo == PDKIM_ALGO_RSA_SHA256 ? "rsa-sha256" : "rsa-sha1",
142 sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
143 sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
144 sig->expires > 0 ? string_sprintf("x=%lu ", sig->expires) : US"",
145 sig->bodylength > -1 ? string_sprintf("l=%lu ", sig->bodylength) : US""
148 switch (sig->verify_status)
150 case PDKIM_VERIFY_NONE:
151 logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
154 case PDKIM_VERIFY_INVALID:
155 logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
156 switch (sig->verify_ext_status)
158 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
159 logmsg = string_append(logmsg, &size, &ptr, 1,
160 "public key record (currently?) unavailable]");
163 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
164 logmsg = string_append(logmsg, &size, &ptr, 1,
165 "overlong public key record]");
168 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
169 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
170 logmsg = string_append(logmsg, &size, &ptr, 1,
171 "syntax error in public key record]");
175 logmsg = string_append(logmsg, &size, &ptr, 1,
176 "unspecified problem]");
180 case PDKIM_VERIFY_FAIL:
182 string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
183 switch (sig->verify_ext_status)
185 case PDKIM_VERIFY_FAIL_BODY:
186 logmsg = string_append(logmsg, &size, &ptr, 1,
187 "body hash mismatch (body probably modified in transit)]");
190 case PDKIM_VERIFY_FAIL_MESSAGE:
191 logmsg = string_append(logmsg, &size, &ptr, 1,
192 "signature did not verify (headers probably modified in transit)]");
196 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
200 case PDKIM_VERIFY_PASS:
202 string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
207 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
209 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
211 dkim_signers = string_append(dkim_signers,
213 &dkim_signers_ptr, 2, sig->domain, ":");
216 dkim_signers = string_append(dkim_signers,
218 &dkim_signers_ptr, 2, sig->identity, ":");
220 /* Process next signature */
223 /* NULL-terminate and chop the last colon from the domain list */
227 dkim_signers[dkim_signers_ptr] = '\0';
228 if (Ustrlen(dkim_signers) > 0)
229 dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
235 dkim_exim_acl_setup(uschar * id)
237 pdkim_signature * sig;
241 dkim_cur_signer = id;
243 if (dkim_disable_verify || !id || !dkim_verify_ctx)
246 /* Find signature to run ACL on */
248 for (sig = dkim_signatures; sig; sig = sig->next)
249 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
250 && strcmpic(cmp_val, id) == 0
255 /* The "dkim_domain" and "dkim_selector" expansion variables have
256 related globals, since they are used in the signing code too.
257 Instead of inventing separate names for verification, we set
258 them here. This is easy since a domain and selector is guaranteed
259 to be in a signature. The other dkim_* expansion items are
260 dynamically fetched from dkim_cur_sig at expansion time (see
263 dkim_signing_domain = US sig->domain;
264 dkim_signing_selector = US sig->selector;
265 dkim_key_length = sig->sigdata.len * 8;
272 dkim_exim_expand_defaults(int what)
276 case DKIM_ALGO: return US"";
277 case DKIM_BODYLENGTH: return US"9999999999999";
278 case DKIM_CANON_BODY: return US"";
279 case DKIM_CANON_HEADERS: return US"";
280 case DKIM_COPIEDHEADERS: return US"";
281 case DKIM_CREATED: return US"0";
282 case DKIM_EXPIRES: return US"9999999999999";
283 case DKIM_HEADERNAMES: return US"";
284 case DKIM_IDENTITY: return US"";
285 case DKIM_KEY_GRANULARITY: return US"*";
286 case DKIM_KEY_SRVTYPE: return US"*";
287 case DKIM_KEY_NOTES: return US"";
288 case DKIM_KEY_TESTING: return US"0";
289 case DKIM_NOSUBDOMAINS: return US"0";
290 case DKIM_VERIFY_STATUS: return US"none";
291 case DKIM_VERIFY_REASON: return US"";
292 default: return US"";
298 dkim_exim_expand_query(int what)
300 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
301 return dkim_exim_expand_defaults(what);
306 switch (dkim_cur_sig->algo)
308 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
309 case PDKIM_ALGO_RSA_SHA256:
310 default: return US"rsa-sha256";
313 case DKIM_BODYLENGTH:
314 return dkim_cur_sig->bodylength >= 0
315 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
316 : dkim_exim_expand_defaults(what);
318 case DKIM_CANON_BODY:
319 switch (dkim_cur_sig->canon_body)
321 case PDKIM_CANON_RELAXED: return US"relaxed";
322 case PDKIM_CANON_SIMPLE:
323 default: return US"simple";
326 case DKIM_CANON_HEADERS:
327 switch (dkim_cur_sig->canon_headers)
329 case PDKIM_CANON_RELAXED: return US"relaxed";
330 case PDKIM_CANON_SIMPLE:
331 default: return US"simple";
334 case DKIM_COPIEDHEADERS:
335 return dkim_cur_sig->copiedheaders
336 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
339 return dkim_cur_sig->created > 0
340 ? string_sprintf("%llu", dkim_cur_sig->created)
341 : dkim_exim_expand_defaults(what);
344 return dkim_cur_sig->expires > 0
345 ? string_sprintf("%llu", dkim_cur_sig->expires)
346 : dkim_exim_expand_defaults(what);
348 case DKIM_HEADERNAMES:
349 return dkim_cur_sig->headernames
350 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
353 return dkim_cur_sig->identity
354 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
356 case DKIM_KEY_GRANULARITY:
357 return dkim_cur_sig->pubkey
358 ? dkim_cur_sig->pubkey->granularity
359 ? US dkim_cur_sig->pubkey->granularity
360 : dkim_exim_expand_defaults(what)
361 : dkim_exim_expand_defaults(what);
363 case DKIM_KEY_SRVTYPE:
364 return dkim_cur_sig->pubkey
365 ? dkim_cur_sig->pubkey->srvtype
366 ? US dkim_cur_sig->pubkey->srvtype
367 : dkim_exim_expand_defaults(what)
368 : dkim_exim_expand_defaults(what);
371 return dkim_cur_sig->pubkey
372 ? dkim_cur_sig->pubkey->notes
373 ? US dkim_cur_sig->pubkey->notes
374 : dkim_exim_expand_defaults(what)
375 : dkim_exim_expand_defaults(what);
377 case DKIM_KEY_TESTING:
378 return dkim_cur_sig->pubkey
379 ? dkim_cur_sig->pubkey->testing
381 : dkim_exim_expand_defaults(what)
382 : dkim_exim_expand_defaults(what);
384 case DKIM_NOSUBDOMAINS:
385 return dkim_cur_sig->pubkey
386 ? dkim_cur_sig->pubkey->no_subdomaining
388 : dkim_exim_expand_defaults(what)
389 : dkim_exim_expand_defaults(what);
391 case DKIM_VERIFY_STATUS:
392 switch (dkim_cur_sig->verify_status)
394 case PDKIM_VERIFY_INVALID: return US"invalid";
395 case PDKIM_VERIFY_FAIL: return US"fail";
396 case PDKIM_VERIFY_PASS: return US"pass";
397 case PDKIM_VERIFY_NONE:
398 default: return US"none";
401 case DKIM_VERIFY_REASON:
402 switch (dkim_cur_sig->verify_ext_status)
404 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
405 return US"pubkey_unavailable";
406 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
407 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
408 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
409 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
419 dkim_exim_sign(int dkim_fd, uschar * dkim_private_key,
420 const uschar * dkim_domain, uschar * dkim_selector,
421 uschar * dkim_canon, uschar * dkim_sign_headers)
424 uschar *seen_items = NULL;
425 int seen_items_size = 0;
426 int seen_items_offset = 0;
428 uschar *dkim_canon_expanded;
429 uschar *dkim_sign_headers_expanded;
430 uschar *dkim_private_key_expanded;
431 pdkim_ctx *ctx = NULL;
433 uschar *sigbuf = NULL;
436 pdkim_signature *signature;
442 int old_pool = store_pool;
444 store_pool = POOL_MAIN;
446 if (!(dkim_domain = expand_cstring(dkim_domain)))
448 /* expansion error, do not send message. */
449 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
450 "dkim_domain: %s", expand_string_message);
455 /* Set $dkim_domain expansion variable to each unique domain in list. */
457 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
458 itembuf, sizeof(itembuf))))
460 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
463 /* Only sign once for each domain, no matter how often it
464 appears in the expanded list. */
468 const uschar *seen_items_list = seen_items;
469 if (match_isinlist(dkim_signing_domain,
470 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
475 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
479 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
480 dkim_signing_domain);
481 seen_items[seen_items_offset] = '\0';
483 /* Set up $dkim_selector expansion variable. */
485 if (!(dkim_signing_selector = expand_string(dkim_selector)))
487 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
488 "dkim_selector: %s", expand_string_message);
493 /* Get canonicalization to use */
495 dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
496 if (!dkim_canon_expanded)
498 /* expansion error, do not send message. */
499 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
500 "dkim_canon: %s", expand_string_message);
505 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
506 pdkim_canon = PDKIM_CANON_RELAXED;
507 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
508 pdkim_canon = PDKIM_CANON_SIMPLE;
511 log_write(0, LOG_MAIN,
512 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
513 dkim_canon_expanded);
514 pdkim_canon = PDKIM_CANON_RELAXED;
517 dkim_sign_headers_expanded = NULL;
518 if (dkim_sign_headers)
519 if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
521 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
522 "dkim_sign_headers: %s", expand_string_message);
526 /* else pass NULL, which means default header list */
528 /* Get private key to use. */
530 if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
532 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
533 "dkim_private_key: %s", expand_string_message);
538 if ( Ustrlen(dkim_private_key_expanded) == 0
539 || Ustrcmp(dkim_private_key_expanded, "0") == 0
540 || Ustrcmp(dkim_private_key_expanded, "false") == 0
542 continue; /* don't sign, but no error */
544 if (dkim_private_key_expanded[0] == '/')
548 /* Looks like a filename, load the private key. */
550 memset(big_buffer, 0, big_buffer_size);
551 privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
554 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
555 "private key file for reading: %s",
556 dkim_private_key_expanded);
561 if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
563 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
564 dkim_private_key_expanded);
569 (void) close(privkey_fd);
570 dkim_private_key_expanded = big_buffer;
573 ctx = pdkim_init_sign( (char *) dkim_signing_domain,
574 (char *) dkim_signing_selector,
575 (char *) dkim_private_key_expanded,
576 PDKIM_ALGO_RSA_SHA256);
577 pdkim_set_optional(ctx,
578 (char *) dkim_sign_headers_expanded,
581 pdkim_canon, -1, 0, 0);
583 lseek(dkim_fd, 0, SEEK_SET);
585 while ((sread = read(dkim_fd, &buf, 4096)) > 0)
586 if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
592 /* Handle failed read above. */
595 debug_printf("DKIM: Error reading -K file.\n");
601 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
603 log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
608 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
609 US signature->signature_header, US"\r\n");
617 sigbuf[sigptr] = '\0';
626 store_pool = old_pool;