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(PDKIM_INPUT_SMTP, &dkim_exim_query_dns_txt);
73 dkim_collect_input = !!dkim_verify_ctx;
75 if (dkim_collect_input)
76 pdkim_set_debug_stream(dkim_verify_ctx, debug_file);
82 dkim_exim_verify_feed(uschar * data, int len)
84 if ( dkim_collect_input
85 && pdkim_feed(dkim_verify_ctx, (char *)data, len) != PDKIM_OK)
86 dkim_collect_input = FALSE;
91 dkim_exim_verify_finish(void)
93 pdkim_signature *sig = NULL;
94 int dkim_signers_size = 0;
95 int dkim_signers_ptr = 0;
98 /* Delete eventual previous signature chain */
100 dkim_signatures = NULL;
102 /* If we have arrived here with dkim_collect_input == FALSE, it
103 means there was a processing error somewhere along the way.
104 Log the incident and disable futher verification. */
106 if (!dkim_collect_input)
108 log_write(0, LOG_MAIN,
109 "DKIM: Error while running this message through validation,"
110 " disabling signature verification.");
111 dkim_disable_verify = TRUE;
115 dkim_collect_input = FALSE;
117 /* Finish DKIM operation and fetch link to signatures chain */
119 if (pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures) != PDKIM_OK)
122 for (sig = dkim_signatures; sig; sig = sig->next)
127 /* Log a line for each signature */
129 uschar *logmsg = string_append(NULL, &size, &ptr, 5,
130 string_sprintf("d=%s s=%s c=%s/%s a=%s b=%d ",
133 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
134 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
135 sig->algo == PDKIM_ALGO_RSA_SHA256 ? "rsa-sha256" : "rsa-sha1",
139 sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
140 sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
141 sig->expires > 0 ? string_sprintf("x=%lu ", sig->expires) : US"",
142 sig->bodylength > -1 ? string_sprintf("l=%lu ", sig->bodylength) : US""
145 switch (sig->verify_status)
147 case PDKIM_VERIFY_NONE:
148 logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
151 case PDKIM_VERIFY_INVALID:
152 logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
153 switch (sig->verify_ext_status)
155 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
156 logmsg = string_append(logmsg, &size, &ptr, 1,
157 "public key record (currently?) unavailable]");
160 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
161 logmsg = string_append(logmsg, &size, &ptr, 1,
162 "overlong public key record]");
165 case PDKIM_VERIFY_INVALID_PUBKEY_PARSING:
166 logmsg = string_append(logmsg, &size, &ptr, 1,
167 "syntax error in public key record]");
171 logmsg = string_append(logmsg, &size, &ptr, 1,
172 "unspecified problem]");
176 case PDKIM_VERIFY_FAIL:
178 string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
179 switch (sig->verify_ext_status)
181 case PDKIM_VERIFY_FAIL_BODY:
182 logmsg = string_append(logmsg, &size, &ptr, 1,
183 "body hash mismatch (body probably modified in transit)]");
186 case PDKIM_VERIFY_FAIL_MESSAGE:
187 logmsg = string_append(logmsg, &size, &ptr, 1,
188 "signature did not verify (headers probably modified in transit)]");
192 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
196 case PDKIM_VERIFY_PASS:
198 string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
203 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
205 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
207 dkim_signers = string_append(dkim_signers,
209 &dkim_signers_ptr, 2, sig->domain, ":");
212 dkim_signers = string_append(dkim_signers,
214 &dkim_signers_ptr, 2, sig->identity, ":");
216 /* Process next signature */
219 /* NULL-terminate and chop the last colon from the domain list */
223 dkim_signers[dkim_signers_ptr] = '\0';
224 if (Ustrlen(dkim_signers) > 0)
225 dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
231 dkim_exim_acl_setup(uschar * id)
233 pdkim_signature * sig;
237 dkim_cur_signer = id;
239 if (dkim_disable_verify || !id || !dkim_verify_ctx)
242 /* Find signature to run ACL on */
244 for (sig = dkim_signatures; sig; sig = sig->next)
245 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
246 && strcmpic(cmp_val, id) == 0
251 /* The "dkim_domain" and "dkim_selector" expansion variables have
252 related globals, since they are used in the signing code too.
253 Instead of inventing separate names for verification, we set
254 them here. This is easy since a domain and selector is guaranteed
255 to be in a signature. The other dkim_* expansion items are
256 dynamically fetched from dkim_cur_sig at expansion time (see
259 dkim_signing_domain = US sig->domain;
260 dkim_signing_selector = US sig->selector;
261 dkim_key_length = sig->sigdata_len * 8;
268 dkim_exim_expand_defaults(int what)
272 case DKIM_ALGO: return US"";
273 case DKIM_BODYLENGTH: return US"9999999999999";
274 case DKIM_CANON_BODY: return US"";
275 case DKIM_CANON_HEADERS: return US"";
276 case DKIM_COPIEDHEADERS: return US"";
277 case DKIM_CREATED: return US"0";
278 case DKIM_EXPIRES: return US"9999999999999";
279 case DKIM_HEADERNAMES: return US"";
280 case DKIM_IDENTITY: return US"";
281 case DKIM_KEY_GRANULARITY: return US"*";
282 case DKIM_KEY_SRVTYPE: return US"*";
283 case DKIM_KEY_NOTES: return US"";
284 case DKIM_KEY_TESTING: return US"0";
285 case DKIM_NOSUBDOMAINS: return US"0";
286 case DKIM_VERIFY_STATUS: return US"none";
287 case DKIM_VERIFY_REASON: return US"";
288 default: return US"";
294 dkim_exim_expand_query(int what)
296 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
297 return dkim_exim_expand_defaults(what);
302 switch (dkim_cur_sig->algo)
304 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
305 case PDKIM_ALGO_RSA_SHA256:
306 default: return US"rsa-sha256";
309 case DKIM_BODYLENGTH:
310 return dkim_cur_sig->bodylength >= 0
311 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
312 : dkim_exim_expand_defaults(what);
314 case DKIM_CANON_BODY:
315 switch (dkim_cur_sig->canon_body)
317 case PDKIM_CANON_RELAXED: return US"relaxed";
318 case PDKIM_CANON_SIMPLE:
319 default: return US"simple";
322 case DKIM_CANON_HEADERS:
323 switch (dkim_cur_sig->canon_headers)
325 case PDKIM_CANON_RELAXED: return US"relaxed";
326 case PDKIM_CANON_SIMPLE:
327 default: return US"simple";
330 case DKIM_COPIEDHEADERS:
331 return dkim_cur_sig->copiedheaders
332 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
335 return dkim_cur_sig->created > 0
336 ? string_sprintf("%llu", dkim_cur_sig->created)
337 : dkim_exim_expand_defaults(what);
340 return dkim_cur_sig->expires > 0
341 ? string_sprintf("%llu", dkim_cur_sig->expires)
342 : dkim_exim_expand_defaults(what);
344 case DKIM_HEADERNAMES:
345 return dkim_cur_sig->headernames
346 ? US dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
349 return dkim_cur_sig->identity
350 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
352 case DKIM_KEY_GRANULARITY:
353 return dkim_cur_sig->pubkey
354 ? dkim_cur_sig->pubkey->granularity
355 ? US dkim_cur_sig->pubkey->granularity
356 : dkim_exim_expand_defaults(what)
357 : dkim_exim_expand_defaults(what);
359 case DKIM_KEY_SRVTYPE:
360 return dkim_cur_sig->pubkey
361 ? dkim_cur_sig->pubkey->srvtype
362 ? US dkim_cur_sig->pubkey->srvtype
363 : dkim_exim_expand_defaults(what)
364 : dkim_exim_expand_defaults(what);
367 return dkim_cur_sig->pubkey
368 ? dkim_cur_sig->pubkey->notes
369 ? US dkim_cur_sig->pubkey->notes
370 : dkim_exim_expand_defaults(what)
371 : dkim_exim_expand_defaults(what);
373 case DKIM_KEY_TESTING:
374 return dkim_cur_sig->pubkey
375 ? dkim_cur_sig->pubkey->testing
377 : dkim_exim_expand_defaults(what)
378 : dkim_exim_expand_defaults(what);
380 case DKIM_NOSUBDOMAINS:
381 return dkim_cur_sig->pubkey
382 ? dkim_cur_sig->pubkey->no_subdomaining
384 : dkim_exim_expand_defaults(what)
385 : dkim_exim_expand_defaults(what);
387 case DKIM_VERIFY_STATUS:
388 switch (dkim_cur_sig->verify_status)
390 case PDKIM_VERIFY_INVALID: return US"invalid";
391 case PDKIM_VERIFY_FAIL: return US"fail";
392 case PDKIM_VERIFY_PASS: return US"pass";
393 case PDKIM_VERIFY_NONE:
394 default: return US"none";
397 case DKIM_VERIFY_REASON:
398 switch (dkim_cur_sig->verify_ext_status)
400 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
401 return US"pubkey_unavailable";
402 case PDKIM_VERIFY_INVALID_PUBKEY_PARSING: return US"pubkey_syntax";
403 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
404 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
414 dkim_exim_sign(int dkim_fd, uschar * dkim_private_key,
415 const uschar * dkim_domain, uschar * dkim_selector,
416 uschar * dkim_canon, uschar * dkim_sign_headers)
419 uschar *seen_items = NULL;
420 int seen_items_size = 0;
421 int seen_items_offset = 0;
423 uschar *dkim_canon_expanded;
424 uschar *dkim_sign_headers_expanded;
425 uschar *dkim_private_key_expanded;
426 pdkim_ctx *ctx = NULL;
428 uschar *sigbuf = NULL;
431 pdkim_signature *signature;
437 int old_pool = store_pool;
439 store_pool = POOL_MAIN;
441 if (!(dkim_domain = expand_cstring(dkim_domain)))
443 /* expansion error, do not send message. */
444 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
445 "dkim_domain: %s", expand_string_message);
450 /* Set $dkim_domain expansion variable to each unique domain in list. */
452 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
453 itembuf, sizeof(itembuf))))
455 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
458 /* Only sign once for each domain, no matter how often it
459 appears in the expanded list. */
463 const uschar *seen_items_list = seen_items;
464 if (match_isinlist(dkim_signing_domain,
465 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
470 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
474 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
475 dkim_signing_domain);
476 seen_items[seen_items_offset] = '\0';
478 /* Set up $dkim_selector expansion variable. */
480 if (!(dkim_signing_selector = expand_string(dkim_selector)))
482 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
483 "dkim_selector: %s", expand_string_message);
488 /* Get canonicalization to use */
490 dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
491 if (!dkim_canon_expanded)
493 /* expansion error, do not send message. */
494 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
495 "dkim_canon: %s", expand_string_message);
500 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
501 pdkim_canon = PDKIM_CANON_RELAXED;
502 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
503 pdkim_canon = PDKIM_CANON_SIMPLE;
506 log_write(0, LOG_MAIN,
507 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
508 dkim_canon_expanded);
509 pdkim_canon = PDKIM_CANON_RELAXED;
512 dkim_sign_headers_expanded = NULL;
513 if (dkim_sign_headers)
514 if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
516 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
517 "dkim_sign_headers: %s", expand_string_message);
521 /* else pass NULL, which means default header list */
523 /* Get private key to use. */
525 if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
527 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
528 "dkim_private_key: %s", expand_string_message);
533 if ( Ustrlen(dkim_private_key_expanded) == 0
534 || Ustrcmp(dkim_private_key_expanded, "0") == 0
535 || Ustrcmp(dkim_private_key_expanded, "false") == 0
537 continue; /* don't sign, but no error */
539 if (dkim_private_key_expanded[0] == '/')
543 /* Looks like a filename, load the private key. */
545 memset(big_buffer, 0, big_buffer_size);
546 privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
549 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
550 "private key file for reading: %s",
551 dkim_private_key_expanded);
556 if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
558 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
559 dkim_private_key_expanded);
564 (void) close(privkey_fd);
565 dkim_private_key_expanded = big_buffer;
568 ctx = pdkim_init_sign(PDKIM_INPUT_SMTP,
569 (char *) dkim_signing_domain,
570 (char *) dkim_signing_selector,
571 (char *) dkim_private_key_expanded);
573 pdkim_set_debug_stream(ctx, debug_file);
575 pdkim_set_optional(ctx,
576 (char *) dkim_sign_headers_expanded,
579 pdkim_canon, -1, PDKIM_ALGO_RSA_SHA256, 0, 0);
581 lseek(dkim_fd, 0, SEEK_SET);
583 while ((sread = read(dkim_fd, &buf, 4096)) > 0)
584 if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
590 /* Handle failed read above. */
593 debug_printf("DKIM: Error reading -K file.\n");
599 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
601 log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
606 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
607 US signature->signature_header, US"\r\n");
615 sigbuf[sigptr] = '\0';
624 store_pool = old_pool;