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_PARSING:
162 logmsg = string_append(logmsg, &size, &ptr, 1,
163 "syntax error in public key record]");
167 logmsg = string_append(logmsg, &size, &ptr, 1,
168 "unspecified problem]");
172 case PDKIM_VERIFY_FAIL:
174 string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
175 switch (sig->verify_ext_status)
177 case PDKIM_VERIFY_FAIL_BODY:
178 logmsg = string_append(logmsg, &size, &ptr, 1,
179 "body hash mismatch (body probably modified in transit)]");
182 case PDKIM_VERIFY_FAIL_MESSAGE:
183 logmsg = string_append(logmsg, &size, &ptr, 1,
184 "signature did not verify (headers probably modified in transit)]");
188 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
192 case PDKIM_VERIFY_PASS:
194 string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
199 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
201 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
203 dkim_signers = string_append(dkim_signers,
205 &dkim_signers_ptr, 2, sig->domain, ":");
208 dkim_signers = string_append(dkim_signers,
210 &dkim_signers_ptr, 2, sig->identity, ":");
212 /* Process next signature */
215 /* NULL-terminate and chop the last colon from the domain list */
219 dkim_signers[dkim_signers_ptr] = '\0';
220 if (Ustrlen(dkim_signers) > 0)
221 dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
227 dkim_exim_acl_setup(uschar * id)
229 pdkim_signature * sig;
233 dkim_cur_signer = id;
235 if (dkim_disable_verify || !id || !dkim_verify_ctx)
238 /* Find signature to run ACL on */
240 for (sig = dkim_signatures; sig; sig = sig->next)
241 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
242 && strcmpic(cmp_val, id) == 0
247 /* The "dkim_domain" and "dkim_selector" expansion variables have
248 related globals, since they are used in the signing code too.
249 Instead of inventing separate names for verification, we set
250 them here. This is easy since a domain and selector is guaranteed
251 to be in a signature. The other dkim_* expansion items are
252 dynamically fetched from dkim_cur_sig at expansion time (see
255 dkim_signing_domain = US sig->domain;
256 dkim_signing_selector = US sig->selector;
257 dkim_key_length = sig->sigdata_len * 8;
264 dkim_exim_expand_defaults(int what)
268 case DKIM_ALGO: return US"";
269 case DKIM_BODYLENGTH: return US"9999999999999";
270 case DKIM_CANON_BODY: return US"";
271 case DKIM_CANON_HEADERS: return US"";
272 case DKIM_COPIEDHEADERS: return US"";
273 case DKIM_CREATED: return US"0";
274 case DKIM_EXPIRES: return US"9999999999999";
275 case DKIM_HEADERNAMES: return US"";
276 case DKIM_IDENTITY: return US"";
277 case DKIM_KEY_GRANULARITY: return US"*";
278 case DKIM_KEY_SRVTYPE: return US"*";
279 case DKIM_KEY_NOTES: return US"";
280 case DKIM_KEY_TESTING: return US"0";
281 case DKIM_NOSUBDOMAINS: return US"0";
282 case DKIM_VERIFY_STATUS: return US"none";
283 case DKIM_VERIFY_REASON: return US"";
284 default: return US"";
290 dkim_exim_expand_query(int what)
292 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
293 return dkim_exim_expand_defaults(what);
298 switch (dkim_cur_sig->algo)
300 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
301 case PDKIM_ALGO_RSA_SHA256:
302 default: return US"rsa-sha256";
305 case DKIM_BODYLENGTH:
306 return dkim_cur_sig->bodylength >= 0
307 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
308 : dkim_exim_expand_defaults(what);
310 case DKIM_CANON_BODY:
311 switch (dkim_cur_sig->canon_body)
313 case PDKIM_CANON_RELAXED: return US"relaxed";
314 case PDKIM_CANON_SIMPLE:
315 default: return US"simple";
318 case DKIM_CANON_HEADERS:
319 switch (dkim_cur_sig->canon_headers)
321 case PDKIM_CANON_RELAXED: return US"relaxed";
322 case PDKIM_CANON_SIMPLE:
323 default: return US"simple";
326 case DKIM_COPIEDHEADERS:
327 return dkim_cur_sig->copiedheaders
328 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
331 return dkim_cur_sig->created > 0
332 ? string_sprintf("%llu", dkim_cur_sig->created)
333 : dkim_exim_expand_defaults(what);
336 return dkim_cur_sig->expires > 0
337 ? string_sprintf("%llu", dkim_cur_sig->expires)
338 : dkim_exim_expand_defaults(what);
340 case DKIM_HEADERNAMES:
341 return dkim_cur_sig->headernames
342 ? US dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
345 return dkim_cur_sig->identity
346 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
348 case DKIM_KEY_GRANULARITY:
349 return dkim_cur_sig->pubkey
350 ? dkim_cur_sig->pubkey->granularity
351 ? US dkim_cur_sig->pubkey->granularity
352 : dkim_exim_expand_defaults(what)
353 : dkim_exim_expand_defaults(what);
355 case DKIM_KEY_SRVTYPE:
356 return dkim_cur_sig->pubkey
357 ? dkim_cur_sig->pubkey->srvtype
358 ? US dkim_cur_sig->pubkey->srvtype
359 : dkim_exim_expand_defaults(what)
360 : dkim_exim_expand_defaults(what);
363 return dkim_cur_sig->pubkey
364 ? dkim_cur_sig->pubkey->notes
365 ? US dkim_cur_sig->pubkey->notes
366 : dkim_exim_expand_defaults(what)
367 : dkim_exim_expand_defaults(what);
369 case DKIM_KEY_TESTING:
370 return dkim_cur_sig->pubkey
371 ? dkim_cur_sig->pubkey->testing
373 : dkim_exim_expand_defaults(what)
374 : dkim_exim_expand_defaults(what);
376 case DKIM_NOSUBDOMAINS:
377 return dkim_cur_sig->pubkey
378 ? dkim_cur_sig->pubkey->no_subdomaining
380 : dkim_exim_expand_defaults(what)
381 : dkim_exim_expand_defaults(what);
383 case DKIM_VERIFY_STATUS:
384 switch (dkim_cur_sig->verify_status)
386 case PDKIM_VERIFY_INVALID: return US"invalid";
387 case PDKIM_VERIFY_FAIL: return US"fail";
388 case PDKIM_VERIFY_PASS: return US"pass";
389 case PDKIM_VERIFY_NONE:
390 default: return US"none";
393 case DKIM_VERIFY_REASON:
394 switch (dkim_cur_sig->verify_ext_status)
396 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
397 return US"pubkey_unavailable";
398 case PDKIM_VERIFY_INVALID_PUBKEY_PARSING: return US"pubkey_syntax";
399 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
400 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
410 dkim_exim_sign(int dkim_fd, uschar * dkim_private_key,
411 const uschar * dkim_domain, uschar * dkim_selector,
412 uschar * dkim_canon, uschar * dkim_sign_headers)
415 uschar *seen_items = NULL;
416 int seen_items_size = 0;
417 int seen_items_offset = 0;
419 uschar *dkim_canon_expanded;
420 uschar *dkim_sign_headers_expanded;
421 uschar *dkim_private_key_expanded;
422 pdkim_ctx *ctx = NULL;
424 uschar *sigbuf = NULL;
427 pdkim_signature *signature;
433 int old_pool = store_pool;
435 store_pool = POOL_MAIN;
437 if (!(dkim_domain = expand_cstring(dkim_domain)))
439 /* expansion error, do not send message. */
440 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
441 "dkim_domain: %s", expand_string_message);
446 /* Set $dkim_domain expansion variable to each unique domain in list. */
448 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
449 itembuf, sizeof(itembuf))))
451 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
454 /* Only sign once for each domain, no matter how often it
455 appears in the expanded list. */
459 const uschar *seen_items_list = seen_items;
460 if (match_isinlist(dkim_signing_domain,
461 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
466 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
470 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
471 dkim_signing_domain);
472 seen_items[seen_items_offset] = '\0';
474 /* Set up $dkim_selector expansion variable. */
476 if (!(dkim_signing_selector = expand_string(dkim_selector)))
478 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
479 "dkim_selector: %s", expand_string_message);
484 /* Get canonicalization to use */
486 dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
487 if (!dkim_canon_expanded)
489 /* expansion error, do not send message. */
490 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
491 "dkim_canon: %s", expand_string_message);
496 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
497 pdkim_canon = PDKIM_CANON_RELAXED;
498 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
499 pdkim_canon = PDKIM_CANON_SIMPLE;
502 log_write(0, LOG_MAIN,
503 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
504 dkim_canon_expanded);
505 pdkim_canon = PDKIM_CANON_RELAXED;
508 dkim_sign_headers_expanded = NULL;
509 if (dkim_sign_headers)
510 if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
512 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
513 "dkim_sign_headers: %s", expand_string_message);
517 /* else pass NULL, which means default header list */
519 /* Get private key to use. */
521 if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
523 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
524 "dkim_private_key: %s", expand_string_message);
529 if ( Ustrlen(dkim_private_key_expanded) == 0
530 || Ustrcmp(dkim_private_key_expanded, "0") == 0
531 || Ustrcmp(dkim_private_key_expanded, "false") == 0
533 continue; /* don't sign, but no error */
535 if (dkim_private_key_expanded[0] == '/')
539 /* Looks like a filename, load the private key. */
541 memset(big_buffer, 0, big_buffer_size);
542 privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
545 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
546 "private key file for reading: %s",
547 dkim_private_key_expanded);
552 if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
554 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
555 dkim_private_key_expanded);
560 (void) close(privkey_fd);
561 dkim_private_key_expanded = big_buffer;
564 ctx = pdkim_init_sign( (char *) dkim_signing_domain,
565 (char *) dkim_signing_selector,
566 (char *) dkim_private_key_expanded,
567 PDKIM_ALGO_RSA_SHA256);
568 pdkim_set_optional(ctx,
569 (char *) dkim_sign_headers_expanded,
572 pdkim_canon, -1, 0, 0);
574 lseek(dkim_fd, 0, SEEK_SET);
576 while ((sread = read(dkim_fd, &buf, 4096)) > 0)
577 if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
583 /* Handle failed read above. */
586 debug_printf("DKIM: Error reading -K file.\n");
592 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
594 log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
599 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
600 US signature->signature_header, US"\r\n");
608 sigbuf[sigptr] = '\0';
617 store_pool = old_pool;