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 <ctype.h>
27 #include <errno.h>
28 #include <event.h>
29 #include <limits.h>
30 #include <netdb.h>
31 #include <opensmtpd.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 "unpack_dns.h"
41 #include "ltok.h"
43 /*
44 * Use RFC8601 (Authentication-Results) codes instead of RFC6376 codes,
45 * since they're more expressive.
46 */
47 enum state {
48 DKIM_UNKNOWN,
49 DKIM_PASS,
50 DKIM_FAIL,
51 DKIM_POLICY,
52 DKIM_NEUTRAL,
53 DKIM_TEMPERROR,
54 DKIM_PERMERROR
55 };
57 struct signature {
58 struct header *header;
59 enum state state;
60 const char *state_reason;
61 int v;
62 const char *a;
63 size_t asz;
64 int ak;
65 int sephash;
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);
305 EVP_PKEY_free(msg->header[i].sig->p);
307 free(msg->header[i].buf);
308 free(msg->header[i].sig);
310 free(msg->header);
311 free(msg);
314 void
315 dkim_header_add(struct osmtpd_ctx *ctx, const char *line)
317 struct message *msg = ctx->local_message;
318 const char *start, *end, *verify;
319 struct header *headers;
320 size_t i;
322 if (msg->nheaders > 0 &&
323 msg->header[msg->nheaders - 1].readdone == 0) {
324 if (line[0] != ' ' && line[0] != '\t') {
325 msg->header[msg->nheaders - 1].readdone = 1;
326 start = msg->header[msg->nheaders - 1].buf;
327 end = osmtpd_ltok_skip_field_name(start, 0);
328 /* In case someone uses an obs-optional */
329 if (end != NULL)
330 verify = osmtpd_ltok_skip_wsp(end, 1);
331 if (end != NULL &&
332 strncasecmp(
333 start, "DKIM-Signature", end - start) == 0 &&
334 verify[0] == ':')
335 dkim_signature_parse(
336 &msg->header[msg->nheaders - 1]);
337 if (line[0] == '\0')
338 return;
339 } else {
340 dkim_header_cat(ctx, line);
341 return;
344 if (msg->nheaders % 10 == 0) {
345 if ((headers = recallocarray(msg->header, msg->nheaders,
346 msg->nheaders + 10, sizeof(*msg->header))) == NULL) {
347 dkim_err(msg, "malloc");
348 return;
350 msg->header = headers;
351 for (i = 0; i < msg->nheaders; i++) {
352 if (msg->header[i].sig == NULL)
353 continue;
354 msg->header[i].sig->header = &msg->header[i];
357 msg->header[msg->nheaders].msg = msg;
358 msg->nheaders++;
359 dkim_header_cat(ctx, line);
362 void
363 dkim_header_cat(struct osmtpd_ctx *ctx, const char *line)
365 struct message *msg = ctx->local_message;
366 struct header *header = &msg->header[msg->nheaders - 1];
367 char *buf;
369 size_t needed = header->buflen + strlen(line) + 2;
371 if (needed > (header->buflen / 1024) + 1) {
372 buf = reallocarray(header->buf, (needed / 1024) + 1, 1024);
373 if (buf == NULL) {
374 dkim_err(msg, "malloc");
375 return;
377 header->buf = buf;
379 header->buflen += snprintf(header->buf + header->buflen,
380 (((needed / 1024) + 1) * 1024) - header->buflen, "%s%s",
381 header->buflen == 0 ? "" : "\r\n", line);
384 void
385 dkim_signature_parse(struct header *header)
387 struct signature *sig;
388 struct asr_query *query;
389 const char *buf, *i, *end;
390 char tagname[3];
391 char subdomain[HOST_NAME_MAX + 1];
392 size_t ilen, dlen;
394 /* Format checked by dkim_header_add */
395 buf = osmtpd_ltok_skip_field_name(header->buf, 0);
396 buf = osmtpd_ltok_skip_wsp(buf, 1) + 1;
398 if ((header->sig = calloc(1, sizeof(*header->sig))) == NULL) {
399 dkim_err(header->msg, "malloc");
400 return;
402 sig = header->sig;
403 sig->header = header;
404 sig->l = -1;
405 sig->t = -1;
406 sig->x = -1;
408 end = osmtpd_ltok_skip_tag_list(buf, 0);
409 if (end == NULL || end[0] != '\0') {
410 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid tag-list");
411 return;
414 while (buf[0] != '\0') {
415 buf = osmtpd_ltok_skip_fws(buf, 1);
416 end = osmtpd_ltok_skip_tag_name(buf, 0);
418 /* Unknown tag-name */
419 if ((size_t)(end - buf) >= sizeof(tagname))
420 tagname[0] = '\0';
421 else
422 strlcpy(tagname, buf, (end - buf) + 1);
423 buf = osmtpd_ltok_skip_fws(end, 1);
424 /* '=' */
425 buf = osmtpd_ltok_skip_fws(buf + 1, 1);
426 end = osmtpd_ltok_skip_tag_value(buf, 1);
427 if (strcmp(tagname, "v") == 0)
428 dkim_signature_parse_v(sig, buf, end);
429 else if (strcmp(tagname, "a") == 0)
430 dkim_signature_parse_a(sig, buf, end);
431 else if (strcmp(tagname, "b") == 0)
432 dkim_signature_parse_b(sig, buf, end);
433 else if (strcmp(tagname, "bh") == 0)
434 dkim_signature_parse_bh(sig, buf, end);
435 else if (strcmp(tagname, "c") == 0)
436 dkim_signature_parse_c(sig, buf, end);
437 else if (strcmp(tagname, "d") == 0)
438 dkim_signature_parse_d(sig, buf, end);
439 else if (strcmp(tagname, "h") == 0)
440 dkim_signature_parse_h(sig, buf, end);
441 else if (strcmp(tagname, "i") == 0)
442 dkim_signature_parse_i(sig, buf, end);
443 else if (strcmp(tagname, "l") == 0)
444 dkim_signature_parse_l(sig, buf, end);
445 else if (strcmp(tagname, "q") == 0)
446 dkim_signature_parse_q(sig, buf, end);
447 else if (strcmp(tagname, "s") == 0)
448 dkim_signature_parse_s(sig, buf, end);
449 else if (strcmp(tagname, "t") == 0)
450 dkim_signature_parse_t(sig, buf, end);
451 else if (strcmp(tagname, "x") == 0)
452 dkim_signature_parse_x(sig, buf, end);
453 else if (strcmp(tagname, "z") == 0)
454 dkim_signature_parse_z(sig, buf, end);
456 buf = osmtpd_ltok_skip_fws(end, 1);
457 if (buf[0] == ';')
458 buf++;
459 else if (buf[0] != '\0') {
460 dkim_signature_state(sig, DKIM_PERMERROR,
461 "Invalid tag-list");
462 return;
465 if (sig->state != DKIM_UNKNOWN)
466 return;
468 if (sig->v != 1)
469 dkim_signature_state(sig, DKIM_PERMERROR, "Missing v tag");
470 else if (sig->ah == NULL)
471 dkim_signature_state(sig, DKIM_PERMERROR, "Missing a tag");
472 else if (sig->b == NULL)
473 dkim_signature_state(sig, DKIM_PERMERROR, "Missing b tag");
474 else if (sig->bhsz == 0)
475 dkim_signature_state(sig, DKIM_PERMERROR, "Missing bh tag");
476 else if (sig->d[0] == '\0')
477 dkim_signature_state(sig, DKIM_PERMERROR, "Missing d tag");
478 else if (sig->h == NULL)
479 dkim_signature_state(sig, DKIM_PERMERROR, "Missing h tag");
480 else if (sig->s[0] == '\0')
481 dkim_signature_state(sig, DKIM_PERMERROR, "Missing s tag");
482 if (sig->state != DKIM_UNKNOWN)
483 return;
485 if (sig->i != NULL) {
486 i = osmtpd_ltok_skip_local_part(sig->i, 1) + 1;
487 ilen = sig->isz - (size_t)(i - sig->i);
488 dlen = strlen(sig->d);
489 if (ilen < dlen) {
490 dkim_signature_state(sig, DKIM_PERMERROR,
491 "i tag not subdomain of d");
492 return;
494 i += ilen - dlen;
495 if ((i[-1] != '.' && i[-1] != '@') ||
496 strncasecmp(i, sig->d, dlen) != 0) {
497 dkim_signature_state(sig, DKIM_PERMERROR,
498 "i tag not subdomain of d");
499 return;
502 if (sig->t != -1 && sig->x != -1 && sig->t > sig->x) {
503 dkim_signature_state(sig, DKIM_PERMERROR, "t tag after x tag");
504 return;
507 if ((size_t)snprintf(subdomain, sizeof(subdomain), "%s._domainkey.%s",
508 sig->s, sig->d) >= sizeof(subdomain)) {
509 dkim_signature_state(sig, DKIM_PERMERROR,
510 "dns/txt query too long");
511 return;
514 if ((query = res_query_async(subdomain, C_IN, T_TXT, NULL)) == NULL) {
515 dkim_err(header->msg, "res_query_async");
516 return;
518 if ((sig->query = event_asr_run(query, dkim_rr_resolve, sig)) == NULL) {
519 dkim_err(header->msg, "event_asr_run");
520 asr_abort(query);
521 return;
525 void
526 dkim_signature_parse_v(struct signature *sig, const char *start, const char *end)
528 if (sig->v != 0) { /* Duplicate tag */
529 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate v tag");
530 return;
532 /* Unsupported version */
533 if (start[0] != '1' || start + 1 != end)
534 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsupported v tag");
535 else
536 sig->v = 1;
539 void
540 dkim_signature_parse_a(struct signature *sig, const char *start, const char *end)
542 char ah[sizeof("sha256")];
544 if (sig->ah != NULL) {
545 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate a tag");
546 return;
549 if (osmtpd_ltok_skip_sig_a_tag_alg(start, 0) != end) {
550 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid a tag");
551 return;
553 sig->a = start;
554 sig->asz = (size_t)(end - start);
555 if (strncmp(start, "rsa-", 4) == 0) {
556 start += 4;
557 sig->ak = EVP_PKEY_RSA;
558 sig->sephash = 0;
559 #if HAVE_ED25519
560 } else if (strncmp(start, "ed25519-", 8) == 0) {
561 start += 8;
562 sig->ak = EVP_PKEY_ED25519;
563 sig->sephash = 1;
564 #endif
565 } else {
566 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag k");
567 return;
569 if ((size_t)(end - start) >= sizeof(ah)) {
570 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
571 return;
573 strlcpy(ah, start, sizeof(ah));
574 ah[end - start] = '\0';
575 if ((sig->ah = EVP_get_digestbyname(ah)) == NULL) {
576 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
577 return;
579 if ((sig->bhctx = EVP_MD_CTX_new()) == NULL) {
580 dkim_err(sig->header->msg, "EVP_MD_CTX_new");
581 return;
583 if (EVP_DigestInit_ex(sig->bhctx, sig->ah, NULL) <= 0) {
584 dkim_err(sig->header->msg, "EVP_DigestInit_ex");
585 return;
589 void
590 dkim_signature_parse_b(struct signature *sig, const char *start, const char *end)
592 int decodesz;
594 if (sig->b != NULL) {
595 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate b tag");
596 return;
598 sig->bheader = start;
599 if ((sig->b = malloc((((end - start) / 4) + 1) * 3)) == NULL) {
600 dkim_err(sig->header->msg, "malloc");
601 return;
603 /* EVP_DecodeBlock doesn't handle internal whitespace */
604 EVP_DecodeInit(ectx);
605 if (EVP_DecodeUpdate(ectx, sig->b, &decodesz, start,
606 (int)(end - start)) == -1) {
607 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
608 return;
610 sig->bsz = decodesz;
611 if (EVP_DecodeFinal(ectx, sig->b + sig->bsz,
612 &decodesz) == -1) {
613 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
614 return;
616 sig->bsz += decodesz;
619 void
620 dkim_signature_parse_bh(struct signature *sig, const char *start, const char *end)
622 const char *b64;
623 size_t n;
624 int decodesz;
626 if (sig->bhsz != 0) {
627 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate bh tag");
628 return;
630 /*
631 * EVP_Decode* expects sig->bh to be large enough,
632 * so count the actual b64 characters.
633 */
634 b64 = start;
635 n = 0;
636 while (1) {
637 b64 = osmtpd_ltok_skip_fws(b64, 1);
638 if (osmtpd_ltok_skip_alphadigitps(b64, 0) == NULL)
639 break;
640 n++;
641 b64++;
643 if (b64[0] == '=') {
644 n++;
645 b64 = osmtpd_ltok_skip_fws(b64 + 1, 1);
646 if (b64[0] == '=') {
647 n++;
648 b64++;
651 /* Invalid tag value */
652 if (b64 != end || n % 4 != 0 || (n / 4) * 3 > sizeof(sig->bh)) {
653 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
654 return;
656 /* EVP_DecodeBlock doesn't handle internal whitespace */
657 EVP_DecodeInit(ectx);
658 if (EVP_DecodeUpdate(ectx, sig->bh, &decodesz, start,
659 (int)(end - start)) == -1) {
660 /* Paranoia check */
661 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
662 return;
664 sig->bhsz = decodesz;
665 if (EVP_DecodeFinal(ectx, sig->bh + sig->bhsz, &decodesz) == -1) {
666 /* Paranoia check */
667 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
668 return;
670 sig->bhsz += decodesz;
673 void
674 dkim_signature_parse_c(struct signature *sig, const char *start, const char *end)
676 if (sig->c != 0) {
677 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate c tag");
678 return;
680 if (strncmp(start, "simple", 6) == 0) {
681 sig->c = CANON_HEADER_SIMPLE;
682 start += 6;
683 } else if (strncmp(start, "relaxed", 7) == 0) {
684 sig->c = CANON_HEADER_RELAXED;
685 start += 7;
686 } else {
687 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
688 return;
690 if (start[0] == '/') {
691 start++;
692 if (strncmp(start, "simple", 6) == 0) {
693 sig->c |= CANON_BODY_SIMPLE;
694 start += 6;
695 } else if (strncmp(start, "relaxed", 7) == 0) {
696 sig->c |= CANON_BODY_RELAXED;
697 start += 7;
698 } else {
699 dkim_signature_state(sig, DKIM_PERMERROR,
700 "Invalid c tag");
701 return;
705 if (start != end) {
706 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
707 return;
709 sig->c |= CANON_DONE;
712 void
713 dkim_signature_parse_d(struct signature *sig, const char *start, const char *end)
715 if (sig->d[0] != '\0') {
716 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate d tag");
717 return;
719 if (osmtpd_ltok_skip_sig_d_tag_value(start, 0) != end ||
720 (size_t)(end - start) >= sizeof(sig->d)) {
721 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid d tag");
722 return;
724 strlcpy(sig->d, start, end - start + 1);
727 void
728 dkim_signature_parse_h(struct signature *sig, const char *start, const char *end)
730 const char *h;
731 size_t n = 0;
733 if (sig->h != NULL) {
734 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate h tag");
735 return;
737 if (osmtpd_ltok_skip_sig_h_tag_value(start, 0) < end) {
738 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid h tag");
739 return;
741 h = start;
742 while (1) {
743 if ((h = osmtpd_ltok_skip_hdr_name(h, 0)) == NULL) {
744 dkim_signature_state(sig, DKIM_PERMERROR,
745 "Invalid h tag");
746 return;
748 n++;
749 /* ';' is part of hdr-name */
750 if (h > end) {
751 h = end;
752 break;
754 h = osmtpd_ltok_skip_fws(h, 1);
755 if (h[0] != ':')
756 break;
757 h = osmtpd_ltok_skip_fws(h + 1, 1);
759 if ((sig->h = calloc(n + 1, sizeof(*sig->h))) == NULL) {
760 dkim_err(sig->header->msg, "malloc");
761 return;
763 n = 0;
764 h = start;
765 while (1) {
766 h = osmtpd_ltok_skip_hdr_name(start, 0);
767 /* ';' is part of hdr-name */
768 if (h > end) {
769 sig->h[n] = strndup(start, end - start);
770 break;
772 if ((sig->h[n++] = strndup(start, h - start)) == NULL) {
773 dkim_err(sig->header->msg, "malloc");
774 return;
776 start = osmtpd_ltok_skip_fws(h, 1);
777 if (start[0] != ':')
778 break;
779 start = osmtpd_ltok_skip_fws(start + 1, 1);
783 void
784 dkim_signature_parse_i(struct signature *sig, const char *start, const char *end)
786 if (sig->i != NULL) {
787 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate i tag");
788 return;
790 if (osmtpd_ltok_skip_sig_i_tag_value(start, 0) != end) {
791 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
792 return;
794 sig->i = start;
795 sig->isz = (size_t)(end - start);
798 void
799 dkim_signature_parse_l(struct signature *sig, const char *start, const char *end)
801 long long l;
802 char *lend;
804 if (sig->l != -1) { /* Duplicate tag */
805 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate l tag");
806 return;
808 errno = 0;
809 l = strtoll(start, &lend, 10);
810 /* > 76 digits in stroll is an overflow */
811 if (osmtpd_ltok_skip_digit(start, 0) == NULL ||
812 lend != end || errno != 0) {
813 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid l tag");
814 return;
816 if (l > SSIZE_MAX) {
817 dkim_signature_state(sig, DKIM_PERMERROR, "l tag too large");
818 return;
820 sig->l = (ssize_t)l;
823 void
824 dkim_signature_parse_q(struct signature *sig, const char *start, const char *end)
826 const char *qend;
828 if (sig->q != 0) {
829 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate q tag");
830 return;
833 while (1) {
834 start = osmtpd_ltok_skip_fws(start, 1);
835 qend = osmtpd_ltok_skip_sig_q_tag_method(start, 0);
836 if (qend == NULL) {
837 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
838 return;
840 if (strncmp(start, "dns/txt", qend - start) == 0)
841 sig->q = 1;
842 start = osmtpd_ltok_skip_fws(qend, 1);
843 if (start[0] != ':')
844 break;
846 if (start != end) {
847 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
848 return;
850 if (sig->q != 1) {
851 sig->q = 1;
852 dkim_signature_state(sig, DKIM_NEUTRAL, "No useable q found");
853 return;
857 void
858 dkim_signature_parse_s(struct signature *sig, const char *start, const char *end)
860 if (sig->s[0] != '\0') {
861 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate s tag");
862 return;
864 if (osmtpd_ltok_skip_selector(start, 0) != end) {
865 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid s tag");
866 return;
868 strlcpy(sig->s, start, end - start + 1);
871 void
872 dkim_signature_parse_t(struct signature *sig, const char *start, const char *end)
874 char *tend;
876 if (sig->t != -1) {
877 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate t tag");
878 return;
880 errno = 0;
881 sig->t = strtoll(start, &tend, 10);
882 if (osmtpd_ltok_skip_digit(start, 0) == NULL || tend != end ||
883 tend - start > 12 || errno != 0) {
884 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid t tag");
885 return;
889 void
890 dkim_signature_parse_x(struct signature *sig, const char *start, const char *end)
892 char *xend;
894 if (sig->x != -1) {
895 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate x tag");
896 return;
898 errno = 0;
899 sig->x = strtoll(start, &xend, 10);
900 if (osmtpd_ltok_skip_digit(start, 0) == NULL || xend != end ||
901 xend - start > 12 || errno != 0) {
902 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid x tag");
903 return;
907 void
908 dkim_signature_parse_z(struct signature *sig, const char *start, const char *end)
910 if (sig->z != 0) {
911 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate z tag");
912 return;
915 sig->z = 1;
916 if (osmtpd_ltok_skip_sig_z_tag_value(start, 0) != end) {
917 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid z tag");
918 return;
922 void
923 dkim_signature_verify(struct signature *sig)
925 struct message *msg = sig->header->msg;
926 static EVP_MD_CTX *bctx = NULL;
927 char digest[EVP_MAX_MD_SIZE];
928 unsigned int digestsz;
929 const char *end;
930 size_t i, header;
932 if (sig->state != DKIM_UNKNOWN)
933 return;
935 if (bctx == NULL) {
936 if ((bctx = EVP_MD_CTX_new()) == NULL) {
937 dkim_errx(msg, "EVP_MD_CTX_new");
938 return;
941 EVP_MD_CTX_reset(bctx);
942 if (!sig->sephash) {
943 if (EVP_DigestVerifyInit(bctx, NULL, sig->ah, NULL,
944 sig->p) != 1) {
945 dkim_errx(msg, "EVP_DigestVerifyInit");
946 return;
948 } else {
949 if (EVP_DigestInit_ex(bctx, sig->ah, NULL) != 1) {
950 dkim_errx(msg, "EVP_DigestInit_ex");
951 return;
955 for (i = 0; i < msg->nheaders; i++)
956 msg->header[i].parsed = 0;
958 for (header = 0; sig->h[header] != NULL; header++) {
959 for (i = msg->nheaders; i > 0; ) {
960 i--;
961 if (msg->header[i].parsed ||
962 strncasecmp(msg->header[i].buf, sig->h[header],
963 strlen(sig->h[header])) != 0 ||
964 msg->header[i].sig == sig)
965 continue;
966 end = osmtpd_ltok_skip_fws(
967 msg->header[i].buf + strlen(sig->h[header]), 1);
968 if (end[0] != ':')
969 continue;
970 dkim_signature_header(bctx, sig, &(msg->header[i]));
971 msg->header[i].parsed = 1;
974 dkim_signature_header(bctx, sig, sig->header);
975 if (!sig->sephash) {
976 if (EVP_DigestVerifyFinal(bctx, sig->b, sig->bsz) != 1)
977 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
978 } else {
979 if (EVP_DigestFinal_ex(bctx, digest, &digestsz) == 0) {
980 dkim_errx(msg, "EVP_DigestFinal_ex");
981 return;
983 if (EVP_DigestVerifyInit(bctx, NULL, NULL, NULL, sig->p) != 1) {
984 dkim_errx(msg, "EVP_DigestVerifyInit");
985 return;
987 switch (EVP_DigestVerify(bctx, sig->b, sig->bsz, digest,
988 digestsz)) {
989 case 1:
990 break;
991 case 0:
992 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
993 break;
994 default:
995 dkim_errx(msg, "EVP_DigestVerify");
996 return;
1001 /* EVP_DigestVerifyUpdate is a macro, so we can't alias this on a variable */
1002 #define dkim_b_digest_update(a, b, c) \
1003 (sig->sephash ? EVP_DigestUpdate((a), (b), (c)) :\
1004 EVP_DigestVerifyUpdate((a), (b), (c)))
1006 void
1007 dkim_signature_header(EVP_MD_CTX *bctx, struct signature *sig,
1008 struct header *header)
1010 char c;
1011 const char *ptr = header->buf, *end;
1012 int inhdrname = 1;
1013 int canon = sig->c & CANON_HEADER;
1015 for (ptr = header->buf; ptr[0] != '\0'; ptr++) {
1016 if (inhdrname) {
1017 if (canon == CANON_HEADER_RELAXED) {
1018 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1019 c = tolower(ptr[0]);
1020 } else
1021 c = ptr[0];
1022 if (c == ':') {
1023 inhdrname = 0;
1024 if (canon == CANON_HEADER_RELAXED)
1025 ptr = osmtpd_ltok_skip_fws(
1026 ptr + 1, 1) - 1;
1028 if (dkim_b_digest_update(bctx, &c, 1) == 0) {
1029 dkim_errx(sig->header->msg,
1030 "dkim_b_digest_update");
1031 return;
1033 continue;
1035 end = osmtpd_ltok_skip_fws(ptr, 1);
1036 if (end == ptr) {
1037 if (sig->header == header && ptr == sig->bheader) {
1038 ptr = osmtpd_ltok_skip_tag_value(
1039 ptr, 0) - 1;
1040 continue;
1042 if (dkim_b_digest_update(bctx, ptr, 1) == 0) {
1043 dkim_errx(sig->header->msg,
1044 "dkim_b_digest_update");
1045 return;
1047 } else {
1048 if (canon == CANON_HEADER_RELAXED) {
1049 if (end[0] == '\0')
1050 continue;
1051 if (dkim_b_digest_update(bctx, " ", 1) == 0) {
1052 dkim_errx(sig->header->msg,
1053 "dkim_b_digest_update");
1054 return;
1056 } else {
1057 if (dkim_b_digest_update(bctx, ptr,
1058 end - ptr) == 0) {
1059 dkim_errx(sig->header->msg,
1060 "dkim_b_digest_update");
1061 return;
1064 ptr = end - 1;
1068 if (sig->header != header) {
1069 if (dkim_b_digest_update(bctx, "\r\n", 2) == 0) {
1070 dkim_errx(sig->header->msg, "dkim_b_digest_update");
1071 return;
1076 void
1077 dkim_signature_state(struct signature *sig, enum state state,
1078 const char *reason)
1080 if (sig->query != NULL) {
1081 event_asr_abort(sig->query);
1082 sig->query = NULL;
1084 switch (sig->state) {
1085 case DKIM_UNKNOWN:
1086 break;
1087 case DKIM_PASS:
1088 case DKIM_FAIL:
1089 osmtpd_errx(1, "Unexpected transition");
1090 case DKIM_POLICY:
1091 if (state == DKIM_PASS)
1092 return;
1093 break;
1094 case DKIM_NEUTRAL:
1095 if (state == DKIM_PASS)
1096 return;
1097 if (state == DKIM_TEMPERROR || state == DKIM_PERMERROR)
1098 break;
1099 osmtpd_errx(1, "Unexpected transition");
1100 case DKIM_TEMPERROR:
1101 if (state == DKIM_PERMERROR)
1102 break;
1103 return;
1104 case DKIM_PERMERROR:
1105 return;
1107 sig->state = state;
1108 sig->state_reason = reason;
1111 const char *
1112 dkim_state2str(enum state state)
1114 switch (state)
1116 case DKIM_UNKNOWN:
1117 return "unknown";
1118 case DKIM_PASS:
1119 return "pass";
1120 case DKIM_FAIL:
1121 return "fail";
1122 case DKIM_POLICY:
1123 return "policy";
1124 case DKIM_NEUTRAL:
1125 return "neutral";
1126 case DKIM_TEMPERROR:
1127 return "temperror";
1128 case DKIM_PERMERROR:
1129 return "permerror";
1133 void
1134 dkim_rr_resolve(struct asr_result *ar, void *arg)
1136 struct signature *sig = arg;
1137 char key[UINT16_MAX + 1];
1138 const char *rr_txt;
1139 size_t keylen, cstrlen;
1140 struct unpack pack;
1141 struct dns_header h;
1142 struct dns_query q;
1143 struct dns_rr rr;
1145 sig->query = NULL;
1147 if (ar->ar_h_errno == TRY_AGAIN || ar->ar_h_errno == NO_RECOVERY) {
1148 dkim_signature_state(sig, DKIM_TEMPERROR,
1149 hstrerror(ar->ar_h_errno));
1150 goto verify;
1152 if (ar->ar_h_errno != NETDB_SUCCESS) {
1153 dkim_signature_state(sig, DKIM_PERMERROR,
1154 hstrerror(ar->ar_h_errno));
1155 goto verify;
1158 unpack_init(&pack, ar->ar_data, ar->ar_datalen);
1159 if (unpack_header(&pack, &h) != 0 ||
1160 unpack_query(&pack, &q) != 0) {
1161 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid dns/txt");
1162 goto verify;
1164 for (; h.ancount > 0; h.ancount--) {
1165 unpack_rr(&pack, &rr);
1166 if (rr.rr_type != T_TXT)
1167 continue;
1169 keylen = 0;
1170 rr_txt = rr.rr.other.rdata;
1171 while (rr.rr.other.rdlen > 0) {
1172 cstrlen = ((const unsigned char *)rr_txt)[0];
1173 if (cstrlen >= rr.rr.other.rdlen ||
1174 keylen + cstrlen >= sizeof(key))
1175 break;
1177 * RFC 6376 Section 3.6.2.2
1178 * Strings in a TXT RR MUST be concatenated together
1179 * before use with no intervening whitespace.
1181 strlcpy(key + keylen, rr_txt + 1, cstrlen + 1);
1182 rr.rr.other.rdlen -= (cstrlen + 1);
1183 rr_txt += (cstrlen + 1);
1184 keylen += cstrlen;
1186 if (rr.rr.other.rdlen > 0) /* Invalid TXT RDATA */
1187 continue;
1189 if (dkim_key_text_parse(sig, key))
1190 break;
1193 if (h.ancount == 0) {
1194 dkim_signature_state(sig, DKIM_PERMERROR,
1195 "No matching key found");
1196 } else {
1197 /* Only verify if all headers have been read */
1198 if (!sig->header->msg->parsing_headers)
1199 dkim_signature_verify(sig);
1201 verify:
1202 free(ar->ar_data);
1203 dkim_message_verify(sig->header->msg);
1206 int
1207 dkim_key_text_parse(struct signature *sig, const char *key)
1209 char tagname, *hashname;
1210 const char *end, *tagvend;
1211 char pkraw[UINT16_MAX] = "", pkimp[UINT16_MAX];
1212 size_t pkrawlen = 0, pkoff, linelen;
1213 int h = 0, k = 0, n = 0, p = 0, s = 0, t = 0, first = 1;
1214 BIO *bio;
1215 #ifdef HAVE_ED25519
1216 size_t pklen;
1217 int tmp;
1218 #endif
1220 key = osmtpd_ltok_skip_fws(key, 1);
1221 /* Validate syntax early */
1222 if ((end = osmtpd_ltok_skip_tag_list(key, 0)) == NULL)
1223 return 0;
1225 while (key[0] != '\0') {
1226 key = osmtpd_ltok_skip_fws(key, 1);
1227 if ((end = osmtpd_ltok_skip_tag_name(key, 0)) == NULL)
1228 return 0;
1230 if ((size_t)(end - key) != 1)
1231 tagname = '\0';
1232 else
1233 tagname = key[0];
1234 key = osmtpd_ltok_skip_fws(end, 1);
1235 /* '=' */
1236 if (key[0] != '=')
1237 return 0;
1238 key = osmtpd_ltok_skip_fws(key + 1, 1);
1239 if ((end = osmtpd_ltok_skip_tag_value(key, 0)) == NULL)
1240 return 0;
1241 switch (tagname) {
1242 case 'v':
1244 * RFC 6376 section 3.6.1, v=:
1245 * RECOMMENDED...This tag MUST be the first tag in the
1246 * record.
1248 if (!first ||
1249 osmtpd_ltok_skip_key_v_tag_value(key, 0) != end)
1250 return 0;
1251 key = end;
1252 break;
1253 case 'h':
1254 if (h != 0) /* Duplicate tag */
1255 return 0;
1256 /* Invalid tag value */
1257 if (osmtpd_ltok_skip_key_h_tag_value(key, 0) != end)
1258 return 0;
1259 while (1) {
1260 if ((tagvend = osmtpd_ltok_skip_key_h_tag_alg(
1261 key, 0)) == NULL)
1262 break;
1263 hashname = strndup(key, tagvend - key);
1264 if (hashname == NULL) {
1265 dkim_err(sig->header->msg, "malloc");
1266 return 0;
1268 if (EVP_get_digestbyname(hashname) == sig->ah) {
1269 free(hashname);
1270 h = 1;
1271 break;
1273 free(hashname);
1274 key = osmtpd_ltok_skip_fws(tagvend, 1);
1275 if (key[0] != ':')
1276 break;
1277 key = osmtpd_ltok_skip_fws(key + 1, 1);
1279 if (h != 1)
1280 return 0;
1281 key = end;
1282 break;
1283 case 'k':
1284 if (k != 0) /* Duplicate tag */
1285 return 0;
1286 k = 1;
1287 if (strncmp(key, "rsa", end - key) == 0) {
1288 if (sig->ak != EVP_PKEY_RSA)
1289 return 0;
1290 #if HAVE_ED25519
1291 } else if (strncmp(key, "ed25519", end - key) == 0) {
1292 if (sig->ak != EVP_PKEY_ED25519)
1293 return 0;
1294 #endif
1295 } else
1296 return 0;
1297 key = end;
1298 break;
1299 case 'n':
1300 if (n != 0) /* Duplicate tag */
1301 return 0;
1302 n = 1;
1303 /* semicolon is part of safe-char */
1304 if (osmtpd_ltok_skip_key_n_tag_value(key, 0) < end)
1305 return 0;
1306 key = end;
1307 break;
1308 case 'p':
1309 if (p != 0) /* Duplicate tag */
1310 return 0;
1311 p = 1;
1312 while (1) {
1313 key = osmtpd_ltok_skip_fws(key, 1);
1314 if (osmtpd_ltok_skip_alphadigitps(
1315 key, 0) == NULL)
1316 break;
1317 pkraw[pkrawlen++] = key++[0];
1318 if (pkrawlen >= sizeof(pkraw))
1319 return 0;
1321 if (key[0] == '=') {
1322 pkraw[pkrawlen++] = '=';
1323 key = osmtpd_ltok_skip_fws(key + 1, 1);
1324 if (pkrawlen >= sizeof(pkraw))
1325 return 0;
1326 if (key[0] == '=') {
1327 pkraw[pkrawlen++] = '=';
1328 key++;
1329 if (pkrawlen >= sizeof(pkraw))
1330 return 0;
1333 /* Invalid tag value */
1334 if (pkrawlen % 4 != 0 || key != end)
1335 return 0;
1336 break;
1337 case 's':
1338 if (s != 0) /* Duplicate tag */
1339 return 0;
1340 /* Invalid tag value */
1341 if (osmtpd_ltok_skip_key_s_tag_value(key, 0) != end)
1342 return 0;
1343 while (1) {
1344 if ((tagvend =
1345 osmtpd_ltok_skip_key_s_tag_type(
1346 key, 0)) == NULL)
1347 break;
1348 if (strncmp(key, "*", tagvend - key) == 0 ||
1349 strncmp(key, "email", tagvend - key) == 0) {
1350 s = 1;
1351 break;
1353 key = osmtpd_ltok_skip_fws(tagvend, 1);
1354 if (key[0] != ':')
1355 break;
1356 key = osmtpd_ltok_skip_fws(key + 1, 1);
1358 if (s != 1)
1359 return 0;
1360 key = end;
1361 break;
1362 case 't':
1363 if (t != 0) /* Duplicate tag */
1364 return 0;
1365 t = 1;
1366 if (osmtpd_ltok_skip_key_t_tag_value(key, 0) != end)
1367 return 0;
1368 while (1) {
1369 tagvend = osmtpd_ltok_skip_key_t_tag_flag(
1370 key, 0);
1371 if (strncmp(key, "y", tagvend - key) == 0)
1372 sig->kt |= KT_Y;
1373 else if (strncmp(key, "s", tagvend - key) == 0)
1374 sig->kt |= KT_S;
1375 key = osmtpd_ltok_skip_fws(tagvend, 1);
1376 if (key[0] != ':')
1377 break;
1378 key = osmtpd_ltok_skip_fws(key + 1, 1);
1380 break;
1381 default:
1382 key = end;
1383 break;
1386 first = 0;
1387 key = osmtpd_ltok_skip_fws(key, 1);
1388 if (key[0] == ';')
1389 key++;
1390 else if (key[0] != '\0')
1391 return 0;
1394 if (!p) /* Missing tag */
1395 return 0;
1396 if (k == 0 && sig->ak != EVP_PKEY_RSA) /* Default to RSA */
1397 return 0;
1399 if (pkraw[0] == '\0') {
1400 dkim_signature_state(sig, DKIM_PERMERROR, "Key is revoked");
1401 return 1;
1404 switch (sig->ak) {
1405 case EVP_PKEY_RSA:
1406 pkoff = strlcpy(pkimp, "-----BEGIN PUBLIC KEY-----\n",
1407 sizeof(pkimp));
1408 linelen = 0;
1409 for (key = pkraw; key[0] != '\0';) {
1410 if (pkoff + 2 >= sizeof(pkimp))
1411 return 0;
1412 pkimp[pkoff++] = key++[0];
1413 if (++linelen == 64) {
1414 pkimp[pkoff++] = '\n';
1415 linelen = 0;
1418 /* Leverage pkoff check in loop */
1419 if (linelen != 0)
1420 pkimp[pkoff++] = '\n';
1421 /* PEM_read_bio_PUBKEY will catch truncated keys */
1422 pkoff += strlcpy(pkimp + pkoff, "-----END PUBLIC KEY-----\n",
1423 sizeof(pkimp) - pkoff);
1424 if ((bio = BIO_new_mem_buf(pkimp, pkoff)) == NULL) {
1425 dkim_err(sig->header->msg, "BIO_new_mem_buf");
1426 return 1;
1428 sig->p = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
1429 BIO_free(bio);
1430 break;
1431 #if HAVE_ED25519
1432 case EVP_PKEY_ED25519:
1433 if ((pkrawlen / 4) * 3 >= sizeof(pkimp))
1434 return 0;
1435 EVP_DecodeInit(ectx);
1436 if (EVP_DecodeUpdate(ectx, pkimp, &tmp, pkraw, pkrawlen) == -1)
1437 return 0;
1438 pklen = tmp;
1439 if (EVP_DecodeFinal(ectx, pkimp, &tmp) == -1)
1440 return 0;
1441 pklen += tmp;
1442 sig->p = EVP_PKEY_new_raw_public_key(sig->ak, NULL, pkimp,
1443 pklen);
1444 break;
1445 #endif
1447 if (sig->p == NULL) {
1449 * XXX No clue how to differentiate between invalid key and
1450 * temporary failure like *alloc.
1451 * Assume invalid key, because it's more likely.
1453 return 0;
1455 return 1;
1458 void
1459 dkim_body_parse(struct message *msg, const char *line)
1461 struct signature *sig;
1462 const char *end = line, *hash, *prev;
1463 size_t hashn, len, i;
1464 int wsp, ret;
1466 if (line[0] == '\0') {
1467 msg->body_whitelines++;
1468 return;
1471 while (msg->body_whitelines-- > 0) {
1472 for (i = 0; i < msg->nheaders; i++) {
1473 if ((sig = msg->header[i].sig) == NULL ||
1474 sig->state != DKIM_UNKNOWN)
1475 continue;
1476 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1477 sig->l -= sig->l == -1 ? 0 : hashn;
1478 if (EVP_DigestUpdate(sig->bhctx, "\r\n", hashn) == 0) {
1479 dkim_errx(msg, "EVP_DigestUpdate");
1480 return;
1484 msg->body_whitelines = 0;
1485 msg->has_body = 1;
1487 while (line[0] != '\0') {
1488 while (1) {
1489 prev = end;
1490 if ((end = osmtpd_ltok_skip_wsp(end, 0)) == NULL)
1491 break;
1493 end = prev;
1494 wsp = end != line;
1495 if (!wsp) {
1496 while (osmtpd_ltok_skip_wsp(end, 0) == NULL &&
1497 end[0] != '\0')
1498 end++;
1500 for (i = 0; i < msg->nheaders; i++) {
1501 sig = msg->header[i].sig;
1502 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1503 continue;
1504 if (wsp &&
1505 (sig->c & CANON_BODY) == CANON_BODY_RELAXED) {
1506 hash = " ";
1507 len = end[0] == '\0' ? 0 : 1;
1508 } else {
1509 hash = line;
1510 len = (size_t)(end - line);
1512 hashn = sig->l == -1 ? len : MIN(len, (size_t)sig->l);
1513 sig->l -= sig->l == -1 ? 0 : hashn;
1514 ret = EVP_DigestUpdate(sig->bhctx, hash, hashn);
1515 if (ret == 0) {
1516 dkim_errx(msg, "EVP_DigestUpdate");
1517 return;
1520 line = end;
1522 for (i = 0; i < msg->nheaders; i++) {
1523 sig = msg->header[i].sig;
1524 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1525 continue;
1526 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1527 sig->l -= sig->l == -1 ? 0 : hashn;
1528 ret = EVP_DigestUpdate(sig->bhctx, "\r\n", hashn);
1529 if (ret == 0) {
1530 dkim_errx(msg, "EVP_DigestUpdate");
1531 return;
1536 void
1537 dkim_body_verify(struct signature *sig)
1539 unsigned char digest[EVP_MAX_MD_SIZE];
1540 unsigned int digestsz;
1542 if (sig->state != DKIM_UNKNOWN)
1543 return;
1545 if ((sig->c & CANON_BODY) == CANON_BODY_SIMPLE &&
1546 !sig->header->msg->has_body) {
1547 if (EVP_DigestUpdate(sig->bhctx, "\r\n",
1548 sig->l == -1 ? 2 : MIN(2, sig->l)) <= 0) {
1549 dkim_errx(sig->header->msg,
1550 "Can't update hash context");
1551 return;
1554 if (sig->l > 0) {
1555 dkim_signature_state(sig, DKIM_PERMERROR,
1556 "l tag larger than body");
1557 return;
1560 if (EVP_DigestFinal_ex(sig->bhctx, digest, &digestsz) == 0) {
1561 dkim_errx(sig->header->msg, "EVP_DigestFinal_ex");
1562 return;
1565 if (digestsz != sig->bhsz || memcmp(digest, sig->bh, digestsz) != 0)
1566 dkim_signature_state(sig, DKIM_FAIL, "bh mismatch");
1569 void
1570 dkim_message_verify(struct message *msg)
1572 struct signature *sig;
1573 size_t i;
1574 ssize_t n, aroff = 0;
1575 int found = 0;
1576 char *line = NULL;
1577 size_t linelen = 0;
1579 if (!msg->readdone)
1580 return;
1582 for (i = 0; i < msg->nheaders; i++) {
1583 if (msg->header[i].sig == NULL)
1584 continue;
1585 if (msg->header[i].sig->query != NULL)
1586 return;
1587 if (msg->header[i].sig->state != DKIM_UNKNOWN)
1588 continue;
1589 dkim_signature_state(msg->header[i].sig, DKIM_PASS, NULL);
1592 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1593 "Authentication-Results: %s", authservid)) == -1) {
1594 dkim_err(msg, "malloc");
1595 goto fail;
1597 for (i = 0; i < msg->nheaders; i++) {
1598 sig = msg->header[i].sig;
1599 if (sig == NULL)
1600 continue;
1601 found = 1;
1602 if ((aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=%s",
1603 dkim_state2str(sig->state))) == -1) {
1604 dkim_err(msg, "malloc");
1605 goto fail;
1607 if (sig->state_reason != NULL) {
1608 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1609 " reason=\"%s\"", sig->state_reason)) == -1) {
1610 dkim_err(msg, "malloc");
1611 goto fail;
1614 if (sig->s[0] != '\0') {
1615 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1616 " header.s=%s", sig->s)) == -1) {
1617 dkim_err(msg, "malloc");
1618 goto fail;
1621 if (sig->d[0] != '\0') {
1622 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1623 " header.d=%s", sig->d)) == -1) {
1624 dkim_err(msg, "malloc");
1625 goto fail;
1629 * Don't print i-tag, since localpart can be a quoted-string,
1630 * which can contain FWS and CFWS.
1632 if (sig->a != NULL) {
1633 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1634 " header.a=%.*s", (int)sig->asz, sig->a)) == -1) {
1635 dkim_err(msg, "malloc");
1636 goto fail;
1640 if (!found) {
1641 aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=none");
1642 if (aroff == -1) {
1643 dkim_err(msg, "malloc");
1644 goto fail;
1647 dkim_ar_print(msg->ctx, line);
1649 rewind(msg->origf);
1650 while ((n = getline(&line, &linelen, msg->origf)) != -1) {
1651 line[n - 1] = '\0';
1652 osmtpd_filter_dataline(msg->ctx, "%s", line);
1654 if (ferror(msg->origf))
1655 dkim_err(msg, "getline");
1656 fail:
1657 free(line);
1658 return;
1661 void
1662 dkim_ar_print(struct osmtpd_ctx *ctx, const char *start)
1664 const char *scan, *checkpoint, *ncheckpoint;
1665 size_t arlen = 0;
1666 int first = 1, arid = 1;
1668 checkpoint = start;
1669 ncheckpoint = osmtpd_ltok_skip_hdr_name(start, 0) + 1;
1670 for (scan = start; scan[0] != '\0'; scan++) {
1671 if (scan[0] == '\t')
1672 arlen = (arlen + 8) & ~7;
1673 else
1674 arlen++;
1675 if (arlen >= AUTHENTICATION_RESULTS_LINELEN) {
1676 osmtpd_filter_dataline(ctx, "%s%.*s", first ? "" : "\t",
1677 (int)((checkpoint == start ?
1678 ncheckpoint : checkpoint) - start), start);
1679 start = osmtpd_ltok_skip_cfws(checkpoint, 1);
1680 scan = start;
1681 arlen = 8;
1682 first = 0;
1684 if (scan == ncheckpoint) {
1685 checkpoint = ncheckpoint;
1686 ncheckpoint = osmtpd_ltok_skip_cfws(ncheckpoint, 1);
1687 /* authserv-id */
1688 if (arid) {
1689 ncheckpoint = osmtpd_ltok_skip_value(
1690 ncheckpoint, 0);
1691 arid = 0;
1692 /* methodspec */
1693 } else if (strncmp(ncheckpoint, "dkim",
1694 sizeof("dkim") - 1) == 0) {
1695 ncheckpoint = osmtpd_ltok_skip_keyword(
1696 ncheckpoint + sizeof("dkim"), 0);
1697 /* reasonspec */
1698 } else if (strncmp(ncheckpoint, "reason",
1699 sizeof("reason") - 1) == 0) {
1700 ncheckpoint = osmtpd_ltok_skip_value(
1701 ncheckpoint + sizeof("reason"), 0);
1702 /* propspec */
1703 } else {
1704 ncheckpoint += sizeof("header.x=") - 1;
1705 ncheckpoint = osmtpd_ltok_skip_ar_pvalue(
1706 ncheckpoint, 0);
1707 if (ncheckpoint[0] == ';')
1708 ncheckpoint++;
1712 osmtpd_filter_dataline(ctx, "%s%s", first ? "" : "\t", start);
1715 ssize_t
1716 dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
1718 va_list ap;
1719 char *artmp;
1720 int size;
1721 size_t nn;
1723 va_start(ap, fmt);
1724 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1725 va_end(ap);
1726 if (size + aroff <= *n)
1727 return (ssize_t)size + aroff;
1728 nn = (((aroff + size) / 256) + 1) * 256;
1729 artmp = realloc(*ar, nn);
1730 if (artmp == NULL)
1731 return -1;
1732 *ar = artmp;
1733 *n = nn;
1734 va_start(ap, fmt);
1735 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1736 va_end(ap);
1737 return (ssize_t)size + aroff;
1740 void
1741 dkim_err(struct message *msg, char *text)
1743 msg->err = 1;
1744 fprintf(stderr, "%s: %s\n", text, strerror(errno));
1747 void
1748 dkim_errx(struct message *msg, char *text)
1750 msg->err = 1;
1751 fprintf(stderr, "%s\n", text);
1754 __dead void
1755 usage(void)
1757 fprintf(stderr, "usage: filter-dkimverify\n");
1758 exit(1);