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