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
)
31 return PDKIM_FAIL
; /*XXX better error detail? logging? */
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
)
54 return PDKIM_FAIL
; /*XXX better error detail? logging? */
59 return PDKIM_FAIL
; /*XXX better error detail? logging? */
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 store_pool
= dkim_verify_oldpool
;
96 dkim_exim_verify_feed(uschar
* data
, int len
)
100 store_pool
= POOL_PERM
;
101 if ( dkim_collect_input
102 && (rc
= pdkim_feed(dkim_verify_ctx
, (char *)data
, len
)) != PDKIM_OK
)
104 log_write(0, LOG_MAIN
,
105 "DKIM: validation error: %.100s", pdkim_errstr(rc
));
106 dkim_collect_input
= FALSE
;
108 store_pool
= dkim_verify_oldpool
;
113 dkim_exim_verify_finish(void)
115 pdkim_signature
*sig
= NULL
;
116 int dkim_signers_size
= 0;
117 int dkim_signers_ptr
= 0;
121 store_pool
= POOL_PERM
;
123 /* Delete eventual previous signature chain */
125 dkim_signatures
= NULL
;
127 /* If we have arrived here with dkim_collect_input == FALSE, it
128 means there was a processing error somewhere along the way.
129 Log the incident and disable futher verification. */
131 if (!dkim_collect_input
)
133 log_write(0, LOG_MAIN
,
134 "DKIM: Error while running this message through validation,"
135 " disabling signature verification.");
136 dkim_disable_verify
= TRUE
;
140 dkim_collect_input
= FALSE
;
142 /* Finish DKIM operation and fetch link to signatures chain */
144 if ((rc
= pdkim_feed_finish(dkim_verify_ctx
, &dkim_signatures
)) != PDKIM_OK
)
146 log_write(0, LOG_MAIN
,
147 "DKIM: validation error: %.100s", pdkim_errstr(rc
));
151 for (sig
= dkim_signatures
; sig
; sig
= sig
->next
)
156 /* Log a line for each signature */
158 uschar
*logmsg
= string_append(NULL
, &size
, &ptr
, 5,
159 string_sprintf("d=%s s=%s c=%s/%s a=%s b=%d ",
162 sig
->canon_headers
== PDKIM_CANON_SIMPLE
? "simple" : "relaxed",
163 sig
->canon_body
== PDKIM_CANON_SIMPLE
? "simple" : "relaxed",
164 sig
->algo
== PDKIM_ALGO_RSA_SHA256
166 : sig
->algo
== PDKIM_ALGO_RSA_SHA1
? "rsa-sha1" : "err",
167 (int)sig
->sigdata
.len
> -1 ? sig
->sigdata
.len
* 8 : 0
170 sig
->identity
? string_sprintf("i=%s ", sig
->identity
) : US
"",
171 sig
->created
> 0 ? string_sprintf("t=%lu ", sig
->created
) : US
"",
172 sig
->expires
> 0 ? string_sprintf("x=%lu ", sig
->expires
) : US
"",
173 sig
->bodylength
> -1 ? string_sprintf("l=%lu ", sig
->bodylength
) : US
""
176 switch (sig
->verify_status
)
178 case PDKIM_VERIFY_NONE
:
179 logmsg
= string_append(logmsg
, &size
, &ptr
, 1, "[not verified]");
182 case PDKIM_VERIFY_INVALID
:
183 logmsg
= string_append(logmsg
, &size
, &ptr
, 1, "[invalid - ");
184 switch (sig
->verify_ext_status
)
186 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
:
187 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
188 "public key record (currently?) unavailable]");
191 case PDKIM_VERIFY_INVALID_BUFFER_SIZE
:
192 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
193 "overlong public key record]");
196 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD
:
197 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT
:
198 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
199 "syntax error in public key record]");
202 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR
:
203 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
204 "signature tag missing or invalid]");
207 case PDKIM_VERIFY_INVALID_DKIM_VERSION
:
208 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
209 "unsupported DKIM version]");
213 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
214 "unspecified problem]");
218 case PDKIM_VERIFY_FAIL
:
220 string_append(logmsg
, &size
, &ptr
, 1, "[verification failed - ");
221 switch (sig
->verify_ext_status
)
223 case PDKIM_VERIFY_FAIL_BODY
:
224 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
225 "body hash mismatch (body probably modified in transit)]");
228 case PDKIM_VERIFY_FAIL_MESSAGE
:
229 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
230 "signature did not verify (headers probably modified in transit)]");
234 logmsg
= string_append(logmsg
, &size
, &ptr
, 1, "unspecified reason]");
238 case PDKIM_VERIFY_PASS
:
240 string_append(logmsg
, &size
, &ptr
, 1, "[verification succeeded]");
245 log_write(0, LOG_MAIN
, "DKIM: %s", logmsg
);
247 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
249 dkim_signers
= string_append(dkim_signers
,
251 &dkim_signers_ptr
, 2, sig
->domain
, ":");
254 dkim_signers
= string_append(dkim_signers
,
256 &dkim_signers_ptr
, 2, sig
->identity
, ":");
258 /* Process next signature */
261 /* NULL-terminate and chop the last colon from the domain list */
265 dkim_signers
[dkim_signers_ptr
] = '\0';
266 if (Ustrlen(dkim_signers
) > 0)
267 dkim_signers
[Ustrlen(dkim_signers
) - 1] = '\0';
271 store_pool
= dkim_verify_oldpool
;
276 dkim_exim_acl_setup(uschar
* id
)
278 pdkim_signature
* sig
;
282 dkim_cur_signer
= id
;
284 if (dkim_disable_verify
|| !id
|| !dkim_verify_ctx
)
287 /* Find signature to run ACL on */
289 for (sig
= dkim_signatures
; sig
; sig
= sig
->next
)
290 if ( (cmp_val
= Ustrchr(id
, '@') != NULL
? US sig
->identity
: US sig
->domain
)
291 && strcmpic(cmp_val
, id
) == 0
296 /* The "dkim_domain" and "dkim_selector" expansion variables have
297 related globals, since they are used in the signing code too.
298 Instead of inventing separate names for verification, we set
299 them here. This is easy since a domain and selector is guaranteed
300 to be in a signature. The other dkim_* expansion items are
301 dynamically fetched from dkim_cur_sig at expansion time (see
304 dkim_signing_domain
= US sig
->domain
;
305 dkim_signing_selector
= US sig
->selector
;
306 dkim_key_length
= sig
->sigdata
.len
* 8;
313 dkim_exim_expand_defaults(int what
)
317 case DKIM_ALGO
: return US
"";
318 case DKIM_BODYLENGTH
: return US
"9999999999999";
319 case DKIM_CANON_BODY
: return US
"";
320 case DKIM_CANON_HEADERS
: return US
"";
321 case DKIM_COPIEDHEADERS
: return US
"";
322 case DKIM_CREATED
: return US
"0";
323 case DKIM_EXPIRES
: return US
"9999999999999";
324 case DKIM_HEADERNAMES
: return US
"";
325 case DKIM_IDENTITY
: return US
"";
326 case DKIM_KEY_GRANULARITY
: return US
"*";
327 case DKIM_KEY_SRVTYPE
: return US
"*";
328 case DKIM_KEY_NOTES
: return US
"";
329 case DKIM_KEY_TESTING
: return US
"0";
330 case DKIM_NOSUBDOMAINS
: return US
"0";
331 case DKIM_VERIFY_STATUS
: return US
"none";
332 case DKIM_VERIFY_REASON
: return US
"";
333 default: return US
"";
339 dkim_exim_expand_query(int what
)
341 if (!dkim_verify_ctx
|| dkim_disable_verify
|| !dkim_cur_sig
)
342 return dkim_exim_expand_defaults(what
);
347 switch (dkim_cur_sig
->algo
)
349 case PDKIM_ALGO_RSA_SHA1
: return US
"rsa-sha1";
350 case PDKIM_ALGO_RSA_SHA256
:
351 default: return US
"rsa-sha256";
354 case DKIM_BODYLENGTH
:
355 return dkim_cur_sig
->bodylength
>= 0
356 ? string_sprintf(OFF_T_FMT
, (LONGLONG_T
) dkim_cur_sig
->bodylength
)
357 : dkim_exim_expand_defaults(what
);
359 case DKIM_CANON_BODY
:
360 switch (dkim_cur_sig
->canon_body
)
362 case PDKIM_CANON_RELAXED
: return US
"relaxed";
363 case PDKIM_CANON_SIMPLE
:
364 default: return US
"simple";
367 case DKIM_CANON_HEADERS
:
368 switch (dkim_cur_sig
->canon_headers
)
370 case PDKIM_CANON_RELAXED
: return US
"relaxed";
371 case PDKIM_CANON_SIMPLE
:
372 default: return US
"simple";
375 case DKIM_COPIEDHEADERS
:
376 return dkim_cur_sig
->copiedheaders
377 ? US dkim_cur_sig
->copiedheaders
: dkim_exim_expand_defaults(what
);
380 return dkim_cur_sig
->created
> 0
381 ? string_sprintf("%llu", dkim_cur_sig
->created
)
382 : dkim_exim_expand_defaults(what
);
385 return dkim_cur_sig
->expires
> 0
386 ? string_sprintf("%llu", dkim_cur_sig
->expires
)
387 : dkim_exim_expand_defaults(what
);
389 case DKIM_HEADERNAMES
:
390 return dkim_cur_sig
->headernames
391 ? dkim_cur_sig
->headernames
: dkim_exim_expand_defaults(what
);
394 return dkim_cur_sig
->identity
395 ? US dkim_cur_sig
->identity
: dkim_exim_expand_defaults(what
);
397 case DKIM_KEY_GRANULARITY
:
398 return dkim_cur_sig
->pubkey
399 ? dkim_cur_sig
->pubkey
->granularity
400 ? US dkim_cur_sig
->pubkey
->granularity
401 : dkim_exim_expand_defaults(what
)
402 : dkim_exim_expand_defaults(what
);
404 case DKIM_KEY_SRVTYPE
:
405 return dkim_cur_sig
->pubkey
406 ? dkim_cur_sig
->pubkey
->srvtype
407 ? US dkim_cur_sig
->pubkey
->srvtype
408 : dkim_exim_expand_defaults(what
)
409 : dkim_exim_expand_defaults(what
);
412 return dkim_cur_sig
->pubkey
413 ? dkim_cur_sig
->pubkey
->notes
414 ? US dkim_cur_sig
->pubkey
->notes
415 : dkim_exim_expand_defaults(what
)
416 : dkim_exim_expand_defaults(what
);
418 case DKIM_KEY_TESTING
:
419 return dkim_cur_sig
->pubkey
420 ? dkim_cur_sig
->pubkey
->testing
422 : dkim_exim_expand_defaults(what
)
423 : dkim_exim_expand_defaults(what
);
425 case DKIM_NOSUBDOMAINS
:
426 return dkim_cur_sig
->pubkey
427 ? dkim_cur_sig
->pubkey
->no_subdomaining
429 : dkim_exim_expand_defaults(what
)
430 : dkim_exim_expand_defaults(what
);
432 case DKIM_VERIFY_STATUS
:
433 switch (dkim_cur_sig
->verify_status
)
435 case PDKIM_VERIFY_INVALID
: return US
"invalid";
436 case PDKIM_VERIFY_FAIL
: return US
"fail";
437 case PDKIM_VERIFY_PASS
: return US
"pass";
438 case PDKIM_VERIFY_NONE
:
439 default: return US
"none";
442 case DKIM_VERIFY_REASON
:
443 switch (dkim_cur_sig
->verify_ext_status
)
445 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
:
446 return US
"pubkey_unavailable";
447 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD
:return US
"pubkey_dns_syntax";
448 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT
: return US
"pubkey_der_syntax";
449 case PDKIM_VERIFY_FAIL_BODY
: return US
"bodyhash_mismatch";
450 case PDKIM_VERIFY_FAIL_MESSAGE
: return US
"signature_incorrect";
460 dkim_exim_sign(int dkim_fd
, uschar
* dkim_private_key
,
461 const uschar
* dkim_domain
, uschar
* dkim_selector
,
462 uschar
* dkim_canon
, uschar
* dkim_sign_headers
)
465 uschar
*seen_items
= NULL
;
466 int seen_items_size
= 0;
467 int seen_items_offset
= 0;
469 uschar
*dkim_canon_expanded
;
470 uschar
*dkim_sign_headers_expanded
;
471 uschar
*dkim_private_key_expanded
;
472 pdkim_ctx
*ctx
= NULL
;
474 uschar
*sigbuf
= NULL
;
477 pdkim_signature
*signature
;
483 int old_pool
= store_pool
;
485 store_pool
= POOL_MAIN
;
487 if (!(dkim_domain
= expand_cstring(dkim_domain
)))
489 /* expansion error, do not send message. */
490 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
491 "dkim_domain: %s", expand_string_message
);
495 /* Set $dkim_domain expansion variable to each unique domain in list. */
497 while ((dkim_signing_domain
= string_nextinlist(&dkim_domain
, &sep
,
498 itembuf
, sizeof(itembuf
))))
500 if (!dkim_signing_domain
|| dkim_signing_domain
[0] == '\0')
503 /* Only sign once for each domain, no matter how often it
504 appears in the expanded list. */
508 const uschar
*seen_items_list
= seen_items
;
509 if (match_isinlist(dkim_signing_domain
,
510 &seen_items_list
, 0, NULL
, NULL
, MCL_STRING
, TRUE
,
515 string_append(seen_items
, &seen_items_size
, &seen_items_offset
, 1, ":");
519 string_append(seen_items
, &seen_items_size
, &seen_items_offset
, 1,
520 dkim_signing_domain
);
521 seen_items
[seen_items_offset
] = '\0';
523 /* Set up $dkim_selector expansion variable. */
525 if (!(dkim_signing_selector
= expand_string(dkim_selector
)))
527 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
528 "dkim_selector: %s", expand_string_message
);
532 /* Get canonicalization to use */
534 dkim_canon_expanded
= dkim_canon
? expand_string(dkim_canon
) : US
"relaxed";
535 if (!dkim_canon_expanded
)
537 /* expansion error, do not send message. */
538 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
539 "dkim_canon: %s", expand_string_message
);
543 if (Ustrcmp(dkim_canon_expanded
, "relaxed") == 0)
544 pdkim_canon
= PDKIM_CANON_RELAXED
;
545 else if (Ustrcmp(dkim_canon_expanded
, "simple") == 0)
546 pdkim_canon
= PDKIM_CANON_SIMPLE
;
549 log_write(0, LOG_MAIN
,
550 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
551 dkim_canon_expanded
);
552 pdkim_canon
= PDKIM_CANON_RELAXED
;
555 dkim_sign_headers_expanded
= NULL
;
556 if (dkim_sign_headers
)
557 if (!(dkim_sign_headers_expanded
= expand_string(dkim_sign_headers
)))
559 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
560 "dkim_sign_headers: %s", expand_string_message
);
563 /* else pass NULL, which means default header list */
565 /* Get private key to use. */
567 if (!(dkim_private_key_expanded
= expand_string(dkim_private_key
)))
569 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
570 "dkim_private_key: %s", expand_string_message
);
574 if ( Ustrlen(dkim_private_key_expanded
) == 0
575 || Ustrcmp(dkim_private_key_expanded
, "0") == 0
576 || Ustrcmp(dkim_private_key_expanded
, "false") == 0
578 continue; /* don't sign, but no error */
580 if (dkim_private_key_expanded
[0] == '/')
584 /* Looks like a filename, load the private key. */
586 memset(big_buffer
, 0, big_buffer_size
);
587 privkey_fd
= open(CS dkim_private_key_expanded
, O_RDONLY
);
590 log_write(0, LOG_MAIN
| LOG_PANIC
, "unable to open "
591 "private key file for reading: %s",
592 dkim_private_key_expanded
);
596 if (read(privkey_fd
, big_buffer
, big_buffer_size
- 2) < 0)
598 log_write(0, LOG_MAIN
|LOG_PANIC
, "unable to read private key file: %s",
599 dkim_private_key_expanded
);
603 (void) close(privkey_fd
);
604 dkim_private_key_expanded
= big_buffer
;
607 ctx
= pdkim_init_sign( CS dkim_signing_domain
,
608 CS dkim_signing_selector
,
609 CS dkim_private_key_expanded
,
610 PDKIM_ALGO_RSA_SHA256
);
611 pdkim_set_optional(ctx
,
612 (char *) dkim_sign_headers_expanded
,
615 pdkim_canon
, -1, 0, 0);
617 lseek(dkim_fd
, 0, SEEK_SET
);
619 while ((sread
= read(dkim_fd
, &buf
, 4096)) > 0)
620 if ((pdkim_rc
= pdkim_feed(ctx
, buf
, sread
)) != PDKIM_OK
)
623 /* Handle failed read above. */
626 debug_printf("DKIM: Error reading -K file.\n");
631 if ((pdkim_rc
= pdkim_feed_finish(ctx
, &signature
)) != PDKIM_OK
)
634 sigbuf
= string_append(sigbuf
, &sigsize
, &sigptr
, 2,
635 US signature
->signature_header
, US
"\r\n");
643 sigbuf
[sigptr
] = '\0';
652 store_pool
= old_pool
;
657 log_write(0, LOG_MAIN
|LOG_PANIC
,
658 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc
));