Blob


1 /*
2 * Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 #include <sys/types.h>
17 #include <sys/socket.h>
19 #include <openssl/evp.h>
20 #include <openssl/pem.h>
21 #include <openssl/sha.h>
22 #include <openssl/err.h>
24 #include <arpa/nameser.h>
26 #include <assert.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <event.h>
30 #include <limits.h>
31 #include <netdb.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <asr.h>
40 #include "opensmtpd.h"
41 #include "unpack_dns.h"
42 #include "ltok.h"
44 /*
45 * Use RFC8601 (Authentication-Results) codes instead of RFC6376 codes,
46 * since they're more expressive.
47 */
48 enum state {
49 DKIM_UNKNOWN,
50 DKIM_PASS,
51 DKIM_FAIL,
52 DKIM_POLICY,
53 DKIM_NEUTRAL,
54 DKIM_TEMPERROR,
55 DKIM_PERMERROR
56 };
58 struct signature {
59 struct header *header;
60 enum state state;
61 const char *state_reason;
62 int v;
63 const char *a;
64 size_t asz;
65 int ak;
66 const EVP_MD *ah;
67 char *b;
68 size_t bsz;
69 const char *bheader;
70 /* Make sure padding bits for base64 decoding fit */
71 char bh[EVP_MAX_MD_SIZE + (3 - (EVP_MAX_MD_SIZE % 3))];
72 size_t bhsz;
73 EVP_MD_CTX *bhctx;
74 int c;
75 #define CANON_HEADER_SIMPLE 0
76 #define CANON_HEADER_RELAXED 1
77 #define CANON_HEADER 1
78 #define CANON_BODY_SIMPLE 0
79 #define CANON_BODY_RELAXED 1 << 1
80 #define CANON_BODY 1 << 1
81 #define CANON_DONE 1 << 2
82 char d[HOST_NAME_MAX + 1];
83 char **h;
84 const char *i;
85 size_t isz;
86 ssize_t l;
87 int q;
88 char s[HOST_NAME_MAX + 1];
89 time_t t; /* Signature t=/timestamp */
90 #define KT_Y 1
91 #define KT_S 1 << 1
92 int kt; /* Key t=/Flags */
93 time_t x;
94 int z;
95 struct event_asr *query;
96 EVP_PKEY *p;
97 };
99 struct header {
100 struct message *msg;
101 uint8_t readdone;
102 uint8_t parsed;
103 char *buf;
104 size_t buflen;
105 struct signature *sig;
106 };
108 #define AUTHENTICATION_RESULTS_LINELEN 78
109 #define MIN(a, b) ((a) < (b) ? (a) : (b))
111 struct message {
112 struct osmtpd_ctx *ctx;
113 FILE *origf;
114 int parsing_headers;
115 size_t body_whitelines;
116 int has_body;
117 struct header *header;
118 size_t nheaders;
119 int err;
120 int readdone;
121 };
123 void usage(void);
124 void dkim_err(struct message *, char *);
125 void dkim_errx(struct message *, char *);
126 void dkim_conf(const char *, const char *);
127 void dkim_dataline(struct osmtpd_ctx *, const char *);
128 void dkim_commit(struct osmtpd_ctx *);
129 void *dkim_message_new(struct osmtpd_ctx *);
130 void dkim_message_free(struct osmtpd_ctx *, void *);
131 void dkim_header_add(struct osmtpd_ctx *, const char *);
132 void dkim_signature_parse(struct header *);
133 void dkim_signature_parse_v(struct signature *, const char *, const char *);
134 void dkim_signature_parse_a(struct signature *, const char *, const char *);
135 void dkim_signature_parse_b(struct signature *, const char *, const char *);
136 void dkim_signature_parse_bh(struct signature *, const char *, const char *);
137 void dkim_signature_parse_c(struct signature *, const char *, const char *);
138 void dkim_signature_parse_d(struct signature *, const char *, const char *);
139 void dkim_signature_parse_h(struct signature *, const char *, const char *);
140 void dkim_signature_parse_i(struct signature *, const char *, const char *);
141 void dkim_signature_parse_l(struct signature *, const char *, const char *);
142 void dkim_signature_parse_q(struct signature *, const char *, const char *);
143 void dkim_signature_parse_s(struct signature *, const char *, const char *);
144 void dkim_signature_parse_t(struct signature *, const char *, const char *);
145 void dkim_signature_parse_x(struct signature *, const char *, const char *);
146 void dkim_signature_parse_z(struct signature *, const char *, const char *);
147 void dkim_signature_verify(struct signature *);
148 void dkim_signature_header(EVP_MD_CTX *, struct signature *, struct header *);
149 void dkim_signature_state(struct signature *, enum state, const char *);
150 const char *dkim_state2str(enum state);
151 void dkim_header_cat(struct osmtpd_ctx *, const char *);
152 void dkim_body_parse(struct message *, const char *);
153 void dkim_body_verify(struct signature *);
154 void dkim_rr_resolve(struct asr_result *, void *);
155 void dkim_message_verify(struct message *);
156 ssize_t dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
157 __attribute__((__format__ (printf, 4, 5)));
158 void dkim_ar_print(struct osmtpd_ctx *, const char *);
159 int dkim_key_text_parse(struct signature *, const char *);
161 char *authservid;
162 EVP_ENCODE_CTX *ectx = NULL;
164 int
165 main(int argc, char *argv[])
167 if (argc != 1)
168 osmtpd_errx(1, "Invalid argument count");
170 OpenSSL_add_all_digests();
172 if (pledge("tmppath stdio dns", NULL) == -1)
173 osmtpd_err(1, "pledge");
175 if ((ectx = EVP_ENCODE_CTX_new()) == NULL)
176 osmtpd_err(1, "EVP_ENCODE_CTX_new");
178 osmtpd_register_conf(dkim_conf);
179 osmtpd_register_filter_dataline(dkim_dataline);
180 osmtpd_register_filter_commit(dkim_commit);
181 osmtpd_local_message(dkim_message_new, dkim_message_free);
182 osmtpd_run();
184 return 0;
187 void
188 dkim_conf(const char *key, const char *value)
190 const char *end;
192 if (key == NULL) {
193 if (authservid == NULL)
194 osmtpd_errx(1, "Didn't receive admd config option");
195 return;
197 if (strcmp(key, "admd") == 0 && authservid == NULL) {
198 if ((authservid = strdup(value)) == NULL)
199 osmtpd_err(1, "malloc");
200 end = osmtpd_ltok_skip_value(authservid, 0);
201 if (authservid + strlen(authservid) != end)
202 osmtpd_errx(1, "Invalid authservid");
206 void
207 dkim_dataline(struct osmtpd_ctx *ctx, const char *line)
209 struct message *msg = ctx->local_message;
210 size_t i;
212 if (msg->err) {
213 if (line[0] == '.' && line[1] =='\0') {
214 msg->readdone = 1;
215 osmtpd_filter_dataline(ctx, ".");
217 return;
220 if (fprintf(msg->origf, "%s\n", line) < 0) {
221 dkim_err(msg, "Couldn't write to tempfile");
222 return;
224 if (line[0] == '.') {
225 line++;
226 if (line[0] == '\0') {
227 msg->readdone = 1;
228 for (i = 0; i < msg->nheaders; i++) {
229 if (msg->header[i].sig == NULL)
230 continue;
231 dkim_body_verify(msg->header[i].sig);
233 dkim_message_verify(msg);
234 return;
237 if (msg->parsing_headers) {
238 dkim_header_add(ctx, line);
239 if (line[0] == '\0') {
240 msg->parsing_headers = 0;
241 for (i = 0; i < msg->nheaders; i++) {
242 if (msg->header[i].sig == NULL)
243 continue;
244 if (msg->header[i].sig->query == NULL)
245 dkim_signature_verify(
246 msg->header[i].sig);
249 return;
250 } else {
251 dkim_body_parse(msg, line);
255 void
256 dkim_commit(struct osmtpd_ctx *ctx)
258 struct message *msg = ctx->local_message;
260 if (msg->err)
261 osmtpd_filter_disconnect(ctx, "Internal server error");
262 else
263 osmtpd_filter_proceed(ctx);
266 void *
267 dkim_message_new(struct osmtpd_ctx *ctx)
269 struct message *msg;
271 if ((msg = malloc(sizeof(*msg))) == NULL)
272 osmtpd_err(1, NULL);
274 if ((msg->origf = tmpfile()) == NULL) {
275 dkim_err(msg, "Can't open tempfile");
276 return NULL;
278 msg->ctx = ctx;
279 msg->parsing_headers = 1;
280 msg->body_whitelines = 0;
281 msg->has_body = 0;
282 msg->header = NULL;
283 msg->nheaders = 0;
284 msg->err = 0;
285 msg->readdone = 0;
287 return msg;
290 void
291 dkim_message_free(struct osmtpd_ctx *ctx, void *data)
293 struct message *msg = data;
294 size_t i, j;
296 fclose(msg->origf);
297 for (i = 0; i < msg->nheaders; i++) {
298 if (msg->header[i].sig != NULL) {
299 free(msg->header[i].sig->b);
300 EVP_MD_CTX_free(msg->header[i].sig->bhctx);
301 for (j = 0; msg->header[i].sig->h != NULL &&
302 msg->header[i].sig->h[j] != NULL; j++)
303 free(msg->header[i].sig->h[j]);
304 free(msg->header[i].sig->h);
306 free(msg->header[i].buf);
307 free(msg->header[i].sig);
309 free(msg->header);
310 free(msg);
313 void
314 dkim_header_add(struct osmtpd_ctx *ctx, const char *line)
316 struct message *msg = ctx->local_message;
317 const char *start, *end, *verify;
318 struct header *headers;
319 size_t i;
321 if (msg->nheaders > 0 &&
322 msg->header[msg->nheaders - 1].readdone == 0) {
323 if (line[0] != ' ' && line[0] != '\t') {
324 msg->header[msg->nheaders - 1].readdone = 1;
325 start = msg->header[msg->nheaders - 1].buf;
326 end = osmtpd_ltok_skip_field_name(start, 0);
327 /* In case someone uses an obs-optional */
328 if (end != NULL)
329 verify = osmtpd_ltok_skip_wsp(end, 1);
330 if (end != NULL &&
331 strncasecmp(
332 start, "DKIM-Signature", end - start) == 0 &&
333 verify[0] == ':')
334 dkim_signature_parse(
335 &msg->header[msg->nheaders - 1]);
336 if (line[0] == '\0')
337 return;
338 } else {
339 dkim_header_cat(ctx, line);
340 return;
343 if (msg->nheaders % 10 == 0) {
344 if ((headers = recallocarray(msg->header, msg->nheaders,
345 msg->nheaders + 10, sizeof(*msg->header))) == NULL) {
346 dkim_err(msg, "malloc");
347 return;
349 msg->header = headers;
350 for (i = 0; i < msg->nheaders; i++) {
351 if (msg->header[i].sig == NULL)
352 continue;
353 msg->header[i].sig->header = &msg->header[i];
356 msg->header[msg->nheaders].msg = msg;
357 msg->nheaders++;
358 dkim_header_cat(ctx, line);
361 void
362 dkim_header_cat(struct osmtpd_ctx *ctx, const char *line)
364 struct message *msg = ctx->local_message;
365 struct header *header = &msg->header[msg->nheaders - 1];
366 char *buf;
368 size_t needed = header->buflen + strlen(line) + 2;
370 if (needed > (header->buflen / 1024) + 1) {
371 buf = reallocarray(header->buf, (needed / 1024) + 1, 1024);
372 if (buf == NULL) {
373 dkim_err(msg, "malloc");
374 return;
376 header->buf = buf;
378 header->buflen += snprintf(header->buf + header->buflen,
379 (((needed / 1024) + 1) * 1024) - header->buflen, "%s%s",
380 header->buflen == 0 ? "" : "\r\n", line);
383 void
384 dkim_signature_parse(struct header *header)
386 struct signature *sig;
387 struct asr_query *query;
388 const char *buf, *i, *end;
389 char tagname[3];
390 char subdomain[HOST_NAME_MAX + 1];
391 size_t ilen, dlen;
393 /* Format checked by dkim_header_add */
394 buf = osmtpd_ltok_skip_field_name(header->buf, 0);
395 buf = osmtpd_ltok_skip_wsp(buf, 1) + 1;
397 if ((header->sig = calloc(1, sizeof(*header->sig))) == NULL) {
398 dkim_err(header->msg, "malloc");
399 return;
401 sig = header->sig;
402 sig->header = header;
403 sig->l = -1;
404 sig->t = -1;
405 sig->x = -1;
407 end = osmtpd_ltok_skip_tag_list(buf, 0);
408 if (end == NULL || end[0] != '\0') {
409 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid tag-list");
410 return;
413 while (buf[0] != '\0') {
414 buf = osmtpd_ltok_skip_fws(buf, 1);
415 end = osmtpd_ltok_skip_tag_name(buf, 0);
417 /* Unknown tag-name */
418 if ((size_t)(end - buf) >= sizeof(tagname))
419 tagname[0] = '\0';
420 else
421 strlcpy(tagname, buf, (end - buf) + 1);
422 buf = osmtpd_ltok_skip_fws(end, 1);
423 /* '=' */
424 buf = osmtpd_ltok_skip_fws(buf + 1, 1);
425 end = osmtpd_ltok_skip_tag_value(buf, 1);
426 if (strcmp(tagname, "v") == 0)
427 dkim_signature_parse_v(sig, buf, end);
428 else if (strcmp(tagname, "a") == 0)
429 dkim_signature_parse_a(sig, buf, end);
430 else if (strcmp(tagname, "b") == 0)
431 dkim_signature_parse_b(sig, buf, end);
432 else if (strcmp(tagname, "bh") == 0)
433 dkim_signature_parse_bh(sig, buf, end);
434 else if (strcmp(tagname, "c") == 0)
435 dkim_signature_parse_c(sig, buf, end);
436 else if (strcmp(tagname, "d") == 0)
437 dkim_signature_parse_d(sig, buf, end);
438 else if (strcmp(tagname, "h") == 0)
439 dkim_signature_parse_h(sig, buf, end);
440 else if (strcmp(tagname, "i") == 0)
441 dkim_signature_parse_i(sig, buf, end);
442 else if (strcmp(tagname, "l") == 0)
443 dkim_signature_parse_l(sig, buf, end);
444 else if (strcmp(tagname, "q") == 0)
445 dkim_signature_parse_q(sig, buf, end);
446 else if (strcmp(tagname, "s") == 0)
447 dkim_signature_parse_s(sig, buf, end);
448 else if (strcmp(tagname, "t") == 0)
449 dkim_signature_parse_t(sig, buf, end);
450 else if (strcmp(tagname, "x") == 0)
451 dkim_signature_parse_x(sig, buf, end);
452 else if (strcmp(tagname, "z") == 0)
453 dkim_signature_parse_z(sig, buf, end);
455 buf = osmtpd_ltok_skip_fws(end, 1);
456 if (buf[0] == ';')
457 buf++;
458 else if (buf[0] != '\0') {
459 dkim_signature_state(sig, DKIM_PERMERROR,
460 "Invalid tag-list");
461 return;
464 if (sig->state != DKIM_UNKNOWN)
465 return;
467 if (sig->v != 1)
468 dkim_signature_state(sig, DKIM_PERMERROR, "Missing v tag");
469 else if (sig->ah == NULL)
470 dkim_signature_state(sig, DKIM_PERMERROR, "Missing a tag");
471 else if (sig->b == NULL)
472 dkim_signature_state(sig, DKIM_PERMERROR, "Missing b tag");
473 else if (sig->bhsz == 0)
474 dkim_signature_state(sig, DKIM_PERMERROR, "Missing bh tag");
475 else if (sig->d[0] == '\0')
476 dkim_signature_state(sig, DKIM_PERMERROR, "Missing d tag");
477 else if (sig->h == NULL)
478 dkim_signature_state(sig, DKIM_PERMERROR, "Missing h tag");
479 else if (sig->s[0] == '\0')
480 dkim_signature_state(sig, DKIM_PERMERROR, "Missing s tag");
481 if (sig->state != DKIM_UNKNOWN)
482 return;
484 if (sig->i != NULL) {
485 i = osmtpd_ltok_skip_local_part(sig->i, 1) + 1;
486 ilen = sig->isz - (size_t)(i - sig->i);
487 dlen = strlen(sig->d);
488 if (ilen < dlen) {
489 dkim_signature_state(sig, DKIM_PERMERROR,
490 "i tag not subdomain of d");
491 return;
493 i += ilen - dlen;
494 if ((i[-1] != '.' && i[-1] != '@') ||
495 strncmp(i, sig->d, dlen) != 0) {
496 dkim_signature_state(sig, DKIM_PERMERROR,
497 "i tag not subdomain of d");
498 return;
501 if (sig->t != -1 && sig->x != -1 && sig->t > sig->x) {
502 dkim_signature_state(sig, DKIM_PERMERROR, "t tag after x tag");
503 return;
506 if ((size_t)snprintf(subdomain, sizeof(subdomain), "%s._domainkey.%s",
507 sig->s, sig->d) >= sizeof(subdomain)) {
508 dkim_signature_state(sig, DKIM_PERMERROR,
509 "dns/txt query too long");
510 return;
513 if ((query = res_query_async(subdomain, C_IN, T_TXT, NULL)) == NULL) {
514 dkim_err(header->msg, "res_query_async");
515 return;
517 if ((sig->query = event_asr_run(query, dkim_rr_resolve, sig)) == NULL) {
518 dkim_err(header->msg, "event_asr_run");
519 asr_abort(query);
520 return;
524 void
525 dkim_signature_parse_v(struct signature *sig, const char *start, const char *end)
527 if (sig->v != 0) { /* Duplicate tag */
528 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate v tag");
529 return;
531 /* Unsupported version */
532 if (start[0] != '1' || start + 1 != end)
533 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsupported v tag");
534 else
535 sig->v = 1;
538 void
539 dkim_signature_parse_a(struct signature *sig, const char *start, const char *end)
541 char ah[sizeof("sha256")];
543 if (sig->ah != NULL) {
544 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate a tag");
545 return;
548 if (osmtpd_ltok_skip_sig_a_tag_alg(start, 0) != end) {
549 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid a tag");
550 return;
552 sig->a = start;
553 sig->asz = (size_t)(end - start);
554 if (strncmp(start, "rsa-", 4) == 0) {
555 start += 4;
556 sig->ak = EVP_PKEY_RSA;
557 } else {
558 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag k");
559 return;
561 if ((size_t)(end - start) >= sizeof(ah)) {
562 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
563 return;
565 strlcpy(ah, start, sizeof(ah));
566 ah[end - start] = '\0';
567 if ((sig->ah = EVP_get_digestbyname(ah)) == NULL) {
568 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
569 return;
571 if ((sig->bhctx = EVP_MD_CTX_new()) == NULL) {
572 dkim_err(sig->header->msg, "EVP_MD_CTX_new");
573 return;
575 if (EVP_DigestInit_ex(sig->bhctx, sig->ah, NULL) <= 0) {
576 dkim_err(sig->header->msg, "EVP_DigestInit_ex");
577 return;
581 void
582 dkim_signature_parse_b(struct signature *sig, const char *start, const char *end)
584 int decodesz;
586 if (sig->b != NULL) {
587 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate b tag");
588 return;
590 sig->bheader = start;
591 if ((sig->b = malloc((((end - start) / 4) + 1) * 3)) == NULL) {
592 dkim_err(sig->header->msg, "malloc");
593 return;
595 /* EVP_DecodeBlock doesn't handle internal whitespace */
596 EVP_DecodeInit(ectx);
597 if (EVP_DecodeUpdate(ectx, sig->b, &decodesz, start,
598 (int)(end - start)) == -1) {
599 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
600 return;
602 sig->bsz = decodesz;
603 if (EVP_DecodeFinal(ectx, sig->b + sig->bsz,
604 &decodesz) == -1) {
605 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
606 return;
608 sig->bsz += decodesz;
611 void
612 dkim_signature_parse_bh(struct signature *sig, const char *start, const char *end)
614 const char *b64;
615 size_t n;
616 int decodesz;
618 if (sig->bhsz != 0) {
619 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate bh tag");
620 return;
622 /*
623 * EVP_Decode* expects sig->bh to be large enough,
624 * so count the actual b64 characters.
625 */
626 b64 = start;
627 n = 0;
628 while (1) {
629 b64 = osmtpd_ltok_skip_fws(b64, 1);
630 if (osmtpd_ltok_skip_alphadigitps(b64, 0) == NULL)
631 break;
632 n++;
633 b64++;
635 if (b64[0] == '=') {
636 n++;
637 b64 = osmtpd_ltok_skip_fws(b64 + 1, 1);
638 if (b64[0] == '=') {
639 n++;
640 b64++;
643 /* Invalid tag value */
644 if (b64 != end || n % 4 != 0 || (n / 4) * 3 > sizeof(sig->bh)) {
645 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
646 return;
648 /* EVP_DecodeBlock doesn't handle internal whitespace */
649 EVP_DecodeInit(ectx);
650 if (EVP_DecodeUpdate(ectx, sig->bh, &decodesz, start,
651 (int)(end - start)) == -1) {
652 /* Paranoia check */
653 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
654 return;
656 sig->bhsz = decodesz;
657 if (EVP_DecodeFinal(ectx, sig->bh + sig->bhsz, &decodesz) == -1) {
658 /* Paranoia check */
659 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
660 return;
662 sig->bhsz += decodesz;
665 void
666 dkim_signature_parse_c(struct signature *sig, const char *start, const char *end)
668 if (sig->c != 0) {
669 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate c tag");
670 return;
672 if (strncmp(start, "simple", 6) == 0) {
673 sig->c = CANON_HEADER_SIMPLE;
674 start += 6;
675 } else if (strncmp(start, "relaxed", 7) == 0) {
676 sig->c = CANON_HEADER_RELAXED;
677 start += 7;
678 } else {
679 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
680 return;
682 if (start[0] == '/') {
683 start++;
684 if (strncmp(start, "simple", 6) == 0) {
685 sig->c |= CANON_BODY_SIMPLE;
686 start += 6;
687 } else if (strncmp(start, "relaxed", 7) == 0) {
688 sig->c |= CANON_BODY_RELAXED;
689 start += 7;
690 } else {
691 dkim_signature_state(sig, DKIM_PERMERROR,
692 "Invalid c tag");
693 return;
697 if (start != end) {
698 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
699 return;
701 sig->c |= CANON_DONE;
704 void
705 dkim_signature_parse_d(struct signature *sig, const char *start, const char *end)
707 if (sig->d[0] != '\0') {
708 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate d tag");
709 return;
711 if (osmtpd_ltok_skip_domain(start, 0) != end ||
712 (size_t)(end - start) >= sizeof(sig->d)) {
713 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid d tag");
714 return;
716 strlcpy(sig->d, start, end - start + 1);
719 void
720 dkim_signature_parse_h(struct signature *sig, const char *start, const char *end)
722 const char *h;
723 size_t n = 0;
725 if (sig->h != NULL) {
726 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate h tag");
727 return;
729 h = start;
730 while (1) {
731 if ((h = osmtpd_ltok_skip_hdr_name(h, 0)) == NULL) {
732 dkim_signature_state(sig, DKIM_PERMERROR,
733 "Invalid h tag");
734 return;
736 n++;
737 /* ';' is part of hdr-name */
738 if (h > end) {
739 h = end;
740 break;
742 h = osmtpd_ltok_skip_fws(h, 1);
743 if (h[0] != ':')
744 break;
745 h = osmtpd_ltok_skip_fws(h + 1, 1);
747 if (h != end) {
748 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid h tag");
749 return;
751 if ((sig->h = calloc(n + 1, sizeof(*sig->h))) == NULL) {
752 dkim_err(sig->header->msg, "malloc");
753 return;
755 n = 0;
756 h = start;
757 while (1) {
758 h = osmtpd_ltok_skip_hdr_name(start, 0);
759 /* ';' is part of hdr-name */
760 if (h > end) {
761 sig->h[n] = strndup(start, end - start);
762 break;
764 if ((sig->h[n++] = strndup(start, h - start)) == NULL) {
765 dkim_err(sig->header->msg, "malloc");
766 return;
768 start = osmtpd_ltok_skip_fws(h, 1);
769 if (start[0] != ':')
770 break;
771 start = osmtpd_ltok_skip_fws(start + 1, 1);
775 void
776 dkim_signature_parse_i(struct signature *sig, const char *start, const char *end)
778 const char *i;
780 if (sig->i != NULL) {
781 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate i tag");
782 return;
784 i = osmtpd_ltok_skip_local_part(start, 1);
785 if (i[0] != '@') {
786 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
787 return;
789 if (osmtpd_ltok_skip_domain(i + 1, 0) != end) {
790 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
791 return;
793 sig->i = start;
794 sig->isz = (size_t)(end - start);
797 void
798 dkim_signature_parse_l(struct signature *sig, const char *start, const char *end)
800 long long l;
801 char *lend;
803 if (sig->l != -1) { /* Duplicate tag */
804 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate l tag");
805 return;
807 errno = 0;
808 l = strtoll(start, &lend, 10);
809 /* > 76 digits in stroll is an overflow */
810 if (osmtpd_ltok_skip_digit(start, 0) == NULL ||
811 lend != end || errno != 0) {
812 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid l tag");
813 return;
815 if (l > SSIZE_MAX) {
816 dkim_signature_state(sig, DKIM_PERMERROR, "l tag too large");
817 return;
819 sig->l = (ssize_t)l;
822 void
823 dkim_signature_parse_q(struct signature *sig, const char *start, const char *end)
825 const char *qend;
827 if (sig->q != 0) {
828 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate q tag");
829 return;
832 while (1) {
833 start = osmtpd_ltok_skip_fws(start, 1);
834 qend = osmtpd_ltok_skip_sig_q_tag_method(start, 0);
835 if (qend == NULL) {
836 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
837 return;
839 if (strncmp(start, "dns/txt", qend - start) == 0)
840 sig->q = 1;
841 start = osmtpd_ltok_skip_fws(qend, 1);
842 if (start[0] != ':')
843 break;
845 if (start != end) {
846 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
847 return;
849 if (sig->q != 1) {
850 sig->q = 1;
851 dkim_signature_state(sig, DKIM_NEUTRAL, "No useable q found");
852 return;
856 void
857 dkim_signature_parse_s(struct signature *sig, const char *start, const char *end)
859 if (sig->s[0] != '\0') {
860 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate s tag");
861 return;
863 if (osmtpd_ltok_skip_selector(start, 0) != end) {
864 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid s tag");
865 return;
867 strlcpy(sig->s, start, end - start + 1);
870 void
871 dkim_signature_parse_t(struct signature *sig, const char *start, const char *end)
873 char *tend;
875 if (sig->t != -1) {
876 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate t tag");
877 return;
879 errno = 0;
880 sig->t = strtoll(start, &tend, 10);
881 if (osmtpd_ltok_skip_digit(start, 0) == NULL || tend != end ||
882 tend - start > 12 || errno != 0) {
883 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid t tag");
884 return;
888 void
889 dkim_signature_parse_x(struct signature *sig, const char *start, const char *end)
891 char *xend;
893 if (sig->x != -1) {
894 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate x tag");
895 return;
897 errno = 0;
898 sig->x = strtoll(start, &xend, 10);
899 if (osmtpd_ltok_skip_digit(start, 0) == NULL || xend != end ||
900 xend - start > 12 || errno != 0) {
901 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid x tag");
902 return;
906 void
907 dkim_signature_parse_z(struct signature *sig, const char *start, const char *end)
909 if (sig->z != 0) {
910 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate z tag");
911 return;
914 sig->z = 1;
915 if (osmtpd_ltok_skip_sig_z_tag_value(start, 0) != end) {
916 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid z tag");
917 return;
921 void
922 dkim_signature_verify(struct signature *sig)
924 struct message *msg = sig->header->msg;
925 static EVP_MD_CTX *bctx = NULL;
926 const char *end;
927 size_t i, header;
929 if (sig->state != DKIM_UNKNOWN)
930 return;
932 if (bctx == NULL) {
933 if ((bctx = EVP_MD_CTX_new()) == NULL) {
934 dkim_errx(msg, "EVP_MD_CTX_new");
935 return;
938 EVP_MD_CTX_reset(bctx);
939 if (EVP_DigestVerifyInit(bctx, NULL, sig->ah, NULL, sig->p) != 1) {
940 dkim_errx(msg, "EVP_DigestVerifyInit");
941 return;
944 for (i = 0; i < msg->nheaders; i++)
945 msg->header[i].parsed = 0;
947 for (header = 0; sig->h[header] != NULL; header++) {
948 for (i = msg->nheaders; i > 0; ) {
949 i--;
950 if (msg->header[i].parsed ||
951 strncasecmp(msg->header[i].buf, sig->h[header],
952 strlen(sig->h[header])) != 0 ||
953 msg->header[i].sig == sig)
954 continue;
955 end = osmtpd_ltok_skip_fws(
956 msg->header[i].buf + strlen(sig->h[header]), 1);
957 if (end[0] != ':')
958 continue;
959 dkim_signature_header(bctx, sig, &(msg->header[i]));
960 msg->header[i].parsed = 1;
963 dkim_signature_header(bctx, sig, sig->header);
964 if (EVP_DigestVerifyFinal(bctx, sig->b, sig->bsz) != 1)
965 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
968 void
969 dkim_signature_header(EVP_MD_CTX *bctx, struct signature *sig,
970 struct header *header)
972 char c;
973 const char *ptr = header->buf, *end;
974 int inhdrname = 1;
975 int canon = sig->c & CANON_HEADER;
977 for (ptr = header->buf; ptr[0] != '\0'; ptr++) {
978 if (inhdrname) {
979 if (canon == CANON_HEADER_RELAXED) {
980 ptr = osmtpd_ltok_skip_fws(ptr, 1);
981 c = tolower(ptr[0]);
982 } else
983 c = ptr[0];
984 if (c == ':') {
985 inhdrname = 0;
986 if (canon == CANON_HEADER_RELAXED)
987 ptr = osmtpd_ltok_skip_fws(
988 ptr + 1, 1) - 1;
990 if (EVP_DigestVerifyUpdate(bctx, &c, 1) == 0) {
991 dkim_errx(sig->header->msg,
992 "EVP_DigestVerifyUpdate");
993 return;
995 continue;
997 end = osmtpd_ltok_skip_fws(ptr, 1);
998 if (end == ptr) {
999 if (sig->header == header && ptr == sig->bheader) {
1000 ptr = osmtpd_ltok_skip_tag_value(
1001 ptr, 0) - 1;
1002 continue;
1004 if (EVP_DigestVerifyUpdate(bctx, ptr, 1) == 0) {
1005 dkim_errx(sig->header->msg,
1006 "EVP_DigestVerifyUpdate");
1007 return;
1009 } else {
1010 if (canon == CANON_HEADER_RELAXED) {
1011 if (end[0] == '\0')
1012 continue;
1013 if (EVP_DigestVerifyUpdate(bctx, " ", 1) == 0) {
1014 dkim_errx(sig->header->msg,
1015 "EVP_DigestVerifyUpdate");
1016 return;
1018 } else {
1019 if (EVP_DigestVerifyUpdate(bctx, ptr,
1020 end - ptr) == 0) {
1021 dkim_errx(sig->header->msg,
1022 "EVP_DigestVerifyUpdate");
1023 return;
1026 ptr = end - 1;
1030 if (sig->header != header) {
1031 if (EVP_DigestVerifyUpdate(bctx, "\r\n", 2) == 0) {
1032 dkim_errx(sig->header->msg, "EVP_DigestVerifyUpdate");
1033 return;
1038 void
1039 dkim_signature_state(struct signature *sig, enum state state,
1040 const char *reason)
1042 if (sig->query != NULL) {
1043 event_asr_abort(sig->query);
1044 sig->query = NULL;
1046 switch (sig->state) {
1047 case DKIM_UNKNOWN:
1048 break;
1049 case DKIM_PASS:
1050 case DKIM_FAIL:
1051 osmtpd_errx(1, "Unexpected transition");
1052 case DKIM_POLICY:
1053 if (state == DKIM_PASS)
1054 return;
1055 break;
1056 case DKIM_NEUTRAL:
1057 if (state == DKIM_PASS)
1058 return;
1059 if (state == DKIM_TEMPERROR || state == DKIM_PERMERROR)
1060 break;
1061 osmtpd_errx(1, "Unexpected transition");
1062 case DKIM_TEMPERROR:
1063 if (state == DKIM_PERMERROR)
1064 break;
1065 return;
1066 case DKIM_PERMERROR:
1067 return;
1069 sig->state = state;
1070 sig->state_reason = reason;
1073 const char *
1074 dkim_state2str(enum state state)
1076 switch (state)
1078 case DKIM_UNKNOWN:
1079 return "unknown";
1080 case DKIM_PASS:
1081 return "pass";
1082 case DKIM_FAIL:
1083 return "fail";
1084 case DKIM_POLICY:
1085 return "policy";
1086 case DKIM_NEUTRAL:
1087 return "neutral";
1088 case DKIM_TEMPERROR:
1089 return "temperror";
1090 case DKIM_PERMERROR:
1091 return "permerror";
1095 void
1096 dkim_rr_resolve(struct asr_result *ar, void *arg)
1098 struct signature *sig = arg;
1099 char key[UINT16_MAX + 1];
1100 const char *rr_txt;
1101 size_t keylen, cstrlen;
1102 struct unpack pack;
1103 struct dns_header h;
1104 struct dns_query q;
1105 struct dns_rr rr;
1107 sig->query = NULL;
1109 if (ar->ar_h_errno == TRY_AGAIN || ar->ar_h_errno == NO_RECOVERY) {
1110 dkim_signature_state(sig, DKIM_TEMPERROR,
1111 hstrerror(ar->ar_h_errno));
1112 goto verify;
1114 if (ar->ar_h_errno != NETDB_SUCCESS) {
1115 dkim_signature_state(sig, DKIM_PERMERROR,
1116 hstrerror(ar->ar_h_errno));
1117 goto verify;
1120 unpack_init(&pack, ar->ar_data, ar->ar_datalen);
1121 if (unpack_header(&pack, &h) != 0 ||
1122 unpack_query(&pack, &q) != 0) {
1123 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid dns/txt");
1124 goto verify;
1126 for (; h.ancount > 0; h.ancount--) {
1127 unpack_rr(&pack, &rr);
1128 if (rr.rr_type != T_TXT)
1129 continue;
1131 keylen = 0;
1132 rr_txt = rr.rr.other.rdata;
1133 while (rr.rr.other.rdlen > 0) {
1134 cstrlen = ((const unsigned char *)rr_txt)[0];
1135 if (cstrlen >= rr.rr.other.rdlen ||
1136 keylen + cstrlen >= sizeof(key))
1137 break;
1139 * RFC 6376 Section 3.6.2.2
1140 * Strings in a TXT RR MUST be concatenated together
1141 * before use with no intervening whitespace.
1143 strlcpy(key + keylen, rr_txt + 1, cstrlen + 1);
1144 rr.rr.other.rdlen -= (cstrlen + 1);
1145 rr_txt += (cstrlen + 1);
1146 keylen += cstrlen;
1148 if (rr.rr.other.rdlen > 0) /* Invalid TXT RDATA */
1149 continue;
1151 if (dkim_key_text_parse(sig, key))
1152 break;
1155 if (h.ancount == 0) {
1156 dkim_signature_state(sig, DKIM_PERMERROR,
1157 "No matching key found");
1158 } else {
1159 /* Only verify if all headers have been read */
1160 if (!sig->header->msg->parsing_headers)
1161 dkim_signature_verify(sig);
1163 verify:
1164 dkim_message_verify(sig->header->msg);
1167 int
1168 dkim_key_text_parse(struct signature *sig, const char *key)
1170 char tagname, *hashname;
1171 const char *end, *tagvend;
1172 char pkraw[UINT16_MAX] = "", pkimp[UINT16_MAX];
1173 size_t pkoff, linelen;
1174 int h = 0, k = 0, n = 0, p = 0, s = 0, t = 0, first = 1;
1175 BIO *bio;
1177 key = osmtpd_ltok_skip_fws(key, 1);
1178 /* Validate syntax early */
1179 if ((end = osmtpd_ltok_skip_tag_list(key, 0)) == NULL)
1180 return 0;
1182 while (key[0] != '\0') {
1183 key = osmtpd_ltok_skip_fws(key, 1);
1184 if ((end = osmtpd_ltok_skip_tag_name(key, 0)) == NULL)
1185 return 0;
1187 if ((size_t)(end - key) != 1)
1188 tagname = '\0';
1189 else
1190 tagname = key[0];
1191 key = osmtpd_ltok_skip_fws(end, 1);
1192 /* '=' */
1193 if (key[0] != '=')
1194 return 0;
1195 key = osmtpd_ltok_skip_fws(key + 1, 1);
1196 if ((end = osmtpd_ltok_skip_tag_value(key, 0)) == NULL)
1197 return 0;
1198 switch (tagname) {
1199 case 'v':
1201 * RFC 6376 section 3.6.1, v=:
1202 * RECOMMENDED...This tag MUST be the first tag in the
1203 * record.
1205 if (!first ||
1206 osmtpd_ltok_skip_key_v_tag_value(key, 0) != end)
1207 return 0;
1208 key = end;
1209 break;
1210 case 'h':
1211 if (h != 0) /* Duplicate tag */
1212 return 0;
1213 /* Invalid tag value */
1214 if (osmtpd_ltok_skip_key_h_tag_value(key, 0) != end)
1215 return 0;
1216 while (1) {
1217 if ((tagvend = osmtpd_ltok_skip_key_h_tag_alg(
1218 key, 0)) == NULL)
1219 break;
1220 hashname = strndup(key, tagvend - key);
1221 if (hashname == NULL) {
1222 dkim_err(sig->header->msg, "malloc");
1223 return 0;
1225 if (EVP_get_digestbyname(hashname) == sig->ah) {
1226 free(hashname);
1227 h = 1;
1228 break;
1230 free(hashname);
1231 key = osmtpd_ltok_skip_fws(tagvend, 1);
1232 if (key[0] != ':')
1233 break;
1234 key = osmtpd_ltok_skip_fws(key + 1, 1);
1236 if (h != 1)
1237 return 0;
1238 key = end;
1239 break;
1240 case 'k':
1241 if (k != 0) /* Duplicate tag */
1242 return 0;
1243 k = 1;
1244 if (strncmp(key, "rsa", end - key) != 0)
1245 return 0;
1246 key = end;
1247 break;
1248 case 'n':
1249 if (n != 0) /* Duplicate tag */
1250 return 0;
1251 n = 1;
1252 if (osmtpd_ltok_skip_key_n_tag_value(key, 0) != end)
1253 return 0;
1254 key = end;
1255 break;
1256 case 'p':
1257 if (p != 0) /* Duplicate tag */
1258 return 0;
1259 p = 1;
1260 tagvend = osmtpd_ltok_skip_base64string(key, 1);
1261 /* Invalid tag value */
1262 if (tagvend != end ||
1263 (size_t)(end - key) >= sizeof(pkraw))
1264 return 0;
1265 strlcpy(pkraw, key, tagvend - key + 1);
1266 key = end;
1267 break;
1268 case 's':
1269 if (s != 0) /* Duplicate tag */
1270 return 0;
1271 /* Invalid tag value */
1272 if (osmtpd_ltok_skip_key_s_tag_value(key, 0) != end)
1273 return 0;
1274 while (1) {
1275 if ((tagvend =
1276 osmtpd_ltok_skip_key_s_tag_type(
1277 key, 0)) == NULL)
1278 break;
1279 if (strncmp(key, "*", tagvend - key) == 0 ||
1280 strncmp(key, "email", tagvend - key) == 0) {
1281 s = 1;
1282 break;
1284 key = osmtpd_ltok_skip_fws(tagvend, 1);
1285 if (key[0] != ':')
1286 break;
1287 key = osmtpd_ltok_skip_fws(key + 1, 1);
1289 if (s != 1)
1290 return 0;
1291 key = end;
1292 break;
1293 case 't':
1294 if (t != 0) /* Duplicate tag */
1295 return 0;
1296 t = 1;
1297 if (osmtpd_ltok_skip_key_t_tag_value(key, 0) != end)
1298 return 0;
1299 while (1) {
1300 tagvend = osmtpd_ltok_skip_key_t_tag_flag(
1301 key, 0);
1302 if (strncmp(key, "y", tagvend - key) == 0)
1303 sig->kt |= KT_Y;
1304 else if (strncmp(key, "s", tagvend - key) == 0)
1305 sig->kt |= KT_S;
1306 key = osmtpd_ltok_skip_fws(tagvend, 1);
1307 if (key[0] != ':')
1308 break;
1309 key = osmtpd_ltok_skip_fws(key + 1, 1);
1311 break;
1312 default:
1313 key = end;
1314 break;
1317 first = 0;
1318 key = osmtpd_ltok_skip_fws(key, 1);
1319 if (key[0] == ';')
1320 key++;
1321 else if (key[0] != '\0')
1322 return 0;
1325 if (p == 0) /* Missing tag */
1326 return 0;
1327 if (k == 0 && sig->ak != EVP_PKEY_RSA) /* Default to RSA */
1328 return 0;
1330 if (pkraw[0] == '\0') {
1331 dkim_signature_state(sig, DKIM_PERMERROR, "Key is revoked");
1332 return 1;
1335 switch (sig->ak) {
1336 case EVP_PKEY_RSA:
1337 pkoff = strlcpy(pkimp, "-----BEGIN PUBLIC KEY-----\n",
1338 sizeof(pkimp));
1339 linelen = 0;
1340 for (key = pkraw; key[0] != '\0';) {
1341 if (pkoff + 2 >= sizeof(pkimp))
1342 return 0;
1343 pkimp[pkoff++] = key[0];
1344 if (++linelen == 64) {
1345 pkimp[pkoff++] = '\n';
1346 linelen = 0;
1348 key = osmtpd_ltok_skip_fws(key + 1, 1);
1350 /* Leverage pkoff check in loop */
1351 if (linelen != 0)
1352 pkimp[pkoff++] = '\n';
1353 /* PEM_read_bio_PUBKEY will catch truncated keys */
1354 pkoff += strlcpy(pkimp + pkoff, "-----END PUBLIC KEY-----\n",
1355 sizeof(pkimp) - pkoff);
1356 if ((bio = BIO_new_mem_buf(pkimp, pkoff)) == NULL) {
1357 dkim_err(sig->header->msg, "BIO_new_mem_buf");
1358 return 1;
1360 sig->p = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
1361 BIO_free(bio);
1362 if (sig->p == NULL) {
1364 * XXX No clue how to differentiate between invalid key
1365 * and temporary failure like *alloc.
1366 * Assume invalid key, because it's more likely.
1368 return 0;
1370 break;
1372 return 1;
1375 void
1376 dkim_body_parse(struct message *msg, const char *line)
1378 struct signature *sig;
1379 const char *end = line, *hash, *prev;
1380 size_t hashn, len, i;
1381 int wsp, ret;
1383 if (line[0] == '\0') {
1384 msg->body_whitelines++;
1385 return;
1388 while (msg->body_whitelines-- > 0) {
1389 for (i = 0; i < msg->nheaders; i++) {
1390 if ((sig = msg->header[i].sig) == NULL ||
1391 sig->state != DKIM_UNKNOWN)
1392 continue;
1393 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1394 sig->l -= sig->l == -1 ? 0 : hashn;
1395 if (EVP_DigestUpdate(sig->bhctx, "\r\n", hashn) == 0) {
1396 dkim_errx(msg, "EVP_DigestUpdate");
1397 return;
1401 msg->body_whitelines = 0;
1402 msg->has_body = 1;
1404 while (line[0] != '\0') {
1405 while (1) {
1406 prev = end;
1407 if ((end = osmtpd_ltok_skip_wsp(end, 0)) == NULL)
1408 break;
1410 end = prev;
1411 wsp = end != line;
1412 if (!wsp) {
1413 while (osmtpd_ltok_skip_wsp(end, 0) == NULL &&
1414 end[0] != '\0')
1415 end++;
1417 for (i = 0; i < msg->nheaders; i++) {
1418 sig = msg->header[i].sig;
1419 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1420 continue;
1421 if (wsp &&
1422 (sig->c & CANON_BODY) == CANON_BODY_RELAXED) {
1423 hash = " ";
1424 len = end[0] == '\0' ? 0 : 1;
1425 } else {
1426 hash = line;
1427 len = (size_t)(end - line);
1429 hashn = sig->l == -1 ? len : MIN(len, (size_t)sig->l);
1430 sig->l -= sig->l == -1 ? 0 : hashn;
1431 ret = EVP_DigestUpdate(sig->bhctx, hash, hashn);
1432 if (ret == 0) {
1433 dkim_errx(msg, "EVP_DigestUpdate");
1434 return;
1437 line = end;
1439 for (i = 0; i < msg->nheaders; i++) {
1440 sig = msg->header[i].sig;
1441 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1442 continue;
1443 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1444 sig->l -= sig->l == -1 ? 0 : hashn;
1445 ret = EVP_DigestUpdate(sig->bhctx, "\r\n", hashn);
1446 if (ret == 0) {
1447 dkim_errx(msg, "EVP_DigestUpdate");
1448 return;
1453 void
1454 dkim_body_verify(struct signature *sig)
1456 unsigned char digest[EVP_MAX_MD_SIZE];
1457 unsigned int digestsz;
1459 if (sig->state != DKIM_UNKNOWN)
1460 return;
1462 if ((sig->c & CANON_BODY) == CANON_BODY_SIMPLE &&
1463 !sig->header->msg->has_body) {
1464 if (EVP_DigestUpdate(sig->bhctx, "\r\n",
1465 sig->l == -1 ? 2 : MIN(2, sig->l)) <= 0) {
1466 dkim_errx(sig->header->msg,
1467 "Can't update hash context");
1468 return;
1471 if (sig->l > 0) {
1472 dkim_signature_state(sig, DKIM_PERMERROR,
1473 "l tag larger than body");
1474 return;
1477 if (EVP_DigestFinal_ex(sig->bhctx, digest, &digestsz) == 0) {
1478 dkim_errx(sig->header->msg, "Can't finalize hash context");
1479 return;
1482 if (digestsz != sig->bhsz || memcmp(digest, sig->bh, digestsz) != 0)
1483 dkim_signature_state(sig, DKIM_FAIL, "bh mismatch");
1486 void
1487 dkim_message_verify(struct message *msg)
1489 struct signature *sig;
1490 size_t i;
1491 ssize_t n, aroff = 0;
1492 int found = 0;
1493 char *line = NULL;
1494 size_t linelen = 0;
1496 if (!msg->readdone)
1497 return;
1499 for (i = 0; i < msg->nheaders; i++) {
1500 if (msg->header[i].sig == NULL)
1501 continue;
1502 if (msg->header[i].sig->query != NULL)
1503 return;
1504 if (msg->header[i].sig->state != DKIM_UNKNOWN)
1505 continue;
1506 dkim_signature_state(msg->header[i].sig, DKIM_PASS, NULL);
1509 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1510 "Authentication-Results: %s", authservid)) == -1) {
1511 dkim_err(msg, "malloc");
1512 goto fail;
1514 for (i = 0; i < msg->nheaders; i++) {
1515 sig = msg->header[i].sig;
1516 if (sig == NULL)
1517 continue;
1518 found = 1;
1519 if ((aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=%s",
1520 dkim_state2str(sig->state))) == -1) {
1521 dkim_err(msg, "malloc");
1522 goto fail;
1524 if (sig->state_reason != NULL) {
1525 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1526 " reason=\"%s\"", sig->state_reason)) == -1) {
1527 dkim_err(msg, "malloc");
1528 goto fail;
1531 if (sig->s[0] != '\0') {
1532 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1533 " header.s=%s", sig->s)) == -1) {
1534 dkim_err(msg, "malloc");
1535 goto fail;
1538 if (sig->d[0] != '\0') {
1539 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1540 " header.d=%s", sig->d)) == -1) {
1541 dkim_err(msg, "malloc");
1542 goto fail;
1546 * Don't print i-tag, since localpart can be a quoted-string,
1547 * which can contain FWS and CFWS.
1549 if (sig->a != NULL) {
1550 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1551 " header.a=%.*s", (int)sig->asz, sig->a)) == -1) {
1552 dkim_err(msg, "malloc");
1553 goto fail;
1557 if (!found) {
1558 aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=none");
1559 if (aroff == -1) {
1560 dkim_err(msg, "malloc");
1561 goto fail;
1564 dkim_ar_print(msg->ctx, line);
1566 rewind(msg->origf);
1567 while ((n = getline(&line, &linelen, msg->origf)) != -1) {
1568 line[n - 1] = '\0';
1569 osmtpd_filter_dataline(msg->ctx, "%s", line);
1571 if (ferror(msg->origf))
1572 dkim_err(msg, "getline");
1573 fail:
1574 free(line);
1575 return;
1578 void
1579 dkim_ar_print(struct osmtpd_ctx *ctx, const char *start)
1581 const char *scan, *checkpoint, *ncheckpoint;
1582 size_t arlen = 0;
1583 int first = 1, arid = 1;
1585 checkpoint = start;
1586 ncheckpoint = osmtpd_ltok_skip_hdr_name(start, 0) + 1;
1587 for (scan = start; scan[0] != '\0'; scan++) {
1588 if (scan[0] == '\t')
1589 arlen = (arlen + 8) & ~7;
1590 else
1591 arlen++;
1592 if (arlen >= AUTHENTICATION_RESULTS_LINELEN) {
1593 osmtpd_filter_dataline(ctx, "%s%.*s", first ? "" : "\t",
1594 (int)((checkpoint == start ?
1595 ncheckpoint : checkpoint) - start), start);
1596 start = osmtpd_ltok_skip_cfws(checkpoint, 1);
1597 scan = start;
1598 arlen = 8;
1599 first = 0;
1601 if (scan == ncheckpoint) {
1602 checkpoint = ncheckpoint;
1603 ncheckpoint = osmtpd_ltok_skip_cfws(ncheckpoint, 1);
1604 /* authserv-id */
1605 if (arid) {
1606 ncheckpoint = osmtpd_ltok_skip_value(
1607 ncheckpoint, 0);
1608 arid = 0;
1609 /* methodspec */
1610 } else if (strncmp(ncheckpoint, "dkim",
1611 sizeof("dkim") - 1) == 0) {
1612 ncheckpoint = osmtpd_ltok_skip_keyword(
1613 ncheckpoint + sizeof("dkim"), 0);
1614 /* reasonspec */
1615 } else if (strncmp(ncheckpoint, "reason",
1616 sizeof("reason") - 1) == 0) {
1617 ncheckpoint = osmtpd_ltok_skip_value(
1618 ncheckpoint + sizeof("reason"), 0);
1619 /* propspec */
1620 } else {
1621 ncheckpoint += sizeof("header.x=") - 1;
1622 ncheckpoint = osmtpd_ltok_skip_ar_pvalue(
1623 ncheckpoint, 0);
1624 if (ncheckpoint[0] == ';')
1625 ncheckpoint++;
1629 osmtpd_filter_dataline(ctx, "%s%s", first ? "" : "\t", start);
1632 ssize_t
1633 dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
1635 va_list ap;
1636 char *artmp;
1637 int size;
1638 size_t nn;
1640 assert(*n >= aroff);
1641 va_start(ap, fmt);
1642 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1643 va_end(ap);
1644 if (size + aroff <= *n)
1645 return (ssize_t)size + aroff;
1646 nn = (((aroff + size) / 256) + 1) * 256;
1647 artmp = realloc(*ar, nn);
1648 if (artmp == NULL)
1649 return -1;
1650 *ar = artmp;
1651 *n = nn;
1652 va_start(ap, fmt);
1653 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1654 va_end(ap);
1655 return (ssize_t)size + aroff;
1658 void
1659 dkim_err(struct message *msg, char *text)
1661 msg->err = 1;
1662 fprintf(stderr, "%s: %s\n", text, strerror(errno));
1665 void
1666 dkim_errx(struct message *msg, char *text)
1668 msg->err = 1;
1669 fprintf(stderr, "%s\n", text);
1672 __dead void
1673 usage(void)
1675 fprintf(stderr, "usage: filter-dkimverify\n");
1676 exit(1);