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