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)
63 dkim_exim_verify_init(void)
65 /* Free previous context if there is one */
68 pdkim_free_ctx(dkim_verify_ctx);
70 /* Create new context */
72 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt);
73 dkim_collect_input = !!dkim_verify_ctx;
78 dkim_exim_verify_feed(uschar * data, int len)
80 if ( dkim_collect_input
81 && pdkim_feed(dkim_verify_ctx, (char *)data, len) != PDKIM_OK)
82 dkim_collect_input = FALSE;
87 dkim_exim_verify_finish(void)
89 pdkim_signature *sig = NULL;
90 int dkim_signers_size = 0;
91 int dkim_signers_ptr = 0;
94 /* Delete eventual previous signature chain */
96 dkim_signatures = NULL;
98 /* If we have arrived here with dkim_collect_input == FALSE, it
99 means there was a processing error somewhere along the way.
100 Log the incident and disable futher verification. */
102 if (!dkim_collect_input)
104 log_write(0, LOG_MAIN,
105 "DKIM: Error while running this message through validation,"
106 " disabling signature verification.");
107 dkim_disable_verify = TRUE;
111 dkim_collect_input = FALSE;
113 /* Finish DKIM operation and fetch link to signatures chain */
115 if (pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures) != PDKIM_OK)
118 for (sig = dkim_signatures; sig; sig = sig->next)
123 /* Log a line for each signature */
125 uschar *logmsg = string_append(NULL, &size, &ptr, 5,
126 string_sprintf("d=%s s=%s c=%s/%s a=%s b=%d ",
129 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
130 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
131 sig->algo == PDKIM_ALGO_RSA_SHA256 ? "rsa-sha256" : "rsa-sha1",
135 sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
136 sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
137 sig->expires > 0 ? string_sprintf("x=%lu ", sig->expires) : US"",
138 sig->bodylength > -1 ? string_sprintf("l=%lu ", sig->bodylength) : US""
141 switch (sig->verify_status)
143 case PDKIM_VERIFY_NONE:
144 logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
147 case PDKIM_VERIFY_INVALID:
148 logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
149 switch (sig->verify_ext_status)
151 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
152 logmsg = string_append(logmsg, &size, &ptr, 1,
153 "public key record (currently?) unavailable]");
156 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
157 logmsg = string_append(logmsg, &size, &ptr, 1,
158 "overlong public key record]");
161 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
162 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
163 logmsg = string_append(logmsg, &size, &ptr, 1,
164 "syntax error in public key record]");
168 logmsg = string_append(logmsg, &size, &ptr, 1,
169 "unspecified problem]");
173 case PDKIM_VERIFY_FAIL:
175 string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
176 switch (sig->verify_ext_status)
178 case PDKIM_VERIFY_FAIL_BODY:
179 logmsg = string_append(logmsg, &size, &ptr, 1,
180 "body hash mismatch (body probably modified in transit)]");
183 case PDKIM_VERIFY_FAIL_MESSAGE:
184 logmsg = string_append(logmsg, &size, &ptr, 1,
185 "signature did not verify (headers probably modified in transit)]");
189 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
193 case PDKIM_VERIFY_PASS:
195 string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
200 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
202 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
204 dkim_signers = string_append(dkim_signers,
206 &dkim_signers_ptr, 2, sig->domain, ":");
209 dkim_signers = string_append(dkim_signers,
211 &dkim_signers_ptr, 2, sig->identity, ":");
213 /* Process next signature */
216 /* NULL-terminate and chop the last colon from the domain list */
220 dkim_signers[dkim_signers_ptr] = '\0';
221 if (Ustrlen(dkim_signers) > 0)
222 dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
228 dkim_exim_acl_setup(uschar * id)
230 pdkim_signature * sig;
234 dkim_cur_signer = id;
236 if (dkim_disable_verify || !id || !dkim_verify_ctx)
239 /* Find signature to run ACL on */
241 for (sig = dkim_signatures; sig; sig = sig->next)
242 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
243 && strcmpic(cmp_val, id) == 0
248 /* The "dkim_domain" and "dkim_selector" expansion variables have
249 related globals, since they are used in the signing code too.
250 Instead of inventing separate names for verification, we set
251 them here. This is easy since a domain and selector is guaranteed
252 to be in a signature. The other dkim_* expansion items are
253 dynamically fetched from dkim_cur_sig at expansion time (see
256 dkim_signing_domain = US sig->domain;
257 dkim_signing_selector = US sig->selector;
258 dkim_key_length = sig->sigdata_len * 8;
265 dkim_exim_expand_defaults(int what)
269 case DKIM_ALGO: return US"";
270 case DKIM_BODYLENGTH: return US"9999999999999";
271 case DKIM_CANON_BODY: return US"";
272 case DKIM_CANON_HEADERS: return US"";
273 case DKIM_COPIEDHEADERS: return US"";
274 case DKIM_CREATED: return US"0";
275 case DKIM_EXPIRES: return US"9999999999999";
276 case DKIM_HEADERNAMES: return US"";
277 case DKIM_IDENTITY: return US"";
278 case DKIM_KEY_GRANULARITY: return US"*";
279 case DKIM_KEY_SRVTYPE: return US"*";
280 case DKIM_KEY_NOTES: return US"";
281 case DKIM_KEY_TESTING: return US"0";
282 case DKIM_NOSUBDOMAINS: return US"0";
283 case DKIM_VERIFY_STATUS: return US"none";
284 case DKIM_VERIFY_REASON: return US"";
285 default: return US"";
291 dkim_exim_expand_query(int what)
293 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
294 return dkim_exim_expand_defaults(what);
299 switch (dkim_cur_sig->algo)
301 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
302 case PDKIM_ALGO_RSA_SHA256:
303 default: return US"rsa-sha256";
306 case DKIM_BODYLENGTH:
307 return dkim_cur_sig->bodylength >= 0
308 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
309 : dkim_exim_expand_defaults(what);
311 case DKIM_CANON_BODY:
312 switch (dkim_cur_sig->canon_body)
314 case PDKIM_CANON_RELAXED: return US"relaxed";
315 case PDKIM_CANON_SIMPLE:
316 default: return US"simple";
319 case DKIM_CANON_HEADERS:
320 switch (dkim_cur_sig->canon_headers)
322 case PDKIM_CANON_RELAXED: return US"relaxed";
323 case PDKIM_CANON_SIMPLE:
324 default: return US"simple";
327 case DKIM_COPIEDHEADERS:
328 return dkim_cur_sig->copiedheaders
329 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
332 return dkim_cur_sig->created > 0
333 ? string_sprintf("%llu", dkim_cur_sig->created)
334 : dkim_exim_expand_defaults(what);
337 return dkim_cur_sig->expires > 0
338 ? string_sprintf("%llu", dkim_cur_sig->expires)
339 : dkim_exim_expand_defaults(what);
341 case DKIM_HEADERNAMES:
342 return dkim_cur_sig->headernames
343 ? US dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
346 return dkim_cur_sig->identity
347 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
349 case DKIM_KEY_GRANULARITY:
350 return dkim_cur_sig->pubkey
351 ? dkim_cur_sig->pubkey->granularity
352 ? US dkim_cur_sig->pubkey->granularity
353 : dkim_exim_expand_defaults(what)
354 : dkim_exim_expand_defaults(what);
356 case DKIM_KEY_SRVTYPE:
357 return dkim_cur_sig->pubkey
358 ? dkim_cur_sig->pubkey->srvtype
359 ? US dkim_cur_sig->pubkey->srvtype
360 : dkim_exim_expand_defaults(what)
361 : dkim_exim_expand_defaults(what);
364 return dkim_cur_sig->pubkey
365 ? dkim_cur_sig->pubkey->notes
366 ? US dkim_cur_sig->pubkey->notes
367 : dkim_exim_expand_defaults(what)
368 : dkim_exim_expand_defaults(what);
370 case DKIM_KEY_TESTING:
371 return dkim_cur_sig->pubkey
372 ? dkim_cur_sig->pubkey->testing
374 : dkim_exim_expand_defaults(what)
375 : dkim_exim_expand_defaults(what);
377 case DKIM_NOSUBDOMAINS:
378 return dkim_cur_sig->pubkey
379 ? dkim_cur_sig->pubkey->no_subdomaining
381 : dkim_exim_expand_defaults(what)
382 : dkim_exim_expand_defaults(what);
384 case DKIM_VERIFY_STATUS:
385 switch (dkim_cur_sig->verify_status)
387 case PDKIM_VERIFY_INVALID: return US"invalid";
388 case PDKIM_VERIFY_FAIL: return US"fail";
389 case PDKIM_VERIFY_PASS: return US"pass";
390 case PDKIM_VERIFY_NONE:
391 default: return US"none";
394 case DKIM_VERIFY_REASON:
395 switch (dkim_cur_sig->verify_ext_status)
397 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
398 return US"pubkey_unavailable";
399 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
400 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
401 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
402 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
412 dkim_exim_sign(int dkim_fd, uschar * dkim_private_key,
413 const uschar * dkim_domain, uschar * dkim_selector,
414 uschar * dkim_canon, uschar * dkim_sign_headers)
417 uschar *seen_items = NULL;
418 int seen_items_size = 0;
419 int seen_items_offset = 0;
421 uschar *dkim_canon_expanded;
422 uschar *dkim_sign_headers_expanded;
423 uschar *dkim_private_key_expanded;
424 pdkim_ctx *ctx = NULL;
426 uschar *sigbuf = NULL;
429 pdkim_signature *signature;
435 int old_pool = store_pool;
437 store_pool = POOL_MAIN;
439 if (!(dkim_domain = expand_cstring(dkim_domain)))
441 /* expansion error, do not send message. */
442 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
443 "dkim_domain: %s", expand_string_message);
448 /* Set $dkim_domain expansion variable to each unique domain in list. */
450 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
451 itembuf, sizeof(itembuf))))
453 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
456 /* Only sign once for each domain, no matter how often it
457 appears in the expanded list. */
461 const uschar *seen_items_list = seen_items;
462 if (match_isinlist(dkim_signing_domain,
463 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
468 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
472 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
473 dkim_signing_domain);
474 seen_items[seen_items_offset] = '\0';
476 /* Set up $dkim_selector expansion variable. */
478 if (!(dkim_signing_selector = expand_string(dkim_selector)))
480 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
481 "dkim_selector: %s", expand_string_message);
486 /* Get canonicalization to use */
488 dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
489 if (!dkim_canon_expanded)
491 /* expansion error, do not send message. */
492 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
493 "dkim_canon: %s", expand_string_message);
498 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
499 pdkim_canon = PDKIM_CANON_RELAXED;
500 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
501 pdkim_canon = PDKIM_CANON_SIMPLE;
504 log_write(0, LOG_MAIN,
505 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
506 dkim_canon_expanded);
507 pdkim_canon = PDKIM_CANON_RELAXED;
510 dkim_sign_headers_expanded = NULL;
511 if (dkim_sign_headers)
512 if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
514 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
515 "dkim_sign_headers: %s", expand_string_message);
519 /* else pass NULL, which means default header list */
521 /* Get private key to use. */
523 if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
525 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
526 "dkim_private_key: %s", expand_string_message);
531 if ( Ustrlen(dkim_private_key_expanded) == 0
532 || Ustrcmp(dkim_private_key_expanded, "0") == 0
533 || Ustrcmp(dkim_private_key_expanded, "false") == 0
535 continue; /* don't sign, but no error */
537 if (dkim_private_key_expanded[0] == '/')
541 /* Looks like a filename, load the private key. */
543 memset(big_buffer, 0, big_buffer_size);
544 privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
547 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
548 "private key file for reading: %s",
549 dkim_private_key_expanded);
554 if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
556 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
557 dkim_private_key_expanded);
562 (void) close(privkey_fd);
563 dkim_private_key_expanded = big_buffer;
566 ctx = pdkim_init_sign( (char *) dkim_signing_domain,
567 (char *) dkim_signing_selector,
568 (char *) dkim_private_key_expanded,
569 PDKIM_ALGO_RSA_SHA256);
570 pdkim_set_optional(ctx,
571 (char *) dkim_sign_headers_expanded,
574 pdkim_canon, -1, 0, 0);
576 lseek(dkim_fd, 0, SEEK_SET);
578 while ((sread = read(dkim_fd, &buf, 4096)) > 0)
579 if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
585 /* Handle failed read above. */
588 debug_printf("DKIM: Error reading -K file.\n");
594 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
596 log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
601 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
602 US signature->signature_header, US"\r\n");
610 sigbuf[sigptr] = '\0';
619 store_pool = old_pool;