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