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