DKIM: dkim_verify_min_keysizes option
[exim.git] / src / src / dkim.c
1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge, 1995 - 2018 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8 /* Code for DKIM support. Other DKIM relevant code is in
9 receive.c, transport.c and transports/smtp.c */
10
11 #include "exim.h"
12
13 #ifndef DISABLE_DKIM
14
15 # include "pdkim/pdkim.h"
16
17 # ifdef MACRO_PREDEF
18 # include "macro_predef.h"
19
20 void
21 params_dkim(void)
22 {
23 builtin_macro_create_var(US"_DKIM_SIGN_HEADERS", US PDKIM_DEFAULT_SIGN_HEADERS);
24 builtin_macro_create_var(US"_DKIM_OVERSIGN_HEADERS", US PDKIM_OVERSIGN_HEADERS);
25 }
26 # else /*!MACRO_PREDEF*/
27
28
29
30 pdkim_ctx dkim_sign_ctx;
31
32 int dkim_verify_oldpool;
33 pdkim_ctx *dkim_verify_ctx = NULL;
34 pdkim_signature *dkim_cur_sig = NULL;
35 static const uschar * dkim_collect_error = NULL;
36
37 #define DKIM_MAX_SIGNATURES 20
38
39
40
41 /* Look up the DKIM record in DNS for the given hostname.
42 Will use the first found if there are multiple.
43 The return string is tainted, having come from off-site.
44 */
45
46 uschar *
47 dkim_exim_query_dns_txt(const uschar * name)
48 {
49 dns_answer * dnsa = store_get_dns_answer();
50 dns_scan dnss;
51 rmark reset_point = store_mark();
52 gstring * g = NULL;
53
54 lookup_dnssec_authenticated = NULL;
55 if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
56 return NULL; /*XXX better error detail? logging? */
57
58 /* Search for TXT record */
59
60 for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
61 rr;
62 rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
63 if (rr->type == T_TXT)
64 {
65 int rr_offset = 0;
66
67 /* Copy record content to the answer buffer */
68
69 while (rr_offset < rr->size)
70 {
71 uschar len = rr->data[rr_offset++];
72
73 g = string_catn(g, US(rr->data + rr_offset), len);
74 if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
75 goto bad;
76
77 rr_offset += len;
78 }
79
80 /* check if this looks like a DKIM record */
81 if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
82 {
83 gstring_release_unused(g);
84 return string_from_gstring(g);
85 }
86
87 if (g) g->ptr = 0; /* overwrite previous record */
88 }
89
90 bad:
91 store_reset(reset_point);
92 return NULL; /*XXX better error detail? logging? */
93 }
94
95
96 void
97 dkim_exim_init(void)
98 {
99 if (f.dkim_init_done) return;
100 f.dkim_init_done = TRUE;
101 pdkim_init();
102 }
103
104
105
106 void
107 dkim_exim_verify_init(BOOL dot_stuffing)
108 {
109 dkim_exim_init();
110
111 /* There is a store-reset between header & body reception
112 so cannot use the main pool. Any allocs done by Exim
113 memory-handling must use the perm pool. */
114
115 dkim_verify_oldpool = store_pool;
116 store_pool = POOL_PERM;
117
118 /* Free previous context if there is one */
119
120 if (dkim_verify_ctx)
121 pdkim_free_ctx(dkim_verify_ctx);
122
123 /* Create new context */
124
125 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
126 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
127 dkim_collect_error = NULL;
128
129 /* Start feed up with any cached data */
130 receive_get_cache();
131
132 store_pool = dkim_verify_oldpool;
133 }
134
135
136 void
137 dkim_exim_verify_feed(uschar * data, int len)
138 {
139 int rc;
140
141 store_pool = POOL_PERM;
142 if ( dkim_collect_input
143 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
144 {
145 dkim_collect_error = pdkim_errstr(rc);
146 log_write(0, LOG_MAIN,
147 "DKIM: validation error: %.100s", dkim_collect_error);
148 dkim_collect_input = 0;
149 }
150 store_pool = dkim_verify_oldpool;
151 }
152
153
154 /* Log the result for the given signature */
155 static void
156 dkim_exim_verify_log_sig(pdkim_signature * sig)
157 {
158 gstring * logmsg;
159 uschar * s;
160
161 if (!sig) return;
162
163 /* Remember the domain for the first pass result */
164
165 if ( !dkim_verify_overall
166 && dkim_verify_status
167 ? Ustrcmp(dkim_verify_status, US"pass") == 0
168 : sig->verify_status == PDKIM_VERIFY_PASS
169 )
170 dkim_verify_overall = string_copy(sig->domain);
171
172 /* Rewrite the sig result if the ACL overrode it. This is only
173 needed because the DMARC code (sigh) peeks at the dkim sigs.
174 Mark the sig for this having been done. */
175
176 if ( dkim_verify_status
177 && ( dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
178 || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
179 ) )
180 { /* overridden by ACL */
181 sig->verify_ext_status = -1;
182 if (Ustrcmp(dkim_verify_status, US"fail") == 0)
183 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
184 else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
185 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
186 else if (Ustrcmp(dkim_verify_status, US"none") == 0)
187 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
188 else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
189 sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
190 else
191 sig->verify_status = -1;
192 }
193
194 if (!LOGGING(dkim_verbose)) return;
195
196
197 logmsg = string_catn(NULL, US"DKIM: ", 6);
198 if (!(s = sig->domain)) s = US"<UNSET>";
199 logmsg = string_append(logmsg, 2, "d=", s);
200 if (!(s = sig->selector)) s = US"<UNSET>";
201 logmsg = string_append(logmsg, 2, " s=", s);
202 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
203 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
204 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
205 dkim_sig_to_a_tag(sig),
206 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
207 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
208 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
209 sig->created);
210 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
211 sig->expires);
212 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
213 sig->bodylength);
214
215 if (sig->verify_status & PDKIM_VERIFY_POLICY)
216 logmsg = string_append(logmsg, 5,
217 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
218 else
219 switch (sig->verify_status)
220 {
221 case PDKIM_VERIFY_NONE:
222 logmsg = string_cat(logmsg, US" [not verified]");
223 break;
224
225 case PDKIM_VERIFY_INVALID:
226 logmsg = string_cat(logmsg, US" [invalid - ");
227 switch (sig->verify_ext_status)
228 {
229 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
230 logmsg = string_cat(logmsg,
231 US"public key record (currently?) unavailable]");
232 break;
233
234 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
235 logmsg = string_cat(logmsg, US"overlong public key record]");
236 break;
237
238 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
239 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
240 logmsg = string_cat(logmsg, US"syntax error in public key record]");
241 break;
242
243 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
244 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
245 break;
246
247 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
248 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
249 break;
250
251 default:
252 logmsg = string_cat(logmsg, US"unspecified problem]");
253 }
254 break;
255
256 case PDKIM_VERIFY_FAIL:
257 logmsg = string_cat(logmsg, US" [verification failed - ");
258 switch (sig->verify_ext_status)
259 {
260 case PDKIM_VERIFY_FAIL_BODY:
261 logmsg = string_cat(logmsg,
262 US"body hash mismatch (body probably modified in transit)]");
263 break;
264
265 case PDKIM_VERIFY_FAIL_MESSAGE:
266 logmsg = string_cat(logmsg,
267 US"signature did not verify "
268 "(headers probably modified in transit)]");
269 break;
270
271 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
272 logmsg = string_cat(logmsg,
273 US"signature invalid (key too short)]");
274 break;
275
276 default:
277 logmsg = string_cat(logmsg, US"unspecified reason]");
278 }
279 break;
280
281 case PDKIM_VERIFY_PASS:
282 logmsg = string_cat(logmsg, US" [verification succeeded]");
283 break;
284 }
285
286 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
287 return;
288 }
289
290
291 /* Log a line for each signature */
292 void
293 dkim_exim_verify_log_all(void)
294 {
295 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
296 dkim_exim_verify_log_sig(sig);
297 }
298
299
300 void
301 dkim_exim_verify_finish(void)
302 {
303 int rc;
304 gstring * g = NULL;
305 const uschar * errstr = NULL;
306
307 store_pool = POOL_PERM;
308
309 /* Delete eventual previous signature chain */
310
311 dkim_signers = NULL;
312 dkim_signatures = NULL;
313
314 if (dkim_collect_error)
315 {
316 log_write(0, LOG_MAIN,
317 "DKIM: Error during validation, disabling signature verification: %.100s",
318 dkim_collect_error);
319 f.dkim_disable_verify = TRUE;
320 goto out;
321 }
322
323 dkim_collect_input = 0;
324
325 /* Finish DKIM operation and fetch link to signatures chain */
326
327 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
328 &errstr);
329 if (rc != PDKIM_OK && errstr)
330 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
331
332 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
333
334 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
335 {
336 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
337 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
338 }
339
340 if (g) dkim_signers = g->s;
341
342 out:
343 store_pool = dkim_verify_oldpool;
344 }
345
346
347
348 /* Args as per dkim_exim_acl_run() below */
349 static int
350 dkim_acl_call(uschar * id, gstring ** res_ptr,
351 uschar ** user_msgptr, uschar ** log_msgptr)
352 {
353 int rc;
354 DEBUG(D_receive)
355 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
356
357 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
358 dkim_exim_verify_log_sig(dkim_cur_sig);
359 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
360 return rc;
361 }
362
363
364
365 /* For the given identity, run the DKIM ACL once for each matching signature.
366
367 Arguments
368 id Identity to look for in dkim signatures
369 res_ptr ptr to growable string-list of status results,
370 appended to per ACL run
371 user_msgptr where to put a user error (for SMTP response)
372 log_msgptr where to put a logging message (not for SMTP response)
373
374 Returns: OK access is granted by an ACCEPT verb
375 DISCARD access is granted by a DISCARD verb
376 FAIL access is denied
377 FAIL_DROP access is denied; drop the connection
378 DEFER can't tell at the moment
379 ERROR disaster
380 */
381
382 int
383 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
384 uschar ** user_msgptr, uschar ** log_msgptr)
385 {
386 uschar * cmp_val;
387 int rc = -1;
388
389 dkim_verify_status = US"none";
390 dkim_verify_reason = US"";
391 dkim_cur_signer = id;
392
393 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
394 return OK;
395
396 /* Find signatures to run ACL on */
397
398 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
399 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
400 && strcmpic(cmp_val, id) == 0
401 )
402 {
403 /* The "dkim_domain" and "dkim_selector" expansion variables have
404 related globals, since they are used in the signing code too.
405 Instead of inventing separate names for verification, we set
406 them here. This is easy since a domain and selector is guaranteed
407 to be in a signature. The other dkim_* expansion items are
408 dynamically fetched from dkim_cur_sig at expansion time (see
409 dkim_exim_expand_query() below). */
410
411 dkim_cur_sig = sig;
412 dkim_signing_domain = US sig->domain;
413 dkim_signing_selector = US sig->selector;
414 dkim_key_length = sig->keybits;
415
416 /* These two return static strings, so we can compare the addr
417 later to see if the ACL overwrote them. Check that when logging */
418
419 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
420 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
421
422 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
423 return rc;
424 }
425
426 if (rc != -1)
427 return rc;
428
429 /* No matching sig found. Call ACL once anyway. */
430
431 dkim_cur_sig = NULL;
432 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
433 }
434
435
436 static uschar *
437 dkim_exim_expand_defaults(int what)
438 {
439 switch (what)
440 {
441 case DKIM_ALGO: return US"";
442 case DKIM_BODYLENGTH: return US"9999999999999";
443 case DKIM_CANON_BODY: return US"";
444 case DKIM_CANON_HEADERS: return US"";
445 case DKIM_COPIEDHEADERS: return US"";
446 case DKIM_CREATED: return US"0";
447 case DKIM_EXPIRES: return US"9999999999999";
448 case DKIM_HEADERNAMES: return US"";
449 case DKIM_IDENTITY: return US"";
450 case DKIM_KEY_GRANULARITY: return US"*";
451 case DKIM_KEY_SRVTYPE: return US"*";
452 case DKIM_KEY_NOTES: return US"";
453 case DKIM_KEY_TESTING: return US"0";
454 case DKIM_NOSUBDOMAINS: return US"0";
455 case DKIM_VERIFY_STATUS: return US"none";
456 case DKIM_VERIFY_REASON: return US"";
457 default: return US"";
458 }
459 }
460
461
462 uschar *
463 dkim_exim_expand_query(int what)
464 {
465 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
466 return dkim_exim_expand_defaults(what);
467
468 switch (what)
469 {
470 case DKIM_ALGO:
471 return dkim_sig_to_a_tag(dkim_cur_sig);
472
473 case DKIM_BODYLENGTH:
474 return dkim_cur_sig->bodylength >= 0
475 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
476 : dkim_exim_expand_defaults(what);
477
478 case DKIM_CANON_BODY:
479 switch (dkim_cur_sig->canon_body)
480 {
481 case PDKIM_CANON_RELAXED: return US"relaxed";
482 case PDKIM_CANON_SIMPLE:
483 default: return US"simple";
484 }
485
486 case DKIM_CANON_HEADERS:
487 switch (dkim_cur_sig->canon_headers)
488 {
489 case PDKIM_CANON_RELAXED: return US"relaxed";
490 case PDKIM_CANON_SIMPLE:
491 default: return US"simple";
492 }
493
494 case DKIM_COPIEDHEADERS:
495 return dkim_cur_sig->copiedheaders
496 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
497
498 case DKIM_CREATED:
499 return dkim_cur_sig->created > 0
500 ? string_sprintf("%lu", dkim_cur_sig->created)
501 : dkim_exim_expand_defaults(what);
502
503 case DKIM_EXPIRES:
504 return dkim_cur_sig->expires > 0
505 ? string_sprintf("%lu", dkim_cur_sig->expires)
506 : dkim_exim_expand_defaults(what);
507
508 case DKIM_HEADERNAMES:
509 return dkim_cur_sig->headernames
510 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
511
512 case DKIM_IDENTITY:
513 return dkim_cur_sig->identity
514 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
515
516 case DKIM_KEY_GRANULARITY:
517 return dkim_cur_sig->pubkey
518 ? dkim_cur_sig->pubkey->granularity
519 ? US dkim_cur_sig->pubkey->granularity
520 : dkim_exim_expand_defaults(what)
521 : dkim_exim_expand_defaults(what);
522
523 case DKIM_KEY_SRVTYPE:
524 return dkim_cur_sig->pubkey
525 ? dkim_cur_sig->pubkey->srvtype
526 ? US dkim_cur_sig->pubkey->srvtype
527 : dkim_exim_expand_defaults(what)
528 : dkim_exim_expand_defaults(what);
529
530 case DKIM_KEY_NOTES:
531 return dkim_cur_sig->pubkey
532 ? dkim_cur_sig->pubkey->notes
533 ? US dkim_cur_sig->pubkey->notes
534 : dkim_exim_expand_defaults(what)
535 : dkim_exim_expand_defaults(what);
536
537 case DKIM_KEY_TESTING:
538 return dkim_cur_sig->pubkey
539 ? dkim_cur_sig->pubkey->testing
540 ? US"1"
541 : dkim_exim_expand_defaults(what)
542 : dkim_exim_expand_defaults(what);
543
544 case DKIM_NOSUBDOMAINS:
545 return dkim_cur_sig->pubkey
546 ? dkim_cur_sig->pubkey->no_subdomaining
547 ? US"1"
548 : dkim_exim_expand_defaults(what)
549 : dkim_exim_expand_defaults(what);
550
551 case DKIM_VERIFY_STATUS:
552 switch (dkim_cur_sig->verify_status)
553 {
554 case PDKIM_VERIFY_INVALID: return US"invalid";
555 case PDKIM_VERIFY_FAIL: return US"fail";
556 case PDKIM_VERIFY_PASS: return US"pass";
557 case PDKIM_VERIFY_NONE:
558 default: return US"none";
559 }
560
561 case DKIM_VERIFY_REASON:
562 switch (dkim_cur_sig->verify_ext_status)
563 {
564 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
565 return US"pubkey_unavailable";
566 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
567 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
568 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
569 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
570 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
571 }
572
573 default:
574 return US"";
575 }
576 }
577
578
579 void
580 dkim_exim_sign_init(void)
581 {
582 int old_pool = store_pool;
583
584 dkim_exim_init();
585 store_pool = POOL_MAIN;
586 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
587 store_pool = old_pool;
588 }
589
590
591 /* Generate signatures for the given file.
592 If a prefix is given, prepend it to the file for the calculations.
593
594 Return:
595 NULL: error; error string written
596 string: signature header(s), or a zero-length string (not an error)
597 */
598
599 gstring *
600 dkim_exim_sign(int fd, off_t off, uschar * prefix,
601 struct ob_dkim * dkim, const uschar ** errstr)
602 {
603 const uschar * dkim_domain = NULL;
604 int sep = 0;
605 gstring * seen_doms = NULL;
606 pdkim_signature * sig;
607 gstring * sigbuf;
608 int pdkim_rc;
609 int sread;
610 uschar buf[4096];
611 int save_errno = 0;
612 int old_pool = store_pool;
613 uschar * errwhen;
614 const uschar * s;
615
616 if (dkim->dot_stuffed)
617 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
618
619 store_pool = POOL_MAIN;
620
621 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
622 /* expansion error, do not send message. */
623 { errwhen = US"dkim_domain"; goto expand_bad; }
624
625 /* Set $dkim_domain expansion variable to each unique domain in list. */
626
627 if (dkim_domain)
628 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
629 {
630 const uschar * dkim_sel;
631 int sel_sep = 0;
632
633 if (dkim_signing_domain[0] == '\0')
634 continue;
635
636 /* Only sign once for each domain, no matter how often it
637 appears in the expanded list. */
638
639 dkim_signing_domain = string_copylc(dkim_signing_domain);
640 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
641 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
642 continue;
643
644 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
645
646 /* Set $dkim_selector expansion variable to each selector in list,
647 for this domain. */
648
649 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
650 { errwhen = US"dkim_selector"; goto expand_bad; }
651
652 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
653 NULL, 0)))
654 {
655 uschar * dkim_canon_expanded;
656 int pdkim_canon;
657 uschar * dkim_sign_headers_expanded = NULL;
658 uschar * dkim_private_key_expanded;
659 uschar * dkim_hash_expanded;
660 uschar * dkim_identity_expanded = NULL;
661 uschar * dkim_timestamps_expanded = NULL;
662 unsigned long tval = 0, xval = 0;
663
664 /* Get canonicalization to use */
665
666 dkim_canon_expanded = dkim->dkim_canon
667 ? expand_string(dkim->dkim_canon) : US"relaxed";
668 if (!dkim_canon_expanded) /* expansion error, do not send message. */
669 { errwhen = US"dkim_canon"; goto expand_bad; }
670
671 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
672 pdkim_canon = PDKIM_CANON_RELAXED;
673 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
674 pdkim_canon = PDKIM_CANON_SIMPLE;
675 else
676 {
677 log_write(0, LOG_MAIN,
678 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
679 dkim_canon_expanded);
680 pdkim_canon = PDKIM_CANON_RELAXED;
681 }
682
683 if ( dkim->dkim_sign_headers
684 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
685 { errwhen = US"dkim_sign_header"; goto expand_bad; }
686 /* else pass NULL, which means default header list */
687
688 /* Get private key to use. */
689
690 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
691 { errwhen = US"dkim_private_key"; goto expand_bad; }
692
693 if ( Ustrlen(dkim_private_key_expanded) == 0
694 || Ustrcmp(dkim_private_key_expanded, "0") == 0
695 || Ustrcmp(dkim_private_key_expanded, "false") == 0
696 )
697 continue; /* don't sign, but no error */
698
699 if ( dkim_private_key_expanded[0] == '/'
700 && !(dkim_private_key_expanded =
701 expand_file_big_buffer(dkim_private_key_expanded)))
702 goto bad;
703
704 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
705 { errwhen = US"dkim_hash"; goto expand_bad; }
706
707 if (dkim->dkim_identity)
708 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
709 { errwhen = US"dkim_identity"; goto expand_bad; }
710 else if (!*dkim_identity_expanded)
711 dkim_identity_expanded = NULL;
712
713 if (dkim->dkim_timestamps)
714 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
715 { errwhen = US"dkim_timestamps"; goto expand_bad; }
716 else
717 xval = (tval = (unsigned long) time(NULL))
718 + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
719
720 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
721 dkim_signing_selector,
722 dkim_private_key_expanded,
723 dkim_hash_expanded,
724 errstr
725 )))
726 goto bad;
727 dkim_private_key_expanded[0] = '\0';
728
729 pdkim_set_optional(sig,
730 CS dkim_sign_headers_expanded,
731 CS dkim_identity_expanded,
732 pdkim_canon,
733 pdkim_canon, -1, tval, xval);
734
735 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
736 goto bad;
737
738 if (!dkim_sign_ctx.sig) /* link sig to context chain */
739 dkim_sign_ctx.sig = sig;
740 else
741 {
742 pdkim_signature * n = dkim_sign_ctx.sig;
743 while (n->next) n = n->next;
744 n->next = sig;
745 }
746 }
747 }
748
749 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
750 produce, if some other package (eg. ARC) is signing. */
751
752 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
753 {
754 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
755 sigbuf = string_get(1); /* return a zero-len string */
756 }
757 else
758 {
759 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
760 goto pk_bad;
761
762 if (lseek(fd, off, SEEK_SET) < 0)
763 sread = -1;
764 else
765 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
766 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
767 goto pk_bad;
768
769 /* Handle failed read above. */
770 if (sread == -1)
771 {
772 debug_printf("DKIM: Error reading -K file.\n");
773 save_errno = errno;
774 goto bad;
775 }
776
777 /* Build string of headers, one per signature */
778
779 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
780 goto pk_bad;
781
782 if (!sig)
783 {
784 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
785 sigbuf = string_get(1); /* return a zero-len string */
786 }
787 else for (sigbuf = NULL; sig; sig = sig->next)
788 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
789 }
790
791 CLEANUP:
792 (void) string_from_gstring(sigbuf);
793 store_pool = old_pool;
794 errno = save_errno;
795 return sigbuf;
796
797 pk_bad:
798 log_write(0, LOG_MAIN|LOG_PANIC,
799 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
800 bad:
801 sigbuf = NULL;
802 goto CLEANUP;
803
804 expand_bad:
805 *errstr = string_sprintf("failed to expand %s: %s",
806 errwhen, expand_string_message);
807 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
808 goto bad;
809 }
810
811
812
813
814 gstring *
815 authres_dkim(gstring * g)
816 {
817 int start = 0; /* compiler quietening */
818
819 DEBUG(D_acl) start = g->ptr;
820
821 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
822 {
823 g = string_catn(g, US";\n\tdkim=", 8);
824
825 if (sig->verify_status & PDKIM_VERIFY_POLICY)
826 g = string_append(g, 5,
827 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
828 else switch(sig->verify_status)
829 {
830 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
831 case PDKIM_VERIFY_INVALID:
832 switch (sig->verify_ext_status)
833 {
834 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
835 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
836 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
837 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
838 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
839 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
840 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
841 break;
842 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
843 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
844 break;
845 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
846 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
847 break;
848 default:
849 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
850 }
851 break;
852 case PDKIM_VERIFY_FAIL:
853 switch (sig->verify_ext_status)
854 {
855 case PDKIM_VERIFY_FAIL_BODY:
856 g = string_cat(g,
857 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
858 break;
859 case PDKIM_VERIFY_FAIL_MESSAGE:
860 g = string_cat(g,
861 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
862 break;
863 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: /* should this really be "polcy"? */
864 g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
865 break;
866 default:
867 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
868 break;
869 }
870 break;
871 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
872 default: g = string_cat(g, US"permerror"); break;
873 }
874 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
875 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
876 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
877 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
878 }
879
880 DEBUG(D_acl)
881 if (g->ptr == start)
882 debug_printf("DKIM: no authres\n");
883 else
884 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
885 return g;
886 }
887
888
889 # endif /*!MACRO_PREDEF*/
890 #endif /*!DISABLE_DKIM*/