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