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