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
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
a79d8834
JH
137/* Log the result for the given signature */
138static void
139dkim_exim_verify_log_sig(pdkim_signature * sig)
1cfe5c1c 140{
cc55f420 141gstring * logmsg;
a79d8834
JH
142uschar * s;
143
cc55f420
JH
144if (!sig) return;
145
aaaa94ea 146logmsg = string_catn(NULL, US"DKIM: ", 6);
a79d8834
JH
147if (!(s = sig->domain)) s = US"<UNSET>";
148logmsg = string_append(logmsg, 2, "d=", s);
149if (!(s = sig->selector)) s = US"<UNSET>";
150logmsg = string_append(logmsg, 2, " s=", s);
151logmsg = string_append(logmsg, 7,
152" c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
153"/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
154" a=", dkim_sig_to_a_tag(sig),
155string_sprintf(" b=" SIZE_T_FMT,
156 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
157if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
158if (sig->created > 0) logmsg = string_cat(logmsg,
159 string_sprintf(" t=%lu", sig->created));
160if (sig->expires > 0) logmsg = string_cat(logmsg,
161 string_sprintf(" x=%lu", sig->expires));
162if (sig->bodylength > -1) logmsg = string_cat(logmsg,
163 string_sprintf(" l=%lu", sig->bodylength));
164
165if ( !dkim_verify_status
166 || ( dkim_verify_status == dkim_exim_expand_query(DKIM_VERIFY_STATUS)
167 && dkim_verify_reason == dkim_exim_expand_query(DKIM_VERIFY_REASON)
168 ) )
1cfe5c1c
JH
169 switch (sig->verify_status)
170 {
171 case PDKIM_VERIFY_NONE:
aaaa94ea 172 logmsg = string_cat(logmsg, US" [not verified]");
80a47a2c 173 break;
1cfe5c1c
JH
174
175 case PDKIM_VERIFY_INVALID:
aaaa94ea 176 logmsg = string_cat(logmsg, US" [invalid - ");
1cfe5c1c
JH
177 switch (sig->verify_ext_status)
178 {
179 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
acec9514 180 logmsg = string_cat(logmsg,
aaaa94ea 181 US"public key record (currently?) unavailable]");
1cfe5c1c
JH
182 break;
183
184 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
aaaa94ea 185 logmsg = string_cat(logmsg, US"overlong public key record]");
1cfe5c1c
JH
186 break;
187
df3def24
JH
188 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
189 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
aaaa94ea 190 logmsg = string_cat(logmsg, US"syntax error in public key record]");
1cfe5c1c 191 break;
07eeb4df 192
a79d8834 193 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
aaaa94ea 194 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
a79d8834 195 break;
07eeb4df 196
a79d8834 197 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
aaaa94ea 198 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
a79d8834 199 break;
1cfe5c1c
JH
200
201 default:
aaaa94ea 202 logmsg = string_cat(logmsg, US"unspecified problem]");
1cfe5c1c 203 }
80a47a2c 204 break;
1cfe5c1c
JH
205
206 case PDKIM_VERIFY_FAIL:
aaaa94ea 207 logmsg = string_cat(logmsg, US" [verification failed - ");
1cfe5c1c
JH
208 switch (sig->verify_ext_status)
209 {
210 case PDKIM_VERIFY_FAIL_BODY:
acec9514 211 logmsg = string_cat(logmsg,
aaaa94ea 212 US"body hash mismatch (body probably modified in transit)]");
1cfe5c1c
JH
213 break;
214
215 case PDKIM_VERIFY_FAIL_MESSAGE:
acec9514 216 logmsg = string_cat(logmsg,
aaaa94ea
JH
217 US"signature did not verify "
218 "(headers probably modified in transit)]");
1cfe5c1c
JH
219 break;
220
221 default:
aaaa94ea 222 logmsg = string_cat(logmsg, US"unspecified reason]");
1cfe5c1c 223 }
80a47a2c 224 break;
1cfe5c1c
JH
225
226 case PDKIM_VERIFY_PASS:
aaaa94ea 227 logmsg = string_cat(logmsg, US" [verification succeeded]");
80a47a2c
TK
228 break;
229 }
a79d8834
JH
230else
231 logmsg = string_append(logmsg, 5,
232 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
233
aaaa94ea 234log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
a79d8834
JH
235return;
236}
237
80a47a2c 238
a79d8834
JH
239/* Log a line for each signature */
240void
241dkim_exim_verify_log_all(void)
242{
243pdkim_signature * sig;
244for (sig = dkim_signatures; sig; sig = sig->next) dkim_exim_verify_log_sig(sig);
245}
1cfe5c1c 246
80a47a2c 247
a79d8834
JH
248void
249dkim_exim_verify_finish(void)
250{
251pdkim_signature * sig;
252int rc;
253gstring * g = NULL;
254const uschar * errstr;
255
256store_pool = POOL_PERM;
257
258/* Delete eventual previous signature chain */
259
260dkim_signers = NULL;
261dkim_signatures = NULL;
262
263if (dkim_collect_error)
264 {
265 log_write(0, LOG_MAIN,
266 "DKIM: Error during validation, disabling signature verification: %.100s",
267 dkim_collect_error);
268 dkim_disable_verify = TRUE;
269 goto out;
270 }
271
272dkim_collect_input = FALSE;
273
274/* Finish DKIM operation and fetch link to signatures chain */
275
276rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
277if (rc != PDKIM_OK)
278 {
279 log_write(0, LOG_MAIN, "DKIM: validation error: %.100s%s%s", pdkim_errstr(rc),
280 errstr ? ": " : "", errstr ? errstr : US"");
281 goto out;
282 }
283
284/* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
285
286for (sig = dkim_signatures; sig; sig = sig->next)
287 {
288 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
289 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
80a47a2c
TK
290 }
291
acec9514
JH
292if (g) dkim_signers = g->s;
293
ca9cb170
JH
294out:
295store_pool = dkim_verify_oldpool;
80a47a2c
TK
296}
297
298
18067c75
JH
299
300/* Args as per dkim_exim_acl_run() below */
301static int
302dkim_acl_call(uschar * id, gstring ** res_ptr,
303 uschar ** user_msgptr, uschar ** log_msgptr)
304{
305int rc;
306DEBUG(D_receive)
307 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
308
309rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
310dkim_exim_verify_log_sig(dkim_cur_sig);
311*res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
312return rc;
313}
314
315
316
317/* For the given identity, run the DKIM ACL once for each matching signature.
318
319Arguments
320 id Identity to look for in dkim signatures
321 res_ptr ptr to growable string-list of status results,
322 appended to per ACL run
323 user_msgptr where to put a user error (for SMTP response)
324 log_msgptr where to put a logging message (not for SMTP response)
325
326Returns: OK access is granted by an ACCEPT verb
327 DISCARD access is granted by a DISCARD verb
328 FAIL access is denied
329 FAIL_DROP access is denied; drop the connection
330 DEFER can't tell at the moment
331 ERROR disaster
332*/
333
334int
335dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
336 uschar ** user_msgptr, uschar ** log_msgptr)
1cfe5c1c
JH
337{
338pdkim_signature * sig;
339uschar * cmp_val;
18067c75 340int rc = -1;
1cfe5c1c 341
cc55f420
JH
342dkim_verify_status = US"none";
343dkim_verify_reason = US"";
1cfe5c1c
JH
344dkim_cur_signer = id;
345
346if (dkim_disable_verify || !id || !dkim_verify_ctx)
18067c75 347 return OK;
1cfe5c1c 348
18067c75 349/* Find signatures to run ACL on */
1cfe5c1c
JH
350
351for (sig = dkim_signatures; sig; sig = sig->next)
352 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
353 && strcmpic(cmp_val, id) == 0
354 )
355 {
1cfe5c1c 356 /* The "dkim_domain" and "dkim_selector" expansion variables have
18067c75
JH
357 related globals, since they are used in the signing code too.
358 Instead of inventing separate names for verification, we set
359 them here. This is easy since a domain and selector is guaranteed
360 to be in a signature. The other dkim_* expansion items are
361 dynamically fetched from dkim_cur_sig at expansion time (see
362 function below). */
1cfe5c1c 363
18067c75 364 dkim_cur_sig = sig;
1cfe5c1c
JH
365 dkim_signing_domain = US sig->domain;
366 dkim_signing_selector = US sig->selector;
dcd03763 367 dkim_key_length = sig->sighash.len * 8;
a79d8834
JH
368
369 /* These two return static strings, so we can compare the addr
370 later to see if the ACL overwrote them. Check that when logging */
371
372 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
373 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
18067c75
JH
374
375 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
376 return rc;
80a47a2c 377 }
18067c75
JH
378
379if (rc != -1)
380 return rc;
381
382/* No matching sig found. Call ACL once anyway. */
383
384dkim_cur_sig = NULL;
385return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
80a47a2c
TK
386}
387
388
1cfe5c1c
JH
389static uschar *
390dkim_exim_expand_defaults(int what)
391{
392switch (what)
393 {
394 case DKIM_ALGO: return US"";
395 case DKIM_BODYLENGTH: return US"9999999999999";
396 case DKIM_CANON_BODY: return US"";
397 case DKIM_CANON_HEADERS: return US"";
398 case DKIM_COPIEDHEADERS: return US"";
399 case DKIM_CREATED: return US"0";
400 case DKIM_EXPIRES: return US"9999999999999";
401 case DKIM_HEADERNAMES: return US"";
402 case DKIM_IDENTITY: return US"";
403 case DKIM_KEY_GRANULARITY: return US"*";
404 case DKIM_KEY_SRVTYPE: return US"*";
405 case DKIM_KEY_NOTES: return US"";
406 case DKIM_KEY_TESTING: return US"0";
407 case DKIM_NOSUBDOMAINS: return US"0";
408 case DKIM_VERIFY_STATUS: return US"none";
409 case DKIM_VERIFY_REASON: return US"";
410 default: return US"";
411 }
412}
80a47a2c 413
80a47a2c 414
1cfe5c1c
JH
415uschar *
416dkim_exim_expand_query(int what)
417{
418if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
419 return dkim_exim_expand_defaults(what);
420
421switch (what)
422 {
423 case DKIM_ALGO:
d73e45df 424 return dkim_sig_to_a_tag(dkim_cur_sig);
1cfe5c1c
JH
425
426 case DKIM_BODYLENGTH:
427 return dkim_cur_sig->bodylength >= 0
bb07bcd3 428 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
1cfe5c1c
JH
429 : dkim_exim_expand_defaults(what);
430
431 case DKIM_CANON_BODY:
432 switch (dkim_cur_sig->canon_body)
433 {
434 case PDKIM_CANON_RELAXED: return US"relaxed";
435 case PDKIM_CANON_SIMPLE:
436 default: return US"simple";
80a47a2c 437 }
1cfe5c1c
JH
438
439 case DKIM_CANON_HEADERS:
a79d8834
JH
440 switch (dkim_cur_sig->canon_headers)
441 {
442 case PDKIM_CANON_RELAXED: return US"relaxed";
443 case PDKIM_CANON_SIMPLE:
444 default: return US"simple";
445 }
1cfe5c1c
JH
446
447 case DKIM_COPIEDHEADERS:
448 return dkim_cur_sig->copiedheaders
449 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
450
451 case DKIM_CREATED:
452 return dkim_cur_sig->created > 0
bb07bcd3 453 ? string_sprintf("%lu", dkim_cur_sig->created)
1cfe5c1c
JH
454 : dkim_exim_expand_defaults(what);
455
456 case DKIM_EXPIRES:
457 return dkim_cur_sig->expires > 0
bb07bcd3 458 ? string_sprintf("%lu", dkim_cur_sig->expires)
1cfe5c1c
JH
459 : dkim_exim_expand_defaults(what);
460
461 case DKIM_HEADERNAMES:
462 return dkim_cur_sig->headernames
2592e6c0 463 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
1cfe5c1c
JH
464
465 case DKIM_IDENTITY:
466 return dkim_cur_sig->identity
467 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
468
469 case DKIM_KEY_GRANULARITY:
470 return dkim_cur_sig->pubkey
471 ? dkim_cur_sig->pubkey->granularity
472 ? US dkim_cur_sig->pubkey->granularity
473 : dkim_exim_expand_defaults(what)
474 : dkim_exim_expand_defaults(what);
475
476 case DKIM_KEY_SRVTYPE:
477 return dkim_cur_sig->pubkey
478 ? dkim_cur_sig->pubkey->srvtype
479 ? US dkim_cur_sig->pubkey->srvtype
480 : dkim_exim_expand_defaults(what)
481 : dkim_exim_expand_defaults(what);
482
483 case DKIM_KEY_NOTES:
484 return dkim_cur_sig->pubkey
485 ? dkim_cur_sig->pubkey->notes
486 ? US dkim_cur_sig->pubkey->notes
487 : dkim_exim_expand_defaults(what)
488 : dkim_exim_expand_defaults(what);
489
490 case DKIM_KEY_TESTING:
491 return dkim_cur_sig->pubkey
492 ? dkim_cur_sig->pubkey->testing
493 ? US"1"
494 : dkim_exim_expand_defaults(what)
495 : dkim_exim_expand_defaults(what);
496
497 case DKIM_NOSUBDOMAINS:
498 return dkim_cur_sig->pubkey
499 ? dkim_cur_sig->pubkey->no_subdomaining
500 ? US"1"
501 : dkim_exim_expand_defaults(what)
502 : dkim_exim_expand_defaults(what);
503
504 case DKIM_VERIFY_STATUS:
505 switch (dkim_cur_sig->verify_status)
506 {
507 case PDKIM_VERIFY_INVALID: return US"invalid";
508 case PDKIM_VERIFY_FAIL: return US"fail";
509 case PDKIM_VERIFY_PASS: return US"pass";
510 case PDKIM_VERIFY_NONE:
511 default: return US"none";
80a47a2c 512 }
80a47a2c 513
1cfe5c1c
JH
514 case DKIM_VERIFY_REASON:
515 switch (dkim_cur_sig->verify_ext_status)
516 {
517 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
518 return US"pubkey_unavailable";
df3def24
JH
519 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
520 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
1cfe5c1c
JH
521 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
522 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
523 }
80a47a2c 524
1cfe5c1c
JH
525 default:
526 return US"";
80a47a2c
TK
527 }
528}
529
530
42055a33
JH
531/* Generate signatures for the given file, returning a string.
532If a prefix is given, prepend it to the file for the calculations.
533*/
534
acec9514 535gstring *
42055a33
JH
536dkim_exim_sign(int fd, off_t off, uschar * prefix,
537 struct ob_dkim * dkim, const uschar ** errstr)
55414b25 538{
e983e85a 539const uschar * dkim_domain;
1cfe5c1c 540int sep = 0;
acec9514 541gstring * seen_doms = NULL;
9e70917d
JH
542pdkim_ctx ctx;
543pdkim_signature * sig;
acec9514 544gstring * sigbuf;
1cfe5c1c
JH
545int pdkim_rc;
546int sread;
ef698bf6 547uschar buf[4096];
1cfe5c1c
JH
548int save_errno = 0;
549int old_pool = store_pool;
7c6ec81b 550uschar * errwhen;
1cfe5c1c
JH
551
552store_pool = POOL_MAIN;
553
9e70917d
JH
554pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
555
e983e85a 556if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
1cfe5c1c 557 /* expansion error, do not send message. */
7c6ec81b 558 { errwhen = US"dkim_domain"; goto expand_bad; }
1cfe5c1c
JH
559
560/* Set $dkim_domain expansion variable to each unique domain in list. */
561
42055a33 562while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
1cfe5c1c 563 {
9e70917d
JH
564 const uschar * dkim_sel;
565 int sel_sep = 0;
566
42055a33 567 if (dkim_signing_domain[0] == '\0')
1cfe5c1c
JH
568 continue;
569
570 /* Only sign once for each domain, no matter how often it
571 appears in the expanded list. */
572
9e70917d
JH
573 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
574 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
575 continue;
1cfe5c1c 576
acec9514 577 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
1cfe5c1c 578
9e70917d
JH
579 /* Set $dkim_selector expansion variable to each selector in list,
580 for this domain. */
1cfe5c1c 581
9e70917d 582 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
e983e85a 583 if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
7c6ec81b 584 { errwhen = US"dkim_selector"; goto expand_bad; }
1cfe5c1c 585
9e70917d
JH
586 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
587 NULL, 0)))
1cfe5c1c 588 {
9e70917d
JH
589 uschar * dkim_canon_expanded;
590 int pdkim_canon;
591 uschar * dkim_sign_headers_expanded = NULL;
592 uschar * dkim_private_key_expanded;
593 uschar * dkim_hash_expanded;
7c6ec81b 594 uschar * dkim_identity_expanded = NULL;
80a47a2c 595
9e70917d 596 /* Get canonicalization to use */
1cfe5c1c 597
9e70917d
JH
598 dkim_canon_expanded = dkim->dkim_canon
599 ? expand_string(dkim->dkim_canon) : US"relaxed";
7c6ec81b
JH
600 if (!dkim_canon_expanded) /* expansion error, do not send message. */
601 { errwhen = US"dkim_canon"; goto expand_bad; }
1cfe5c1c 602
9e70917d
JH
603 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
604 pdkim_canon = PDKIM_CANON_RELAXED;
605 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
606 pdkim_canon = PDKIM_CANON_SIMPLE;
607 else
608 {
609 log_write(0, LOG_MAIN,
610 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
611 dkim_canon_expanded);
612 pdkim_canon = PDKIM_CANON_RELAXED;
613 }
1cfe5c1c 614
7c6ec81b
JH
615 if ( dkim->dkim_sign_headers
616 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
617 { errwhen = US"dkim_sign_header"; goto expand_bad; }
618 /* else pass NULL, which means default header list */
1cfe5c1c 619
9e70917d 620 /* Get private key to use. */
e983e85a 621
9e70917d 622 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
7c6ec81b 623 { errwhen = US"dkim_private_key"; goto expand_bad; }
80a47a2c 624
9e70917d
JH
625 if ( Ustrlen(dkim_private_key_expanded) == 0
626 || Ustrcmp(dkim_private_key_expanded, "0") == 0
627 || Ustrcmp(dkim_private_key_expanded, "false") == 0
628 )
629 continue; /* don't sign, but no error */
630
631 if (dkim_private_key_expanded[0] == '/')
1cfe5c1c 632 {
9e70917d
JH
633 int privkey_fd, off = 0, len;
634
635 /* Looks like a filename, load the private key. */
636
637 memset(big_buffer, 0, big_buffer_size);
638
639 if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
59d98039 640 {
9e70917d
JH
641 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
642 "private key file for reading: %s",
59d98039
JH
643 dkim_private_key_expanded);
644 goto bad;
645 }
9e70917d
JH
646
647 do
648 {
649 if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
650 {
651 (void) close(privkey_fd);
652 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
653 dkim_private_key_expanded);
654 goto bad;
655 }
656 off += len;
657 }
658 while (len > 0);
659
660 (void) close(privkey_fd);
661 big_buffer[off] = '\0';
662 dkim_private_key_expanded = big_buffer;
1ac6b2e7 663 }
80a47a2c 664
9e70917d 665 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
7c6ec81b
JH
666 { errwhen = US"dkim_hash"; goto expand_bad; }
667
668 if (dkim->dkim_identity)
669 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
670 { errwhen = US"dkim_identity"; goto expand_bad; }
671 else if (!*dkim_identity_expanded)
672 dkim_identity_expanded = NULL;
1cfe5c1c 673
9e70917d
JH
674 /*XXX so we currently nail signing to RSA + this hash.
675 Need to extract algo from privkey and check for disallowed combos. */
d73e45df 676
9e70917d
JH
677 if (!(sig = pdkim_init_sign(&ctx, dkim_signing_domain,
678 dkim_signing_selector,
679 dkim_private_key_expanded,
680 dkim_hash_expanded,
681 errstr
682 )))
683 goto bad;
684 dkim_private_key_expanded[0] = '\0';
685
686 pdkim_set_optional(sig,
687 CS dkim_sign_headers_expanded,
27fd1318 688 CS dkim_identity_expanded,
9e70917d
JH
689 pdkim_canon,
690 pdkim_canon, -1, 0, 0);
691
692 if (!ctx.sig) /* link sig to context chain */
693 ctx.sig = sig;
694 else
695 {
696 pdkim_signature * n = ctx.sig;
697 while (n->next) n = n->next;
698 n->next = sig;
699 }
80a47a2c 700 }
9e70917d 701 }
80a47a2c 702
9e70917d
JH
703if (prefix)
704 pdkim_feed(&ctx, prefix, Ustrlen(prefix));
80a47a2c 705
9e70917d
JH
706if (lseek(fd, off, SEEK_SET) < 0)
707 sread = -1;
708else
709 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
710 if ((pdkim_rc = pdkim_feed(&ctx, buf, sread)) != PDKIM_OK)
711 goto pk_bad;
80a47a2c 712
9e70917d
JH
713/* Handle failed read above. */
714if (sread == -1)
715 {
716 debug_printf("DKIM: Error reading -K file.\n");
717 save_errno = errno;
718 goto bad;
80a47a2c 719 }
a8e1eeba 720
9e70917d
JH
721/* Build string of headers, one per signature */
722
723if ((pdkim_rc = pdkim_feed_finish(&ctx, &sig, errstr)) != PDKIM_OK)
724 goto pk_bad;
725
acec9514
JH
726for (sigbuf = NULL; sig; sig = sig->next)
727 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
9e70917d 728
acec9514 729(void) string_from_gstring(sigbuf);
1cfe5c1c
JH
730
731CLEANUP:
f7302073
JH
732 store_pool = old_pool;
733 errno = save_errno;
9e70917d 734 return sigbuf;
f7302073
JH
735
736pk_bad:
737 log_write(0, LOG_MAIN|LOG_PANIC,
738 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
739bad:
9e70917d 740 sigbuf = NULL;
f7302073 741 goto CLEANUP;
7c6ec81b
JH
742
743expand_bad:
744 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
745 errwhen, expand_string_message);
746 goto bad;
93f2d376 747}
80a47a2c 748
970424a5
JH
749# endif /*!MACRO_PREDEF*/
750#endif /*!DISABLE_DKIM*/