DKIM: fix $dkim_key_length in verify
[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         default:
272           logmsg = string_cat(logmsg, US"unspecified reason]");
273         }
274       break;
275
276     case PDKIM_VERIFY_PASS:
277       logmsg = string_cat(logmsg, US" [verification succeeded]");
278       break;
279     }
280
281 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
282 return;
283 }
284
285
286 /* Log a line for each signature */
287 void
288 dkim_exim_verify_log_all(void)
289 {
290 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
291   dkim_exim_verify_log_sig(sig);
292 }
293
294
295 void
296 dkim_exim_verify_finish(void)
297 {
298 int rc;
299 gstring * g = NULL;
300 const uschar * errstr = NULL;
301
302 store_pool = POOL_PERM;
303
304 /* Delete eventual previous signature chain */
305
306 dkim_signers = NULL;
307 dkim_signatures = NULL;
308
309 if (dkim_collect_error)
310   {
311   log_write(0, LOG_MAIN,
312       "DKIM: Error during validation, disabling signature verification: %.100s",
313       dkim_collect_error);
314   f.dkim_disable_verify = TRUE;
315   goto out;
316   }
317
318 dkim_collect_input = 0;
319
320 /* Finish DKIM operation and fetch link to signatures chain */
321
322 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
323                         &errstr);
324 if (rc != PDKIM_OK && errstr)
325   log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
326
327 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
328
329 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
330   {
331   if (sig->domain)   g = string_append_listele(g, ':', sig->domain);
332   if (sig->identity) g = string_append_listele(g, ':', sig->identity);
333   }
334
335 if (g) dkim_signers = g->s;
336
337 out:
338 store_pool = dkim_verify_oldpool;
339 }
340
341
342
343 /* Args as per dkim_exim_acl_run() below */
344 static int
345 dkim_acl_call(uschar * id, gstring ** res_ptr,
346   uschar ** user_msgptr, uschar ** log_msgptr)
347 {
348 int rc;
349 DEBUG(D_receive)
350   debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
351
352 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
353 dkim_exim_verify_log_sig(dkim_cur_sig);
354 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
355 return rc;
356 }
357
358
359
360 /* For the given identity, run the DKIM ACL once for each matching signature.
361
362 Arguments
363  id             Identity to look for in dkim signatures
364  res_ptr        ptr to growable string-list of status results,
365                 appended to per ACL run
366  user_msgptr    where to put a user error (for SMTP response)
367  log_msgptr     where to put a logging message (not for SMTP response)
368
369 Returns:       OK         access is granted by an ACCEPT verb
370                DISCARD    access is granted by a DISCARD verb
371                FAIL       access is denied
372                FAIL_DROP  access is denied; drop the connection
373                DEFER      can't tell at the moment
374                ERROR      disaster
375 */
376
377 int
378 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
379   uschar ** user_msgptr, uschar ** log_msgptr)
380 {
381 uschar * cmp_val;
382 int rc = -1;
383
384 dkim_verify_status = US"none";
385 dkim_verify_reason = US"";
386 dkim_cur_signer = id;
387
388 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
389   return OK;
390
391 /* Find signatures to run ACL on */
392
393 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
394   if (  (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
395      && strcmpic(cmp_val, id) == 0
396      )
397     {
398     /* The "dkim_domain" and "dkim_selector" expansion variables have
399     related globals, since they are used in the signing code too.
400     Instead of inventing separate names for verification, we set
401     them here. This is easy since a domain and selector is guaranteed
402     to be in a signature. The other dkim_* expansion items are
403     dynamically fetched from dkim_cur_sig at expansion time (see
404     dkim_exim_expand_query() below). */
405
406     dkim_cur_sig = sig;
407     dkim_signing_domain = US sig->domain;
408     dkim_signing_selector = US sig->selector;
409     dkim_key_length = sig->keybits;
410
411     /* These two return static strings, so we can compare the addr
412     later to see if the ACL overwrote them.  Check that when logging */
413
414     dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
415     dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
416
417     if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
418       return rc;
419     }
420
421 if (rc != -1)
422   return rc;
423
424 /* No matching sig found.  Call ACL once anyway. */
425
426 dkim_cur_sig = NULL;
427 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
428 }
429
430
431 static uschar *
432 dkim_exim_expand_defaults(int what)
433 {
434 switch (what)
435   {
436   case DKIM_ALGO:               return US"";
437   case DKIM_BODYLENGTH:         return US"9999999999999";
438   case DKIM_CANON_BODY:         return US"";
439   case DKIM_CANON_HEADERS:      return US"";
440   case DKIM_COPIEDHEADERS:      return US"";
441   case DKIM_CREATED:            return US"0";
442   case DKIM_EXPIRES:            return US"9999999999999";
443   case DKIM_HEADERNAMES:        return US"";
444   case DKIM_IDENTITY:           return US"";
445   case DKIM_KEY_GRANULARITY:    return US"*";
446   case DKIM_KEY_SRVTYPE:        return US"*";
447   case DKIM_KEY_NOTES:          return US"";
448   case DKIM_KEY_TESTING:        return US"0";
449   case DKIM_NOSUBDOMAINS:       return US"0";
450   case DKIM_VERIFY_STATUS:      return US"none";
451   case DKIM_VERIFY_REASON:      return US"";
452   default:                      return US"";
453   }
454 }
455
456
457 uschar *
458 dkim_exim_expand_query(int what)
459 {
460 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
461   return dkim_exim_expand_defaults(what);
462
463 switch (what)
464   {
465   case DKIM_ALGO:
466     return dkim_sig_to_a_tag(dkim_cur_sig);
467
468   case DKIM_BODYLENGTH:
469     return dkim_cur_sig->bodylength >= 0
470       ? string_sprintf("%ld", dkim_cur_sig->bodylength)
471       : dkim_exim_expand_defaults(what);
472
473   case DKIM_CANON_BODY:
474     switch (dkim_cur_sig->canon_body)
475       {
476       case PDKIM_CANON_RELAXED: return US"relaxed";
477       case PDKIM_CANON_SIMPLE:
478       default:                  return US"simple";
479       }
480
481   case DKIM_CANON_HEADERS:
482     switch (dkim_cur_sig->canon_headers)
483       {
484       case PDKIM_CANON_RELAXED: return US"relaxed";
485       case PDKIM_CANON_SIMPLE:
486       default:                  return US"simple";
487       }
488
489   case DKIM_COPIEDHEADERS:
490     return dkim_cur_sig->copiedheaders
491       ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
492
493   case DKIM_CREATED:
494     return dkim_cur_sig->created > 0
495       ? string_sprintf("%lu", dkim_cur_sig->created)
496       : dkim_exim_expand_defaults(what);
497
498   case DKIM_EXPIRES:
499     return dkim_cur_sig->expires > 0
500       ? string_sprintf("%lu", dkim_cur_sig->expires)
501       : dkim_exim_expand_defaults(what);
502
503   case DKIM_HEADERNAMES:
504     return dkim_cur_sig->headernames
505       ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
506
507   case DKIM_IDENTITY:
508     return dkim_cur_sig->identity
509       ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
510
511   case DKIM_KEY_GRANULARITY:
512     return dkim_cur_sig->pubkey
513       ? dkim_cur_sig->pubkey->granularity
514       ? US dkim_cur_sig->pubkey->granularity
515       : dkim_exim_expand_defaults(what)
516       : dkim_exim_expand_defaults(what);
517
518   case DKIM_KEY_SRVTYPE:
519     return dkim_cur_sig->pubkey
520       ? dkim_cur_sig->pubkey->srvtype
521       ? US dkim_cur_sig->pubkey->srvtype
522       : dkim_exim_expand_defaults(what)
523       : dkim_exim_expand_defaults(what);
524
525   case DKIM_KEY_NOTES:
526     return dkim_cur_sig->pubkey
527       ? dkim_cur_sig->pubkey->notes
528       ? US dkim_cur_sig->pubkey->notes
529       : dkim_exim_expand_defaults(what)
530       : dkim_exim_expand_defaults(what);
531
532   case DKIM_KEY_TESTING:
533     return dkim_cur_sig->pubkey
534       ? dkim_cur_sig->pubkey->testing
535       ? US"1"
536       : dkim_exim_expand_defaults(what)
537       : dkim_exim_expand_defaults(what);
538
539   case DKIM_NOSUBDOMAINS:
540     return dkim_cur_sig->pubkey
541       ? dkim_cur_sig->pubkey->no_subdomaining
542       ? US"1"
543       : dkim_exim_expand_defaults(what)
544       : dkim_exim_expand_defaults(what);
545
546   case DKIM_VERIFY_STATUS:
547     switch (dkim_cur_sig->verify_status)
548       {
549       case PDKIM_VERIFY_INVALID:        return US"invalid";
550       case PDKIM_VERIFY_FAIL:           return US"fail";
551       case PDKIM_VERIFY_PASS:           return US"pass";
552       case PDKIM_VERIFY_NONE:
553       default:                          return US"none";
554       }
555
556   case DKIM_VERIFY_REASON:
557     switch (dkim_cur_sig->verify_ext_status)
558       {
559       case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
560                                                 return US"pubkey_unavailable";
561       case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
562       case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:  return US"pubkey_der_syntax";
563       case PDKIM_VERIFY_FAIL_BODY:              return US"bodyhash_mismatch";
564       case PDKIM_VERIFY_FAIL_MESSAGE:           return US"signature_incorrect";
565       }
566
567   default:
568     return US"";
569   }
570 }
571
572
573 void
574 dkim_exim_sign_init(void)
575 {
576 int old_pool = store_pool;
577
578 dkim_exim_init();
579 store_pool = POOL_MAIN;
580 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
581 store_pool = old_pool;
582 }
583
584
585 /* Generate signatures for the given file.
586 If a prefix is given, prepend it to the file for the calculations.
587
588 Return:
589   NULL:         error; error string written
590   string:       signature header(s), or a zero-length string (not an error)
591 */
592
593 gstring *
594 dkim_exim_sign(int fd, off_t off, uschar * prefix,
595   struct ob_dkim * dkim, const uschar ** errstr)
596 {
597 const uschar * dkim_domain = NULL;
598 int sep = 0;
599 gstring * seen_doms = NULL;
600 pdkim_signature * sig;
601 gstring * sigbuf;
602 int pdkim_rc;
603 int sread;
604 uschar buf[4096];
605 int save_errno = 0;
606 int old_pool = store_pool;
607 uschar * errwhen;
608 const uschar * s;
609
610 if (dkim->dot_stuffed)
611   dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
612
613 store_pool = POOL_MAIN;
614
615 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
616   /* expansion error, do not send message. */
617   { errwhen = US"dkim_domain"; goto expand_bad; }
618
619 /* Set $dkim_domain expansion variable to each unique domain in list. */
620
621 if (dkim_domain)
622   while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
623   {
624   const uschar * dkim_sel;
625   int sel_sep = 0;
626
627   if (dkim_signing_domain[0] == '\0')
628     continue;
629
630   /* Only sign once for each domain, no matter how often it
631   appears in the expanded list. */
632
633   dkim_signing_domain = string_copylc(dkim_signing_domain);
634   if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
635       0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
636     continue;
637
638   seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
639
640   /* Set $dkim_selector expansion variable to each selector in list,
641   for this domain. */
642
643   if (!(dkim_sel = expand_string(dkim->dkim_selector)))
644     { errwhen = US"dkim_selector"; goto expand_bad; }
645
646   while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
647           NULL, 0)))
648     {
649     uschar * dkim_canon_expanded;
650     int pdkim_canon;
651     uschar * dkim_sign_headers_expanded = NULL;
652     uschar * dkim_private_key_expanded;
653     uschar * dkim_hash_expanded;
654     uschar * dkim_identity_expanded = NULL;
655     uschar * dkim_timestamps_expanded = NULL;
656     unsigned long tval = 0, xval = 0;
657
658     /* Get canonicalization to use */
659
660     dkim_canon_expanded = dkim->dkim_canon
661       ? expand_string(dkim->dkim_canon) : US"relaxed";
662     if (!dkim_canon_expanded)   /* expansion error, do not send message. */
663       { errwhen = US"dkim_canon"; goto expand_bad; }
664
665     if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
666       pdkim_canon = PDKIM_CANON_RELAXED;
667     else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
668       pdkim_canon = PDKIM_CANON_SIMPLE;
669     else
670       {
671       log_write(0, LOG_MAIN,
672                  "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
673                  dkim_canon_expanded);
674       pdkim_canon = PDKIM_CANON_RELAXED;
675       }
676
677     if (  dkim->dkim_sign_headers
678        && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
679       { errwhen = US"dkim_sign_header"; goto expand_bad; }
680     /* else pass NULL, which means default header list */
681
682     /* Get private key to use. */
683
684     if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
685       { errwhen = US"dkim_private_key"; goto expand_bad; }
686
687     if (  Ustrlen(dkim_private_key_expanded) == 0
688        || Ustrcmp(dkim_private_key_expanded, "0") == 0
689        || Ustrcmp(dkim_private_key_expanded, "false") == 0
690        )
691       continue;         /* don't sign, but no error */
692
693     if (  dkim_private_key_expanded[0] == '/'
694        && !(dkim_private_key_expanded =
695              expand_file_big_buffer(dkim_private_key_expanded)))
696       goto bad;
697
698     if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
699       { errwhen = US"dkim_hash"; goto expand_bad; }
700
701     if (dkim->dkim_identity)
702       if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
703         { errwhen = US"dkim_identity"; goto expand_bad; }
704       else if (!*dkim_identity_expanded)
705         dkim_identity_expanded = NULL;
706
707     if (dkim->dkim_timestamps)
708       if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
709         { errwhen = US"dkim_timestamps"; goto expand_bad; }
710       else
711         xval = (tval = (unsigned long) time(NULL))
712               + strtoul(CCS dkim_timestamps_expanded, NULL, 10);
713
714     if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
715                           dkim_signing_selector,
716                           dkim_private_key_expanded,
717                           dkim_hash_expanded,
718                           errstr
719                           )))
720       goto bad;
721     dkim_private_key_expanded[0] = '\0';
722
723     pdkim_set_optional(sig,
724                         CS dkim_sign_headers_expanded,
725                         CS dkim_identity_expanded,
726                         pdkim_canon,
727                         pdkim_canon, -1, tval, xval);
728
729     if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
730       goto bad;
731
732     if (!dkim_sign_ctx.sig)             /* link sig to context chain */
733       dkim_sign_ctx.sig = sig;
734     else
735       {
736       pdkim_signature * n = dkim_sign_ctx.sig;
737       while (n->next) n = n->next;
738       n->next = sig;
739       }
740     }
741   }
742
743 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
744 produce, if some other package (eg. ARC) is signing. */
745
746 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
747   {
748   DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
749   sigbuf = string_get(1);       /* return a zero-len string */
750   }
751 else
752   {
753   if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
754     goto pk_bad;
755
756   if (lseek(fd, off, SEEK_SET) < 0)
757     sread = -1;
758   else
759     while ((sread = read(fd, &buf, sizeof(buf))) > 0)
760       if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
761         goto pk_bad;
762
763   /* Handle failed read above. */
764   if (sread == -1)
765     {
766     debug_printf("DKIM: Error reading -K file.\n");
767     save_errno = errno;
768     goto bad;
769     }
770
771   /* Build string of headers, one per signature */
772
773   if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
774     goto pk_bad;
775
776   if (!sig)
777     {
778     DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
779     sigbuf = string_get(1);     /* return a zero-len string */
780     }
781   else for (sigbuf = NULL; sig; sig = sig->next)
782     sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
783   }
784
785 CLEANUP:
786   (void) string_from_gstring(sigbuf);
787   store_pool = old_pool;
788   errno = save_errno;
789   return sigbuf;
790
791 pk_bad:
792   log_write(0, LOG_MAIN|LOG_PANIC,
793                 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
794 bad:
795   sigbuf = NULL;
796   goto CLEANUP;
797
798 expand_bad:
799   *errstr = string_sprintf("failed to expand %s: %s",
800               errwhen, expand_string_message);
801   log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
802   goto bad;
803 }
804
805
806
807
808 gstring *
809 authres_dkim(gstring * g)
810 {
811 int start = 0;          /* compiler quietening */
812
813 DEBUG(D_acl) start = g->ptr;
814
815 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
816   {
817   g = string_catn(g, US";\n\tdkim=", 8);
818
819   if (sig->verify_status & PDKIM_VERIFY_POLICY)
820     g = string_append(g, 5,
821       US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
822   else switch(sig->verify_status)
823     {
824     case PDKIM_VERIFY_NONE:    g = string_cat(g, US"none"); break;
825     case PDKIM_VERIFY_INVALID:
826       switch (sig->verify_ext_status)
827         {
828         case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
829           g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
830         case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
831           g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
832         case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
833         case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
834           g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
835           break;
836         case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
837           g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
838           break;
839         case PDKIM_VERIFY_INVALID_DKIM_VERSION:
840           g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
841           break;
842         default:
843           g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
844         }
845       break;
846     case PDKIM_VERIFY_FAIL:
847       switch (sig->verify_ext_status)
848         {
849         case PDKIM_VERIFY_FAIL_BODY:
850           g = string_cat(g,
851             US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
852           break;
853         case PDKIM_VERIFY_FAIL_MESSAGE:
854           g = string_cat(g,
855             US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
856           break;
857         default:
858           g = string_cat(g, US"fail (unspecified reason)\n\t\t");
859           break;
860         }
861       break;
862     case PDKIM_VERIFY_PASS:    g = string_cat(g, US"pass"); break;
863     default:                   g = string_cat(g, US"permerror"); break;
864     }
865   if (sig->domain)   g = string_append(g, 2, US" header.d=", sig->domain);
866   if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
867   if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
868   g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
869   }
870
871 DEBUG(D_acl)
872   if (g->ptr == start)
873     debug_printf("DKIM: no authres\n");
874   else
875     debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
876 return g;
877 }
878
879
880 # endif /*!MACRO_PREDEF*/
881 #endif  /*!DISABLE_DKIM*/