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