tidying
[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 default:
272 logmsg = string_cat(logmsg, US"unspecified reason]");
273 }
274 break;
275
276 case PDKIM_VERIFY_PASS:
277 logmsg = string_cat(logmsg, US" [verification succeeded]");
278 break;
279 }
280
281 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
282 return;
283 }
284
285
286 /* Log a line for each signature */
287 void
288 dkim_exim_verify_log_all(void)
289 {
290 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
291 dkim_exim_verify_log_sig(sig);
292 }
293
294
295 void
296 dkim_exim_verify_finish(void)
297 {
298 int rc;
299 gstring * g = NULL;
300 const uschar * errstr = NULL;
301
302 store_pool = POOL_PERM;
303
304 /* Delete eventual previous signature chain */
305
306 dkim_signers = NULL;
307 dkim_signatures = NULL;
308
309 if (dkim_collect_error)
310 {
311 log_write(0, LOG_MAIN,
312 "DKIM: Error during validation, disabling signature verification: %.100s",
313 dkim_collect_error);
314 f.dkim_disable_verify = TRUE;
315 goto out;
316 }
317
318 dkim_collect_input = 0;
319
320 /* Finish DKIM operation and fetch link to signatures chain */
321
322 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
323 &errstr);
324 if (rc != PDKIM_OK && errstr)
325 log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
326
327 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
328
329 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
330 {
331 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
332 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
333 }
334
335 if (g) dkim_signers = g->s;
336
337 out:
338 store_pool = dkim_verify_oldpool;
339 }
340
341
342
343 /* Args as per dkim_exim_acl_run() below */
344 static int
345 dkim_acl_call(uschar * id, gstring ** res_ptr,
346 uschar ** user_msgptr, uschar ** log_msgptr)
347 {
348 int rc;
349 DEBUG(D_receive)
350 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
351
352 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
353 dkim_exim_verify_log_sig(dkim_cur_sig);
354 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
355 return rc;
356 }
357
358
359
360 /* For the given identity, run the DKIM ACL once for each matching signature.
361
362 Arguments
363 id Identity to look for in dkim signatures
364 res_ptr ptr to growable string-list of status results,
365 appended to per ACL run
366 user_msgptr where to put a user error (for SMTP response)
367 log_msgptr where to put a logging message (not for SMTP response)
368
369 Returns: OK access is granted by an ACCEPT verb
370 DISCARD access is granted by a DISCARD verb
371 FAIL access is denied
372 FAIL_DROP access is denied; drop the connection
373 DEFER can't tell at the moment
374 ERROR disaster
375 */
376
377 int
378 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
379 uschar ** user_msgptr, uschar ** log_msgptr)
380 {
381 uschar * cmp_val;
382 int rc = -1;
383
384 dkim_verify_status = US"none";
385 dkim_verify_reason = US"";
386 dkim_cur_signer = id;
387
388 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
389 return OK;
390
391 /* Find signatures to run ACL on */
392
393 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
394 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
395 && strcmpic(cmp_val, id) == 0
396 )
397 {
398 /* The "dkim_domain" and "dkim_selector" expansion variables have
399 related globals, since they are used in the signing code too.
400 Instead of inventing separate names for verification, we set
401 them here. This is easy since a domain and selector is guaranteed
402 to be in a signature. The other dkim_* expansion items are
403 dynamically fetched from dkim_cur_sig at expansion time (see
404 dkim_exim_expand_query() below). */
405
406 dkim_cur_sig = sig;
407 dkim_signing_domain = US sig->domain;
408 dkim_signing_selector = US sig->selector;
409 dkim_key_length = sig->sighash.len * 8;
410
411 /* These two return static strings, so we can compare the addr
412 later to see if the ACL overwrote them. Check that when logging */
413
414 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
415 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
416
417 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
418 return rc;
419 }
420
421 if (rc != -1)
422 return rc;
423
424 /* No matching sig found. Call ACL once anyway. */
425
426 dkim_cur_sig = NULL;
427 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
428 }
429
430
431 static uschar *
432 dkim_exim_expand_defaults(int what)
433 {
434 switch (what)
435 {
436 case DKIM_ALGO: return US"";
437 case DKIM_BODYLENGTH: return US"9999999999999";
438 case DKIM_CANON_BODY: return US"";
439 case DKIM_CANON_HEADERS: return US"";
440 case DKIM_COPIEDHEADERS: return US"";
441 case DKIM_CREATED: return US"0";
442 case DKIM_EXPIRES: return US"9999999999999";
443 case DKIM_HEADERNAMES: return US"";
444 case DKIM_IDENTITY: return US"";
445 case DKIM_KEY_GRANULARITY: return US"*";
446 case DKIM_KEY_SRVTYPE: return US"*";
447 case DKIM_KEY_NOTES: return US"";
448 case DKIM_KEY_TESTING: return US"0";
449 case DKIM_NOSUBDOMAINS: return US"0";
450 case DKIM_VERIFY_STATUS: return US"none";
451 case DKIM_VERIFY_REASON: return US"";
452 default: return US"";
453 }
454 }
455
456
457 uschar *
458 dkim_exim_expand_query(int what)
459 {
460 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
461 return dkim_exim_expand_defaults(what);
462
463 switch (what)
464 {
465 case DKIM_ALGO:
466 return dkim_sig_to_a_tag(dkim_cur_sig);
467
468 case DKIM_BODYLENGTH:
469 return dkim_cur_sig->bodylength >= 0
470 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
471 : dkim_exim_expand_defaults(what);
472
473 case DKIM_CANON_BODY:
474 switch (dkim_cur_sig->canon_body)
475 {
476 case PDKIM_CANON_RELAXED: return US"relaxed";
477 case PDKIM_CANON_SIMPLE:
478 default: return US"simple";
479 }
480
481 case DKIM_CANON_HEADERS:
482 switch (dkim_cur_sig->canon_headers)
483 {
484 case PDKIM_CANON_RELAXED: return US"relaxed";
485 case PDKIM_CANON_SIMPLE:
486 default: return US"simple";
487 }
488
489 case DKIM_COPIEDHEADERS:
490 return dkim_cur_sig->copiedheaders
491 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
492
493 case DKIM_CREATED:
494 return dkim_cur_sig->created > 0
495 ? string_sprintf("%lu", dkim_cur_sig->created)
496 : dkim_exim_expand_defaults(what);
497
498 case DKIM_EXPIRES:
499 return dkim_cur_sig->expires > 0
500 ? string_sprintf("%lu", dkim_cur_sig->expires)
501 : dkim_exim_expand_defaults(what);
502
503 case DKIM_HEADERNAMES:
504 return dkim_cur_sig->headernames
505 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
506
507 case DKIM_IDENTITY:
508 return dkim_cur_sig->identity
509 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
510
511 case DKIM_KEY_GRANULARITY:
512 return dkim_cur_sig->pubkey
513 ? dkim_cur_sig->pubkey->granularity
514 ? US dkim_cur_sig->pubkey->granularity
515 : dkim_exim_expand_defaults(what)
516 : dkim_exim_expand_defaults(what);
517
518 case DKIM_KEY_SRVTYPE:
519 return dkim_cur_sig->pubkey
520 ? dkim_cur_sig->pubkey->srvtype
521 ? US dkim_cur_sig->pubkey->srvtype
522 : dkim_exim_expand_defaults(what)
523 : dkim_exim_expand_defaults(what);
524
525 case DKIM_KEY_NOTES:
526 return dkim_cur_sig->pubkey
527 ? dkim_cur_sig->pubkey->notes
528 ? US dkim_cur_sig->pubkey->notes
529 : dkim_exim_expand_defaults(what)
530 : dkim_exim_expand_defaults(what);
531
532 case DKIM_KEY_TESTING:
533 return dkim_cur_sig->pubkey
534 ? dkim_cur_sig->pubkey->testing
535 ? US"1"
536 : dkim_exim_expand_defaults(what)
537 : dkim_exim_expand_defaults(what);
538
539 case DKIM_NOSUBDOMAINS:
540 return dkim_cur_sig->pubkey
541 ? dkim_cur_sig->pubkey->no_subdomaining
542 ? US"1"
543 : dkim_exim_expand_defaults(what)
544 : dkim_exim_expand_defaults(what);
545
546 case DKIM_VERIFY_STATUS:
547 switch (dkim_cur_sig->verify_status)
548 {
549 case PDKIM_VERIFY_INVALID: return US"invalid";
550 case PDKIM_VERIFY_FAIL: return US"fail";
551 case PDKIM_VERIFY_PASS: return US"pass";
552 case PDKIM_VERIFY_NONE:
553 default: return US"none";
554 }
555
556 case DKIM_VERIFY_REASON:
557 switch (dkim_cur_sig->verify_ext_status)
558 {
559 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
560 return US"pubkey_unavailable";
561 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
562 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
563 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
564 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
565 }
566
567 default:
568 return US"";
569 }
570 }
571
572
573 void
574 dkim_exim_sign_init(void)
575 {
576 int old_pool = store_pool;
577
578 dkim_exim_init();
579 store_pool = POOL_MAIN;
580 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
581 store_pool = old_pool;
582 }
583
584
585 /* Generate signatures for the given file.
586 If a prefix is given, prepend it to the file for the calculations.
587
588 Return:
589 NULL: error; error string written
590 string: signature header(s), or a zero-length string (not an error)
591 */
592
593 gstring *
594 dkim_exim_sign(int fd, off_t off, uschar * prefix,
595 struct ob_dkim * dkim, const uschar ** errstr)
596 {
597 const uschar * dkim_domain = NULL;
598 int sep = 0;
599 gstring * seen_doms = NULL;
600 pdkim_signature * sig;
601 gstring * sigbuf;
602 int pdkim_rc;
603 int sread;
604 uschar buf[4096];
605 int save_errno = 0;
606 int old_pool = store_pool;
607 uschar * errwhen;
608 const uschar * s;
609
610 if (dkim->dot_stuffed)
611 dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
612
613 store_pool = POOL_MAIN;
614
615 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
616 /* expansion error, do not send message. */
617 { errwhen = US"dkim_domain"; goto expand_bad; }
618
619 /* Set $dkim_domain expansion variable to each unique domain in list. */
620
621 if (dkim_domain)
622 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
623 {
624 const uschar * dkim_sel;
625 int sel_sep = 0;
626
627 if (dkim_signing_domain[0] == '\0')
628 continue;
629
630 /* Only sign once for each domain, no matter how often it
631 appears in the expanded list. */
632
633 dkim_signing_domain = string_copylc(dkim_signing_domain);
634 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
635 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
636 continue;
637
638 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
639
640 /* Set $dkim_selector expansion variable to each selector in list,
641 for this domain. */
642
643 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
644 { errwhen = US"dkim_selector"; goto expand_bad; }
645
646 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
647 NULL, 0)))
648 {
649 uschar * dkim_canon_expanded;
650 int pdkim_canon;
651 uschar * dkim_sign_headers_expanded = NULL;
652 uschar * dkim_private_key_expanded;
653 uschar * dkim_hash_expanded;
654 uschar * dkim_identity_expanded = NULL;
655 uschar * dkim_timestamps_expanded = NULL;
656 unsigned long tval = 0, xval = 0;
657
658 /* Get canonicalization to use */
659
660 dkim_canon_expanded = dkim->dkim_canon
661 ? expand_string(dkim->dkim_canon) : US"relaxed";
662 if (!dkim_canon_expanded) /* expansion error, do not send message. */
663 { errwhen = US"dkim_canon"; goto expand_bad; }
664
665 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
666 pdkim_canon = PDKIM_CANON_RELAXED;
667 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
668 pdkim_canon = PDKIM_CANON_SIMPLE;
669 else
670 {
671 log_write(0, LOG_MAIN,
672 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
673 dkim_canon_expanded);
674 pdkim_canon = PDKIM_CANON_RELAXED;
675 }
676
677 if ( dkim->dkim_sign_headers
678 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
679 { errwhen = US"dkim_sign_header"; goto expand_bad; }
680 /* else pass NULL, which means default header list */
681
682 /* Get private key to use. */
683
684 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
685 { errwhen = US"dkim_private_key"; goto expand_bad; }
686
687 if ( Ustrlen(dkim_private_key_expanded) == 0
688 || Ustrcmp(dkim_private_key_expanded, "0") == 0
689 || Ustrcmp(dkim_private_key_expanded, "false") == 0
690 )
691 continue; /* don't sign, but no error */
692
693 if ( dkim_private_key_expanded[0] == '/'
694 && !(dkim_private_key_expanded =
695 expand_file_big_buffer(dkim_private_key_expanded)))
696 goto bad;
697
698 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
699 { errwhen = US"dkim_hash"; goto expand_bad; }
700
701 if (dkim->dkim_identity)
702 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
703 { errwhen = US"dkim_identity"; goto expand_bad; }
704 else if (!*dkim_identity_expanded)
705 dkim_identity_expanded = NULL;
706
707 if (dkim->dkim_timestamps)
708 if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
709 { errwhen = US"dkim_timestamps"; goto expand_bad; }
710 else
711 xval = (tval = (unsigned long) time(NULL))
712 + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
713
714 if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
715 dkim_signing_selector,
716 dkim_private_key_expanded,
717 dkim_hash_expanded,
718 errstr
719 )))
720 goto bad;
721 dkim_private_key_expanded[0] = '\0';
722
723 pdkim_set_optional(sig,
724 CS dkim_sign_headers_expanded,
725 CS dkim_identity_expanded,
726 pdkim_canon,
727 pdkim_canon, -1, tval, xval);
728
729 if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
730 goto bad;
731
732 if (!dkim_sign_ctx.sig) /* link sig to context chain */
733 dkim_sign_ctx.sig = sig;
734 else
735 {
736 pdkim_signature * n = dkim_sign_ctx.sig;
737 while (n->next) n = n->next;
738 n->next = sig;
739 }
740 }
741 }
742
743 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
744 produce, if some other package (eg. ARC) is signing. */
745
746 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
747 {
748 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
749 sigbuf = string_get(1); /* return a zero-len string */
750 }
751 else
752 {
753 if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
754 goto pk_bad;
755
756 if (lseek(fd, off, SEEK_SET) < 0)
757 sread = -1;
758 else
759 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
760 if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
761 goto pk_bad;
762
763 /* Handle failed read above. */
764 if (sread == -1)
765 {
766 debug_printf("DKIM: Error reading -K file.\n");
767 save_errno = errno;
768 goto bad;
769 }
770
771 /* Build string of headers, one per signature */
772
773 if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
774 goto pk_bad;
775
776 if (!sig)
777 {
778 DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
779 sigbuf = string_get(1); /* return a zero-len string */
780 }
781 else for (sigbuf = NULL; sig; sig = sig->next)
782 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
783 }
784
785 CLEANUP:
786 (void) string_from_gstring(sigbuf);
787 store_pool = old_pool;
788 errno = save_errno;
789 return sigbuf;
790
791 pk_bad:
792 log_write(0, LOG_MAIN|LOG_PANIC,
793 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
794 bad:
795 sigbuf = NULL;
796 goto CLEANUP;
797
798 expand_bad:
799 *errstr = string_sprintf("failed to expand %s: %s",
800 errwhen, expand_string_message);
801 log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
802 goto bad;
803 }
804
805
806
807
808 gstring *
809 authres_dkim(gstring * g)
810 {
811 int start = 0; /* compiler quietening */
812
813 DEBUG(D_acl) start = g->ptr;
814
815 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
816 {
817 g = string_catn(g, US";\n\tdkim=", 8);
818
819 if (sig->verify_status & PDKIM_VERIFY_POLICY)
820 g = string_append(g, 5,
821 US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
822 else switch(sig->verify_status)
823 {
824 case PDKIM_VERIFY_NONE: g = string_cat(g, US"none"); break;
825 case PDKIM_VERIFY_INVALID:
826 switch (sig->verify_ext_status)
827 {
828 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
829 g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
830 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
831 g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
832 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
833 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
834 g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
835 break;
836 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
837 g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
838 break;
839 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
840 g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
841 break;
842 default:
843 g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
844 }
845 break;
846 case PDKIM_VERIFY_FAIL:
847 switch (sig->verify_ext_status)
848 {
849 case PDKIM_VERIFY_FAIL_BODY:
850 g = string_cat(g,
851 US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
852 break;
853 case PDKIM_VERIFY_FAIL_MESSAGE:
854 g = string_cat(g,
855 US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
856 break;
857 default:
858 g = string_cat(g, US"fail (unspecified reason)\n\t\t");
859 break;
860 }
861 break;
862 case PDKIM_VERIFY_PASS: g = string_cat(g, US"pass"); break;
863 default: g = string_cat(g, US"permerror"); break;
864 }
865 if (sig->domain) g = string_append(g, 2, US" header.d=", sig->domain);
866 if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
867 if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
868 g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
869 }
870
871 DEBUG(D_acl)
872 if (g->ptr == start)
873 debug_printf("DKIM: no authres\n");
874 else
875 debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
876 return g;
877 }
878
879
880 # endif /*!MACRO_PREDEF*/
881 #endif /*!DISABLE_DKIM*/