2d4af50caf0d9dfe4e0814e80108b30e73daddd7
[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 b=%d ",
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 sig->sigdata_len * 8
137 ),
138
139 sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
140 sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
141 sig->expires > 0 ? string_sprintf("x=%lu ", sig->expires) : US"",
142 sig->bodylength > -1 ? string_sprintf("l=%lu ", sig->bodylength) : US""
143 );
144
145 switch (sig->verify_status)
146 {
147 case PDKIM_VERIFY_NONE:
148 logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
149 break;
150
151 case PDKIM_VERIFY_INVALID:
152 logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
153 switch (sig->verify_ext_status)
154 {
155 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
156 logmsg = string_append(logmsg, &size, &ptr, 1,
157 "public key record (currently?) unavailable]");
158 break;
159
160 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
161 logmsg = string_append(logmsg, &size, &ptr, 1,
162 "overlong public key record]");
163 break;
164
165 case PDKIM_VERIFY_INVALID_PUBKEY_PARSING:
166 logmsg = string_append(logmsg, &size, &ptr, 1,
167 "syntax error in public key record]");
168 break;
169
170 default:
171 logmsg = string_append(logmsg, &size, &ptr, 1,
172 "unspecified problem]");
173 }
174 break;
175
176 case PDKIM_VERIFY_FAIL:
177 logmsg =
178 string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
179 switch (sig->verify_ext_status)
180 {
181 case PDKIM_VERIFY_FAIL_BODY:
182 logmsg = string_append(logmsg, &size, &ptr, 1,
183 "body hash mismatch (body probably modified in transit)]");
184 break;
185
186 case PDKIM_VERIFY_FAIL_MESSAGE:
187 logmsg = string_append(logmsg, &size, &ptr, 1,
188 "signature did not verify (headers probably modified in transit)]");
189 break;
190
191 default:
192 logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
193 }
194 break;
195
196 case PDKIM_VERIFY_PASS:
197 logmsg =
198 string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
199 break;
200 }
201
202 logmsg[ptr] = '\0';
203 log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
204
205 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
206
207 dkim_signers = string_append(dkim_signers,
208 &dkim_signers_size,
209 &dkim_signers_ptr, 2, sig->domain, ":");
210
211 if (sig->identity)
212 dkim_signers = string_append(dkim_signers,
213 &dkim_signers_size,
214 &dkim_signers_ptr, 2, sig->identity, ":");
215
216 /* Process next signature */
217 }
218
219 /* NULL-terminate and chop the last colon from the domain list */
220
221 if (dkim_signers)
222 {
223 dkim_signers[dkim_signers_ptr] = '\0';
224 if (Ustrlen(dkim_signers) > 0)
225 dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
226 }
227 }
228
229
230 void
231 dkim_exim_acl_setup(uschar * id)
232 {
233 pdkim_signature * sig;
234 uschar * cmp_val;
235
236 dkim_cur_sig = NULL;
237 dkim_cur_signer = id;
238
239 if (dkim_disable_verify || !id || !dkim_verify_ctx)
240 return;
241
242 /* Find signature to run ACL on */
243
244 for (sig = dkim_signatures; sig; sig = sig->next)
245 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
246 && strcmpic(cmp_val, id) == 0
247 )
248 {
249 dkim_cur_sig = sig;
250
251 /* The "dkim_domain" and "dkim_selector" expansion variables have
252 related globals, since they are used in the signing code too.
253 Instead of inventing separate names for verification, we set
254 them here. This is easy since a domain and selector is guaranteed
255 to be in a signature. The other dkim_* expansion items are
256 dynamically fetched from dkim_cur_sig at expansion time (see
257 function below). */
258
259 dkim_signing_domain = US sig->domain;
260 dkim_signing_selector = US sig->selector;
261 dkim_key_length = sig->sigdata_len * 8;
262 return;
263 }
264 }
265
266
267 static uschar *
268 dkim_exim_expand_defaults(int what)
269 {
270 switch (what)
271 {
272 case DKIM_ALGO: return US"";
273 case DKIM_BODYLENGTH: return US"9999999999999";
274 case DKIM_CANON_BODY: return US"";
275 case DKIM_CANON_HEADERS: return US"";
276 case DKIM_COPIEDHEADERS: return US"";
277 case DKIM_CREATED: return US"0";
278 case DKIM_EXPIRES: return US"9999999999999";
279 case DKIM_HEADERNAMES: return US"";
280 case DKIM_IDENTITY: return US"";
281 case DKIM_KEY_GRANULARITY: return US"*";
282 case DKIM_KEY_SRVTYPE: return US"*";
283 case DKIM_KEY_NOTES: return US"";
284 case DKIM_KEY_TESTING: return US"0";
285 case DKIM_NOSUBDOMAINS: return US"0";
286 case DKIM_VERIFY_STATUS: return US"none";
287 case DKIM_VERIFY_REASON: return US"";
288 default: return US"";
289 }
290 }
291
292
293 uschar *
294 dkim_exim_expand_query(int what)
295 {
296 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
297 return dkim_exim_expand_defaults(what);
298
299 switch (what)
300 {
301 case DKIM_ALGO:
302 switch (dkim_cur_sig->algo)
303 {
304 case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
305 case PDKIM_ALGO_RSA_SHA256:
306 default: return US"rsa-sha256";
307 }
308
309 case DKIM_BODYLENGTH:
310 return dkim_cur_sig->bodylength >= 0
311 ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
312 : dkim_exim_expand_defaults(what);
313
314 case DKIM_CANON_BODY:
315 switch (dkim_cur_sig->canon_body)
316 {
317 case PDKIM_CANON_RELAXED: return US"relaxed";
318 case PDKIM_CANON_SIMPLE:
319 default: return US"simple";
320 }
321
322 case DKIM_CANON_HEADERS:
323 switch (dkim_cur_sig->canon_headers)
324 {
325 case PDKIM_CANON_RELAXED: return US"relaxed";
326 case PDKIM_CANON_SIMPLE:
327 default: return US"simple";
328 }
329
330 case DKIM_COPIEDHEADERS:
331 return dkim_cur_sig->copiedheaders
332 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
333
334 case DKIM_CREATED:
335 return dkim_cur_sig->created > 0
336 ? string_sprintf("%llu", dkim_cur_sig->created)
337 : dkim_exim_expand_defaults(what);
338
339 case DKIM_EXPIRES:
340 return dkim_cur_sig->expires > 0
341 ? string_sprintf("%llu", dkim_cur_sig->expires)
342 : dkim_exim_expand_defaults(what);
343
344 case DKIM_HEADERNAMES:
345 return dkim_cur_sig->headernames
346 ? US dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
347
348 case DKIM_IDENTITY:
349 return dkim_cur_sig->identity
350 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
351
352 case DKIM_KEY_GRANULARITY:
353 return dkim_cur_sig->pubkey
354 ? dkim_cur_sig->pubkey->granularity
355 ? US dkim_cur_sig->pubkey->granularity
356 : dkim_exim_expand_defaults(what)
357 : dkim_exim_expand_defaults(what);
358
359 case DKIM_KEY_SRVTYPE:
360 return dkim_cur_sig->pubkey
361 ? dkim_cur_sig->pubkey->srvtype
362 ? US dkim_cur_sig->pubkey->srvtype
363 : dkim_exim_expand_defaults(what)
364 : dkim_exim_expand_defaults(what);
365
366 case DKIM_KEY_NOTES:
367 return dkim_cur_sig->pubkey
368 ? dkim_cur_sig->pubkey->notes
369 ? US dkim_cur_sig->pubkey->notes
370 : dkim_exim_expand_defaults(what)
371 : dkim_exim_expand_defaults(what);
372
373 case DKIM_KEY_TESTING:
374 return dkim_cur_sig->pubkey
375 ? dkim_cur_sig->pubkey->testing
376 ? US"1"
377 : dkim_exim_expand_defaults(what)
378 : dkim_exim_expand_defaults(what);
379
380 case DKIM_NOSUBDOMAINS:
381 return dkim_cur_sig->pubkey
382 ? dkim_cur_sig->pubkey->no_subdomaining
383 ? US"1"
384 : dkim_exim_expand_defaults(what)
385 : dkim_exim_expand_defaults(what);
386
387 case DKIM_VERIFY_STATUS:
388 switch (dkim_cur_sig->verify_status)
389 {
390 case PDKIM_VERIFY_INVALID: return US"invalid";
391 case PDKIM_VERIFY_FAIL: return US"fail";
392 case PDKIM_VERIFY_PASS: return US"pass";
393 case PDKIM_VERIFY_NONE:
394 default: return US"none";
395 }
396
397 case DKIM_VERIFY_REASON:
398 switch (dkim_cur_sig->verify_ext_status)
399 {
400 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
401 return US"pubkey_unavailable";
402 case PDKIM_VERIFY_INVALID_PUBKEY_PARSING: return US"pubkey_syntax";
403 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
404 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
405 }
406
407 default:
408 return US"";
409 }
410 }
411
412
413 uschar *
414 dkim_exim_sign(int dkim_fd, uschar * dkim_private_key,
415 const uschar * dkim_domain, uschar * dkim_selector,
416 uschar * dkim_canon, uschar * dkim_sign_headers)
417 {
418 int sep = 0;
419 uschar *seen_items = NULL;
420 int seen_items_size = 0;
421 int seen_items_offset = 0;
422 uschar itembuf[256];
423 uschar *dkim_canon_expanded;
424 uschar *dkim_sign_headers_expanded;
425 uschar *dkim_private_key_expanded;
426 pdkim_ctx *ctx = NULL;
427 uschar *rc = NULL;
428 uschar *sigbuf = NULL;
429 int sigsize = 0;
430 int sigptr = 0;
431 pdkim_signature *signature;
432 int pdkim_canon;
433 int pdkim_rc;
434 int sread;
435 char buf[4096];
436 int save_errno = 0;
437 int old_pool = store_pool;
438
439 store_pool = POOL_MAIN;
440
441 if (!(dkim_domain = expand_cstring(dkim_domain)))
442 {
443 /* expansion error, do not send message. */
444 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
445 "dkim_domain: %s", expand_string_message);
446 rc = NULL;
447 goto CLEANUP;
448 }
449
450 /* Set $dkim_domain expansion variable to each unique domain in list. */
451
452 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
453 itembuf, sizeof(itembuf))))
454 {
455 if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
456 continue;
457
458 /* Only sign once for each domain, no matter how often it
459 appears in the expanded list. */
460
461 if (seen_items)
462 {
463 const uschar *seen_items_list = seen_items;
464 if (match_isinlist(dkim_signing_domain,
465 &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
466 NULL) == OK)
467 continue;
468
469 seen_items =
470 string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
471 }
472
473 seen_items =
474 string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
475 dkim_signing_domain);
476 seen_items[seen_items_offset] = '\0';
477
478 /* Set up $dkim_selector expansion variable. */
479
480 if (!(dkim_signing_selector = expand_string(dkim_selector)))
481 {
482 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
483 "dkim_selector: %s", expand_string_message);
484 rc = NULL;
485 goto CLEANUP;
486 }
487
488 /* Get canonicalization to use */
489
490 dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
491 if (!dkim_canon_expanded)
492 {
493 /* expansion error, do not send message. */
494 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
495 "dkim_canon: %s", expand_string_message);
496 rc = NULL;
497 goto CLEANUP;
498 }
499
500 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
501 pdkim_canon = PDKIM_CANON_RELAXED;
502 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
503 pdkim_canon = PDKIM_CANON_SIMPLE;
504 else
505 {
506 log_write(0, LOG_MAIN,
507 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
508 dkim_canon_expanded);
509 pdkim_canon = PDKIM_CANON_RELAXED;
510 }
511
512 dkim_sign_headers_expanded = NULL;
513 if (dkim_sign_headers)
514 if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
515 {
516 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
517 "dkim_sign_headers: %s", expand_string_message);
518 rc = NULL;
519 goto CLEANUP;
520 }
521 /* else pass NULL, which means default header list */
522
523 /* Get private key to use. */
524
525 if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
526 {
527 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
528 "dkim_private_key: %s", expand_string_message);
529 rc = NULL;
530 goto CLEANUP;
531 }
532
533 if ( Ustrlen(dkim_private_key_expanded) == 0
534 || Ustrcmp(dkim_private_key_expanded, "0") == 0
535 || Ustrcmp(dkim_private_key_expanded, "false") == 0
536 )
537 continue; /* don't sign, but no error */
538
539 if (dkim_private_key_expanded[0] == '/')
540 {
541 int privkey_fd = 0;
542
543 /* Looks like a filename, load the private key. */
544
545 memset(big_buffer, 0, big_buffer_size);
546 privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
547 if (privkey_fd < 0)
548 {
549 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
550 "private key file for reading: %s",
551 dkim_private_key_expanded);
552 rc = NULL;
553 goto CLEANUP;
554 }
555
556 if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
557 {
558 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
559 dkim_private_key_expanded);
560 rc = NULL;
561 goto CLEANUP;
562 }
563
564 (void) close(privkey_fd);
565 dkim_private_key_expanded = big_buffer;
566 }
567
568 ctx = pdkim_init_sign(PDKIM_INPUT_SMTP,
569 (char *) dkim_signing_domain,
570 (char *) dkim_signing_selector,
571 (char *) dkim_private_key_expanded);
572 #ifdef PDKIM_DEBUG
573 pdkim_set_debug_stream(ctx, debug_file);
574 #endif
575 pdkim_set_optional(ctx,
576 (char *) dkim_sign_headers_expanded,
577 NULL,
578 pdkim_canon,
579 pdkim_canon, -1, PDKIM_ALGO_RSA_SHA256, 0, 0);
580
581 lseek(dkim_fd, 0, SEEK_SET);
582
583 while ((sread = read(dkim_fd, &buf, 4096)) > 0)
584 if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
585 {
586 rc = NULL;
587 goto CLEANUP;
588 }
589
590 /* Handle failed read above. */
591 if (sread == -1)
592 {
593 debug_printf("DKIM: Error reading -K file.\n");
594 save_errno = errno;
595 rc = NULL;
596 goto CLEANUP;
597 }
598
599 if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
600 {
601 log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
602 rc = NULL;
603 goto CLEANUP;
604 }
605
606 sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
607 US signature->signature_header, US"\r\n");
608
609 pdkim_free_ctx(ctx);
610 ctx = NULL;
611 }
612
613 if (sigbuf)
614 {
615 sigbuf[sigptr] = '\0';
616 rc = sigbuf;
617 }
618 else
619 rc = US"";
620
621 CLEANUP:
622 if (ctx)
623 pdkim_free_ctx(ctx);
624 store_pool = old_pool;
625 errno = save_errno;
626 return rc;
627 }
628
629 #endif