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