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