746a7a6b757612536b0f55aae3d219539480e434
[exim.git] / src / src / dkim.c
1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge, 1995 - 2017 */
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 Could we hand back an allocated string?
40 */
41
42 static int
43 dkim_exim_query_dns_txt(char *name, char *answer)
44 {
45 dns_answer dnsa;
46 dns_scan dnss;
47 dns_record *rr;
48
49 lookup_dnssec_authenticated = NULL;
50 if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
51 return PDKIM_FAIL; /*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 int answer_offset = 0;
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,
70 "%.*s", (int)len, CS (rr->data + rr_offset));
71 rr_offset += len;
72 answer_offset += len;
73 if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
74 return PDKIM_FAIL; /*XXX better error detail? logging? */
75 }
76
77 /* check if this looks like a DKIM record */
78 if (strncasecmp(answer, "v=dkim", 6) != 0) continue;
79 return PDKIM_OK;
80 }
81
82 return PDKIM_FAIL; /*XXX better error detail? logging? */
83 }
84
85
86 void
87 dkim_exim_init(void)
88 {
89 pdkim_init();
90 }
91
92
93
94 void
95 dkim_exim_verify_init(BOOL dot_stuffing)
96 {
97 /* There is a store-reset between header & body reception
98 so cannot use the main pool. Any allocs done by Exim
99 memory-handling must use the perm pool. */
100
101 dkim_verify_oldpool = store_pool;
102 store_pool = POOL_PERM;
103
104 /* Free previous context if there is one */
105
106 if (dkim_verify_ctx)
107 pdkim_free_ctx(dkim_verify_ctx);
108
109 /* Create new context */
110
111 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
112 dkim_collect_input = !!dkim_verify_ctx;
113 dkim_collect_error = NULL;
114
115 /* Start feed up with any cached data */
116 receive_get_cache();
117
118 store_pool = dkim_verify_oldpool;
119 }
120
121
122 void
123 dkim_exim_verify_feed(uschar * data, int len)
124 {
125 int rc;
126
127 store_pool = POOL_PERM;
128 if ( dkim_collect_input
129 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
130 {
131 dkim_collect_error = pdkim_errstr(rc);
132 log_write(0, LOG_MAIN,
133 "DKIM: validation error: %.100s", dkim_collect_error);
134 dkim_collect_input = FALSE;
135 }
136 store_pool = dkim_verify_oldpool;
137 }
138
139
140 /* Log the result for the given signature */
141 static void
142 dkim_exim_verify_log_sig(pdkim_signature * sig)
143 {
144 gstring * logmsg;
145 uschar * s;
146
147 if (!sig) return;
148
149 if ( !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
156 if (!LOGGING(dkim_verbose)) return;
157
158 logmsg = string_catn(NULL, US"DKIM: ", 6);
159 if (!(s = sig->domain)) s = US"<UNSET>";
160 logmsg = string_append(logmsg, 2, "d=", s);
161 if (!(s = sig->selector)) s = US"<UNSET>";
162 logmsg = string_append(logmsg, 2, " s=", s);
163 logmsg = string_append(logmsg, 7,
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),
167 string_sprintf(" b=" SIZE_T_FMT,
168 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
169 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
170 if (sig->created > 0) logmsg = string_cat(logmsg,
171 string_sprintf(" t=%lu", sig->created));
172 if (sig->expires > 0) logmsg = string_cat(logmsg,
173 string_sprintf(" x=%lu", sig->expires));
174 if (sig->bodylength > -1) logmsg = string_cat(logmsg,
175 string_sprintf(" l=%lu", sig->bodylength));
176
177 if ( !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 ) )
181 switch (sig->verify_status)
182 {
183 case PDKIM_VERIFY_NONE:
184 logmsg = string_cat(logmsg, US" [not verified]");
185 break;
186
187 case PDKIM_VERIFY_INVALID:
188 logmsg = string_cat(logmsg, US" [invalid - ");
189 switch (sig->verify_ext_status)
190 {
191 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
192 logmsg = string_cat(logmsg,
193 US"public key record (currently?) unavailable]");
194 break;
195
196 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
197 logmsg = string_cat(logmsg, US"overlong public key record]");
198 break;
199
200 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
201 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
202 logmsg = string_cat(logmsg, US"syntax error in public key record]");
203 break;
204
205 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
206 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
207 break;
208
209 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
210 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
211 break;
212
213 default:
214 logmsg = string_cat(logmsg, US"unspecified problem]");
215 }
216 break;
217
218 case PDKIM_VERIFY_FAIL:
219 logmsg = string_cat(logmsg, US" [verification failed - ");
220 switch (sig->verify_ext_status)
221 {
222 case PDKIM_VERIFY_FAIL_BODY:
223 logmsg = string_cat(logmsg,
224 US"body hash mismatch (body probably modified in transit)]");
225 break;
226
227 case PDKIM_VERIFY_FAIL_MESSAGE:
228 logmsg = string_cat(logmsg,
229 US"signature did not verify "
230 "(headers probably modified in transit)]");
231 break;
232
233 default:
234 logmsg = string_cat(logmsg, US"unspecified reason]");
235 }
236 break;
237
238 case PDKIM_VERIFY_PASS:
239 logmsg = string_cat(logmsg, US" [verification succeeded]");
240 break;
241 }
242 else
243 logmsg = string_append(logmsg, 5,
244 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
245
246 log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
247 return;
248 }
249
250
251 /* Log a line for each signature */
252 void
253 dkim_exim_verify_log_all(void)
254 {
255 pdkim_signature * sig;
256 for (sig = dkim_signatures; sig; sig = sig->next) dkim_exim_verify_log_sig(sig);
257 }
258
259
260 void
261 dkim_exim_verify_finish(void)
262 {
263 pdkim_signature * sig;
264 int rc;
265 gstring * g = NULL;
266 const uschar * errstr;
267
268 store_pool = POOL_PERM;
269
270 /* Delete eventual previous signature chain */
271
272 dkim_signers = NULL;
273 dkim_signatures = NULL;
274
275 if (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
284 dkim_collect_input = FALSE;
285
286 /* Finish DKIM operation and fetch link to signatures chain */
287
288 rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
289 if (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
298 for (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);
302 }
303
304 if (g) dkim_signers = g->s;
305
306 out:
307 store_pool = dkim_verify_oldpool;
308 }
309
310
311
312 /* Args as per dkim_exim_acl_run() below */
313 static int
314 dkim_acl_call(uschar * id, gstring ** res_ptr,
315 uschar ** user_msgptr, uschar ** log_msgptr)
316 {
317 int rc;
318 DEBUG(D_receive)
319 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
320
321 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
322 dkim_exim_verify_log_sig(dkim_cur_sig);
323 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
324 return rc;
325 }
326
327
328
329 /* For the given identity, run the DKIM ACL once for each matching signature.
330
331 Arguments
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
338 Returns: 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
346 int
347 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
348 uschar ** user_msgptr, uschar ** log_msgptr)
349 {
350 pdkim_signature * sig;
351 uschar * cmp_val;
352 int rc = -1;
353
354 dkim_verify_status = US"none";
355 dkim_verify_reason = US"";
356 dkim_cur_signer = id;
357
358 if (dkim_disable_verify || !id || !dkim_verify_ctx)
359 return OK;
360
361 /* Find signatures to run ACL on */
362
363 for (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 {
368 /* The "dkim_domain" and "dkim_selector" expansion variables have
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). */
375
376 dkim_cur_sig = sig;
377 dkim_signing_domain = US sig->domain;
378 dkim_signing_selector = US sig->selector;
379 dkim_key_length = sig->sighash.len * 8;
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);
386
387 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
388 return rc;
389 }
390
391 if (rc != -1)
392 return rc;
393
394 /* No matching sig found. Call ACL once anyway. */
395
396 dkim_cur_sig = NULL;
397 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
398 }
399
400
401 static uschar *
402 dkim_exim_expand_defaults(int what)
403 {
404 switch (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 }
425
426
427 uschar *
428 dkim_exim_expand_query(int what)
429 {
430 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
431 return dkim_exim_expand_defaults(what);
432
433 switch (what)
434 {
435 case DKIM_ALGO:
436 return dkim_sig_to_a_tag(dkim_cur_sig);
437
438 case DKIM_BODYLENGTH:
439 return dkim_cur_sig->bodylength >= 0
440 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
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";
449 }
450
451 case DKIM_CANON_HEADERS:
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 }
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
465 ? string_sprintf("%lu", dkim_cur_sig->created)
466 : dkim_exim_expand_defaults(what);
467
468 case DKIM_EXPIRES:
469 return dkim_cur_sig->expires > 0
470 ? string_sprintf("%lu", dkim_cur_sig->expires)
471 : dkim_exim_expand_defaults(what);
472
473 case DKIM_HEADERNAMES:
474 return dkim_cur_sig->headernames
475 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
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";
524 }
525
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";
531 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
532 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
533 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
534 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
535 }
536
537 default:
538 return US"";
539 }
540 }
541
542
543 /* Generate signatures for the given file, returning a string.
544 If a prefix is given, prepend it to the file for the calculations.
545 */
546
547 gstring *
548 dkim_exim_sign(int fd, off_t off, uschar * prefix,
549 struct ob_dkim * dkim, const uschar ** errstr)
550 {
551 const uschar * dkim_domain;
552 int sep = 0;
553 gstring * seen_doms = NULL;
554 pdkim_ctx ctx;
555 pdkim_signature * sig;
556 gstring * sigbuf;
557 int pdkim_rc;
558 int sread;
559 uschar buf[4096];
560 int save_errno = 0;
561 int old_pool = store_pool;
562 uschar * errwhen;
563
564 store_pool = POOL_MAIN;
565
566 pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
567
568 if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
569 /* expansion error, do not send message. */
570 { errwhen = US"dkim_domain"; goto expand_bad; }
571
572 /* Set $dkim_domain expansion variable to each unique domain in list. */
573
574 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
575 {
576 const uschar * dkim_sel;
577 int sel_sep = 0;
578
579 if (dkim_signing_domain[0] == '\0')
580 continue;
581
582 /* Only sign once for each domain, no matter how often it
583 appears in the expanded list. */
584
585 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
586 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
587 continue;
588
589 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
590
591 /* Set $dkim_selector expansion variable to each selector in list,
592 for this domain. */
593
594 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
595 if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
596 { errwhen = US"dkim_selector"; goto expand_bad; }
597
598 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
599 NULL, 0)))
600 {
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;
606 uschar * dkim_identity_expanded = NULL;
607
608 /* Get canonicalization to use */
609
610 dkim_canon_expanded = dkim->dkim_canon
611 ? expand_string(dkim->dkim_canon) : US"relaxed";
612 if (!dkim_canon_expanded) /* expansion error, do not send message. */
613 { errwhen = US"dkim_canon"; goto expand_bad; }
614
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 }
626
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 */
631
632 /* Get private key to use. */
633
634 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
635 { errwhen = US"dkim_private_key"; goto expand_bad; }
636
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] == '/')
644 {
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)
652 {
653 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
654 "private key file for reading: %s",
655 dkim_private_key_expanded);
656 goto bad;
657 }
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;
675 }
676
677 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
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;
685
686 /*XXX so we currently nail signing to RSA + this hash.
687 Need to extract algo from privkey and check for disallowed combos. */
688
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,
700 CS dkim_identity_expanded,
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 }
712 }
713 }
714
715 if (prefix)
716 pdkim_feed(&ctx, prefix, Ustrlen(prefix));
717
718 if (lseek(fd, off, SEEK_SET) < 0)
719 sread = -1;
720 else
721 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
722 if ((pdkim_rc = pdkim_feed(&ctx, buf, sread)) != PDKIM_OK)
723 goto pk_bad;
724
725 /* Handle failed read above. */
726 if (sread == -1)
727 {
728 debug_printf("DKIM: Error reading -K file.\n");
729 save_errno = errno;
730 goto bad;
731 }
732
733 /* Build string of headers, one per signature */
734
735 if ((pdkim_rc = pdkim_feed_finish(&ctx, &sig, errstr)) != PDKIM_OK)
736 goto pk_bad;
737
738 for (sigbuf = NULL; sig; sig = sig->next)
739 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
740
741 (void) string_from_gstring(sigbuf);
742
743 CLEANUP:
744 store_pool = old_pool;
745 errno = save_errno;
746 return sigbuf;
747
748 pk_bad:
749 log_write(0, LOG_MAIN|LOG_PANIC,
750 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
751 bad:
752 sigbuf = NULL;
753 goto CLEANUP;
754
755 expand_bad:
756 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
757 errwhen, expand_string_message);
758 goto bad;
759 }
760
761 # endif /*!MACRO_PREDEF*/
762 #endif /*!DISABLE_DKIM*/