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 size_t bheadersz;
71 #define HEADER_B_MAX_LEN 8
72 char bheaderclean[HEADER_B_MAX_LEN + 1];
73 /* Make sure padding bits for base64 decoding fit */
74 char bh[EVP_MAX_MD_SIZE + (3 - (EVP_MAX_MD_SIZE % 3))];
75 size_t bhsz;
76 EVP_MD_CTX *bhctx;
77 int c;
78 #define CANON_HEADER_SIMPLE 0
79 #define CANON_HEADER_RELAXED 1
80 #define CANON_HEADER 1
81 #define CANON_BODY_SIMPLE 0
82 #define CANON_BODY_RELAXED 1 << 1
83 #define CANON_BODY 1 << 1
84 #define CANON_DONE 1 << 2
85 char d[HOST_NAME_MAX + 1];
86 char **h;
87 const char *i;
88 size_t isz;
89 ssize_t l;
90 int q;
91 char s[HOST_NAME_MAX + 1];
92 time_t t; /* Signature t=/timestamp */
93 #define KT_Y 1
94 #define KT_S 1 << 1
95 int kt; /* Key t=/Flags */
96 time_t x;
97 int z;
98 struct event_asr *query;
99 EVP_PKEY *p;
100 };
102 struct header {
103 struct message *msg;
104 uint8_t readdone;
105 uint8_t parsed;
106 char *buf;
107 size_t buflen;
108 struct signature *sig;
109 };
111 #define AUTHENTICATION_RESULTS_LINELEN 78
112 #define MIN(a, b) ((a) < (b) ? (a) : (b))
114 struct message {
115 struct osmtpd_ctx *ctx;
116 FILE *origf;
117 int parsing_headers;
118 size_t body_whitelines;
119 int has_body;
120 struct header *header;
121 size_t nheaders;
122 int err;
123 int readdone;
124 };
126 void usage(void);
127 void dkim_err(struct message *, char *);
128 void dkim_errx(struct message *, char *);
129 void dkim_conf(const char *, const char *);
130 void dkim_dataline(struct osmtpd_ctx *, const char *);
131 void dkim_commit(struct osmtpd_ctx *);
132 void *dkim_message_new(struct osmtpd_ctx *);
133 void dkim_message_free(struct osmtpd_ctx *, void *);
134 void dkim_header_add(struct osmtpd_ctx *, const char *);
135 void dkim_signature_parse(struct header *);
136 void dkim_signature_parse_v(struct signature *, const char *, const char *);
137 void dkim_signature_parse_a(struct signature *, const char *, const char *);
138 void dkim_signature_parse_b(struct signature *, const char *, const char *);
139 void dkim_signature_parse_bh(struct signature *, const char *, const char *);
140 void dkim_signature_parse_c(struct signature *, const char *, const char *);
141 void dkim_signature_parse_d(struct signature *, const char *, const char *);
142 void dkim_signature_parse_h(struct signature *, const char *, const char *);
143 void dkim_signature_parse_i(struct signature *, const char *, const char *);
144 void dkim_signature_parse_l(struct signature *, const char *, const char *);
145 void dkim_signature_parse_q(struct signature *, const char *, const char *);
146 void dkim_signature_parse_s(struct signature *, const char *, const char *);
147 void dkim_signature_parse_t(struct signature *, const char *, const char *);
148 void dkim_signature_parse_x(struct signature *, const char *, const char *);
149 void dkim_signature_parse_z(struct signature *, const char *, const char *);
150 void dkim_signature_verify(struct signature *);
151 void dkim_signature_header(EVP_MD_CTX *, struct signature *, struct header *);
152 void dkim_signature_state(struct signature *, enum state, const char *);
153 const char *dkim_state2str(enum state);
154 void dkim_header_cat(struct osmtpd_ctx *, const char *);
155 void dkim_body_parse(struct message *, const char *);
156 void dkim_body_verify(struct signature *);
157 void dkim_rr_resolve(struct asr_result *, void *);
158 void dkim_message_verify(struct message *);
159 ssize_t dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
160 __attribute__((__format__ (printf, 4, 5)));
161 int dkim_ar_print(struct osmtpd_ctx *, const char *);
162 int dkim_key_text_parse(struct signature *, const char *);
164 char *authservid;
165 EVP_ENCODE_CTX *ectx = NULL;
167 int
168 main(int argc, char *argv[])
170 if (argc != 1)
171 osmtpd_errx(1, "Invalid argument count");
173 OpenSSL_add_all_digests();
175 if (pledge("tmppath stdio dns", NULL) == -1)
176 osmtpd_err(1, "pledge");
178 if ((ectx = EVP_ENCODE_CTX_new()) == NULL)
179 osmtpd_err(1, "EVP_ENCODE_CTX_new");
181 osmtpd_register_conf(dkim_conf);
182 osmtpd_register_filter_dataline(dkim_dataline);
183 osmtpd_register_filter_commit(dkim_commit);
184 osmtpd_local_message(dkim_message_new, dkim_message_free);
185 osmtpd_run();
187 return 0;
190 void
191 dkim_conf(const char *key, const char *value)
193 const char *end;
195 if (key == NULL) {
196 if (authservid == NULL)
197 osmtpd_errx(1, "Didn't receive admd config option");
198 return;
200 if (strcmp(key, "admd") == 0 && authservid == NULL) {
201 if ((authservid = strdup(value)) == NULL)
202 osmtpd_err(1, "malloc");
203 end = osmtpd_ltok_skip_value(authservid, 0);
204 if (authservid + strlen(authservid) != end)
205 osmtpd_errx(1, "Invalid authservid");
209 void
210 dkim_dataline(struct osmtpd_ctx *ctx, const char *line)
212 struct message *msg = ctx->local_message;
213 size_t i;
215 if (msg->err) {
216 if (line[0] == '.' && line[1] =='\0') {
217 msg->readdone = 1;
218 osmtpd_filter_dataline(ctx, ".");
220 return;
223 if (fprintf(msg->origf, "%s\n", line) < 0) {
224 dkim_err(msg, "Couldn't write to tempfile");
225 return;
227 if (line[0] == '.') {
228 line++;
229 if (line[0] == '\0') {
230 msg->readdone = 1;
231 for (i = 0; i < msg->nheaders; i++) {
232 if (msg->header[i].sig == NULL)
233 continue;
234 dkim_body_verify(msg->header[i].sig);
236 dkim_message_verify(msg);
237 return;
240 if (msg->parsing_headers) {
241 dkim_header_add(ctx, line);
242 if (line[0] == '\0') {
243 msg->parsing_headers = 0;
244 for (i = 0; i < msg->nheaders; i++) {
245 if (msg->header[i].sig == NULL)
246 continue;
247 if (msg->header[i].sig->query == NULL)
248 dkim_signature_verify(
249 msg->header[i].sig);
252 return;
253 } else {
254 dkim_body_parse(msg, line);
258 void
259 dkim_commit(struct osmtpd_ctx *ctx)
261 struct message *msg = ctx->local_message;
263 if (msg->err)
264 osmtpd_filter_disconnect(ctx, "Internal server error");
265 else
266 osmtpd_filter_proceed(ctx);
269 void *
270 dkim_message_new(struct osmtpd_ctx *ctx)
272 struct message *msg;
274 if ((msg = malloc(sizeof(*msg))) == NULL)
275 osmtpd_err(1, NULL);
277 if ((msg->origf = tmpfile()) == NULL) {
278 dkim_err(msg, "Can't open tempfile");
279 free(msg);
280 return NULL;
282 msg->ctx = ctx;
283 msg->parsing_headers = 1;
284 msg->body_whitelines = 0;
285 msg->has_body = 0;
286 msg->header = NULL;
287 msg->nheaders = 0;
288 msg->err = 0;
289 msg->readdone = 0;
291 return msg;
294 void
295 dkim_message_free(struct osmtpd_ctx *ctx, void *data)
297 struct message *msg = data;
298 size_t i, j;
300 fclose(msg->origf);
301 for (i = 0; i < msg->nheaders; i++) {
302 if (msg->header[i].sig != NULL) {
303 free(msg->header[i].sig->b);
304 EVP_MD_CTX_free(msg->header[i].sig->bhctx);
305 for (j = 0; msg->header[i].sig->h != NULL &&
306 msg->header[i].sig->h[j] != NULL; j++)
307 free(msg->header[i].sig->h[j]);
308 free(msg->header[i].sig->h);
309 EVP_PKEY_free(msg->header[i].sig->p);
311 free(msg->header[i].buf);
312 free(msg->header[i].sig);
314 free(msg->header);
315 free(msg);
318 void
319 dkim_header_add(struct osmtpd_ctx *ctx, const char *line)
321 struct message *msg = ctx->local_message;
322 const char *start, *end, *verify;
323 struct header *headers;
324 size_t i;
326 if (msg->nheaders > 0 &&
327 msg->header[msg->nheaders - 1].readdone == 0) {
328 if (line[0] != ' ' && line[0] != '\t') {
329 msg->header[msg->nheaders - 1].readdone = 1;
330 start = msg->header[msg->nheaders - 1].buf;
331 end = osmtpd_ltok_skip_field_name(start, 0);
332 /* In case someone uses an obs-optional */
333 if (end != NULL)
334 verify = osmtpd_ltok_skip_wsp(end, 1);
335 if (end != NULL &&
336 strncasecmp(
337 start, "DKIM-Signature", end - start) == 0 &&
338 verify[0] == ':')
339 dkim_signature_parse(
340 &msg->header[msg->nheaders - 1]);
341 if (line[0] == '\0')
342 return;
343 } else {
344 dkim_header_cat(ctx, line);
345 return;
348 if (msg->nheaders % 10 == 0) {
349 if ((headers = recallocarray(msg->header, msg->nheaders,
350 msg->nheaders + 10, sizeof(*msg->header))) == NULL) {
351 dkim_err(msg, "malloc");
352 return;
354 msg->header = headers;
355 for (i = 0; i < msg->nheaders; i++) {
356 if (msg->header[i].sig == NULL)
357 continue;
358 msg->header[i].sig->header = &msg->header[i];
361 msg->header[msg->nheaders].msg = msg;
362 msg->nheaders++;
363 dkim_header_cat(ctx, line);
366 void
367 dkim_header_cat(struct osmtpd_ctx *ctx, const char *line)
369 struct message *msg = ctx->local_message;
370 struct header *header = &msg->header[msg->nheaders - 1];
371 char *buf;
373 size_t needed = header->buflen + strlen(line) + 2;
375 if (needed > (header->buflen / 1024) + 1) {
376 buf = reallocarray(header->buf, (needed / 1024) + 1, 1024);
377 if (buf == NULL) {
378 dkim_err(msg, "malloc");
379 return;
381 header->buf = buf;
383 header->buflen += snprintf(header->buf + header->buflen,
384 (((needed / 1024) + 1) * 1024) - header->buflen, "%s%s",
385 header->buflen == 0 ? "" : "\r\n", line);
388 void
389 dkim_signature_parse(struct header *header)
391 struct signature *sig;
392 struct asr_query *query;
393 const char *buf, *i, *end;
394 char tagname[3];
395 char subdomain[HOST_NAME_MAX + 1];
396 size_t ilen, dlen;
398 /* Format checked by dkim_header_add */
399 buf = osmtpd_ltok_skip_field_name(header->buf, 0);
400 buf = osmtpd_ltok_skip_wsp(buf, 1) + 1;
402 if ((header->sig = calloc(1, sizeof(*header->sig))) == NULL) {
403 dkim_err(header->msg, "malloc");
404 return;
406 sig = header->sig;
407 sig->header = header;
408 sig->l = -1;
409 sig->t = -1;
410 sig->x = -1;
412 end = osmtpd_ltok_skip_tag_list(buf, 0);
413 if (end == NULL || end[0] != '\0') {
414 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid tag-list");
415 return;
418 while (buf[0] != '\0') {
419 buf = osmtpd_ltok_skip_fws(buf, 1);
420 end = osmtpd_ltok_skip_tag_name(buf, 0);
422 /* Unknown tag-name */
423 if ((size_t)(end - buf) >= sizeof(tagname))
424 tagname[0] = '\0';
425 else
426 strlcpy(tagname, buf, (end - buf) + 1);
427 buf = osmtpd_ltok_skip_fws(end, 1);
428 /* '=' */
429 buf = osmtpd_ltok_skip_fws(buf + 1, 1);
430 end = osmtpd_ltok_skip_tag_value(buf, 1);
431 if (strcmp(tagname, "v") == 0)
432 dkim_signature_parse_v(sig, buf, end);
433 else if (strcmp(tagname, "a") == 0)
434 dkim_signature_parse_a(sig, buf, end);
435 else if (strcmp(tagname, "b") == 0)
436 dkim_signature_parse_b(sig, buf, end);
437 else if (strcmp(tagname, "bh") == 0)
438 dkim_signature_parse_bh(sig, buf, end);
439 else if (strcmp(tagname, "c") == 0)
440 dkim_signature_parse_c(sig, buf, end);
441 else if (strcmp(tagname, "d") == 0)
442 dkim_signature_parse_d(sig, buf, end);
443 else if (strcmp(tagname, "h") == 0)
444 dkim_signature_parse_h(sig, buf, end);
445 else if (strcmp(tagname, "i") == 0)
446 dkim_signature_parse_i(sig, buf, end);
447 else if (strcmp(tagname, "l") == 0)
448 dkim_signature_parse_l(sig, buf, end);
449 else if (strcmp(tagname, "q") == 0)
450 dkim_signature_parse_q(sig, buf, end);
451 else if (strcmp(tagname, "s") == 0)
452 dkim_signature_parse_s(sig, buf, end);
453 else if (strcmp(tagname, "t") == 0)
454 dkim_signature_parse_t(sig, buf, end);
455 else if (strcmp(tagname, "x") == 0)
456 dkim_signature_parse_x(sig, buf, end);
457 else if (strcmp(tagname, "z") == 0)
458 dkim_signature_parse_z(sig, buf, end);
460 buf = osmtpd_ltok_skip_fws(end, 1);
461 if (buf[0] == ';')
462 buf++;
463 else if (buf[0] != '\0') {
464 dkim_signature_state(sig, DKIM_PERMERROR,
465 "Invalid tag-list");
466 return;
469 if (sig->state != DKIM_UNKNOWN)
470 return;
472 if (sig->v != 1)
473 dkim_signature_state(sig, DKIM_PERMERROR, "Missing v tag");
474 else if (sig->ah == NULL)
475 dkim_signature_state(sig, DKIM_PERMERROR, "Missing a tag");
476 else if (sig->b == NULL)
477 dkim_signature_state(sig, DKIM_PERMERROR, "Missing b tag");
478 else if (sig->bhsz == 0)
479 dkim_signature_state(sig, DKIM_PERMERROR, "Missing bh tag");
480 else if (sig->d[0] == '\0')
481 dkim_signature_state(sig, DKIM_PERMERROR, "Missing d tag");
482 else if (sig->h == NULL)
483 dkim_signature_state(sig, DKIM_PERMERROR, "Missing h tag");
484 else if (sig->s[0] == '\0')
485 dkim_signature_state(sig, DKIM_PERMERROR, "Missing s tag");
486 if (sig->state != DKIM_UNKNOWN)
487 return;
489 if (sig->i != NULL) {
490 i = osmtpd_ltok_skip_local_part(sig->i, 1) + 1;
491 ilen = sig->isz - (size_t)(i - sig->i);
492 dlen = strlen(sig->d);
493 if (ilen < dlen) {
494 dkim_signature_state(sig, DKIM_PERMERROR,
495 "i tag not subdomain of d");
496 return;
498 i += ilen - dlen;
499 if ((i[-1] != '.' && i[-1] != '@') ||
500 strncasecmp(i, sig->d, dlen) != 0) {
501 dkim_signature_state(sig, DKIM_PERMERROR,
502 "i tag not subdomain of d");
503 return;
506 if (sig->t != -1 && sig->x != -1 && sig->t > sig->x) {
507 dkim_signature_state(sig, DKIM_PERMERROR, "t tag after x tag");
508 return;
511 if ((size_t)snprintf(subdomain, sizeof(subdomain), "%s._domainkey.%s",
512 sig->s, sig->d) >= sizeof(subdomain)) {
513 dkim_signature_state(sig, DKIM_PERMERROR,
514 "dns/txt query too long");
515 return;
518 if ((query = res_query_async(subdomain, C_IN, T_TXT, NULL)) == NULL) {
519 dkim_err(header->msg, "res_query_async");
520 return;
522 if ((sig->query = event_asr_run(query, dkim_rr_resolve, sig)) == NULL) {
523 dkim_err(header->msg, "event_asr_run");
524 asr_abort(query);
525 return;
529 void
530 dkim_signature_parse_v(struct signature *sig, const char *start, const char *end)
532 if (sig->v != 0) { /* Duplicate tag */
533 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate v tag");
534 return;
536 /* Unsupported version */
537 if (start[0] != '1' || start + 1 != end)
538 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsupported v tag");
539 else
540 sig->v = 1;
543 void
544 dkim_signature_parse_a(struct signature *sig, const char *start, const char *end)
546 char ah[sizeof("sha256")];
548 if (sig->ah != NULL) {
549 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate a tag");
550 return;
553 if (osmtpd_ltok_skip_sig_a_tag_alg(start, 0) != end) {
554 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid a tag");
555 return;
557 sig->a = start;
558 sig->asz = (size_t)(end - start);
559 if (strncmp(start, "rsa-", 4) == 0) {
560 start += 4;
561 sig->ak = EVP_PKEY_RSA;
562 sig->sephash = 0;
563 #if HAVE_ED25519
564 } else if (strncmp(start, "ed25519-", 8) == 0) {
565 start += 8;
566 sig->ak = EVP_PKEY_ED25519;
567 sig->sephash = 1;
568 #endif
569 } else {
570 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag k");
571 return;
573 if ((size_t)(end - start) >= sizeof(ah)) {
574 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
575 return;
577 strlcpy(ah, start, sizeof(ah));
578 ah[end - start] = '\0';
579 if ((sig->ah = EVP_get_digestbyname(ah)) == NULL) {
580 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
581 return;
583 if ((sig->bhctx = EVP_MD_CTX_new()) == NULL) {
584 dkim_err(sig->header->msg, "EVP_MD_CTX_new");
585 return;
587 if (EVP_DigestInit_ex(sig->bhctx, sig->ah, NULL) <= 0) {
588 dkim_err(sig->header->msg, "EVP_DigestInit_ex");
589 return;
593 void
594 dkim_signature_parse_b(struct signature *sig, const char *start, const char *end)
596 int decodesz;
597 size_t i, j;
599 if (sig->b != NULL) {
600 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate b tag");
601 return;
603 sig->bheader = start;
604 sig->bheadersz = end - start;
605 if ((sig->b = malloc(((sig->bheadersz / 4) + 1) * 3)) == NULL)
606 osmtpd_err(1, "malloc");
607 /* EVP_DecodeBlock doesn't handle internal whitespace */
608 EVP_DecodeInit(ectx);
609 if (EVP_DecodeUpdate(ectx, sig->b, &decodesz, sig->bheader,
610 (int) sig->bheadersz) == -1) {
611 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
612 return;
614 sig->bsz = decodesz;
615 if (EVP_DecodeFinal(ectx, sig->b + sig->bsz,
616 &decodesz) == -1) {
617 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
618 return;
620 sig->bsz += decodesz;
621 for (i = 0, j = 0;
622 i < sig->bheadersz && j < HEADER_B_MAX_LEN; i++) {
623 if (isalnum(sig->bheader[i]) || sig->bheader[i] == '/'
624 || sig->bheader[i] == '+' || sig->bheader[i] == '=')
625 sig->bheaderclean[j++] = sig->bheader[i];
627 sig->bheaderclean[j] = '\0';
630 void
631 dkim_signature_parse_bh(struct signature *sig, const char *start, const char *end)
633 const char *b64;
634 size_t n;
635 int decodesz;
637 if (sig->bhsz != 0) {
638 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate bh tag");
639 return;
641 /*
642 * EVP_Decode* expects sig->bh to be large enough,
643 * so count the actual b64 characters.
644 */
645 b64 = start;
646 n = 0;
647 while (1) {
648 b64 = osmtpd_ltok_skip_fws(b64, 1);
649 if (osmtpd_ltok_skip_alphadigitps(b64, 0) == NULL)
650 break;
651 n++;
652 b64++;
654 if (b64[0] == '=') {
655 n++;
656 b64 = osmtpd_ltok_skip_fws(b64 + 1, 1);
657 if (b64[0] == '=') {
658 n++;
659 b64++;
662 /* Invalid tag value */
663 if (b64 != end || n % 4 != 0 || (n / 4) * 3 > sizeof(sig->bh)) {
664 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
665 return;
667 /* EVP_DecodeBlock doesn't handle internal whitespace */
668 EVP_DecodeInit(ectx);
669 if (EVP_DecodeUpdate(ectx, sig->bh, &decodesz, start,
670 (int)(end - start)) == -1) {
671 /* Paranoia check */
672 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
673 return;
675 sig->bhsz = decodesz;
676 if (EVP_DecodeFinal(ectx, sig->bh + sig->bhsz, &decodesz) == -1) {
677 /* Paranoia check */
678 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
679 return;
681 sig->bhsz += decodesz;
684 void
685 dkim_signature_parse_c(struct signature *sig, const char *start, const char *end)
687 if (sig->c != 0) {
688 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate c tag");
689 return;
691 if (strncmp(start, "simple", 6) == 0) {
692 sig->c = CANON_HEADER_SIMPLE;
693 start += 6;
694 } else if (strncmp(start, "relaxed", 7) == 0) {
695 sig->c = CANON_HEADER_RELAXED;
696 start += 7;
697 } else {
698 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
699 return;
701 if (start[0] == '/') {
702 start++;
703 if (strncmp(start, "simple", 6) == 0) {
704 sig->c |= CANON_BODY_SIMPLE;
705 start += 6;
706 } else if (strncmp(start, "relaxed", 7) == 0) {
707 sig->c |= CANON_BODY_RELAXED;
708 start += 7;
709 } else {
710 dkim_signature_state(sig, DKIM_PERMERROR,
711 "Invalid c tag");
712 return;
716 if (start != end) {
717 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
718 return;
720 sig->c |= CANON_DONE;
723 void
724 dkim_signature_parse_d(struct signature *sig, const char *start, const char *end)
726 if (sig->d[0] != '\0') {
727 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate d tag");
728 return;
730 if (osmtpd_ltok_skip_sig_d_tag_value(start, 0) != end ||
731 (size_t)(end - start) >= sizeof(sig->d)) {
732 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid d tag");
733 return;
735 strlcpy(sig->d, start, end - start + 1);
738 void
739 dkim_signature_parse_h(struct signature *sig, const char *start, const char *end)
741 const char *h;
742 size_t n = 0;
744 if (sig->h != NULL) {
745 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate h tag");
746 return;
748 if (osmtpd_ltok_skip_sig_h_tag_value(start, 0) < end) {
749 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid h tag");
750 return;
752 h = start;
753 while (1) {
754 if ((h = osmtpd_ltok_skip_hdr_name(h, 0)) == NULL) {
755 dkim_signature_state(sig, DKIM_PERMERROR,
756 "Invalid h tag");
757 return;
759 n++;
760 /* ';' is part of hdr-name */
761 if (h > end) {
762 h = end;
763 break;
765 h = osmtpd_ltok_skip_fws(h, 1);
766 if (h[0] != ':')
767 break;
768 h = osmtpd_ltok_skip_fws(h + 1, 1);
770 if ((sig->h = calloc(n + 1, sizeof(*sig->h))) == NULL) {
771 dkim_err(sig->header->msg, "malloc");
772 return;
774 n = 0;
775 h = start;
776 while (1) {
777 h = osmtpd_ltok_skip_hdr_name(start, 0);
778 /* ';' is part of hdr-name */
779 if (h > end) {
780 sig->h[n] = strndup(start, end - start);
781 break;
783 if ((sig->h[n++] = strndup(start, h - start)) == NULL) {
784 dkim_err(sig->header->msg, "malloc");
785 return;
787 start = osmtpd_ltok_skip_fws(h, 1);
788 if (start[0] != ':')
789 break;
790 start = osmtpd_ltok_skip_fws(start + 1, 1);
794 void
795 dkim_signature_parse_i(struct signature *sig, const char *start, const char *end)
797 if (sig->i != NULL) {
798 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate i tag");
799 return;
801 if (osmtpd_ltok_skip_sig_i_tag_value(start, 0) != end) {
802 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
803 return;
805 sig->i = start;
806 sig->isz = (size_t)(end - start);
809 void
810 dkim_signature_parse_l(struct signature *sig, const char *start, const char *end)
812 long long l;
813 char *lend;
815 if (sig->l != -1) { /* Duplicate tag */
816 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate l tag");
817 return;
819 errno = 0;
820 l = strtoll(start, &lend, 10);
821 /* > 76 digits in stroll is an overflow */
822 if (osmtpd_ltok_skip_digit(start, 0) == NULL ||
823 lend != end || errno != 0) {
824 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid l tag");
825 return;
827 if (l > SSIZE_MAX) {
828 dkim_signature_state(sig, DKIM_PERMERROR, "l tag too large");
829 return;
831 sig->l = (ssize_t)l;
834 void
835 dkim_signature_parse_q(struct signature *sig, const char *start, const char *end)
837 const char *qend;
839 if (sig->q != 0) {
840 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate q tag");
841 return;
844 while (1) {
845 start = osmtpd_ltok_skip_fws(start, 1);
846 qend = osmtpd_ltok_skip_sig_q_tag_method(start, 0);
847 if (qend == NULL) {
848 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
849 return;
851 if (strncmp(start, "dns/txt", qend - start) == 0)
852 sig->q = 1;
853 start = osmtpd_ltok_skip_fws(qend, 1);
854 if (start[0] != ':')
855 break;
857 if (start != end) {
858 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
859 return;
861 if (sig->q != 1) {
862 sig->q = 1;
863 dkim_signature_state(sig, DKIM_NEUTRAL, "No useable q found");
864 return;
868 void
869 dkim_signature_parse_s(struct signature *sig, const char *start, const char *end)
871 if (sig->s[0] != '\0') {
872 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate s tag");
873 return;
875 if (osmtpd_ltok_skip_selector(start, 0) != end) {
876 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid s tag");
877 return;
879 strlcpy(sig->s, start, end - start + 1);
882 void
883 dkim_signature_parse_t(struct signature *sig, const char *start, const char *end)
885 char *tend;
887 if (sig->t != -1) {
888 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate t tag");
889 return;
891 errno = 0;
892 sig->t = strtoll(start, &tend, 10);
893 if (osmtpd_ltok_skip_digit(start, 0) == NULL || tend != end ||
894 tend - start > 12 || errno != 0) {
895 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid t tag");
896 return;
900 void
901 dkim_signature_parse_x(struct signature *sig, const char *start, const char *end)
903 char *xend;
905 if (sig->x != -1) {
906 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate x tag");
907 return;
909 errno = 0;
910 sig->x = strtoll(start, &xend, 10);
911 if (osmtpd_ltok_skip_digit(start, 0) == NULL || xend != end ||
912 xend - start > 12 || errno != 0) {
913 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid x tag");
914 return;
918 void
919 dkim_signature_parse_z(struct signature *sig, const char *start, const char *end)
921 if (sig->z != 0) {
922 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate z tag");
923 return;
926 sig->z = 1;
927 if (osmtpd_ltok_skip_sig_z_tag_value(start, 0) != end) {
928 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid z tag");
929 return;
933 void
934 dkim_signature_verify(struct signature *sig)
936 struct message *msg = sig->header->msg;
937 static EVP_MD_CTX *bctx = NULL;
938 char digest[EVP_MAX_MD_SIZE];
939 unsigned int digestsz;
940 const char *end;
941 size_t i, header;
943 if (sig->state != DKIM_UNKNOWN)
944 return;
946 if (bctx == NULL) {
947 if ((bctx = EVP_MD_CTX_new()) == NULL) {
948 dkim_errx(msg, "EVP_MD_CTX_new");
949 return;
952 EVP_MD_CTX_reset(bctx);
953 if (!sig->sephash) {
954 if (EVP_DigestVerifyInit(bctx, NULL, sig->ah, NULL,
955 sig->p) != 1) {
956 dkim_errx(msg, "EVP_DigestVerifyInit");
957 return;
959 } else {
960 if (EVP_DigestInit_ex(bctx, sig->ah, NULL) != 1) {
961 dkim_errx(msg, "EVP_DigestInit_ex");
962 return;
966 for (i = 0; i < msg->nheaders; i++)
967 msg->header[i].parsed = 0;
969 for (header = 0; sig->h[header] != NULL; header++) {
970 for (i = msg->nheaders; i > 0; ) {
971 i--;
972 if (msg->header[i].parsed ||
973 strncasecmp(msg->header[i].buf, sig->h[header],
974 strlen(sig->h[header])) != 0 ||
975 msg->header[i].sig == sig)
976 continue;
977 end = osmtpd_ltok_skip_fws(
978 msg->header[i].buf + strlen(sig->h[header]), 1);
979 if (end[0] != ':')
980 continue;
981 dkim_signature_header(bctx, sig, &(msg->header[i]));
982 msg->header[i].parsed = 1;
983 break;
986 dkim_signature_header(bctx, sig, sig->header);
987 if (!sig->sephash) {
988 if (EVP_DigestVerifyFinal(bctx, sig->b, sig->bsz) != 1)
989 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
990 } else {
991 if (EVP_DigestFinal_ex(bctx, digest, &digestsz) == 0) {
992 dkim_errx(msg, "EVP_DigestFinal_ex");
993 return;
995 if (EVP_DigestVerifyInit(bctx, NULL, NULL, NULL, sig->p) != 1) {
996 dkim_errx(msg, "EVP_DigestVerifyInit");
997 return;
999 switch (EVP_DigestVerify(bctx, sig->b, sig->bsz, digest,
1000 digestsz)) {
1001 case 1:
1002 break;
1003 case 0:
1004 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
1005 break;
1006 default:
1007 dkim_errx(msg, "EVP_DigestVerify");
1008 return;
1013 /* EVP_DigestVerifyUpdate is a macro, so we can't alias this on a variable */
1014 #define dkim_b_digest_update(a, b, c) \
1015 (sig->sephash ? EVP_DigestUpdate((a), (b), (c)) :\
1016 EVP_DigestVerifyUpdate((a), (b), (c)))
1018 void
1019 dkim_signature_header(EVP_MD_CTX *bctx, struct signature *sig,
1020 struct header *header)
1022 char c;
1023 const char *ptr = header->buf, *end;
1024 int inhdrname = 1;
1025 int canon = sig->c & CANON_HEADER;
1027 for (ptr = header->buf; ptr[0] != '\0'; ptr++) {
1028 if (inhdrname) {
1029 if (canon == CANON_HEADER_RELAXED) {
1030 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1031 c = tolower(ptr[0]);
1032 } else
1033 c = ptr[0];
1034 if (c == ':') {
1035 inhdrname = 0;
1036 if (canon == CANON_HEADER_RELAXED)
1037 ptr = osmtpd_ltok_skip_fws(
1038 ptr + 1, 1) - 1;
1040 if (dkim_b_digest_update(bctx, &c, 1) == 0) {
1041 dkim_errx(sig->header->msg,
1042 "dkim_b_digest_update");
1043 return;
1045 continue;
1047 end = osmtpd_ltok_skip_fws(ptr, 1);
1048 if (end == ptr) {
1049 if (sig->header == header && ptr == sig->bheader) {
1050 ptr = osmtpd_ltok_skip_tag_value(
1051 ptr, 0) - 1;
1052 continue;
1054 if (dkim_b_digest_update(bctx, ptr, 1) == 0) {
1055 dkim_errx(sig->header->msg,
1056 "dkim_b_digest_update");
1057 return;
1059 } else {
1060 if (canon == CANON_HEADER_RELAXED) {
1061 if (end[0] == '\0')
1062 continue;
1063 if (dkim_b_digest_update(bctx, " ", 1) == 0) {
1064 dkim_errx(sig->header->msg,
1065 "dkim_b_digest_update");
1066 return;
1068 } else {
1069 if (dkim_b_digest_update(bctx, ptr,
1070 end - ptr) == 0) {
1071 dkim_errx(sig->header->msg,
1072 "dkim_b_digest_update");
1073 return;
1076 ptr = end - 1;
1080 if (sig->header != header) {
1081 if (dkim_b_digest_update(bctx, "\r\n", 2) == 0) {
1082 dkim_errx(sig->header->msg, "dkim_b_digest_update");
1083 return;
1088 void
1089 dkim_signature_state(struct signature *sig, enum state state,
1090 const char *reason)
1092 if (sig->query != NULL) {
1093 event_asr_abort(sig->query);
1094 sig->query = NULL;
1096 switch (sig->state) {
1097 case DKIM_UNKNOWN:
1098 break;
1099 case DKIM_PASS:
1100 case DKIM_FAIL:
1101 osmtpd_errx(1, "Unexpected transition");
1102 case DKIM_POLICY:
1103 if (state == DKIM_PASS)
1104 return;
1105 break;
1106 case DKIM_NEUTRAL:
1107 if (state == DKIM_PASS)
1108 return;
1109 if (state == DKIM_TEMPERROR || state == DKIM_PERMERROR)
1110 break;
1111 osmtpd_errx(1, "Unexpected transition");
1112 case DKIM_TEMPERROR:
1113 if (state == DKIM_PERMERROR)
1114 break;
1115 return;
1116 case DKIM_PERMERROR:
1117 return;
1119 sig->state = state;
1120 sig->state_reason = reason;
1123 const char *
1124 dkim_state2str(enum state state)
1126 switch (state)
1128 case DKIM_UNKNOWN:
1129 return "unknown";
1130 case DKIM_PASS:
1131 return "pass";
1132 case DKIM_FAIL:
1133 return "fail";
1134 case DKIM_POLICY:
1135 return "policy";
1136 case DKIM_NEUTRAL:
1137 return "neutral";
1138 case DKIM_TEMPERROR:
1139 return "temperror";
1140 case DKIM_PERMERROR:
1141 return "permerror";
1145 void
1146 dkim_rr_resolve(struct asr_result *ar, void *arg)
1148 struct signature *sig = arg;
1149 char key[UINT16_MAX + 1];
1150 const char *rr_txt;
1151 size_t keylen, cstrlen;
1152 struct unpack pack;
1153 struct dns_header h;
1154 struct dns_query q;
1155 struct dns_rr rr;
1157 sig->query = NULL;
1159 if (ar->ar_h_errno == TRY_AGAIN || ar->ar_h_errno == NO_RECOVERY) {
1160 dkim_signature_state(sig, DKIM_TEMPERROR,
1161 hstrerror(ar->ar_h_errno));
1162 goto verify;
1164 if (ar->ar_h_errno != NETDB_SUCCESS) {
1165 dkim_signature_state(sig, DKIM_PERMERROR,
1166 hstrerror(ar->ar_h_errno));
1167 goto verify;
1170 unpack_init(&pack, ar->ar_data, ar->ar_datalen);
1171 if (unpack_header(&pack, &h) != 0 ||
1172 unpack_query(&pack, &q) != 0) {
1173 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid dns/txt");
1174 goto verify;
1176 for (; h.ancount > 0; h.ancount--) {
1177 unpack_rr(&pack, &rr);
1178 if (rr.rr_type != T_TXT)
1179 continue;
1181 keylen = 0;
1182 rr_txt = rr.rr.other.rdata;
1183 while (rr.rr.other.rdlen > 0) {
1184 cstrlen = ((const unsigned char *)rr_txt)[0];
1185 if (cstrlen >= rr.rr.other.rdlen ||
1186 keylen + cstrlen >= sizeof(key))
1187 break;
1189 * RFC 6376 Section 3.6.2.2
1190 * Strings in a TXT RR MUST be concatenated together
1191 * before use with no intervening whitespace.
1193 strlcpy(key + keylen, rr_txt + 1, cstrlen + 1);
1194 rr.rr.other.rdlen -= (cstrlen + 1);
1195 rr_txt += (cstrlen + 1);
1196 keylen += cstrlen;
1198 if (rr.rr.other.rdlen > 0) /* Invalid TXT RDATA */
1199 continue;
1201 if (dkim_key_text_parse(sig, key))
1202 break;
1205 if (h.ancount == 0) {
1206 dkim_signature_state(sig, DKIM_PERMERROR,
1207 "No matching key found");
1208 } else {
1209 /* Only verify if all headers have been read */
1210 if (!sig->header->msg->parsing_headers)
1211 dkim_signature_verify(sig);
1213 verify:
1214 free(ar->ar_data);
1215 dkim_message_verify(sig->header->msg);
1218 int
1219 dkim_key_text_parse(struct signature *sig, const char *key)
1221 char tagname, *hashname;
1222 const char *end, *tagvend;
1223 char pkraw[UINT16_MAX] = "", pkimp[UINT16_MAX];
1224 size_t pkrawlen = 0, pkoff, linelen;
1225 int h = 0, k = 0, n = 0, p = 0, s = 0, t = 0, first = 1;
1226 BIO *bio;
1227 #ifdef HAVE_ED25519
1228 size_t pklen;
1229 int tmp;
1230 #endif
1232 key = osmtpd_ltok_skip_fws(key, 1);
1233 /* Validate syntax early */
1234 if ((end = osmtpd_ltok_skip_tag_list(key, 0)) == NULL)
1235 return 0;
1237 while (key[0] != '\0') {
1238 key = osmtpd_ltok_skip_fws(key, 1);
1239 if ((end = osmtpd_ltok_skip_tag_name(key, 0)) == NULL)
1240 return 0;
1242 if ((size_t)(end - key) != 1)
1243 tagname = '\0';
1244 else
1245 tagname = key[0];
1246 key = osmtpd_ltok_skip_fws(end, 1);
1247 /* '=' */
1248 if (key[0] != '=')
1249 return 0;
1250 key = osmtpd_ltok_skip_fws(key + 1, 1);
1251 if ((end = osmtpd_ltok_skip_tag_value(key, 0)) == NULL)
1252 return 0;
1253 switch (tagname) {
1254 case 'v':
1256 * RFC 6376 section 3.6.1, v=:
1257 * RECOMMENDED...This tag MUST be the first tag in the
1258 * record.
1260 if (!first ||
1261 osmtpd_ltok_skip_key_v_tag_value(key, 0) != end)
1262 return 0;
1263 key = end;
1264 break;
1265 case 'h':
1266 if (h != 0) /* Duplicate tag */
1267 return 0;
1268 /* Invalid tag value */
1269 if (osmtpd_ltok_skip_key_h_tag_value(key, 0) != end)
1270 return 0;
1271 while (1) {
1272 if ((tagvend = osmtpd_ltok_skip_key_h_tag_alg(
1273 key, 0)) == NULL)
1274 break;
1275 hashname = strndup(key, tagvend - key);
1276 if (hashname == NULL) {
1277 dkim_err(sig->header->msg, "malloc");
1278 return 0;
1280 if (EVP_get_digestbyname(hashname) == sig->ah) {
1281 free(hashname);
1282 h = 1;
1283 break;
1285 free(hashname);
1286 key = osmtpd_ltok_skip_fws(tagvend, 1);
1287 if (key[0] != ':')
1288 break;
1289 key = osmtpd_ltok_skip_fws(key + 1, 1);
1291 if (h != 1)
1292 return 0;
1293 key = end;
1294 break;
1295 case 'k':
1296 if (k != 0) /* Duplicate tag */
1297 return 0;
1298 k = 1;
1299 if (strncmp(key, "rsa", end - key) == 0) {
1300 if (sig->ak != EVP_PKEY_RSA)
1301 return 0;
1302 #if HAVE_ED25519
1303 } else if (strncmp(key, "ed25519", end - key) == 0) {
1304 if (sig->ak != EVP_PKEY_ED25519)
1305 return 0;
1306 #endif
1307 } else
1308 return 0;
1309 key = end;
1310 break;
1311 case 'n':
1312 if (n != 0) /* Duplicate tag */
1313 return 0;
1314 n = 1;
1315 /* semicolon is part of safe-char */
1316 if (osmtpd_ltok_skip_key_n_tag_value(key, 0) < end)
1317 return 0;
1318 key = end;
1319 break;
1320 case 'p':
1321 if (p != 0) /* Duplicate tag */
1322 return 0;
1323 p = 1;
1324 while (1) {
1325 key = osmtpd_ltok_skip_fws(key, 1);
1326 if (osmtpd_ltok_skip_alphadigitps(
1327 key, 0) == NULL)
1328 break;
1329 pkraw[pkrawlen++] = key++[0];
1330 if (pkrawlen >= sizeof(pkraw))
1331 return 0;
1333 if (key[0] == '=') {
1334 pkraw[pkrawlen++] = '=';
1335 key = osmtpd_ltok_skip_fws(key + 1, 1);
1336 if (pkrawlen >= sizeof(pkraw))
1337 return 0;
1338 if (key[0] == '=') {
1339 pkraw[pkrawlen++] = '=';
1340 key++;
1341 if (pkrawlen >= sizeof(pkraw))
1342 return 0;
1345 /* Invalid tag value */
1346 if (pkrawlen % 4 != 0 || key != end)
1347 return 0;
1348 break;
1349 case 's':
1350 if (s != 0) /* Duplicate tag */
1351 return 0;
1352 /* Invalid tag value */
1353 if (osmtpd_ltok_skip_key_s_tag_value(key, 0) != end)
1354 return 0;
1355 while (1) {
1356 if ((tagvend =
1357 osmtpd_ltok_skip_key_s_tag_type(
1358 key, 0)) == NULL)
1359 break;
1360 if (strncmp(key, "*", tagvend - key) == 0 ||
1361 strncmp(key, "email", tagvend - key) == 0) {
1362 s = 1;
1363 break;
1365 key = osmtpd_ltok_skip_fws(tagvend, 1);
1366 if (key[0] != ':')
1367 break;
1368 key = osmtpd_ltok_skip_fws(key + 1, 1);
1370 if (s != 1)
1371 return 0;
1372 key = end;
1373 break;
1374 case 't':
1375 if (t != 0) /* Duplicate tag */
1376 return 0;
1377 t = 1;
1378 if (osmtpd_ltok_skip_key_t_tag_value(key, 0) != end)
1379 return 0;
1380 while (1) {
1381 tagvend = osmtpd_ltok_skip_key_t_tag_flag(
1382 key, 0);
1383 if (strncmp(key, "y", tagvend - key) == 0)
1384 sig->kt |= KT_Y;
1385 else if (strncmp(key, "s", tagvend - key) == 0)
1386 sig->kt |= KT_S;
1387 key = osmtpd_ltok_skip_fws(tagvend, 1);
1388 if (key[0] != ':')
1389 break;
1390 key = osmtpd_ltok_skip_fws(key + 1, 1);
1392 break;
1393 default:
1394 key = end;
1395 break;
1398 first = 0;
1399 key = osmtpd_ltok_skip_fws(key, 1);
1400 if (key[0] == ';')
1401 key++;
1402 else if (key[0] != '\0')
1403 return 0;
1406 if (!p) /* Missing tag */
1407 return 0;
1408 if (k == 0 && sig->ak != EVP_PKEY_RSA) /* Default to RSA */
1409 return 0;
1411 if (pkraw[0] == '\0') {
1412 dkim_signature_state(sig, DKIM_PERMERROR, "Key is revoked");
1413 return 1;
1416 switch (sig->ak) {
1417 case EVP_PKEY_RSA:
1418 pkoff = strlcpy(pkimp, "-----BEGIN PUBLIC KEY-----\n",
1419 sizeof(pkimp));
1420 linelen = 0;
1421 for (key = pkraw; key[0] != '\0';) {
1422 if (pkoff + 2 >= sizeof(pkimp))
1423 return 0;
1424 pkimp[pkoff++] = key++[0];
1425 if (++linelen == 64) {
1426 pkimp[pkoff++] = '\n';
1427 linelen = 0;
1430 /* Leverage pkoff check in loop */
1431 if (linelen != 0)
1432 pkimp[pkoff++] = '\n';
1433 /* PEM_read_bio_PUBKEY will catch truncated keys */
1434 pkoff += strlcpy(pkimp + pkoff, "-----END PUBLIC KEY-----\n",
1435 sizeof(pkimp) - pkoff);
1436 if ((bio = BIO_new_mem_buf(pkimp, pkoff)) == NULL) {
1437 dkim_err(sig->header->msg, "BIO_new_mem_buf");
1438 return 1;
1440 sig->p = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
1441 BIO_free(bio);
1442 break;
1443 #if HAVE_ED25519
1444 case EVP_PKEY_ED25519:
1445 if ((pkrawlen / 4) * 3 >= sizeof(pkimp))
1446 return 0;
1447 EVP_DecodeInit(ectx);
1448 if (EVP_DecodeUpdate(ectx, pkimp, &tmp, pkraw, pkrawlen) == -1)
1449 return 0;
1450 pklen = tmp;
1451 if (EVP_DecodeFinal(ectx, pkimp, &tmp) == -1)
1452 return 0;
1453 pklen += tmp;
1454 sig->p = EVP_PKEY_new_raw_public_key(sig->ak, NULL, pkimp,
1455 pklen);
1456 break;
1457 #endif
1459 if (sig->p == NULL) {
1461 * XXX No clue how to differentiate between invalid key and
1462 * temporary failure like *alloc.
1463 * Assume invalid key, because it's more likely.
1465 return 0;
1467 return 1;
1470 void
1471 dkim_body_parse(struct message *msg, const char *line)
1473 struct signature *sig;
1474 const char *end = line, *hash, *prev;
1475 size_t hashn, len, i;
1476 int wsp, ret;
1478 if (line[0] == '\0') {
1479 msg->body_whitelines++;
1480 return;
1483 while (msg->body_whitelines-- > 0) {
1484 for (i = 0; i < msg->nheaders; i++) {
1485 if ((sig = msg->header[i].sig) == NULL ||
1486 sig->state != DKIM_UNKNOWN)
1487 continue;
1488 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1489 sig->l -= sig->l == -1 ? 0 : hashn;
1490 if (EVP_DigestUpdate(sig->bhctx, "\r\n", hashn) == 0) {
1491 dkim_errx(msg, "EVP_DigestUpdate");
1492 return;
1496 msg->body_whitelines = 0;
1497 msg->has_body = 1;
1499 while (line[0] != '\0') {
1500 while (1) {
1501 prev = end;
1502 if ((end = osmtpd_ltok_skip_wsp(end, 0)) == NULL)
1503 break;
1505 end = prev;
1506 wsp = end != line;
1507 if (!wsp) {
1508 while (osmtpd_ltok_skip_wsp(end, 0) == NULL &&
1509 end[0] != '\0')
1510 end++;
1512 for (i = 0; i < msg->nheaders; i++) {
1513 sig = msg->header[i].sig;
1514 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1515 continue;
1516 if (wsp &&
1517 (sig->c & CANON_BODY) == CANON_BODY_RELAXED) {
1518 hash = " ";
1519 len = end[0] == '\0' ? 0 : 1;
1520 } else {
1521 hash = line;
1522 len = (size_t)(end - line);
1524 hashn = sig->l == -1 ? len : MIN(len, (size_t)sig->l);
1525 sig->l -= sig->l == -1 ? 0 : hashn;
1526 ret = EVP_DigestUpdate(sig->bhctx, hash, hashn);
1527 if (ret == 0) {
1528 dkim_errx(msg, "EVP_DigestUpdate");
1529 return;
1532 line = end;
1534 for (i = 0; i < msg->nheaders; i++) {
1535 sig = msg->header[i].sig;
1536 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1537 continue;
1538 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1539 sig->l -= sig->l == -1 ? 0 : hashn;
1540 ret = EVP_DigestUpdate(sig->bhctx, "\r\n", hashn);
1541 if (ret == 0) {
1542 dkim_errx(msg, "EVP_DigestUpdate");
1543 return;
1548 void
1549 dkim_body_verify(struct signature *sig)
1551 unsigned char digest[EVP_MAX_MD_SIZE];
1552 unsigned int digestsz;
1554 if (sig->state != DKIM_UNKNOWN)
1555 return;
1557 if ((sig->c & CANON_BODY) == CANON_BODY_SIMPLE &&
1558 !sig->header->msg->has_body) {
1559 if (EVP_DigestUpdate(sig->bhctx, "\r\n",
1560 sig->l == -1 ? 2 : MIN(2, sig->l)) <= 0) {
1561 dkim_errx(sig->header->msg,
1562 "Can't update hash context");
1563 return;
1566 if (sig->l > 0) {
1567 dkim_signature_state(sig, DKIM_PERMERROR,
1568 "l tag larger than body");
1569 return;
1572 if (EVP_DigestFinal_ex(sig->bhctx, digest, &digestsz) == 0) {
1573 dkim_errx(sig->header->msg, "EVP_DigestFinal_ex");
1574 return;
1577 if (digestsz != sig->bhsz || memcmp(digest, sig->bh, digestsz) != 0)
1578 dkim_signature_state(sig, DKIM_FAIL, "bh mismatch");
1581 void
1582 dkim_message_verify(struct message *msg)
1584 struct signature *sig;
1585 size_t i;
1586 ssize_t n, aroff = 0;
1587 int found = 0;
1588 char *line = NULL;
1589 size_t linelen = 0;
1591 if (!msg->readdone)
1592 return;
1594 for (i = 0; i < msg->nheaders; i++) {
1595 if (msg->header[i].sig == NULL)
1596 continue;
1597 if (msg->header[i].sig->query != NULL)
1598 return;
1599 if (msg->header[i].sig->state != DKIM_UNKNOWN)
1600 continue;
1601 dkim_signature_state(msg->header[i].sig, DKIM_PASS, NULL);
1604 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1605 "Authentication-Results: %s", authservid)) == -1) {
1606 dkim_err(msg, "malloc");
1607 goto fail;
1609 for (i = 0; i < msg->nheaders; i++) {
1610 sig = msg->header[i].sig;
1611 if (sig == NULL)
1612 continue;
1613 found = 1;
1614 if ((aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=%s",
1615 dkim_state2str(sig->state))) == -1) {
1616 dkim_err(msg, "malloc");
1617 goto fail;
1619 if (sig->state_reason != NULL) {
1620 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1621 " reason=\"%s\"", sig->state_reason)) == -1) {
1622 dkim_err(msg, "malloc");
1623 goto fail;
1626 if (sig->s[0] != '\0') {
1627 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1628 " header.s=%s", sig->s)) == -1) {
1629 dkim_err(msg, "malloc");
1630 goto fail;
1633 if (sig->d[0] != '\0') {
1634 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1635 " header.d=%s", sig->d)) == -1) {
1636 dkim_err(msg, "malloc");
1637 goto fail;
1641 * Don't print i-tag, since localpart can be a quoted-string,
1642 * which can contain FWS and CFWS.
1644 if (sig->a != NULL) {
1645 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1646 " header.a=%.*s", (int)sig->asz, sig->a)) == -1) {
1647 dkim_err(msg, "malloc");
1648 goto fail;
1651 if (sig->bheaderclean[0] != '\0') {
1652 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1653 " header.b=%s", sig->bheaderclean)) == -1) {
1654 dkim_err(msg, "malloc");
1655 goto fail;
1659 if (!found) {
1660 aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=none");
1661 if (aroff == -1) {
1662 dkim_err(msg, "malloc");
1663 goto fail;
1666 if (dkim_ar_print(msg->ctx, line) != 0) {
1667 dkim_err(msg, "Mallformed AR header");
1668 goto fail;
1671 rewind(msg->origf);
1672 while ((n = getline(&line, &linelen, msg->origf)) != -1) {
1673 line[n - 1] = '\0';
1674 osmtpd_filter_dataline(msg->ctx, "%s", line);
1676 if (ferror(msg->origf))
1677 dkim_err(msg, "getline");
1678 fail:
1679 free(line);
1680 return;
1683 int
1684 dkim_ar_print(struct osmtpd_ctx *ctx, const char *start)
1686 const char *scan, *checkpoint, *ncheckpoint;
1687 int arlen = 0, first = 1, arid = 1;
1689 checkpoint = start;
1690 ncheckpoint = osmtpd_ltok_skip_hdr_name(start, 0) + 1;
1691 for (scan = start; scan[0] != '\0'; scan++) {
1692 if (scan[0] == '\t')
1693 arlen = (arlen + 8) & ~7;
1694 else
1695 arlen++;
1696 if (arlen >= AUTHENTICATION_RESULTS_LINELEN) {
1697 arlen = (int)(checkpoint - start);
1698 if (arlen <= 0) {
1699 arlen = (int)(ncheckpoint - start);
1700 checkpoint = ncheckpoint;
1702 osmtpd_filter_dataline(ctx, "%s%.*s", first ? "" : "\t",
1703 arlen, start);
1704 start = osmtpd_ltok_skip_cfws(checkpoint, 1);
1705 if (*start == '\0')
1706 return 0;
1707 ncheckpoint = start;
1708 scan = start;
1709 arlen = 8;
1710 first = 0;
1712 if (scan == ncheckpoint) {
1713 checkpoint = ncheckpoint;
1714 ncheckpoint = osmtpd_ltok_skip_cfws(ncheckpoint, 1);
1715 /* authserv-id */
1716 if (arid) {
1717 ncheckpoint = osmtpd_ltok_skip_value(
1718 ncheckpoint, 0);
1719 arid = 0;
1720 /* methodspec */
1721 } else if (strncmp(ncheckpoint, "dkim=",
1722 sizeof("dkim=") - 1) == 0) {
1723 ncheckpoint = osmtpd_ltok_skip_keyword(
1724 ncheckpoint + sizeof("dkim=") - 1, 0);
1725 /* reasonspec */
1726 } else if (strncmp(ncheckpoint, "reason=",
1727 sizeof("reason=") - 1) == 0) {
1728 ncheckpoint = osmtpd_ltok_skip_ar_reasonspec(
1729 ncheckpoint, 0);
1730 /* propspec */
1731 } else {
1732 ncheckpoint = osmtpd_ltok_skip_ar_propspec(
1733 ncheckpoint, 0);
1736 if (ncheckpoint == NULL)
1737 return -1;
1739 if (*ncheckpoint == ';')
1740 ncheckpoint++;
1743 osmtpd_filter_dataline(ctx, "%s%s", first ? "" : "\t", start);
1744 return 0;
1747 ssize_t
1748 dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
1750 va_list ap;
1751 char *artmp;
1752 int size;
1753 size_t nn;
1755 va_start(ap, fmt);
1756 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1757 va_end(ap);
1758 if (size + aroff < *n)
1759 return (ssize_t)size + aroff;
1760 nn = (((aroff + size) / 256) + 1) * 256;
1761 artmp = realloc(*ar, nn);
1762 if (artmp == NULL)
1763 return -1;
1764 *ar = artmp;
1765 *n = nn;
1766 va_start(ap, fmt);
1767 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1768 va_end(ap);
1769 return (ssize_t)size + aroff;
1772 void
1773 dkim_err(struct message *msg, char *text)
1775 msg->err = 1;
1776 fprintf(stderr, "%s: %s\n", text, strerror(errno));
1779 void
1780 dkim_errx(struct message *msg, char *text)
1782 msg->err = 1;
1783 fprintf(stderr, "%s\n", text);
1786 __dead void
1787 usage(void)
1789 fprintf(stderr, "usage: filter-dkimverify\n");
1790 exit(1);