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