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