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