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 ",
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"),
137 sig
->identity
? string_sprintf("i=%s ", sig
->identity
) : US
"",
138 sig
->created
> 0 ? string_sprintf("t=%lu ", sig
->created
) : US
"",
139 sig
->expires
> 0 ? string_sprintf("x=%lu ", sig
->expires
) : US
"",
140 sig
->bodylength
> -1 ? string_sprintf("l=%lu ", sig
->bodylength
) : US
""
143 switch (sig
->verify_status
)
145 case PDKIM_VERIFY_NONE
:
146 logmsg
= string_append(logmsg
, &size
, &ptr
, 1, "[not verified]");
149 case PDKIM_VERIFY_INVALID
:
150 logmsg
= string_append(logmsg
, &size
, &ptr
, 1, "[invalid - ");
151 switch (sig
->verify_ext_status
)
153 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
:
154 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
155 "public key record (currently?) unavailable]");
158 case PDKIM_VERIFY_INVALID_BUFFER_SIZE
:
159 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
160 "overlong public key record]");
163 case PDKIM_VERIFY_INVALID_PUBKEY_PARSING
:
164 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
165 "syntax error in public key record]");
169 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
170 "unspecified problem]");
174 case PDKIM_VERIFY_FAIL
:
176 string_append(logmsg
, &size
, &ptr
, 1, "[verification failed - ");
177 switch (sig
->verify_ext_status
)
179 case PDKIM_VERIFY_FAIL_BODY
:
180 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
181 "body hash mismatch (body probably modified in transit)]");
184 case PDKIM_VERIFY_FAIL_MESSAGE
:
185 logmsg
= string_append(logmsg
, &size
, &ptr
, 1,
186 "signature did not verify (headers probably modified in transit)]");
190 logmsg
= string_append(logmsg
, &size
, &ptr
, 1, "unspecified reason]");
194 case PDKIM_VERIFY_PASS
:
196 string_append(logmsg
, &size
, &ptr
, 1, "[verification succeeded]");
201 log_write(0, LOG_MAIN
, "DKIM: %s", logmsg
);
203 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
205 dkim_signers
= string_append(dkim_signers
,
207 &dkim_signers_ptr
, 2, sig
->domain
, ":");
210 dkim_signers
= string_append(dkim_signers
,
212 &dkim_signers_ptr
, 2, sig
->identity
, ":");
214 /* Process next signature */
217 /* NULL-terminate and chop the last colon from the domain list */
221 dkim_signers
[dkim_signers_ptr
] = '\0';
222 if (Ustrlen(dkim_signers
) > 0)
223 dkim_signers
[Ustrlen(dkim_signers
) - 1] = '\0';
229 dkim_exim_acl_setup(uschar
* id
)
231 pdkim_signature
* sig
;
235 dkim_cur_signer
= id
;
237 if (dkim_disable_verify
|| !id
|| !dkim_verify_ctx
)
240 /* Find signature to run ACL on */
242 for (sig
= dkim_signatures
; sig
; sig
= sig
->next
)
243 if ( (cmp_val
= Ustrchr(id
, '@') != NULL
? US sig
->identity
: US sig
->domain
)
244 && strcmpic(cmp_val
, id
) == 0
249 /* The "dkim_domain" and "dkim_selector" expansion variables have
250 related globals, since they are used in the signing code too.
251 Instead of inventing separate names for verification, we set
252 them here. This is easy since a domain and selector is guaranteed
253 to be in a signature. The other dkim_* expansion items are
254 dynamically fetched from dkim_cur_sig at expansion time (see
257 dkim_signing_domain
= US sig
->domain
;
258 dkim_signing_selector
= US sig
->selector
;
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_PARSING
: return US
"pubkey_syntax";
400 case PDKIM_VERIFY_FAIL_BODY
: return US
"bodyhash_mismatch";
401 case PDKIM_VERIFY_FAIL_MESSAGE
: return US
"signature_incorrect";
411 dkim_exim_sign(int dkim_fd
, uschar
* dkim_private_key
,
412 const uschar
* dkim_domain
, uschar
* dkim_selector
,
413 uschar
* dkim_canon
, uschar
* dkim_sign_headers
)
416 uschar
*seen_items
= NULL
;
417 int seen_items_size
= 0;
418 int seen_items_offset
= 0;
420 uschar
*dkim_canon_expanded
;
421 uschar
*dkim_sign_headers_expanded
;
422 uschar
*dkim_private_key_expanded
;
423 pdkim_ctx
*ctx
= NULL
;
425 uschar
*sigbuf
= NULL
;
428 pdkim_signature
*signature
;
434 int old_pool
= store_pool
;
436 store_pool
= POOL_MAIN
;
438 if (!(dkim_domain
= expand_cstring(dkim_domain
)))
440 /* expansion error, do not send message. */
441 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
442 "dkim_domain: %s", expand_string_message
);
447 /* Set $dkim_domain expansion variable to each unique domain in list. */
449 while ((dkim_signing_domain
= string_nextinlist(&dkim_domain
, &sep
,
450 itembuf
, sizeof(itembuf
))))
452 if (!dkim_signing_domain
|| dkim_signing_domain
[0] == '\0')
455 /* Only sign once for each domain, no matter how often it
456 appears in the expanded list. */
460 const uschar
*seen_items_list
= seen_items
;
461 if (match_isinlist(dkim_signing_domain
,
462 &seen_items_list
, 0, NULL
, NULL
, MCL_STRING
, TRUE
,
467 string_append(seen_items
, &seen_items_size
, &seen_items_offset
, 1, ":");
471 string_append(seen_items
, &seen_items_size
, &seen_items_offset
, 1,
472 dkim_signing_domain
);
473 seen_items
[seen_items_offset
] = '\0';
475 /* Set up $dkim_selector expansion variable. */
477 if (!(dkim_signing_selector
= expand_string(dkim_selector
)))
479 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
480 "dkim_selector: %s", expand_string_message
);
485 /* Get canonicalization to use */
487 dkim_canon_expanded
= dkim_canon
? expand_string(dkim_canon
) : US
"relaxed";
488 if (!dkim_canon_expanded
)
490 /* expansion error, do not send message. */
491 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
492 "dkim_canon: %s", expand_string_message
);
497 if (Ustrcmp(dkim_canon_expanded
, "relaxed") == 0)
498 pdkim_canon
= PDKIM_CANON_RELAXED
;
499 else if (Ustrcmp(dkim_canon_expanded
, "simple") == 0)
500 pdkim_canon
= PDKIM_CANON_SIMPLE
;
503 log_write(0, LOG_MAIN
,
504 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
505 dkim_canon_expanded
);
506 pdkim_canon
= PDKIM_CANON_RELAXED
;
509 dkim_sign_headers_expanded
= NULL
;
510 if (dkim_sign_headers
)
511 if (!(dkim_sign_headers_expanded
= expand_string(dkim_sign_headers
)))
513 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
514 "dkim_sign_headers: %s", expand_string_message
);
518 /* else pass NULL, which means default header list */
520 /* Get private key to use. */
522 if (!(dkim_private_key_expanded
= expand_string(dkim_private_key
)))
524 log_write(0, LOG_MAIN
| LOG_PANIC
, "failed to expand "
525 "dkim_private_key: %s", expand_string_message
);
530 if ( Ustrlen(dkim_private_key_expanded
) == 0
531 || Ustrcmp(dkim_private_key_expanded
, "0") == 0
532 || Ustrcmp(dkim_private_key_expanded
, "false") == 0
534 continue; /* don't sign, but no error */
536 if (dkim_private_key_expanded
[0] == '/')
540 /* Looks like a filename, load the private key. */
542 memset(big_buffer
, 0, big_buffer_size
);
543 privkey_fd
= open(CS dkim_private_key_expanded
, O_RDONLY
);
546 log_write(0, LOG_MAIN
| LOG_PANIC
, "unable to open "
547 "private key file for reading: %s",
548 dkim_private_key_expanded
);
553 if (read(privkey_fd
, big_buffer
, big_buffer_size
- 2) < 0)
555 log_write(0, LOG_MAIN
|LOG_PANIC
, "unable to read private key file: %s",
556 dkim_private_key_expanded
);
561 (void) close(privkey_fd
);
562 dkim_private_key_expanded
= big_buffer
;
565 ctx
= pdkim_init_sign(PDKIM_INPUT_SMTP
,
566 (char *) dkim_signing_domain
,
567 (char *) dkim_signing_selector
,
568 (char *) dkim_private_key_expanded
);
570 pdkim_set_debug_stream(ctx
, debug_file
);
572 pdkim_set_optional(ctx
,
573 (char *) dkim_sign_headers_expanded
,
576 pdkim_canon
, -1, PDKIM_ALGO_RSA_SHA256
, 0, 0);
578 lseek(dkim_fd
, 0, SEEK_SET
);
580 while ((sread
= read(dkim_fd
, &buf
, 4096)) > 0)
581 if (pdkim_feed(ctx
, buf
, sread
) != PDKIM_OK
)
587 /* Handle failed read above. */
590 debug_printf("DKIM: Error reading -K file.\n");
596 if ((pdkim_rc
= pdkim_feed_finish(ctx
, &signature
)) != PDKIM_OK
)
598 log_write(0, LOG_MAIN
|LOG_PANIC
, "DKIM: signing failed (RC %d)", pdkim_rc
);
603 sigbuf
= string_append(sigbuf
, &sigsize
, &sigptr
, 2,
604 US signature
->signature_header
, US
"\r\n");
612 sigbuf
[sigptr
] = '\0';
621 store_pool
= old_pool
;