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