debug: prettify expansion condition trace output
[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,
07eeb4df 151 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
152 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
153 sig->algo == PDKIM_ALGO_RSA_SHA256
154 ? "rsa-sha256"
155 : sig->algo == PDKIM_ALGO_RSA_SHA1 ? "rsa-sha1" : "err",
156 (int)sig->sigdata.len > -1 ? sig->sigdata.len * 8 : 0
abe1010c 157 ),
1cfe5c1c
JH
158
159 sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
160 sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
161 sig->expires > 0 ? string_sprintf("x=%lu ", sig->expires) : US"",
162 sig->bodylength > -1 ? string_sprintf("l=%lu ", sig->bodylength) : US""
163 );
164
165 switch (sig->verify_status)
166 {
167 case PDKIM_VERIFY_NONE:
168 logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
80a47a2c 169 break;
1cfe5c1c
JH
170
171 case PDKIM_VERIFY_INVALID:
172 logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
173 switch (sig->verify_ext_status)
174 {
175 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
176 logmsg = string_append(logmsg, &size, &ptr, 1,
177 "public key record (currently?) unavailable]");
178 break;
179
180 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
181 logmsg = string_append(logmsg, &size, &ptr, 1,
182 "overlong public key record]");
183 break;
184
df3def24
JH
185 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
186 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
1cfe5c1c
JH
187 logmsg = string_append(logmsg, &size, &ptr, 1,
188 "syntax error in public key record]");
189 break;
07eeb4df 190
191 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
192 logmsg = string_append(logmsg, &size, &ptr, 1,
193 "signature tag missing or invalid]");
194 break;
195
196 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
197 logmsg = string_append(logmsg, &size, &ptr, 1,
198 "unsupported DKIM version]");
199 break;
1cfe5c1c
JH
200
201 default:
202 logmsg = string_append(logmsg, &size, &ptr, 1,
203 "unspecified problem]");
204 }
80a47a2c 205 break;
1cfe5c1c
JH
206
207 case PDKIM_VERIFY_FAIL:
208 logmsg =
209 string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
210 switch (sig->verify_ext_status)
211 {
212 case PDKIM_VERIFY_FAIL_BODY:
213 logmsg = string_append(logmsg, &size, &ptr, 1,
214 "body hash mismatch (body probably modified in transit)]");
215 break;
216
217 case PDKIM_VERIFY_FAIL_MESSAGE:
218 logmsg = string_append(logmsg, &size, &ptr, 1,
219 "signature did not verify (headers probably modified in transit)]");
220 break;
221
222 default:
223 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
224 }
80a47a2c 225 break;
1cfe5c1c
JH
226
227 case PDKIM_VERIFY_PASS:
228 logmsg =
229 string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
80a47a2c
TK
230 break;
231 }
232
1cfe5c1c
JH
233 logmsg[ptr] = '\0';
234 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
80a47a2c 235
1cfe5c1c
JH
236 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
237
238 dkim_signers = string_append(dkim_signers,
239 &dkim_signers_size,
240 &dkim_signers_ptr, 2, sig->domain, ":");
241
242 if (sig->identity)
9e5d6b55 243 dkim_signers = string_append(dkim_signers,
1cfe5c1c
JH
244 &dkim_signers_size,
245 &dkim_signers_ptr, 2, sig->identity, ":");
80a47a2c 246
1cfe5c1c 247 /* Process next signature */
80a47a2c
TK
248 }
249
1cfe5c1c
JH
250/* NULL-terminate and chop the last colon from the domain list */
251
252if (dkim_signers)
253 {
254 dkim_signers[dkim_signers_ptr] = '\0';
255 if (Ustrlen(dkim_signers) > 0)
256 dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
0d2b278d 257 }
ca9cb170
JH
258
259out:
260store_pool = dkim_verify_oldpool;
80a47a2c
TK
261}
262
263
1cfe5c1c
JH
264void
265dkim_exim_acl_setup(uschar * id)
266{
267pdkim_signature * sig;
268uschar * cmp_val;
269
1cfe5c1c
JH
270dkim_cur_sig = NULL;
271dkim_cur_signer = id;
272
273if (dkim_disable_verify || !id || !dkim_verify_ctx)
274 return;
275
276/* Find signature to run ACL on */
277
278for (sig = dkim_signatures; sig; sig = sig->next)
279 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
280 && strcmpic(cmp_val, id) == 0
281 )
282 {
283 dkim_cur_sig = sig;
284
285 /* The "dkim_domain" and "dkim_selector" expansion variables have
286 related globals, since they are used in the signing code too.
287 Instead of inventing separate names for verification, we set
288 them here. This is easy since a domain and selector is guaranteed
289 to be in a signature. The other dkim_* expansion items are
290 dynamically fetched from dkim_cur_sig at expansion time (see
291 function below). */
292
293 dkim_signing_domain = US sig->domain;
294 dkim_signing_selector = US sig->selector;
2592e6c0 295 dkim_key_length = sig->sigdata.len * 8;
1cfe5c1c 296 return;
80a47a2c 297 }
80a47a2c
TK
298}
299
300
1cfe5c1c
JH
301static uschar *
302dkim_exim_expand_defaults(int what)
303{
304switch (what)
305 {
306 case DKIM_ALGO: return US"";
307 case DKIM_BODYLENGTH: return US"9999999999999";
308 case DKIM_CANON_BODY: return US"";
309 case DKIM_CANON_HEADERS: return US"";
310 case DKIM_COPIEDHEADERS: return US"";
311 case DKIM_CREATED: return US"0";
312 case DKIM_EXPIRES: return US"9999999999999";
313 case DKIM_HEADERNAMES: return US"";
314 case DKIM_IDENTITY: return US"";
315 case DKIM_KEY_GRANULARITY: return US"*";
316 case DKIM_KEY_SRVTYPE: return US"*";
317 case DKIM_KEY_NOTES: return US"";
318 case DKIM_KEY_TESTING: return US"0";
319 case DKIM_NOSUBDOMAINS: return US"0";
320 case DKIM_VERIFY_STATUS: return US"none";
321 case DKIM_VERIFY_REASON: return US"";
322 default: return US"";
323 }
324}
80a47a2c 325
80a47a2c 326
1cfe5c1c
JH
327uschar *
328dkim_exim_expand_query(int what)
329{
330if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
331 return dkim_exim_expand_defaults(what);
332
333switch (what)
334 {
335 case DKIM_ALGO:
336 switch (dkim_cur_sig->algo)
337 {
338 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
339 case PDKIM_ALGO_RSA_SHA256:
340 default: return US"rsa-sha256";
da5dfc3a 341 }
1cfe5c1c
JH
342
343 case DKIM_BODYLENGTH:
344 return dkim_cur_sig->bodylength >= 0
345 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
346 : dkim_exim_expand_defaults(what);
347
348 case DKIM_CANON_BODY:
349 switch (dkim_cur_sig->canon_body)
350 {
351 case PDKIM_CANON_RELAXED: return US"relaxed";
352 case PDKIM_CANON_SIMPLE:
353 default: return US"simple";
80a47a2c 354 }
1cfe5c1c
JH
355
356 case DKIM_CANON_HEADERS:
357 switch (dkim_cur_sig->canon_headers)
358 {
359 case PDKIM_CANON_RELAXED: return US"relaxed";
360 case PDKIM_CANON_SIMPLE:
361 default: return US"simple";
362 }
363
364 case DKIM_COPIEDHEADERS:
365 return dkim_cur_sig->copiedheaders
366 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
367
368 case DKIM_CREATED:
369 return dkim_cur_sig->created > 0
370 ? string_sprintf("%llu", dkim_cur_sig->created)
371 : dkim_exim_expand_defaults(what);
372
373 case DKIM_EXPIRES:
374 return dkim_cur_sig->expires > 0
375 ? string_sprintf("%llu", dkim_cur_sig->expires)
376 : dkim_exim_expand_defaults(what);
377
378 case DKIM_HEADERNAMES:
379 return dkim_cur_sig->headernames
2592e6c0 380 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
1cfe5c1c
JH
381
382 case DKIM_IDENTITY:
383 return dkim_cur_sig->identity
384 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
385
386 case DKIM_KEY_GRANULARITY:
387 return dkim_cur_sig->pubkey
388 ? dkim_cur_sig->pubkey->granularity
389 ? US dkim_cur_sig->pubkey->granularity
390 : dkim_exim_expand_defaults(what)
391 : dkim_exim_expand_defaults(what);
392
393 case DKIM_KEY_SRVTYPE:
394 return dkim_cur_sig->pubkey
395 ? dkim_cur_sig->pubkey->srvtype
396 ? US dkim_cur_sig->pubkey->srvtype
397 : dkim_exim_expand_defaults(what)
398 : dkim_exim_expand_defaults(what);
399
400 case DKIM_KEY_NOTES:
401 return dkim_cur_sig->pubkey
402 ? dkim_cur_sig->pubkey->notes
403 ? US dkim_cur_sig->pubkey->notes
404 : dkim_exim_expand_defaults(what)
405 : dkim_exim_expand_defaults(what);
406
407 case DKIM_KEY_TESTING:
408 return dkim_cur_sig->pubkey
409 ? dkim_cur_sig->pubkey->testing
410 ? US"1"
411 : dkim_exim_expand_defaults(what)
412 : dkim_exim_expand_defaults(what);
413
414 case DKIM_NOSUBDOMAINS:
415 return dkim_cur_sig->pubkey
416 ? dkim_cur_sig->pubkey->no_subdomaining
417 ? US"1"
418 : dkim_exim_expand_defaults(what)
419 : dkim_exim_expand_defaults(what);
420
421 case DKIM_VERIFY_STATUS:
422 switch (dkim_cur_sig->verify_status)
423 {
424 case PDKIM_VERIFY_INVALID: return US"invalid";
425 case PDKIM_VERIFY_FAIL: return US"fail";
426 case PDKIM_VERIFY_PASS: return US"pass";
427 case PDKIM_VERIFY_NONE:
428 default: return US"none";
80a47a2c 429 }
80a47a2c 430
1cfe5c1c
JH
431 case DKIM_VERIFY_REASON:
432 switch (dkim_cur_sig->verify_ext_status)
433 {
434 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
435 return US"pubkey_unavailable";
df3def24
JH
436 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
437 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
1cfe5c1c
JH
438 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
439 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
440 }
80a47a2c 441
1cfe5c1c
JH
442 default:
443 return US"";
80a47a2c
TK
444 }
445}
446
447
55414b25 448uschar *
1cfe5c1c
JH
449dkim_exim_sign(int dkim_fd, uschar * dkim_private_key,
450 const uschar * dkim_domain, uschar * dkim_selector,
451 uschar * dkim_canon, uschar * dkim_sign_headers)
55414b25 452{
1cfe5c1c
JH
453int sep = 0;
454uschar *seen_items = NULL;
455int seen_items_size = 0;
456int seen_items_offset = 0;
457uschar itembuf[256];
458uschar *dkim_canon_expanded;
459uschar *dkim_sign_headers_expanded;
460uschar *dkim_private_key_expanded;
461pdkim_ctx *ctx = NULL;
462uschar *rc = NULL;
463uschar *sigbuf = NULL;
464int sigsize = 0;
465int sigptr = 0;
466pdkim_signature *signature;
467int pdkim_canon;
468int pdkim_rc;
469int sread;
470char buf[4096];
471int save_errno = 0;
472int old_pool = store_pool;
473
474store_pool = POOL_MAIN;
475
476if (!(dkim_domain = expand_cstring(dkim_domain)))
477 {
478 /* expansion error, do not send message. */
479 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
480 "dkim_domain: %s", expand_string_message);
481 rc = NULL;
482 goto CLEANUP;
483 }
484
485/* Set $dkim_domain expansion variable to each unique domain in list. */
486
487while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
488 itembuf, sizeof(itembuf))))
489 {
490 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
491 continue;
492
493 /* Only sign once for each domain, no matter how often it
494 appears in the expanded list. */
495
496 if (seen_items)
497 {
498 const uschar *seen_items_list = seen_items;
499 if (match_isinlist(dkim_signing_domain,
500 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
501 NULL) == OK)
502 continue;
503
504 seen_items =
505 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
506 }
507
508 seen_items =
509 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
510 dkim_signing_domain);
511 seen_items[seen_items_offset] = '\0';
512
513 /* Set up $dkim_selector expansion variable. */
514
515 if (!(dkim_signing_selector = expand_string(dkim_selector)))
516 {
517 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
518 "dkim_selector: %s", expand_string_message);
519 rc = NULL;
520 goto CLEANUP;
521 }
522
523 /* Get canonicalization to use */
524
525 dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
526 if (!dkim_canon_expanded)
527 {
80a47a2c 528 /* expansion error, do not send message. */
1cfe5c1c
JH
529 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
530 "dkim_canon: %s", expand_string_message);
80a47a2c
TK
531 rc = NULL;
532 goto CLEANUP;
1cfe5c1c 533 }
80a47a2c 534
1cfe5c1c
JH
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;
a8e1eeba 545 }
1cfe5c1c
JH
546
547 dkim_sign_headers_expanded = NULL;
548 if (dkim_sign_headers)
549 if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
550 {
551 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
552 "dkim_sign_headers: %s", expand_string_message);
a8e1eeba
MH
553 rc = NULL;
554 goto CLEANUP;
1cfe5c1c
JH
555 }
556 /* else pass NULL, which means default header list */
557
558 /* Get private key to use. */
559
560 if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
561 {
562 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
563 "dkim_private_key: %s", expand_string_message);
564 rc = NULL;
565 goto CLEANUP;
a8e1eeba 566 }
80a47a2c 567
1cfe5c1c
JH
568 if ( Ustrlen(dkim_private_key_expanded) == 0
569 || Ustrcmp(dkim_private_key_expanded, "0") == 0
570 || Ustrcmp(dkim_private_key_expanded, "false") == 0
571 )
572 continue; /* don't sign, but no error */
573
574 if (dkim_private_key_expanded[0] == '/')
575 {
576 int privkey_fd = 0;
577
578 /* Looks like a filename, load the private key. */
579
580 memset(big_buffer, 0, big_buffer_size);
581 privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
582 if (privkey_fd < 0)
583 {
584 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
585 "private key file for reading: %s",
586 dkim_private_key_expanded);
80a47a2c
TK
587 rc = NULL;
588 goto CLEANUP;
db4d0902 589 }
80a47a2c 590
1cfe5c1c
JH
591 if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
592 {
593 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
594 dkim_private_key_expanded);
cf745305
TK
595 rc = NULL;
596 goto CLEANUP;
1ac6b2e7 597 }
80a47a2c 598
1cfe5c1c
JH
599 (void) close(privkey_fd);
600 dkim_private_key_expanded = big_buffer;
a8e1eeba 601 }
1cfe5c1c 602
0d04a285 603 ctx = pdkim_init_sign( (char *) dkim_signing_domain,
1cfe5c1c 604 (char *) dkim_signing_selector,
f444c2c7
JH
605 (char *) dkim_private_key_expanded,
606 PDKIM_ALGO_RSA_SHA256);
1cfe5c1c
JH
607 pdkim_set_optional(ctx,
608 (char *) dkim_sign_headers_expanded,
609 NULL,
610 pdkim_canon,
f444c2c7 611 pdkim_canon, -1, 0, 0);
1cfe5c1c
JH
612
613 lseek(dkim_fd, 0, SEEK_SET);
614
615 while ((sread = read(dkim_fd, &buf, 4096)) > 0)
616 if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
617 {
80a47a2c
TK
618 rc = NULL;
619 goto CLEANUP;
1cfe5c1c
JH
620 }
621
622 /* Handle failed read above. */
623 if (sread == -1)
624 {
625 debug_printf("DKIM: Error reading -K file.\n");
626 save_errno = errno;
627 rc = NULL;
628 goto CLEANUP;
80a47a2c 629 }
80a47a2c 630
1cfe5c1c
JH
631 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
632 {
633 log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
634 rc = NULL;
635 goto CLEANUP;
a8e1eeba 636 }
80a47a2c 637
1cfe5c1c
JH
638 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
639 US signature->signature_header, US"\r\n");
80a47a2c 640
1cfe5c1c
JH
641 pdkim_free_ctx(ctx);
642 ctx = NULL;
80a47a2c 643 }
a8e1eeba 644
1cfe5c1c
JH
645if (sigbuf)
646 {
647 sigbuf[sigptr] = '\0';
648 rc = sigbuf;
649 }
650else
651 rc = US"";
652
653CLEANUP:
654if (ctx)
655 pdkim_free_ctx(ctx);
656store_pool = old_pool;
657errno = save_errno;
658return rc;
93f2d376 659}
80a47a2c
TK
660
661#endif