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