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