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