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