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