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