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