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