tidying
[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
ef698bf6 107 && (rc = pdkim_feed(dkim_verify_ctx, 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 253 if (sig->domain)
4226691b
JH
254 dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size,
255 &dkim_signers_ptr, ':', sig->domain);
1cfe5c1c
JH
256
257 if (sig->identity)
4226691b
JH
258 dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size,
259 &dkim_signers_ptr, ':', sig->identity);
80a47a2c 260
1cfe5c1c 261 /* Process next signature */
80a47a2c
TK
262 }
263
ca9cb170
JH
264out:
265store_pool = dkim_verify_oldpool;
80a47a2c
TK
266}
267
268
1cfe5c1c
JH
269void
270dkim_exim_acl_setup(uschar * id)
271{
272pdkim_signature * sig;
273uschar * cmp_val;
274
1cfe5c1c
JH
275dkim_cur_sig = NULL;
276dkim_cur_signer = id;
277
278if (dkim_disable_verify || !id || !dkim_verify_ctx)
279 return;
280
281/* Find signature to run ACL on */
282
283for (sig = dkim_signatures; sig; sig = sig->next)
284 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
285 && strcmpic(cmp_val, id) == 0
286 )
287 {
288 dkim_cur_sig = sig;
289
290 /* The "dkim_domain" and "dkim_selector" expansion variables have
291 related globals, since they are used in the signing code too.
292 Instead of inventing separate names for verification, we set
293 them here. This is easy since a domain and selector is guaranteed
294 to be in a signature. The other dkim_* expansion items are
295 dynamically fetched from dkim_cur_sig at expansion time (see
296 function below). */
297
298 dkim_signing_domain = US sig->domain;
299 dkim_signing_selector = US sig->selector;
dcd03763 300 dkim_key_length = sig->sighash.len * 8;
1cfe5c1c 301 return;
80a47a2c 302 }
80a47a2c
TK
303}
304
305
1cfe5c1c
JH
306static uschar *
307dkim_exim_expand_defaults(int what)
308{
309switch (what)
310 {
311 case DKIM_ALGO: return US"";
312 case DKIM_BODYLENGTH: return US"9999999999999";
313 case DKIM_CANON_BODY: return US"";
314 case DKIM_CANON_HEADERS: return US"";
315 case DKIM_COPIEDHEADERS: return US"";
316 case DKIM_CREATED: return US"0";
317 case DKIM_EXPIRES: return US"9999999999999";
318 case DKIM_HEADERNAMES: return US"";
319 case DKIM_IDENTITY: return US"";
320 case DKIM_KEY_GRANULARITY: return US"*";
321 case DKIM_KEY_SRVTYPE: return US"*";
322 case DKIM_KEY_NOTES: return US"";
323 case DKIM_KEY_TESTING: return US"0";
324 case DKIM_NOSUBDOMAINS: return US"0";
325 case DKIM_VERIFY_STATUS: return US"none";
326 case DKIM_VERIFY_REASON: return US"";
327 default: return US"";
328 }
329}
80a47a2c 330
80a47a2c 331
1cfe5c1c
JH
332uschar *
333dkim_exim_expand_query(int what)
334{
335if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
336 return dkim_exim_expand_defaults(what);
337
338switch (what)
339 {
340 case DKIM_ALGO:
341 switch (dkim_cur_sig->algo)
342 {
343 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
344 case PDKIM_ALGO_RSA_SHA256:
345 default: return US"rsa-sha256";
da5dfc3a 346 }
1cfe5c1c
JH
347
348 case DKIM_BODYLENGTH:
349 return dkim_cur_sig->bodylength >= 0
350 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
351 : dkim_exim_expand_defaults(what);
352
353 case DKIM_CANON_BODY:
354 switch (dkim_cur_sig->canon_body)
355 {
356 case PDKIM_CANON_RELAXED: return US"relaxed";
357 case PDKIM_CANON_SIMPLE:
358 default: return US"simple";
80a47a2c 359 }
1cfe5c1c
JH
360
361 case DKIM_CANON_HEADERS:
362 switch (dkim_cur_sig->canon_headers)
363 {
364 case PDKIM_CANON_RELAXED: return US"relaxed";
365 case PDKIM_CANON_SIMPLE:
366 default: return US"simple";
367 }
368
369 case DKIM_COPIEDHEADERS:
370 return dkim_cur_sig->copiedheaders
371 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
372
373 case DKIM_CREATED:
374 return dkim_cur_sig->created > 0
375 ? string_sprintf("%llu", dkim_cur_sig->created)
376 : dkim_exim_expand_defaults(what);
377
378 case DKIM_EXPIRES:
379 return dkim_cur_sig->expires > 0
380 ? string_sprintf("%llu", dkim_cur_sig->expires)
381 : dkim_exim_expand_defaults(what);
382
383 case DKIM_HEADERNAMES:
384 return dkim_cur_sig->headernames
2592e6c0 385 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
1cfe5c1c
JH
386
387 case DKIM_IDENTITY:
388 return dkim_cur_sig->identity
389 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
390
391 case DKIM_KEY_GRANULARITY:
392 return dkim_cur_sig->pubkey
393 ? dkim_cur_sig->pubkey->granularity
394 ? US dkim_cur_sig->pubkey->granularity
395 : dkim_exim_expand_defaults(what)
396 : dkim_exim_expand_defaults(what);
397
398 case DKIM_KEY_SRVTYPE:
399 return dkim_cur_sig->pubkey
400 ? dkim_cur_sig->pubkey->srvtype
401 ? US dkim_cur_sig->pubkey->srvtype
402 : dkim_exim_expand_defaults(what)
403 : dkim_exim_expand_defaults(what);
404
405 case DKIM_KEY_NOTES:
406 return dkim_cur_sig->pubkey
407 ? dkim_cur_sig->pubkey->notes
408 ? US dkim_cur_sig->pubkey->notes
409 : dkim_exim_expand_defaults(what)
410 : dkim_exim_expand_defaults(what);
411
412 case DKIM_KEY_TESTING:
413 return dkim_cur_sig->pubkey
414 ? dkim_cur_sig->pubkey->testing
415 ? US"1"
416 : dkim_exim_expand_defaults(what)
417 : dkim_exim_expand_defaults(what);
418
419 case DKIM_NOSUBDOMAINS:
420 return dkim_cur_sig->pubkey
421 ? dkim_cur_sig->pubkey->no_subdomaining
422 ? US"1"
423 : dkim_exim_expand_defaults(what)
424 : dkim_exim_expand_defaults(what);
425
426 case DKIM_VERIFY_STATUS:
427 switch (dkim_cur_sig->verify_status)
428 {
429 case PDKIM_VERIFY_INVALID: return US"invalid";
430 case PDKIM_VERIFY_FAIL: return US"fail";
431 case PDKIM_VERIFY_PASS: return US"pass";
432 case PDKIM_VERIFY_NONE:
433 default: return US"none";
80a47a2c 434 }
80a47a2c 435
1cfe5c1c
JH
436 case DKIM_VERIFY_REASON:
437 switch (dkim_cur_sig->verify_ext_status)
438 {
439 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
440 return US"pubkey_unavailable";
df3def24
JH
441 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
442 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
1cfe5c1c
JH
443 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
444 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
445 }
80a47a2c 446
1cfe5c1c
JH
447 default:
448 return US"";
80a47a2c
TK
449 }
450}
451
452
42055a33
JH
453/* Generate signatures for the given file, returning a string.
454If a prefix is given, prepend it to the file for the calculations.
455*/
456
55414b25 457uschar *
42055a33
JH
458dkim_exim_sign(int fd, off_t off, uschar * prefix,
459 struct ob_dkim * dkim, const uschar ** errstr)
55414b25 460{
e983e85a 461const uschar * dkim_domain;
1cfe5c1c
JH
462int sep = 0;
463uschar *seen_items = NULL;
464int seen_items_size = 0;
465int seen_items_offset = 0;
1cfe5c1c
JH
466uschar *dkim_canon_expanded;
467uschar *dkim_sign_headers_expanded;
468uschar *dkim_private_key_expanded;
469pdkim_ctx *ctx = NULL;
470uschar *rc = NULL;
471uschar *sigbuf = NULL;
472int sigsize = 0;
473int sigptr = 0;
474pdkim_signature *signature;
475int pdkim_canon;
476int pdkim_rc;
477int sread;
ef698bf6 478uschar buf[4096];
1cfe5c1c
JH
479int save_errno = 0;
480int old_pool = store_pool;
481
482store_pool = POOL_MAIN;
483
e983e85a 484if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
1cfe5c1c
JH
485 {
486 /* expansion error, do not send message. */
487 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
488 "dkim_domain: %s", expand_string_message);
f7302073 489 goto bad;
1cfe5c1c
JH
490 }
491
492/* Set $dkim_domain expansion variable to each unique domain in list. */
493
42055a33 494while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
1cfe5c1c 495 {
42055a33 496 if (dkim_signing_domain[0] == '\0')
1cfe5c1c
JH
497 continue;
498
499 /* Only sign once for each domain, no matter how often it
500 appears in the expanded list. */
501
502 if (seen_items)
503 {
504 const uschar *seen_items_list = seen_items;
505 if (match_isinlist(dkim_signing_domain,
506 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
507 NULL) == OK)
508 continue;
509
510 seen_items =
511 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
512 }
513
514 seen_items =
515 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
516 dkim_signing_domain);
517 seen_items[seen_items_offset] = '\0';
518
519 /* Set up $dkim_selector expansion variable. */
520
e983e85a 521 if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
1cfe5c1c
JH
522 {
523 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
524 "dkim_selector: %s", expand_string_message);
f7302073 525 goto bad;
1cfe5c1c
JH
526 }
527
528 /* Get canonicalization to use */
529
e983e85a
JH
530 dkim_canon_expanded = dkim->dkim_canon
531 ? expand_string(dkim->dkim_canon) : US"relaxed";
1cfe5c1c
JH
532 if (!dkim_canon_expanded)
533 {
80a47a2c 534 /* expansion error, do not send message. */
1cfe5c1c
JH
535 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
536 "dkim_canon: %s", expand_string_message);
f7302073 537 goto bad;
1cfe5c1c 538 }
80a47a2c 539
1cfe5c1c
JH
540 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
541 pdkim_canon = PDKIM_CANON_RELAXED;
542 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
543 pdkim_canon = PDKIM_CANON_SIMPLE;
544 else
545 {
546 log_write(0, LOG_MAIN,
547 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
548 dkim_canon_expanded);
549 pdkim_canon = PDKIM_CANON_RELAXED;
a8e1eeba 550 }
1cfe5c1c
JH
551
552 dkim_sign_headers_expanded = NULL;
e983e85a
JH
553 if (dkim->dkim_sign_headers)
554 if (!(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
1cfe5c1c
JH
555 {
556 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
557 "dkim_sign_headers: %s", expand_string_message);
f7302073 558 goto bad;
1cfe5c1c
JH
559 }
560 /* else pass NULL, which means default header list */
561
562 /* Get private key to use. */
563
e983e85a 564 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
1cfe5c1c
JH
565 {
566 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
567 "dkim_private_key: %s", expand_string_message);
f7302073 568 goto bad;
a8e1eeba 569 }
80a47a2c 570
1cfe5c1c
JH
571 if ( Ustrlen(dkim_private_key_expanded) == 0
572 || Ustrcmp(dkim_private_key_expanded, "0") == 0
573 || Ustrcmp(dkim_private_key_expanded, "false") == 0
574 )
575 continue; /* don't sign, but no error */
576
577 if (dkim_private_key_expanded[0] == '/')
578 {
59d98039 579 int privkey_fd, off = 0, len;
1cfe5c1c
JH
580
581 /* Looks like a filename, load the private key. */
582
583 memset(big_buffer, 0, big_buffer_size);
e983e85a
JH
584
585 if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
1cfe5c1c
JH
586 {
587 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
588 "private key file for reading: %s",
589 dkim_private_key_expanded);
f7302073 590 goto bad;
db4d0902 591 }
80a47a2c 592
59d98039 593 do
1cfe5c1c 594 {
59d98039
JH
595 if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
596 {
597 (void) close(privkey_fd);
598 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
599 dkim_private_key_expanded);
600 goto bad;
601 }
602 off += len;
1ac6b2e7 603 }
59d98039 604 while (len > 0);
80a47a2c 605
1cfe5c1c 606 (void) close(privkey_fd);
59d98039 607 big_buffer[off] = '\0';
1cfe5c1c 608 dkim_private_key_expanded = big_buffer;
a8e1eeba 609 }
1cfe5c1c 610
b9df1829 611 if (!(ctx = pdkim_init_sign(CS dkim_signing_domain,
cd1a5fe0
JH
612 CS dkim_signing_selector,
613 CS dkim_private_key_expanded,
614 PDKIM_ALGO_RSA_SHA256,
615 dkim->dot_stuffed,
b9df1829
JH
616 &dkim_exim_query_dns_txt,
617 errstr
618 )))
619 goto bad;
87cb4a16 620 dkim_private_key_expanded[0] = '\0';
1cfe5c1c 621 pdkim_set_optional(ctx,
e983e85a 622 CS dkim_sign_headers_expanded,
1cfe5c1c
JH
623 NULL,
624 pdkim_canon,
f444c2c7 625 pdkim_canon, -1, 0, 0);
1cfe5c1c 626
42055a33
JH
627 if (prefix)
628 pdkim_feed(ctx, prefix, Ustrlen(prefix));
629
d315eda1
JH
630 if (lseek(fd, off, SEEK_SET) < 0)
631 sread = -1;
632 else
633 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
634 if ((pdkim_rc = pdkim_feed(ctx, buf, sread)) != PDKIM_OK)
635 goto pk_bad;
1cfe5c1c
JH
636
637 /* Handle failed read above. */
638 if (sread == -1)
639 {
640 debug_printf("DKIM: Error reading -K file.\n");
641 save_errno = errno;
f7302073 642 goto bad;
80a47a2c 643 }
80a47a2c 644
b9df1829 645 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature, errstr)) != PDKIM_OK)
f7302073 646 goto pk_bad;
80a47a2c 647
1cfe5c1c
JH
648 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
649 US signature->signature_header, US"\r\n");
80a47a2c 650
1cfe5c1c
JH
651 pdkim_free_ctx(ctx);
652 ctx = NULL;
80a47a2c 653 }
a8e1eeba 654
1cfe5c1c
JH
655if (sigbuf)
656 {
657 sigbuf[sigptr] = '\0';
658 rc = sigbuf;
659 }
660else
661 rc = US"";
662
663CLEANUP:
f7302073
JH
664 if (ctx)
665 pdkim_free_ctx(ctx);
666 store_pool = old_pool;
667 errno = save_errno;
668 return rc;
669
670pk_bad:
671 log_write(0, LOG_MAIN|LOG_PANIC,
672 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
673bad:
674 rc = NULL;
675 goto CLEANUP;
93f2d376 676}
80a47a2c
TK
677
678#endif