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