receive with DKIM
[exim.git] / src / src / dkim.c
CommitLineData
80a47a2c
TK
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
80fea873 5/* Copyright (c) University of Cambridge, 1995 - 2016 */
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
15#include "pdkim/pdkim.h"
16
ca9cb170 17int dkim_verify_oldpool;
1cfe5c1c 18pdkim_ctx *dkim_verify_ctx = NULL;
80a47a2c 19pdkim_signature *dkim_signatures = NULL;
1cfe5c1c 20pdkim_signature *dkim_cur_sig = NULL;
80a47a2c 21
1cfe5c1c
JH
22static int
23dkim_exim_query_dns_txt(char *name, char *answer)
24{
25dns_answer dnsa;
26dns_scan dnss;
27dns_record *rr;
80a47a2c 28
1cfe5c1c
JH
29lookup_dnssec_authenticated = NULL;
30if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
31 return PDKIM_FAIL;
80a47a2c 32
1cfe5c1c 33/* Search for TXT record */
80a47a2c 34
1cfe5c1c
JH
35for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
36 rr;
37 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
38 if (rr->type == T_TXT)
39 {
80a47a2c
TK
40 int rr_offset = 0;
41 int answer_offset = 0;
1cfe5c1c
JH
42
43 /* Copy record content to the answer buffer */
44
45 while (rr_offset < rr->size)
46 {
47 uschar len = rr->data[rr_offset++];
48 snprintf(answer + answer_offset,
49 PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
50 "%.*s", (int)len, (char *) (rr->data + rr_offset));
51 rr_offset += len;
52 answer_offset += len;
53 if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
54 return PDKIM_FAIL;
4263f395 55 }
1cfe5c1c 56 return PDKIM_OK;
80a47a2c 57 }
80a47a2c 58
1cfe5c1c 59return PDKIM_FAIL;
80a47a2c
TK
60}
61
62
2592e6c0
JH
63void
64dkim_exim_init(void)
65{
66pdkim_init();
67}
68
69
ca9cb170 70
1cfe5c1c
JH
71void
72dkim_exim_verify_init(void)
73{
ca9cb170
JH
74/* There is a store-reset between header & body reception
75so cannot use the main pool. Any allocs done by Exim
76memory-handling must use the perm pool. */
77
78dkim_verify_oldpool = store_pool;
79store_pool = POOL_PERM;
80
1cfe5c1c 81/* Free previous context if there is one */
80a47a2c 82
1cfe5c1c
JH
83if (dkim_verify_ctx)
84 pdkim_free_ctx(dkim_verify_ctx);
80a47a2c 85
1cfe5c1c 86/* Create new context */
80a47a2c 87
0d04a285 88dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt);
3b957582 89dkim_collect_input = !!dkim_verify_ctx;
ca9cb170 90
584e96c6
JH
91/* Start feed up with any cached data */
92receive_get_cache();
93
ca9cb170 94store_pool = dkim_verify_oldpool;
80a47a2c
TK
95}
96
97
1cfe5c1c
JH
98void
99dkim_exim_verify_feed(uschar * data, int len)
100{
ca9cb170 101store_pool = POOL_PERM;
1cfe5c1c
JH
102if ( dkim_collect_input
103 && pdkim_feed(dkim_verify_ctx, (char *)data, len) != PDKIM_OK)
104 dkim_collect_input = FALSE;
ca9cb170 105store_pool = dkim_verify_oldpool;
80a47a2c
TK
106}
107
108
1cfe5c1c
JH
109void
110dkim_exim_verify_finish(void)
111{
112pdkim_signature *sig = NULL;
113int dkim_signers_size = 0;
114int dkim_signers_ptr = 0;
115dkim_signers = NULL;
116
ca9cb170
JH
117store_pool = POOL_PERM;
118
1cfe5c1c
JH
119/* Delete eventual previous signature chain */
120
121dkim_signatures = NULL;
122
123/* If we have arrived here with dkim_collect_input == FALSE, it
124means there was a processing error somewhere along the way.
125Log the incident and disable futher verification. */
126
127if (!dkim_collect_input)
128 {
129 log_write(0, LOG_MAIN,
130 "DKIM: Error while running this message through validation,"
131 " disabling signature verification.");
132 dkim_disable_verify = TRUE;
ca9cb170 133 goto out;
1cfe5c1c 134 }
80a47a2c 135
1cfe5c1c 136dkim_collect_input = FALSE;
80a47a2c 137
1cfe5c1c 138/* Finish DKIM operation and fetch link to signatures chain */
80a47a2c 139
1cfe5c1c 140if (pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures) != PDKIM_OK)
ca9cb170 141 goto out;
1cfe5c1c
JH
142
143for (sig = dkim_signatures; sig; sig = sig->next)
144 {
145 int size = 0;
146 int ptr = 0;
147
148 /* Log a line for each signature */
149
150 uschar *logmsg = string_append(NULL, &size, &ptr, 5,
abe1010c 151 string_sprintf("d=%s s=%s c=%s/%s a=%s b=%d ",
1cfe5c1c
JH
152 sig->domain,
153 sig->selector,
07eeb4df 154 sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
155 sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
156 sig->algo == PDKIM_ALGO_RSA_SHA256
157 ? "rsa-sha256"
158 : sig->algo == PDKIM_ALGO_RSA_SHA1 ? "rsa-sha1" : "err",
159 (int)sig->sigdata.len > -1 ? sig->sigdata.len * 8 : 0
abe1010c 160 ),
1cfe5c1c
JH
161
162 sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
163 sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
164 sig->expires > 0 ? string_sprintf("x=%lu ", sig->expires) : US"",
165 sig->bodylength > -1 ? string_sprintf("l=%lu ", sig->bodylength) : US""
166 );
167
168 switch (sig->verify_status)
169 {
170 case PDKIM_VERIFY_NONE:
171 logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
80a47a2c 172 break;
1cfe5c1c
JH
173
174 case PDKIM_VERIFY_INVALID:
175 logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
176 switch (sig->verify_ext_status)
177 {
178 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
179 logmsg = string_append(logmsg, &size, &ptr, 1,
180 "public key record (currently?) unavailable]");
181 break;
182
183 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
184 logmsg = string_append(logmsg, &size, &ptr, 1,
185 "overlong public key record]");
186 break;
187
df3def24
JH
188 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
189 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
1cfe5c1c
JH
190 logmsg = string_append(logmsg, &size, &ptr, 1,
191 "syntax error in public key record]");
192 break;
07eeb4df 193
194 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
195 logmsg = string_append(logmsg, &size, &ptr, 1,
196 "signature tag missing or invalid]");
197 break;
198
199 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
200 logmsg = string_append(logmsg, &size, &ptr, 1,
201 "unsupported DKIM version]");
202 break;
1cfe5c1c
JH
203
204 default:
205 logmsg = string_append(logmsg, &size, &ptr, 1,
206 "unspecified problem]");
207 }
80a47a2c 208 break;
1cfe5c1c
JH
209
210 case PDKIM_VERIFY_FAIL:
211 logmsg =
212 string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
213 switch (sig->verify_ext_status)
214 {
215 case PDKIM_VERIFY_FAIL_BODY:
216 logmsg = string_append(logmsg, &size, &ptr, 1,
217 "body hash mismatch (body probably modified in transit)]");
218 break;
219
220 case PDKIM_VERIFY_FAIL_MESSAGE:
221 logmsg = string_append(logmsg, &size, &ptr, 1,
222 "signature did not verify (headers probably modified in transit)]");
223 break;
224
225 default:
226 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
227 }
80a47a2c 228 break;
1cfe5c1c
JH
229
230 case PDKIM_VERIFY_PASS:
231 logmsg =
232 string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
80a47a2c
TK
233 break;
234 }
235
1cfe5c1c
JH
236 logmsg[ptr] = '\0';
237 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
80a47a2c 238
1cfe5c1c
JH
239 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
240
241 dkim_signers = string_append(dkim_signers,
242 &dkim_signers_size,
243 &dkim_signers_ptr, 2, sig->domain, ":");
244
245 if (sig->identity)
9e5d6b55 246 dkim_signers = string_append(dkim_signers,
1cfe5c1c
JH
247 &dkim_signers_size,
248 &dkim_signers_ptr, 2, sig->identity, ":");
80a47a2c 249
1cfe5c1c 250 /* Process next signature */
80a47a2c
TK
251 }
252
1cfe5c1c
JH
253/* NULL-terminate and chop the last colon from the domain list */
254
255if (dkim_signers)
256 {
257 dkim_signers[dkim_signers_ptr] = '\0';
258 if (Ustrlen(dkim_signers) > 0)
259 dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
0d2b278d 260 }
ca9cb170
JH
261
262out:
263store_pool = dkim_verify_oldpool;
80a47a2c
TK
264}
265
266
1cfe5c1c
JH
267void
268dkim_exim_acl_setup(uschar * id)
269{
270pdkim_signature * sig;
271uschar * cmp_val;
272
1cfe5c1c
JH
273dkim_cur_sig = NULL;
274dkim_cur_signer = id;
275
276if (dkim_disable_verify || !id || !dkim_verify_ctx)
277 return;
278
279/* Find signature to run ACL on */
280
281for (sig = dkim_signatures; sig; sig = sig->next)
282 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
283 && strcmpic(cmp_val, id) == 0
284 )
285 {
286 dkim_cur_sig = sig;
287
288 /* The "dkim_domain" and "dkim_selector" expansion variables have
289 related globals, since they are used in the signing code too.
290 Instead of inventing separate names for verification, we set
291 them here. This is easy since a domain and selector is guaranteed
292 to be in a signature. The other dkim_* expansion items are
293 dynamically fetched from dkim_cur_sig at expansion time (see
294 function below). */
295
296 dkim_signing_domain = US sig->domain;
297 dkim_signing_selector = US sig->selector;
2592e6c0 298 dkim_key_length = sig->sigdata.len * 8;
1cfe5c1c 299 return;
80a47a2c 300 }
80a47a2c
TK
301}
302
303
1cfe5c1c
JH
304static uschar *
305dkim_exim_expand_defaults(int what)
306{
307switch (what)
308 {
309 case DKIM_ALGO: return US"";
310 case DKIM_BODYLENGTH: return US"9999999999999";
311 case DKIM_CANON_BODY: return US"";
312 case DKIM_CANON_HEADERS: return US"";
313 case DKIM_COPIEDHEADERS: return US"";
314 case DKIM_CREATED: return US"0";
315 case DKIM_EXPIRES: return US"9999999999999";
316 case DKIM_HEADERNAMES: return US"";
317 case DKIM_IDENTITY: return US"";
318 case DKIM_KEY_GRANULARITY: return US"*";
319 case DKIM_KEY_SRVTYPE: return US"*";
320 case DKIM_KEY_NOTES: return US"";
321 case DKIM_KEY_TESTING: return US"0";
322 case DKIM_NOSUBDOMAINS: return US"0";
323 case DKIM_VERIFY_STATUS: return US"none";
324 case DKIM_VERIFY_REASON: return US"";
325 default: return US"";
326 }
327}
80a47a2c 328
80a47a2c 329
1cfe5c1c
JH
330uschar *
331dkim_exim_expand_query(int what)
332{
333if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
334 return dkim_exim_expand_defaults(what);
335
336switch (what)
337 {
338 case DKIM_ALGO:
339 switch (dkim_cur_sig->algo)
340 {
341 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
342 case PDKIM_ALGO_RSA_SHA256:
343 default: return US"rsa-sha256";
da5dfc3a 344 }
1cfe5c1c
JH
345
346 case DKIM_BODYLENGTH:
347 return dkim_cur_sig->bodylength >= 0
348 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
349 : dkim_exim_expand_defaults(what);
350
351 case DKIM_CANON_BODY:
352 switch (dkim_cur_sig->canon_body)
353 {
354 case PDKIM_CANON_RELAXED: return US"relaxed";
355 case PDKIM_CANON_SIMPLE:
356 default: return US"simple";
80a47a2c 357 }
1cfe5c1c
JH
358
359 case DKIM_CANON_HEADERS:
360 switch (dkim_cur_sig->canon_headers)
361 {
362 case PDKIM_CANON_RELAXED: return US"relaxed";
363 case PDKIM_CANON_SIMPLE:
364 default: return US"simple";
365 }
366
367 case DKIM_COPIEDHEADERS:
368 return dkim_cur_sig->copiedheaders
369 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
370
371 case DKIM_CREATED:
372 return dkim_cur_sig->created > 0
373 ? string_sprintf("%llu", dkim_cur_sig->created)
374 : dkim_exim_expand_defaults(what);
375
376 case DKIM_EXPIRES:
377 return dkim_cur_sig->expires > 0
378 ? string_sprintf("%llu", dkim_cur_sig->expires)
379 : dkim_exim_expand_defaults(what);
380
381 case DKIM_HEADERNAMES:
382 return dkim_cur_sig->headernames
2592e6c0 383 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
1cfe5c1c
JH
384
385 case DKIM_IDENTITY:
386 return dkim_cur_sig->identity
387 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
388
389 case DKIM_KEY_GRANULARITY:
390 return dkim_cur_sig->pubkey
391 ? dkim_cur_sig->pubkey->granularity
392 ? US dkim_cur_sig->pubkey->granularity
393 : dkim_exim_expand_defaults(what)
394 : dkim_exim_expand_defaults(what);
395
396 case DKIM_KEY_SRVTYPE:
397 return dkim_cur_sig->pubkey
398 ? dkim_cur_sig->pubkey->srvtype
399 ? US dkim_cur_sig->pubkey->srvtype
400 : dkim_exim_expand_defaults(what)
401 : dkim_exim_expand_defaults(what);
402
403 case DKIM_KEY_NOTES:
404 return dkim_cur_sig->pubkey
405 ? dkim_cur_sig->pubkey->notes
406 ? US dkim_cur_sig->pubkey->notes
407 : dkim_exim_expand_defaults(what)
408 : dkim_exim_expand_defaults(what);
409
410 case DKIM_KEY_TESTING:
411 return dkim_cur_sig->pubkey
412 ? dkim_cur_sig->pubkey->testing
413 ? US"1"
414 : dkim_exim_expand_defaults(what)
415 : dkim_exim_expand_defaults(what);
416
417 case DKIM_NOSUBDOMAINS:
418 return dkim_cur_sig->pubkey
419 ? dkim_cur_sig->pubkey->no_subdomaining
420 ? US"1"
421 : dkim_exim_expand_defaults(what)
422 : dkim_exim_expand_defaults(what);
423
424 case DKIM_VERIFY_STATUS:
425 switch (dkim_cur_sig->verify_status)
426 {
427 case PDKIM_VERIFY_INVALID: return US"invalid";
428 case PDKIM_VERIFY_FAIL: return US"fail";
429 case PDKIM_VERIFY_PASS: return US"pass";
430 case PDKIM_VERIFY_NONE:
431 default: return US"none";
80a47a2c 432 }
80a47a2c 433
1cfe5c1c
JH
434 case DKIM_VERIFY_REASON:
435 switch (dkim_cur_sig->verify_ext_status)
436 {
437 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
438 return US"pubkey_unavailable";
df3def24
JH
439 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
440 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
1cfe5c1c
JH
441 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
442 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
443 }
80a47a2c 444
1cfe5c1c
JH
445 default:
446 return US"";
80a47a2c
TK
447 }
448}
449
450
55414b25 451uschar *
1cfe5c1c
JH
452dkim_exim_sign(int dkim_fd, uschar * dkim_private_key,
453 const uschar * dkim_domain, uschar * dkim_selector,
454 uschar * dkim_canon, uschar * dkim_sign_headers)
55414b25 455{
1cfe5c1c
JH
456int sep = 0;
457uschar *seen_items = NULL;
458int seen_items_size = 0;
459int seen_items_offset = 0;
460uschar itembuf[256];
461uschar *dkim_canon_expanded;
462uschar *dkim_sign_headers_expanded;
463uschar *dkim_private_key_expanded;
464pdkim_ctx *ctx = NULL;
465uschar *rc = NULL;
466uschar *sigbuf = NULL;
467int sigsize = 0;
468int sigptr = 0;
469pdkim_signature *signature;
470int pdkim_canon;
471int pdkim_rc;
472int sread;
473char buf[4096];
474int save_errno = 0;
475int old_pool = store_pool;
476
477store_pool = POOL_MAIN;
478
479if (!(dkim_domain = expand_cstring(dkim_domain)))
480 {
481 /* expansion error, do not send message. */
482 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
483 "dkim_domain: %s", expand_string_message);
484 rc = NULL;
485 goto CLEANUP;
486 }
487
488/* Set $dkim_domain expansion variable to each unique domain in list. */
489
490while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
491 itembuf, sizeof(itembuf))))
492 {
493 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
494 continue;
495
496 /* Only sign once for each domain, no matter how often it
497 appears in the expanded list. */
498
499 if (seen_items)
500 {
501 const uschar *seen_items_list = seen_items;
502 if (match_isinlist(dkim_signing_domain,
503 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
504 NULL) == OK)
505 continue;
506
507 seen_items =
508 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
509 }
510
511 seen_items =
512 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
513 dkim_signing_domain);
514 seen_items[seen_items_offset] = '\0';
515
516 /* Set up $dkim_selector expansion variable. */
517
518 if (!(dkim_signing_selector = expand_string(dkim_selector)))
519 {
520 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
521 "dkim_selector: %s", expand_string_message);
522 rc = NULL;
523 goto CLEANUP;
524 }
525
526 /* Get canonicalization to use */
527
528 dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
529 if (!dkim_canon_expanded)
530 {
80a47a2c 531 /* expansion error, do not send message. */
1cfe5c1c
JH
532 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
533 "dkim_canon: %s", expand_string_message);
80a47a2c
TK
534 rc = NULL;
535 goto CLEANUP;
1cfe5c1c 536 }
80a47a2c 537
1cfe5c1c
JH
538 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
539 pdkim_canon = PDKIM_CANON_RELAXED;
540 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
541 pdkim_canon = PDKIM_CANON_SIMPLE;
542 else
543 {
544 log_write(0, LOG_MAIN,
545 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
546 dkim_canon_expanded);
547 pdkim_canon = PDKIM_CANON_RELAXED;
a8e1eeba 548 }
1cfe5c1c
JH
549
550 dkim_sign_headers_expanded = NULL;
551 if (dkim_sign_headers)
552 if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
553 {
554 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
555 "dkim_sign_headers: %s", expand_string_message);
a8e1eeba
MH
556 rc = NULL;
557 goto CLEANUP;
1cfe5c1c
JH
558 }
559 /* else pass NULL, which means default header list */
560
561 /* Get private key to use. */
562
563 if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
564 {
565 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
566 "dkim_private_key: %s", expand_string_message);
567 rc = NULL;
568 goto CLEANUP;
a8e1eeba 569 }
80a47a2c 570
1cfe5c1c
JH
571 if ( Ustrlen(dkim_private_key_expanded) == 0
572 || Ustrcmp(dkim_private_key_expanded, "0") == 0
573 || Ustrcmp(dkim_private_key_expanded, "false") == 0
574 )
575 continue; /* don't sign, but no error */
576
577 if (dkim_private_key_expanded[0] == '/')
578 {
579 int privkey_fd = 0;
580
581 /* Looks like a filename, load the private key. */
582
583 memset(big_buffer, 0, big_buffer_size);
584 privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
585 if (privkey_fd < 0)
586 {
587 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
588 "private key file for reading: %s",
589 dkim_private_key_expanded);
80a47a2c
TK
590 rc = NULL;
591 goto CLEANUP;
db4d0902 592 }
80a47a2c 593
1cfe5c1c
JH
594 if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
595 {
596 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
597 dkim_private_key_expanded);
cf745305
TK
598 rc = NULL;
599 goto CLEANUP;
1ac6b2e7 600 }
80a47a2c 601
1cfe5c1c
JH
602 (void) close(privkey_fd);
603 dkim_private_key_expanded = big_buffer;
a8e1eeba 604 }
1cfe5c1c 605
0d04a285 606 ctx = pdkim_init_sign( (char *) dkim_signing_domain,
1cfe5c1c 607 (char *) dkim_signing_selector,
f444c2c7
JH
608 (char *) dkim_private_key_expanded,
609 PDKIM_ALGO_RSA_SHA256);
1cfe5c1c
JH
610 pdkim_set_optional(ctx,
611 (char *) dkim_sign_headers_expanded,
612 NULL,
613 pdkim_canon,
f444c2c7 614 pdkim_canon, -1, 0, 0);
1cfe5c1c
JH
615
616 lseek(dkim_fd, 0, SEEK_SET);
617
618 while ((sread = read(dkim_fd, &buf, 4096)) > 0)
619 if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
620 {
80a47a2c
TK
621 rc = NULL;
622 goto CLEANUP;
1cfe5c1c
JH
623 }
624
625 /* Handle failed read above. */
626 if (sread == -1)
627 {
628 debug_printf("DKIM: Error reading -K file.\n");
629 save_errno = errno;
630 rc = NULL;
631 goto CLEANUP;
80a47a2c 632 }
80a47a2c 633
1cfe5c1c
JH
634 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
635 {
636 log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
637 rc = NULL;
638 goto CLEANUP;
a8e1eeba 639 }
80a47a2c 640
1cfe5c1c
JH
641 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
642 US signature->signature_header, US"\r\n");
80a47a2c 643
1cfe5c1c
JH
644 pdkim_free_ctx(ctx);
645 ctx = NULL;
80a47a2c 646 }
a8e1eeba 647
1cfe5c1c
JH
648if (sigbuf)
649 {
650 sigbuf[sigptr] = '\0';
651 rc = sigbuf;
652 }
653else
654 rc = US"";
655
656CLEANUP:
657if (ctx)
658 pdkim_free_ctx(ctx);
659store_pool = old_pool;
660errno = save_errno;
661return rc;
93f2d376 662}
80a47a2c
TK
663
664#endif