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