Configure the default opendmarc.tlds file in EDITME
[exim.git] / src / src / dkim.c
CommitLineData
80a47a2c
TK
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
d4e5e70b 5/* Copyright (c) University of Cambridge, 1995 - 2017 */
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;
b9df1829 21static const uschar * dkim_collect_error = NULL;
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;
b9df1829 91dkim_collect_error = NULL;
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 108 {
b9df1829 109 dkim_collect_error = pdkim_errstr(rc);
f7302073 110 log_write(0, LOG_MAIN,
b9df1829 111 "DKIM: validation error: %.100s", dkim_collect_error);
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{
41468ba1 121pdkim_signature * sig = NULL;
b9df1829
JH
122int dkim_signers_size = 0, dkim_signers_ptr = 0, rc;
123const uschar * errstr;
1cfe5c1c 124
ca9cb170
JH
125store_pool = POOL_PERM;
126
1cfe5c1c
JH
127/* Delete eventual previous signature chain */
128
41468ba1 129dkim_signers = NULL;
1cfe5c1c
JH
130dkim_signatures = NULL;
131
bd8fbe36 132if (dkim_collect_error)
1cfe5c1c
JH
133 {
134 log_write(0, LOG_MAIN,
b9df1829
JH
135 "DKIM: Error during validation, disabling signature verification: %.100s",
136 dkim_collect_error);
1cfe5c1c 137 dkim_disable_verify = TRUE;
ca9cb170 138 goto out;
1cfe5c1c 139 }
80a47a2c 140
1cfe5c1c 141dkim_collect_input = FALSE;
80a47a2c 142
1cfe5c1c 143/* Finish DKIM operation and fetch link to signatures chain */
80a47a2c 144
b9df1829
JH
145rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
146if (rc != PDKIM_OK)
f7302073 147 {
b9df1829
JH
148 log_write(0, LOG_MAIN, "DKIM: validation error: %.100s%s%s", pdkim_errstr(rc),
149 errstr ? ": " : "", errstr ? errstr : US"");
ca9cb170 150 goto out;
f7302073 151 }
1cfe5c1c
JH
152
153for (sig = dkim_signatures; sig; sig = sig->next)
154 {
41468ba1
JH
155 int size = 0, ptr = 0;
156 uschar * logmsg = NULL, * s;
1cfe5c1c
JH
157
158 /* Log a line for each signature */
159
41468ba1
JH
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));
31323b30
HSHR
172 if ((s= sig->identity)) logmsg = string_append(logmsg, &size, &ptr, 2, " i=", s);
173 if (sig->created > 0) logmsg = string_append(logmsg, &size, &ptr, 1,
41468ba1 174 string_sprintf(" t=%lu", sig->created));
31323b30 175 if (sig->expires > 0) logmsg = string_append(logmsg, &size, &ptr, 1,
41468ba1 176 string_sprintf(" x=%lu", sig->expires));
31323b30 177 if (sig->bodylength > -1) logmsg = string_append(logmsg, &size, &ptr, 1,
41468ba1 178 string_sprintf(" l=%lu", sig->bodylength));
1cfe5c1c
JH
179
180 switch (sig->verify_status)
181 {
182 case PDKIM_VERIFY_NONE:
41468ba1 183 logmsg = string_append(logmsg, &size, &ptr, 1, " [not verified]");
80a47a2c 184 break;
1cfe5c1c
JH
185
186 case PDKIM_VERIFY_INVALID:
41468ba1 187 logmsg = string_append(logmsg, &size, &ptr, 1, " [invalid - ");
1cfe5c1c
JH
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
df3def24
JH
200 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
201 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
1cfe5c1c
JH
202 logmsg = string_append(logmsg, &size, &ptr, 1,
203 "syntax error in public key record]");
204 break;
07eeb4df 205
206 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
207 logmsg = string_append(logmsg, &size, &ptr, 1,
208 "signature tag missing or invalid]");
209 break;
210
211 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
212 logmsg = string_append(logmsg, &size, &ptr, 1,
213 "unsupported DKIM version]");
214 break;
1cfe5c1c
JH
215
216 default:
217 logmsg = string_append(logmsg, &size, &ptr, 1,
218 "unspecified problem]");
219 }
80a47a2c 220 break;
1cfe5c1c
JH
221
222 case PDKIM_VERIFY_FAIL:
223 logmsg =
41468ba1 224 string_append(logmsg, &size, &ptr, 1, " [verification failed - ");
1cfe5c1c
JH
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 }
80a47a2c 240 break;
1cfe5c1c
JH
241
242 case PDKIM_VERIFY_PASS:
243 logmsg =
41468ba1 244 string_append(logmsg, &size, &ptr, 1, " [verification succeeded]");
80a47a2c
TK
245 break;
246 }
247
1cfe5c1c
JH
248 logmsg[ptr] = '\0';
249 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
80a47a2c 250
1cfe5c1c
JH
251 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
252
41468ba1
JH
253 if (sig->domain)
254 dkim_signers = string_append_listele(dkim_signers, ':', sig->domain);
1cfe5c1c
JH
255
256 if (sig->identity)
41468ba1 257 dkim_signers = string_append_listele(dkim_signers, ':', sig->identity);
80a47a2c 258
1cfe5c1c 259 /* Process next signature */
80a47a2c
TK
260 }
261
ca9cb170
JH
262out:
263store_pool = dkim_verify_oldpool;
80a47a2c
TK
264}
265
266
1cfe5c1c
JH
267void
268dkim_exim_acl_setup(uschar * id)
269{
270pdkim_signature * sig;
271uschar * cmp_val;
272
1cfe5c1c
JH
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;
dcd03763 298 dkim_key_length = sig->sighash.len * 8;
1cfe5c1c 299 return;
80a47a2c 300 }
80a47a2c
TK
301}
302
303
1cfe5c1c
JH
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}
80a47a2c 328
80a47a2c 329
1cfe5c1c
JH
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";
da5dfc3a 344 }
1cfe5c1c
JH
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";
80a47a2c 357 }
1cfe5c1c
JH
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
2592e6c0 383 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
1cfe5c1c
JH
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";
80a47a2c 432 }
80a47a2c 433
1cfe5c1c
JH
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";
df3def24
JH
439 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
440 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
1cfe5c1c
JH
441 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
442 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
443 }
80a47a2c 444
1cfe5c1c
JH
445 default:
446 return US"";
80a47a2c
TK
447 }
448}
449
450
42055a33
JH
451/* Generate signatures for the given file, returning a string.
452If a prefix is given, prepend it to the file for the calculations.
453*/
454
55414b25 455uschar *
42055a33
JH
456dkim_exim_sign(int fd, off_t off, uschar * prefix,
457 struct ob_dkim * dkim, const uschar ** errstr)
55414b25 458{
e983e85a 459const uschar * dkim_domain;
1cfe5c1c
JH
460int sep = 0;
461uschar *seen_items = NULL;
462int seen_items_size = 0;
463int seen_items_offset = 0;
1cfe5c1c
JH
464uschar *dkim_canon_expanded;
465uschar *dkim_sign_headers_expanded;
466uschar *dkim_private_key_expanded;
467pdkim_ctx *ctx = NULL;
468uschar *rc = NULL;
469uschar *sigbuf = NULL;
470int sigsize = 0;
471int sigptr = 0;
472pdkim_signature *signature;
473int pdkim_canon;
474int pdkim_rc;
475int sread;
476char buf[4096];
477int save_errno = 0;
478int old_pool = store_pool;
479
480store_pool = POOL_MAIN;
481
e983e85a 482if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
1cfe5c1c
JH
483 {
484 /* expansion error, do not send message. */
485 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
486 "dkim_domain: %s", expand_string_message);
f7302073 487 goto bad;
1cfe5c1c
JH
488 }
489
490/* Set $dkim_domain expansion variable to each unique domain in list. */
491
42055a33 492while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
1cfe5c1c 493 {
42055a33 494 if (dkim_signing_domain[0] == '\0')
1cfe5c1c
JH
495 continue;
496
497 /* Only sign once for each domain, no matter how often it
498 appears in the expanded list. */
499
500 if (seen_items)
501 {
502 const uschar *seen_items_list = seen_items;
503 if (match_isinlist(dkim_signing_domain,
504 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
505 NULL) == OK)
506 continue;
507
508 seen_items =
509 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
510 }
511
512 seen_items =
513 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
514 dkim_signing_domain);
515 seen_items[seen_items_offset] = '\0';
516
517 /* Set up $dkim_selector expansion variable. */
518
e983e85a 519 if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
1cfe5c1c
JH
520 {
521 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
522 "dkim_selector: %s", expand_string_message);
f7302073 523 goto bad;
1cfe5c1c
JH
524 }
525
526 /* Get canonicalization to use */
527
e983e85a
JH
528 dkim_canon_expanded = dkim->dkim_canon
529 ? expand_string(dkim->dkim_canon) : US"relaxed";
1cfe5c1c
JH
530 if (!dkim_canon_expanded)
531 {
80a47a2c 532 /* expansion error, do not send message. */
1cfe5c1c
JH
533 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
534 "dkim_canon: %s", expand_string_message);
f7302073 535 goto bad;
1cfe5c1c 536 }
80a47a2c 537
1cfe5c1c
JH
538 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
539 pdkim_canon = PDKIM_CANON_RELAXED;
540 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
541 pdkim_canon = PDKIM_CANON_SIMPLE;
542 else
543 {
544 log_write(0, LOG_MAIN,
545 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
546 dkim_canon_expanded);
547 pdkim_canon = PDKIM_CANON_RELAXED;
a8e1eeba 548 }
1cfe5c1c
JH
549
550 dkim_sign_headers_expanded = NULL;
e983e85a
JH
551 if (dkim->dkim_sign_headers)
552 if (!(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
1cfe5c1c
JH
553 {
554 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
555 "dkim_sign_headers: %s", expand_string_message);
f7302073 556 goto bad;
1cfe5c1c
JH
557 }
558 /* else pass NULL, which means default header list */
559
560 /* Get private key to use. */
561
e983e85a 562 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
1cfe5c1c
JH
563 {
564 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
565 "dkim_private_key: %s", expand_string_message);
f7302073 566 goto bad;
a8e1eeba 567 }
80a47a2c 568
1cfe5c1c
JH
569 if ( Ustrlen(dkim_private_key_expanded) == 0
570 || Ustrcmp(dkim_private_key_expanded, "0") == 0
571 || Ustrcmp(dkim_private_key_expanded, "false") == 0
572 )
573 continue; /* don't sign, but no error */
574
575 if (dkim_private_key_expanded[0] == '/')
576 {
59d98039 577 int privkey_fd, off = 0, len;
1cfe5c1c
JH
578
579 /* Looks like a filename, load the private key. */
580
581 memset(big_buffer, 0, big_buffer_size);
e983e85a
JH
582
583 if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
1cfe5c1c
JH
584 {
585 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
586 "private key file for reading: %s",
587 dkim_private_key_expanded);
f7302073 588 goto bad;
db4d0902 589 }
80a47a2c 590
59d98039 591 do
1cfe5c1c 592 {
59d98039
JH
593 if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
594 {
595 (void) close(privkey_fd);
596 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
597 dkim_private_key_expanded);
598 goto bad;
599 }
600 off += len;
1ac6b2e7 601 }
59d98039 602 while (len > 0);
80a47a2c 603
1cfe5c1c 604 (void) close(privkey_fd);
59d98039 605 big_buffer[off] = '\0';
1cfe5c1c 606 dkim_private_key_expanded = big_buffer;
a8e1eeba 607 }
1cfe5c1c 608
b9df1829 609 if (!(ctx = pdkim_init_sign(CS dkim_signing_domain,
cd1a5fe0
JH
610 CS dkim_signing_selector,
611 CS dkim_private_key_expanded,
612 PDKIM_ALGO_RSA_SHA256,
613 dkim->dot_stuffed,
b9df1829
JH
614 &dkim_exim_query_dns_txt,
615 errstr
616 )))
617 goto bad;
87cb4a16 618 dkim_private_key_expanded[0] = '\0';
1cfe5c1c 619 pdkim_set_optional(ctx,
e983e85a 620 CS dkim_sign_headers_expanded,
1cfe5c1c
JH
621 NULL,
622 pdkim_canon,
f444c2c7 623 pdkim_canon, -1, 0, 0);
1cfe5c1c 624
42055a33
JH
625 if (prefix)
626 pdkim_feed(ctx, prefix, Ustrlen(prefix));
627
d315eda1
JH
628 if (lseek(fd, off, SEEK_SET) < 0)
629 sread = -1;
630 else
631 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
632 if ((pdkim_rc = pdkim_feed(ctx, buf, sread)) != PDKIM_OK)
633 goto pk_bad;
1cfe5c1c
JH
634
635 /* Handle failed read above. */
636 if (sread == -1)
637 {
638 debug_printf("DKIM: Error reading -K file.\n");
639 save_errno = errno;
f7302073 640 goto bad;
80a47a2c 641 }
80a47a2c 642
b9df1829 643 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature, errstr)) != PDKIM_OK)
f7302073 644 goto pk_bad;
80a47a2c 645
1cfe5c1c
JH
646 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
647 US signature->signature_header, US"\r\n");
80a47a2c 648
1cfe5c1c
JH
649 pdkim_free_ctx(ctx);
650 ctx = NULL;
80a47a2c 651 }
a8e1eeba 652
1cfe5c1c
JH
653if (sigbuf)
654 {
655 sigbuf[sigptr] = '\0';
656 rc = sigbuf;
657 }
658else
659 rc = US"";
660
661CLEANUP:
f7302073
JH
662 if (ctx)
663 pdkim_free_ctx(ctx);
664 store_pool = old_pool;
665 errno = save_errno;
666 return rc;
667
668pk_bad:
669 log_write(0, LOG_MAIN|LOG_PANIC,
670 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
671bad:
672 rc = NULL;
673 goto CLEANUP;
93f2d376 674}
80a47a2c
TK
675
676#endif