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