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