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 <paths.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include <asr.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 int sephash;
67 const EVP_MD *ah;
68 char *b;
69 size_t bsz;
70 const char *bheader;
71 /* Make sure padding bits for base64 decoding fit */
72 char bh[EVP_MAX_MD_SIZE + (3 - (EVP_MAX_MD_SIZE % 3))];
73 size_t bhsz;
74 EVP_MD_CTX *bhctx;
75 int c;
76 #define CANON_HEADER_SIMPLE 0
77 #define CANON_HEADER_RELAXED 1
78 #define CANON_HEADER 1
79 #define CANON_BODY_SIMPLE 0
80 #define CANON_BODY_RELAXED 1 << 1
81 #define CANON_BODY 1 << 1
82 #define CANON_DONE 1 << 2
83 char d[HOST_NAME_MAX + 1];
84 char **h;
85 const char *i;
86 size_t isz;
87 ssize_t l;
88 int q;
89 char s[HOST_NAME_MAX + 1];
90 time_t t; /* Signature t=/timestamp */
91 #define KT_Y 1
92 #define KT_S 1 << 1
93 int kt; /* Key t=/Flags */
94 time_t x;
95 int z;
96 struct event_asr *query;
97 EVP_PKEY *p;
98 };
100 struct header {
101 struct message *msg;
102 uint8_t readdone;
103 uint8_t parsed;
104 char *buf;
105 size_t buflen;
106 struct signature *sig;
107 };
109 #define AUTHENTICATION_RESULTS_LINELEN 78
110 #define MIN(a, b) ((a) < (b) ? (a) : (b))
112 struct message {
113 struct osmtpd_ctx *ctx;
114 FILE *origf;
115 int parsing_headers;
116 size_t body_whitelines;
117 int has_body;
118 struct header *header;
119 size_t nheaders;
120 int err;
121 int readdone;
122 };
124 void usage(void);
125 void dkim_err(struct message *, char *);
126 void dkim_errx(struct message *, char *);
127 void dkim_conf(const char *, const char *);
128 void dkim_dataline(struct osmtpd_ctx *, const char *);
129 void dkim_commit(struct osmtpd_ctx *);
130 void *dkim_message_new(struct osmtpd_ctx *);
131 void dkim_message_free(struct osmtpd_ctx *, void *);
132 void dkim_header_add(struct osmtpd_ctx *, const char *);
133 void dkim_signature_parse(struct header *);
134 void dkim_signature_parse_v(struct signature *, const char *, const char *);
135 void dkim_signature_parse_a(struct signature *, const char *, const char *);
136 void dkim_signature_parse_b(struct signature *, const char *, const char *);
137 void dkim_signature_parse_bh(struct signature *, const char *, const char *);
138 void dkim_signature_parse_c(struct signature *, const char *, const char *);
139 void dkim_signature_parse_d(struct signature *, const char *, const char *);
140 void dkim_signature_parse_h(struct signature *, const char *, const char *);
141 void dkim_signature_parse_i(struct signature *, const char *, const char *);
142 void dkim_signature_parse_l(struct signature *, const char *, const char *);
143 void dkim_signature_parse_q(struct signature *, const char *, const char *);
144 void dkim_signature_parse_s(struct signature *, const char *, const char *);
145 void dkim_signature_parse_t(struct signature *, const char *, const char *);
146 void dkim_signature_parse_x(struct signature *, const char *, const char *);
147 void dkim_signature_parse_z(struct signature *, const char *, const char *);
148 void dkim_signature_verify(struct signature *);
149 void dkim_signature_header(EVP_MD_CTX *, struct signature *, struct header *);
150 void dkim_signature_state(struct signature *, enum state, const char *);
151 const char *dkim_state2str(enum state);
152 void dkim_header_cat(struct osmtpd_ctx *, const char *);
153 void dkim_body_parse(struct message *, const char *);
154 void dkim_body_verify(struct signature *);
155 void dkim_rr_resolve(struct asr_result *, void *);
156 void dkim_message_verify(struct message *);
157 ssize_t dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
158 __attribute__((__format__ (printf, 4, 5)));
159 void dkim_ar_print(struct osmtpd_ctx *, const char *);
160 int dkim_key_text_parse(struct signature *, const char *);
162 char *authservid;
163 EVP_ENCODE_CTX *ectx = NULL;
165 int
166 main(int argc, char *argv[])
168 if (argc != 1)
169 osmtpd_errx(1, "Invalid argument count");
171 OpenSSL_add_all_digests();
173 if (unveil(_PATH_TMP, "rwc") == -1)
174 osmtpd_err(1, "unveil");
175 if (pledge("stdio rpath wpath cpath 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 return NULL;
281 msg->ctx = ctx;
282 msg->parsing_headers = 1;
283 msg->body_whitelines = 0;
284 msg->has_body = 0;
285 msg->header = NULL;
286 msg->nheaders = 0;
287 msg->err = 0;
288 msg->readdone = 0;
290 return msg;
293 void
294 dkim_message_free(struct osmtpd_ctx *ctx, void *data)
296 struct message *msg = data;
297 size_t i, j;
299 fclose(msg->origf);
300 for (i = 0; i < msg->nheaders; i++) {
301 if (msg->header[i].sig != NULL) {
302 free(msg->header[i].sig->b);
303 EVP_MD_CTX_free(msg->header[i].sig->bhctx);
304 for (j = 0; msg->header[i].sig->h != NULL &&
305 msg->header[i].sig->h[j] != NULL; j++)
306 free(msg->header[i].sig->h[j]);
307 free(msg->header[i].sig->h);
308 EVP_PKEY_free(msg->header[i].sig->p);
310 free(msg->header[i].buf);
311 free(msg->header[i].sig);
313 free(msg->header);
314 free(msg);
317 void
318 dkim_header_add(struct osmtpd_ctx *ctx, const char *line)
320 struct message *msg = ctx->local_message;
321 const char *start, *end, *verify;
322 struct header *headers;
323 size_t i;
325 if (msg->nheaders > 0 &&
326 msg->header[msg->nheaders - 1].readdone == 0) {
327 if (line[0] != ' ' && line[0] != '\t') {
328 msg->header[msg->nheaders - 1].readdone = 1;
329 start = msg->header[msg->nheaders - 1].buf;
330 end = osmtpd_ltok_skip_field_name(start, 0);
331 /* In case someone uses an obs-optional */
332 if (end != NULL)
333 verify = osmtpd_ltok_skip_wsp(end, 1);
334 if (end != NULL &&
335 strncasecmp(
336 start, "DKIM-Signature", end - start) == 0 &&
337 verify[0] == ':')
338 dkim_signature_parse(
339 &msg->header[msg->nheaders - 1]);
340 if (line[0] == '\0')
341 return;
342 } else {
343 dkim_header_cat(ctx, line);
344 return;
347 if (msg->nheaders % 10 == 0) {
348 if ((headers = recallocarray(msg->header, msg->nheaders,
349 msg->nheaders + 10, sizeof(*msg->header))) == NULL) {
350 dkim_err(msg, "malloc");
351 return;
353 msg->header = headers;
354 for (i = 0; i < msg->nheaders; i++) {
355 if (msg->header[i].sig == NULL)
356 continue;
357 msg->header[i].sig->header = &msg->header[i];
360 msg->header[msg->nheaders].msg = msg;
361 msg->nheaders++;
362 dkim_header_cat(ctx, line);
365 void
366 dkim_header_cat(struct osmtpd_ctx *ctx, const char *line)
368 struct message *msg = ctx->local_message;
369 struct header *header = &msg->header[msg->nheaders - 1];
370 char *buf;
372 size_t needed = header->buflen + strlen(line) + 2;
374 if (needed > (header->buflen / 1024) + 1) {
375 buf = reallocarray(header->buf, (needed / 1024) + 1, 1024);
376 if (buf == NULL) {
377 dkim_err(msg, "malloc");
378 return;
380 header->buf = buf;
382 header->buflen += snprintf(header->buf + header->buflen,
383 (((needed / 1024) + 1) * 1024) - header->buflen, "%s%s",
384 header->buflen == 0 ? "" : "\r\n", line);
387 void
388 dkim_signature_parse(struct header *header)
390 struct signature *sig;
391 struct asr_query *query;
392 const char *buf, *i, *end;
393 char tagname[3];
394 char subdomain[HOST_NAME_MAX + 1];
395 size_t ilen, dlen;
397 /* Format checked by dkim_header_add */
398 buf = osmtpd_ltok_skip_field_name(header->buf, 0);
399 buf = osmtpd_ltok_skip_wsp(buf, 1) + 1;
401 if ((header->sig = calloc(1, sizeof(*header->sig))) == NULL) {
402 dkim_err(header->msg, "malloc");
403 return;
405 sig = header->sig;
406 sig->header = header;
407 sig->l = -1;
408 sig->t = -1;
409 sig->x = -1;
411 end = osmtpd_ltok_skip_tag_list(buf, 0);
412 if (end == NULL || end[0] != '\0') {
413 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid tag-list");
414 return;
417 while (buf[0] != '\0') {
418 buf = osmtpd_ltok_skip_fws(buf, 1);
419 end = osmtpd_ltok_skip_tag_name(buf, 0);
421 /* Unknown tag-name */
422 if ((size_t)(end - buf) >= sizeof(tagname))
423 tagname[0] = '\0';
424 else
425 strlcpy(tagname, buf, (end - buf) + 1);
426 buf = osmtpd_ltok_skip_fws(end, 1);
427 /* '=' */
428 buf = osmtpd_ltok_skip_fws(buf + 1, 1);
429 end = osmtpd_ltok_skip_tag_value(buf, 1);
430 if (strcmp(tagname, "v") == 0)
431 dkim_signature_parse_v(sig, buf, end);
432 else if (strcmp(tagname, "a") == 0)
433 dkim_signature_parse_a(sig, buf, end);
434 else if (strcmp(tagname, "b") == 0)
435 dkim_signature_parse_b(sig, buf, end);
436 else if (strcmp(tagname, "bh") == 0)
437 dkim_signature_parse_bh(sig, buf, end);
438 else if (strcmp(tagname, "c") == 0)
439 dkim_signature_parse_c(sig, buf, end);
440 else if (strcmp(tagname, "d") == 0)
441 dkim_signature_parse_d(sig, buf, end);
442 else if (strcmp(tagname, "h") == 0)
443 dkim_signature_parse_h(sig, buf, end);
444 else if (strcmp(tagname, "i") == 0)
445 dkim_signature_parse_i(sig, buf, end);
446 else if (strcmp(tagname, "l") == 0)
447 dkim_signature_parse_l(sig, buf, end);
448 else if (strcmp(tagname, "q") == 0)
449 dkim_signature_parse_q(sig, buf, end);
450 else if (strcmp(tagname, "s") == 0)
451 dkim_signature_parse_s(sig, buf, end);
452 else if (strcmp(tagname, "t") == 0)
453 dkim_signature_parse_t(sig, buf, end);
454 else if (strcmp(tagname, "x") == 0)
455 dkim_signature_parse_x(sig, buf, end);
456 else if (strcmp(tagname, "z") == 0)
457 dkim_signature_parse_z(sig, buf, end);
459 buf = osmtpd_ltok_skip_fws(end, 1);
460 if (buf[0] == ';')
461 buf++;
462 else if (buf[0] != '\0') {
463 dkim_signature_state(sig, DKIM_PERMERROR,
464 "Invalid tag-list");
465 return;
468 if (sig->state != DKIM_UNKNOWN)
469 return;
471 if (sig->v != 1)
472 dkim_signature_state(sig, DKIM_PERMERROR, "Missing v tag");
473 else if (sig->ah == NULL)
474 dkim_signature_state(sig, DKIM_PERMERROR, "Missing a tag");
475 else if (sig->b == NULL)
476 dkim_signature_state(sig, DKIM_PERMERROR, "Missing b tag");
477 else if (sig->bhsz == 0)
478 dkim_signature_state(sig, DKIM_PERMERROR, "Missing bh tag");
479 else if (sig->d[0] == '\0')
480 dkim_signature_state(sig, DKIM_PERMERROR, "Missing d tag");
481 else if (sig->h == NULL)
482 dkim_signature_state(sig, DKIM_PERMERROR, "Missing h tag");
483 else if (sig->s[0] == '\0')
484 dkim_signature_state(sig, DKIM_PERMERROR, "Missing s tag");
485 if (sig->state != DKIM_UNKNOWN)
486 return;
488 if (sig->i != NULL) {
489 i = osmtpd_ltok_skip_local_part(sig->i, 1) + 1;
490 ilen = sig->isz - (size_t)(i - sig->i);
491 dlen = strlen(sig->d);
492 if (ilen < dlen) {
493 dkim_signature_state(sig, DKIM_PERMERROR,
494 "i tag not subdomain of d");
495 return;
497 i += ilen - dlen;
498 if ((i[-1] != '.' && i[-1] != '@') ||
499 strncasecmp(i, sig->d, dlen) != 0) {
500 dkim_signature_state(sig, DKIM_PERMERROR,
501 "i tag not subdomain of d");
502 return;
505 if (sig->t != -1 && sig->x != -1 && sig->t > sig->x) {
506 dkim_signature_state(sig, DKIM_PERMERROR, "t tag after x tag");
507 return;
510 if ((size_t)snprintf(subdomain, sizeof(subdomain), "%s._domainkey.%s",
511 sig->s, sig->d) >= sizeof(subdomain)) {
512 dkim_signature_state(sig, DKIM_PERMERROR,
513 "dns/txt query too long");
514 return;
517 if ((query = res_query_async(subdomain, C_IN, T_TXT, NULL)) == NULL) {
518 dkim_err(header->msg, "res_query_async");
519 return;
521 if ((sig->query = event_asr_run(query, dkim_rr_resolve, sig)) == NULL) {
522 dkim_err(header->msg, "event_asr_run");
523 asr_abort(query);
524 return;
528 void
529 dkim_signature_parse_v(struct signature *sig, const char *start, const char *end)
531 if (sig->v != 0) { /* Duplicate tag */
532 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate v tag");
533 return;
535 /* Unsupported version */
536 if (start[0] != '1' || start + 1 != end)
537 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsupported v tag");
538 else
539 sig->v = 1;
542 void
543 dkim_signature_parse_a(struct signature *sig, const char *start, const char *end)
545 char ah[sizeof("sha256")];
547 if (sig->ah != NULL) {
548 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate a tag");
549 return;
552 if (osmtpd_ltok_skip_sig_a_tag_alg(start, 0) != end) {
553 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid a tag");
554 return;
556 sig->a = start;
557 sig->asz = (size_t)(end - start);
558 if (strncmp(start, "rsa-", 4) == 0) {
559 start += 4;
560 sig->ak = EVP_PKEY_RSA;
561 sig->sephash = 0;
562 #if HAVE_ED25519
563 } else if (strncmp(start, "ed25519-", 8) == 0) {
564 start += 8;
565 sig->ak = EVP_PKEY_ED25519;
566 sig->sephash = 1;
567 #endif
568 } else {
569 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag k");
570 return;
572 if ((size_t)(end - start) >= sizeof(ah)) {
573 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
574 return;
576 strlcpy(ah, start, sizeof(ah));
577 ah[end - start] = '\0';
578 if ((sig->ah = EVP_get_digestbyname(ah)) == NULL) {
579 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
580 return;
582 if ((sig->bhctx = EVP_MD_CTX_new()) == NULL) {
583 dkim_err(sig->header->msg, "EVP_MD_CTX_new");
584 return;
586 if (EVP_DigestInit_ex(sig->bhctx, sig->ah, NULL) <= 0) {
587 dkim_err(sig->header->msg, "EVP_DigestInit_ex");
588 return;
592 void
593 dkim_signature_parse_b(struct signature *sig, const char *start, const char *end)
595 int decodesz;
597 if (sig->b != NULL) {
598 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate b tag");
599 return;
601 sig->bheader = start;
602 if ((sig->b = malloc((((end - start) / 4) + 1) * 3)) == NULL) {
603 dkim_err(sig->header->msg, "malloc");
604 return;
606 /* EVP_DecodeBlock doesn't handle internal whitespace */
607 EVP_DecodeInit(ectx);
608 if (EVP_DecodeUpdate(ectx, sig->b, &decodesz, start,
609 (int)(end - start)) == -1) {
610 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
611 return;
613 sig->bsz = decodesz;
614 if (EVP_DecodeFinal(ectx, sig->b + sig->bsz,
615 &decodesz) == -1) {
616 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
617 return;
619 sig->bsz += decodesz;
622 void
623 dkim_signature_parse_bh(struct signature *sig, const char *start, const char *end)
625 const char *b64;
626 size_t n;
627 int decodesz;
629 if (sig->bhsz != 0) {
630 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate bh tag");
631 return;
633 /*
634 * EVP_Decode* expects sig->bh to be large enough,
635 * so count the actual b64 characters.
636 */
637 b64 = start;
638 n = 0;
639 while (1) {
640 b64 = osmtpd_ltok_skip_fws(b64, 1);
641 if (osmtpd_ltok_skip_alphadigitps(b64, 0) == NULL)
642 break;
643 n++;
644 b64++;
646 if (b64[0] == '=') {
647 n++;
648 b64 = osmtpd_ltok_skip_fws(b64 + 1, 1);
649 if (b64[0] == '=') {
650 n++;
651 b64++;
654 /* Invalid tag value */
655 if (b64 != end || n % 4 != 0 || (n / 4) * 3 > sizeof(sig->bh)) {
656 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
657 return;
659 /* EVP_DecodeBlock doesn't handle internal whitespace */
660 EVP_DecodeInit(ectx);
661 if (EVP_DecodeUpdate(ectx, sig->bh, &decodesz, start,
662 (int)(end - start)) == -1) {
663 /* Paranoia check */
664 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
665 return;
667 sig->bhsz = decodesz;
668 if (EVP_DecodeFinal(ectx, sig->bh + sig->bhsz, &decodesz) == -1) {
669 /* Paranoia check */
670 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
671 return;
673 sig->bhsz += decodesz;
676 void
677 dkim_signature_parse_c(struct signature *sig, const char *start, const char *end)
679 if (sig->c != 0) {
680 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate c tag");
681 return;
683 if (strncmp(start, "simple", 6) == 0) {
684 sig->c = CANON_HEADER_SIMPLE;
685 start += 6;
686 } else if (strncmp(start, "relaxed", 7) == 0) {
687 sig->c = CANON_HEADER_RELAXED;
688 start += 7;
689 } else {
690 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
691 return;
693 if (start[0] == '/') {
694 start++;
695 if (strncmp(start, "simple", 6) == 0) {
696 sig->c |= CANON_BODY_SIMPLE;
697 start += 6;
698 } else if (strncmp(start, "relaxed", 7) == 0) {
699 sig->c |= CANON_BODY_RELAXED;
700 start += 7;
701 } else {
702 dkim_signature_state(sig, DKIM_PERMERROR,
703 "Invalid c tag");
704 return;
708 if (start != end) {
709 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
710 return;
712 sig->c |= CANON_DONE;
715 void
716 dkim_signature_parse_d(struct signature *sig, const char *start, const char *end)
718 if (sig->d[0] != '\0') {
719 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate d tag");
720 return;
722 if (osmtpd_ltok_skip_sig_d_tag_value(start, 0) != end ||
723 (size_t)(end - start) >= sizeof(sig->d)) {
724 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid d tag");
725 return;
727 strlcpy(sig->d, start, end - start + 1);
730 void
731 dkim_signature_parse_h(struct signature *sig, const char *start, const char *end)
733 const char *h;
734 size_t n = 0;
736 if (sig->h != NULL) {
737 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate h tag");
738 return;
740 if (osmtpd_ltok_skip_sig_h_tag_value(start, 0) < end) {
741 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid h tag");
742 return;
744 h = start;
745 while (1) {
746 if ((h = osmtpd_ltok_skip_hdr_name(h, 0)) == NULL) {
747 dkim_signature_state(sig, DKIM_PERMERROR,
748 "Invalid h tag");
749 return;
751 n++;
752 /* ';' is part of hdr-name */
753 if (h > end) {
754 h = end;
755 break;
757 h = osmtpd_ltok_skip_fws(h, 1);
758 if (h[0] != ':')
759 break;
760 h = osmtpd_ltok_skip_fws(h + 1, 1);
762 if ((sig->h = calloc(n + 1, sizeof(*sig->h))) == NULL) {
763 dkim_err(sig->header->msg, "malloc");
764 return;
766 n = 0;
767 h = start;
768 while (1) {
769 h = osmtpd_ltok_skip_hdr_name(start, 0);
770 /* ';' is part of hdr-name */
771 if (h > end) {
772 sig->h[n] = strndup(start, end - start);
773 break;
775 if ((sig->h[n++] = strndup(start, h - start)) == NULL) {
776 dkim_err(sig->header->msg, "malloc");
777 return;
779 start = osmtpd_ltok_skip_fws(h, 1);
780 if (start[0] != ':')
781 break;
782 start = osmtpd_ltok_skip_fws(start + 1, 1);
786 void
787 dkim_signature_parse_i(struct signature *sig, const char *start, const char *end)
789 if (sig->i != NULL) {
790 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate i tag");
791 return;
793 if (osmtpd_ltok_skip_sig_i_tag_value(start, 0) != end) {
794 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
795 return;
797 sig->i = start;
798 sig->isz = (size_t)(end - start);
801 void
802 dkim_signature_parse_l(struct signature *sig, const char *start, const char *end)
804 long long l;
805 char *lend;
807 if (sig->l != -1) { /* Duplicate tag */
808 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate l tag");
809 return;
811 errno = 0;
812 l = strtoll(start, &lend, 10);
813 /* > 76 digits in stroll is an overflow */
814 if (osmtpd_ltok_skip_digit(start, 0) == NULL ||
815 lend != end || errno != 0) {
816 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid l tag");
817 return;
819 if (l > SSIZE_MAX) {
820 dkim_signature_state(sig, DKIM_PERMERROR, "l tag too large");
821 return;
823 sig->l = (ssize_t)l;
826 void
827 dkim_signature_parse_q(struct signature *sig, const char *start, const char *end)
829 const char *qend;
831 if (sig->q != 0) {
832 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate q tag");
833 return;
836 while (1) {
837 start = osmtpd_ltok_skip_fws(start, 1);
838 qend = osmtpd_ltok_skip_sig_q_tag_method(start, 0);
839 if (qend == NULL) {
840 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
841 return;
843 if (strncmp(start, "dns/txt", qend - start) == 0)
844 sig->q = 1;
845 start = osmtpd_ltok_skip_fws(qend, 1);
846 if (start[0] != ':')
847 break;
849 if (start != end) {
850 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
851 return;
853 if (sig->q != 1) {
854 sig->q = 1;
855 dkim_signature_state(sig, DKIM_NEUTRAL, "No useable q found");
856 return;
860 void
861 dkim_signature_parse_s(struct signature *sig, const char *start, const char *end)
863 if (sig->s[0] != '\0') {
864 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate s tag");
865 return;
867 if (osmtpd_ltok_skip_selector(start, 0) != end) {
868 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid s tag");
869 return;
871 strlcpy(sig->s, start, end - start + 1);
874 void
875 dkim_signature_parse_t(struct signature *sig, const char *start, const char *end)
877 char *tend;
879 if (sig->t != -1) {
880 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate t tag");
881 return;
883 errno = 0;
884 sig->t = strtoll(start, &tend, 10);
885 if (osmtpd_ltok_skip_digit(start, 0) == NULL || tend != end ||
886 tend - start > 12 || errno != 0) {
887 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid t tag");
888 return;
892 void
893 dkim_signature_parse_x(struct signature *sig, const char *start, const char *end)
895 char *xend;
897 if (sig->x != -1) {
898 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate x tag");
899 return;
901 errno = 0;
902 sig->x = strtoll(start, &xend, 10);
903 if (osmtpd_ltok_skip_digit(start, 0) == NULL || xend != end ||
904 xend - start > 12 || errno != 0) {
905 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid x tag");
906 return;
910 void
911 dkim_signature_parse_z(struct signature *sig, const char *start, const char *end)
913 if (sig->z != 0) {
914 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate z tag");
915 return;
918 sig->z = 1;
919 if (osmtpd_ltok_skip_sig_z_tag_value(start, 0) != end) {
920 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid z tag");
921 return;
925 void
926 dkim_signature_verify(struct signature *sig)
928 struct message *msg = sig->header->msg;
929 static EVP_MD_CTX *bctx = NULL;
930 char digest[EVP_MAX_MD_SIZE];
931 unsigned int digestsz;
932 const char *end;
933 size_t i, header;
935 if (sig->state != DKIM_UNKNOWN)
936 return;
938 if (bctx == NULL) {
939 if ((bctx = EVP_MD_CTX_new()) == NULL) {
940 dkim_errx(msg, "EVP_MD_CTX_new");
941 return;
944 EVP_MD_CTX_reset(bctx);
945 if (!sig->sephash) {
946 if (EVP_DigestVerifyInit(bctx, NULL, sig->ah, NULL,
947 sig->p) != 1) {
948 dkim_errx(msg, "EVP_DigestVerifyInit");
949 return;
951 } else {
952 if (EVP_DigestInit_ex(bctx, sig->ah, NULL) != 1) {
953 dkim_errx(msg, "EVP_DigestInit_ex");
954 return;
958 for (i = 0; i < msg->nheaders; i++)
959 msg->header[i].parsed = 0;
961 for (header = 0; sig->h[header] != NULL; header++) {
962 for (i = msg->nheaders; i > 0; ) {
963 i--;
964 if (msg->header[i].parsed ||
965 strncasecmp(msg->header[i].buf, sig->h[header],
966 strlen(sig->h[header])) != 0 ||
967 msg->header[i].sig == sig)
968 continue;
969 end = osmtpd_ltok_skip_fws(
970 msg->header[i].buf + strlen(sig->h[header]), 1);
971 if (end[0] != ':')
972 continue;
973 dkim_signature_header(bctx, sig, &(msg->header[i]));
974 msg->header[i].parsed = 1;
977 dkim_signature_header(bctx, sig, sig->header);
978 if (!sig->sephash) {
979 if (EVP_DigestVerifyFinal(bctx, sig->b, sig->bsz) != 1)
980 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
981 } else {
982 if (EVP_DigestFinal_ex(bctx, digest, &digestsz) == 0) {
983 dkim_errx(msg, "EVP_DigestFinal_ex");
984 return;
986 if (EVP_DigestVerifyInit(bctx, NULL, NULL, NULL, sig->p) != 1) {
987 dkim_errx(msg, "EVP_DigestVerifyInit");
988 return;
990 switch (EVP_DigestVerify(bctx, sig->b, sig->bsz, digest,
991 digestsz)) {
992 case 1:
993 break;
994 case 0:
995 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
996 break;
997 default:
998 dkim_errx(msg, "EVP_DigestVerify");
999 return;
1004 /* EVP_DigestVerifyUpdate is a macro, so we can't alias this on a variable */
1005 #define dkim_b_digest_update(a, b, c) \
1006 (sig->sephash ? EVP_DigestUpdate((a), (b), (c)) :\
1007 EVP_DigestVerifyUpdate((a), (b), (c)))
1009 void
1010 dkim_signature_header(EVP_MD_CTX *bctx, struct signature *sig,
1011 struct header *header)
1013 char c;
1014 const char *ptr = header->buf, *end;
1015 int inhdrname = 1;
1016 int canon = sig->c & CANON_HEADER;
1018 for (ptr = header->buf; ptr[0] != '\0'; ptr++) {
1019 if (inhdrname) {
1020 if (canon == CANON_HEADER_RELAXED) {
1021 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1022 c = tolower(ptr[0]);
1023 } else
1024 c = ptr[0];
1025 if (c == ':') {
1026 inhdrname = 0;
1027 if (canon == CANON_HEADER_RELAXED)
1028 ptr = osmtpd_ltok_skip_fws(
1029 ptr + 1, 1) - 1;
1031 if (dkim_b_digest_update(bctx, &c, 1) == 0) {
1032 dkim_errx(sig->header->msg,
1033 "dkim_b_digest_update");
1034 return;
1036 continue;
1038 end = osmtpd_ltok_skip_fws(ptr, 1);
1039 if (end == ptr) {
1040 if (sig->header == header && ptr == sig->bheader) {
1041 ptr = osmtpd_ltok_skip_tag_value(
1042 ptr, 0) - 1;
1043 continue;
1045 if (dkim_b_digest_update(bctx, ptr, 1) == 0) {
1046 dkim_errx(sig->header->msg,
1047 "dkim_b_digest_update");
1048 return;
1050 } else {
1051 if (canon == CANON_HEADER_RELAXED) {
1052 if (end[0] == '\0')
1053 continue;
1054 if (dkim_b_digest_update(bctx, " ", 1) == 0) {
1055 dkim_errx(sig->header->msg,
1056 "dkim_b_digest_update");
1057 return;
1059 } else {
1060 if (dkim_b_digest_update(bctx, ptr,
1061 end - ptr) == 0) {
1062 dkim_errx(sig->header->msg,
1063 "dkim_b_digest_update");
1064 return;
1067 ptr = end - 1;
1071 if (sig->header != header) {
1072 if (dkim_b_digest_update(bctx, "\r\n", 2) == 0) {
1073 dkim_errx(sig->header->msg, "dkim_b_digest_update");
1074 return;
1079 void
1080 dkim_signature_state(struct signature *sig, enum state state,
1081 const char *reason)
1083 if (sig->query != NULL) {
1084 event_asr_abort(sig->query);
1085 sig->query = NULL;
1087 switch (sig->state) {
1088 case DKIM_UNKNOWN:
1089 break;
1090 case DKIM_PASS:
1091 case DKIM_FAIL:
1092 osmtpd_errx(1, "Unexpected transition");
1093 case DKIM_POLICY:
1094 if (state == DKIM_PASS)
1095 return;
1096 break;
1097 case DKIM_NEUTRAL:
1098 if (state == DKIM_PASS)
1099 return;
1100 if (state == DKIM_TEMPERROR || state == DKIM_PERMERROR)
1101 break;
1102 osmtpd_errx(1, "Unexpected transition");
1103 case DKIM_TEMPERROR:
1104 if (state == DKIM_PERMERROR)
1105 break;
1106 return;
1107 case DKIM_PERMERROR:
1108 return;
1110 sig->state = state;
1111 sig->state_reason = reason;
1114 const char *
1115 dkim_state2str(enum state state)
1117 switch (state)
1119 case DKIM_UNKNOWN:
1120 return "unknown";
1121 case DKIM_PASS:
1122 return "pass";
1123 case DKIM_FAIL:
1124 return "fail";
1125 case DKIM_POLICY:
1126 return "policy";
1127 case DKIM_NEUTRAL:
1128 return "neutral";
1129 case DKIM_TEMPERROR:
1130 return "temperror";
1131 case DKIM_PERMERROR:
1132 return "permerror";
1136 void
1137 dkim_rr_resolve(struct asr_result *ar, void *arg)
1139 struct signature *sig = arg;
1140 char key[UINT16_MAX + 1];
1141 const char *rr_txt;
1142 size_t keylen, cstrlen;
1143 struct unpack pack;
1144 struct dns_header h;
1145 struct dns_query q;
1146 struct dns_rr rr;
1148 sig->query = NULL;
1150 if (ar->ar_h_errno == TRY_AGAIN || ar->ar_h_errno == NO_RECOVERY) {
1151 dkim_signature_state(sig, DKIM_TEMPERROR,
1152 hstrerror(ar->ar_h_errno));
1153 goto verify;
1155 if (ar->ar_h_errno != NETDB_SUCCESS) {
1156 dkim_signature_state(sig, DKIM_PERMERROR,
1157 hstrerror(ar->ar_h_errno));
1158 goto verify;
1161 unpack_init(&pack, ar->ar_data, ar->ar_datalen);
1162 if (unpack_header(&pack, &h) != 0 ||
1163 unpack_query(&pack, &q) != 0) {
1164 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid dns/txt");
1165 goto verify;
1167 for (; h.ancount > 0; h.ancount--) {
1168 unpack_rr(&pack, &rr);
1169 if (rr.rr_type != T_TXT)
1170 continue;
1172 keylen = 0;
1173 rr_txt = rr.rr.other.rdata;
1174 while (rr.rr.other.rdlen > 0) {
1175 cstrlen = ((const unsigned char *)rr_txt)[0];
1176 if (cstrlen >= rr.rr.other.rdlen ||
1177 keylen + cstrlen >= sizeof(key))
1178 break;
1180 * RFC 6376 Section 3.6.2.2
1181 * Strings in a TXT RR MUST be concatenated together
1182 * before use with no intervening whitespace.
1184 strlcpy(key + keylen, rr_txt + 1, cstrlen + 1);
1185 rr.rr.other.rdlen -= (cstrlen + 1);
1186 rr_txt += (cstrlen + 1);
1187 keylen += cstrlen;
1189 if (rr.rr.other.rdlen > 0) /* Invalid TXT RDATA */
1190 continue;
1192 if (dkim_key_text_parse(sig, key))
1193 break;
1196 if (h.ancount == 0) {
1197 dkim_signature_state(sig, DKIM_PERMERROR,
1198 "No matching key found");
1199 } else {
1200 /* Only verify if all headers have been read */
1201 if (!sig->header->msg->parsing_headers)
1202 dkim_signature_verify(sig);
1204 verify:
1205 free(ar->ar_data);
1206 dkim_message_verify(sig->header->msg);
1209 int
1210 dkim_key_text_parse(struct signature *sig, const char *key)
1212 char tagname, *hashname;
1213 const char *end, *tagvend;
1214 char pkraw[UINT16_MAX] = "", pkimp[UINT16_MAX];
1215 size_t pkrawlen = 0, pkoff, linelen;
1216 int h = 0, k = 0, n = 0, p = 0, s = 0, t = 0, first = 1;
1217 BIO *bio;
1218 #ifdef HAVE_ED25519
1219 size_t pklen;
1220 int tmp;
1221 #endif
1223 key = osmtpd_ltok_skip_fws(key, 1);
1224 /* Validate syntax early */
1225 if ((end = osmtpd_ltok_skip_tag_list(key, 0)) == NULL)
1226 return 0;
1228 while (key[0] != '\0') {
1229 key = osmtpd_ltok_skip_fws(key, 1);
1230 if ((end = osmtpd_ltok_skip_tag_name(key, 0)) == NULL)
1231 return 0;
1233 if ((size_t)(end - key) != 1)
1234 tagname = '\0';
1235 else
1236 tagname = key[0];
1237 key = osmtpd_ltok_skip_fws(end, 1);
1238 /* '=' */
1239 if (key[0] != '=')
1240 return 0;
1241 key = osmtpd_ltok_skip_fws(key + 1, 1);
1242 if ((end = osmtpd_ltok_skip_tag_value(key, 0)) == NULL)
1243 return 0;
1244 switch (tagname) {
1245 case 'v':
1247 * RFC 6376 section 3.6.1, v=:
1248 * RECOMMENDED...This tag MUST be the first tag in the
1249 * record.
1251 if (!first ||
1252 osmtpd_ltok_skip_key_v_tag_value(key, 0) != end)
1253 return 0;
1254 key = end;
1255 break;
1256 case 'h':
1257 if (h != 0) /* Duplicate tag */
1258 return 0;
1259 /* Invalid tag value */
1260 if (osmtpd_ltok_skip_key_h_tag_value(key, 0) != end)
1261 return 0;
1262 while (1) {
1263 if ((tagvend = osmtpd_ltok_skip_key_h_tag_alg(
1264 key, 0)) == NULL)
1265 break;
1266 hashname = strndup(key, tagvend - key);
1267 if (hashname == NULL) {
1268 dkim_err(sig->header->msg, "malloc");
1269 return 0;
1271 if (EVP_get_digestbyname(hashname) == sig->ah) {
1272 free(hashname);
1273 h = 1;
1274 break;
1276 free(hashname);
1277 key = osmtpd_ltok_skip_fws(tagvend, 1);
1278 if (key[0] != ':')
1279 break;
1280 key = osmtpd_ltok_skip_fws(key + 1, 1);
1282 if (h != 1)
1283 return 0;
1284 key = end;
1285 break;
1286 case 'k':
1287 if (k != 0) /* Duplicate tag */
1288 return 0;
1289 k = 1;
1290 if (strncmp(key, "rsa", end - key) == 0) {
1291 if (sig->ak != EVP_PKEY_RSA)
1292 return 0;
1293 #if HAVE_ED25519
1294 } else if (strncmp(key, "ed25519", end - key) == 0) {
1295 if (sig->ak != EVP_PKEY_ED25519)
1296 return 0;
1297 #endif
1298 } else
1299 return 0;
1300 key = end;
1301 break;
1302 case 'n':
1303 if (n != 0) /* Duplicate tag */
1304 return 0;
1305 n = 1;
1306 /* semicolon is part of safe-char */
1307 if (osmtpd_ltok_skip_key_n_tag_value(key, 0) < end)
1308 return 0;
1309 key = end;
1310 break;
1311 case 'p':
1312 if (p != 0) /* Duplicate tag */
1313 return 0;
1314 p = 1;
1315 while (1) {
1316 key = osmtpd_ltok_skip_fws(key, 1);
1317 if (osmtpd_ltok_skip_alphadigitps(
1318 key, 0) == NULL)
1319 break;
1320 pkraw[pkrawlen++] = key++[0];
1321 if (pkrawlen >= sizeof(pkraw))
1322 return 0;
1324 if (key[0] == '=') {
1325 pkraw[pkrawlen++] = '=';
1326 key = osmtpd_ltok_skip_fws(key + 1, 1);
1327 if (pkrawlen >= sizeof(pkraw))
1328 return 0;
1329 if (key[0] == '=') {
1330 pkraw[pkrawlen++] = '=';
1331 key++;
1332 if (pkrawlen >= sizeof(pkraw))
1333 return 0;
1336 /* Invalid tag value */
1337 if (pkrawlen % 4 != 0 || key != end)
1338 return 0;
1339 break;
1340 case 's':
1341 if (s != 0) /* Duplicate tag */
1342 return 0;
1343 /* Invalid tag value */
1344 if (osmtpd_ltok_skip_key_s_tag_value(key, 0) != end)
1345 return 0;
1346 while (1) {
1347 if ((tagvend =
1348 osmtpd_ltok_skip_key_s_tag_type(
1349 key, 0)) == NULL)
1350 break;
1351 if (strncmp(key, "*", tagvend - key) == 0 ||
1352 strncmp(key, "email", tagvend - key) == 0) {
1353 s = 1;
1354 break;
1356 key = osmtpd_ltok_skip_fws(tagvend, 1);
1357 if (key[0] != ':')
1358 break;
1359 key = osmtpd_ltok_skip_fws(key + 1, 1);
1361 if (s != 1)
1362 return 0;
1363 key = end;
1364 break;
1365 case 't':
1366 if (t != 0) /* Duplicate tag */
1367 return 0;
1368 t = 1;
1369 if (osmtpd_ltok_skip_key_t_tag_value(key, 0) != end)
1370 return 0;
1371 while (1) {
1372 tagvend = osmtpd_ltok_skip_key_t_tag_flag(
1373 key, 0);
1374 if (strncmp(key, "y", tagvend - key) == 0)
1375 sig->kt |= KT_Y;
1376 else if (strncmp(key, "s", tagvend - key) == 0)
1377 sig->kt |= KT_S;
1378 key = osmtpd_ltok_skip_fws(tagvend, 1);
1379 if (key[0] != ':')
1380 break;
1381 key = osmtpd_ltok_skip_fws(key + 1, 1);
1383 break;
1384 default:
1385 key = end;
1386 break;
1389 first = 0;
1390 key = osmtpd_ltok_skip_fws(key, 1);
1391 if (key[0] == ';')
1392 key++;
1393 else if (key[0] != '\0')
1394 return 0;
1397 if (!p) /* Missing tag */
1398 return 0;
1399 if (k == 0 && sig->ak != EVP_PKEY_RSA) /* Default to RSA */
1400 return 0;
1402 if (pkraw[0] == '\0') {
1403 dkim_signature_state(sig, DKIM_PERMERROR, "Key is revoked");
1404 return 1;
1407 switch (sig->ak) {
1408 case EVP_PKEY_RSA:
1409 pkoff = strlcpy(pkimp, "-----BEGIN PUBLIC KEY-----\n",
1410 sizeof(pkimp));
1411 linelen = 0;
1412 for (key = pkraw; key[0] != '\0';) {
1413 if (pkoff + 2 >= sizeof(pkimp))
1414 return 0;
1415 pkimp[pkoff++] = key++[0];
1416 if (++linelen == 64) {
1417 pkimp[pkoff++] = '\n';
1418 linelen = 0;
1421 /* Leverage pkoff check in loop */
1422 if (linelen != 0)
1423 pkimp[pkoff++] = '\n';
1424 /* PEM_read_bio_PUBKEY will catch truncated keys */
1425 pkoff += strlcpy(pkimp + pkoff, "-----END PUBLIC KEY-----\n",
1426 sizeof(pkimp) - pkoff);
1427 if ((bio = BIO_new_mem_buf(pkimp, pkoff)) == NULL) {
1428 dkim_err(sig->header->msg, "BIO_new_mem_buf");
1429 return 1;
1431 sig->p = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
1432 BIO_free(bio);
1433 break;
1434 #if HAVE_ED25519
1435 case EVP_PKEY_ED25519:
1436 if ((pkrawlen / 4) * 3 >= sizeof(pkimp))
1437 return 0;
1438 EVP_DecodeInit(ectx);
1439 if (EVP_DecodeUpdate(ectx, pkimp, &tmp, pkraw, pkrawlen) == -1)
1440 return 0;
1441 pklen = tmp;
1442 if (EVP_DecodeFinal(ectx, pkimp, &tmp) == -1)
1443 return 0;
1444 pklen += tmp;
1445 sig->p = EVP_PKEY_new_raw_public_key(sig->ak, NULL, pkimp,
1446 pklen);
1447 break;
1448 #endif
1450 if (sig->p == NULL) {
1452 * XXX No clue how to differentiate between invalid key and
1453 * temporary failure like *alloc.
1454 * Assume invalid key, because it's more likely.
1456 return 0;
1458 return 1;
1461 void
1462 dkim_body_parse(struct message *msg, const char *line)
1464 struct signature *sig;
1465 const char *end = line, *hash, *prev;
1466 size_t hashn, len, i;
1467 int wsp, ret;
1469 if (line[0] == '\0') {
1470 msg->body_whitelines++;
1471 return;
1474 while (msg->body_whitelines-- > 0) {
1475 for (i = 0; i < msg->nheaders; i++) {
1476 if ((sig = msg->header[i].sig) == NULL ||
1477 sig->state != DKIM_UNKNOWN)
1478 continue;
1479 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1480 sig->l -= sig->l == -1 ? 0 : hashn;
1481 if (EVP_DigestUpdate(sig->bhctx, "\r\n", hashn) == 0) {
1482 dkim_errx(msg, "EVP_DigestUpdate");
1483 return;
1487 msg->body_whitelines = 0;
1488 msg->has_body = 1;
1490 while (line[0] != '\0') {
1491 while (1) {
1492 prev = end;
1493 if ((end = osmtpd_ltok_skip_wsp(end, 0)) == NULL)
1494 break;
1496 end = prev;
1497 wsp = end != line;
1498 if (!wsp) {
1499 while (osmtpd_ltok_skip_wsp(end, 0) == NULL &&
1500 end[0] != '\0')
1501 end++;
1503 for (i = 0; i < msg->nheaders; i++) {
1504 sig = msg->header[i].sig;
1505 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1506 continue;
1507 if (wsp &&
1508 (sig->c & CANON_BODY) == CANON_BODY_RELAXED) {
1509 hash = " ";
1510 len = end[0] == '\0' ? 0 : 1;
1511 } else {
1512 hash = line;
1513 len = (size_t)(end - line);
1515 hashn = sig->l == -1 ? len : MIN(len, (size_t)sig->l);
1516 sig->l -= sig->l == -1 ? 0 : hashn;
1517 ret = EVP_DigestUpdate(sig->bhctx, hash, hashn);
1518 if (ret == 0) {
1519 dkim_errx(msg, "EVP_DigestUpdate");
1520 return;
1523 line = end;
1525 for (i = 0; i < msg->nheaders; i++) {
1526 sig = msg->header[i].sig;
1527 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1528 continue;
1529 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1530 sig->l -= sig->l == -1 ? 0 : hashn;
1531 ret = EVP_DigestUpdate(sig->bhctx, "\r\n", hashn);
1532 if (ret == 0) {
1533 dkim_errx(msg, "EVP_DigestUpdate");
1534 return;
1539 void
1540 dkim_body_verify(struct signature *sig)
1542 unsigned char digest[EVP_MAX_MD_SIZE];
1543 unsigned int digestsz;
1545 if (sig->state != DKIM_UNKNOWN)
1546 return;
1548 if ((sig->c & CANON_BODY) == CANON_BODY_SIMPLE &&
1549 !sig->header->msg->has_body) {
1550 if (EVP_DigestUpdate(sig->bhctx, "\r\n",
1551 sig->l == -1 ? 2 : MIN(2, sig->l)) <= 0) {
1552 dkim_errx(sig->header->msg,
1553 "Can't update hash context");
1554 return;
1557 if (sig->l > 0) {
1558 dkim_signature_state(sig, DKIM_PERMERROR,
1559 "l tag larger than body");
1560 return;
1563 if (EVP_DigestFinal_ex(sig->bhctx, digest, &digestsz) == 0) {
1564 dkim_errx(sig->header->msg, "EVP_DigestFinal_ex");
1565 return;
1568 if (digestsz != sig->bhsz || memcmp(digest, sig->bh, digestsz) != 0)
1569 dkim_signature_state(sig, DKIM_FAIL, "bh mismatch");
1572 void
1573 dkim_message_verify(struct message *msg)
1575 struct signature *sig;
1576 size_t i;
1577 ssize_t n, aroff = 0;
1578 int found = 0;
1579 char *line = NULL;
1580 size_t linelen = 0;
1582 if (!msg->readdone)
1583 return;
1585 for (i = 0; i < msg->nheaders; i++) {
1586 if (msg->header[i].sig == NULL)
1587 continue;
1588 if (msg->header[i].sig->query != NULL)
1589 return;
1590 if (msg->header[i].sig->state != DKIM_UNKNOWN)
1591 continue;
1592 dkim_signature_state(msg->header[i].sig, DKIM_PASS, NULL);
1595 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1596 "Authentication-Results: %s", authservid)) == -1) {
1597 dkim_err(msg, "malloc");
1598 goto fail;
1600 for (i = 0; i < msg->nheaders; i++) {
1601 sig = msg->header[i].sig;
1602 if (sig == NULL)
1603 continue;
1604 found = 1;
1605 if ((aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=%s",
1606 dkim_state2str(sig->state))) == -1) {
1607 dkim_err(msg, "malloc");
1608 goto fail;
1610 if (sig->state_reason != NULL) {
1611 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1612 " reason=\"%s\"", sig->state_reason)) == -1) {
1613 dkim_err(msg, "malloc");
1614 goto fail;
1617 if (sig->s[0] != '\0') {
1618 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1619 " header.s=%s", sig->s)) == -1) {
1620 dkim_err(msg, "malloc");
1621 goto fail;
1624 if (sig->d[0] != '\0') {
1625 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1626 " header.d=%s", sig->d)) == -1) {
1627 dkim_err(msg, "malloc");
1628 goto fail;
1632 * Don't print i-tag, since localpart can be a quoted-string,
1633 * which can contain FWS and CFWS.
1635 if (sig->a != NULL) {
1636 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1637 " header.a=%.*s", (int)sig->asz, sig->a)) == -1) {
1638 dkim_err(msg, "malloc");
1639 goto fail;
1643 if (!found) {
1644 aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=none");
1645 if (aroff == -1) {
1646 dkim_err(msg, "malloc");
1647 goto fail;
1650 dkim_ar_print(msg->ctx, line);
1652 rewind(msg->origf);
1653 while ((n = getline(&line, &linelen, msg->origf)) != -1) {
1654 line[n - 1] = '\0';
1655 osmtpd_filter_dataline(msg->ctx, "%s", line);
1657 if (ferror(msg->origf))
1658 dkim_err(msg, "getline");
1659 fail:
1660 free(line);
1661 return;
1664 void
1665 dkim_ar_print(struct osmtpd_ctx *ctx, const char *start)
1667 const char *scan, *checkpoint, *ncheckpoint;
1668 size_t arlen = 0;
1669 int first = 1, arid = 1;
1671 checkpoint = start;
1672 ncheckpoint = osmtpd_ltok_skip_hdr_name(start, 0) + 1;
1673 for (scan = start; scan[0] != '\0'; scan++) {
1674 if (scan[0] == '\t')
1675 arlen = (arlen + 8) & ~7;
1676 else
1677 arlen++;
1678 if (arlen >= AUTHENTICATION_RESULTS_LINELEN) {
1679 osmtpd_filter_dataline(ctx, "%s%.*s", first ? "" : "\t",
1680 (int)((checkpoint == start ?
1681 ncheckpoint : checkpoint) - start), start);
1682 start = osmtpd_ltok_skip_cfws(checkpoint, 1);
1683 scan = start;
1684 arlen = 8;
1685 first = 0;
1687 if (scan == ncheckpoint) {
1688 checkpoint = ncheckpoint;
1689 ncheckpoint = osmtpd_ltok_skip_cfws(ncheckpoint, 1);
1690 /* authserv-id */
1691 if (arid) {
1692 ncheckpoint = osmtpd_ltok_skip_value(
1693 ncheckpoint, 0);
1694 arid = 0;
1695 /* methodspec */
1696 } else if (strncmp(ncheckpoint, "dkim",
1697 sizeof("dkim") - 1) == 0) {
1698 ncheckpoint = osmtpd_ltok_skip_keyword(
1699 ncheckpoint + sizeof("dkim"), 0);
1700 /* reasonspec */
1701 } else if (strncmp(ncheckpoint, "reason",
1702 sizeof("reason") - 1) == 0) {
1703 ncheckpoint = osmtpd_ltok_skip_value(
1704 ncheckpoint + sizeof("reason"), 0);
1705 /* propspec */
1706 } else {
1707 ncheckpoint += sizeof("header.x=") - 1;
1708 ncheckpoint = osmtpd_ltok_skip_ar_pvalue(
1709 ncheckpoint, 0);
1710 if (ncheckpoint[0] == ';')
1711 ncheckpoint++;
1715 osmtpd_filter_dataline(ctx, "%s%s", first ? "" : "\t", start);
1718 ssize_t
1719 dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
1721 va_list ap;
1722 char *artmp;
1723 int size;
1724 size_t nn;
1726 va_start(ap, fmt);
1727 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1728 va_end(ap);
1729 if (size + aroff <= *n)
1730 return (ssize_t)size + aroff;
1731 nn = (((aroff + size) / 256) + 1) * 256;
1732 artmp = realloc(*ar, nn);
1733 if (artmp == NULL)
1734 return -1;
1735 *ar = artmp;
1736 *n = nn;
1737 va_start(ap, fmt);
1738 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1739 va_end(ap);
1740 return (ssize_t)size + aroff;
1743 void
1744 dkim_err(struct message *msg, char *text)
1746 msg->err = 1;
1747 fprintf(stderr, "%s: %s\n", text, strerror(errno));
1750 void
1751 dkim_errx(struct message *msg, char *text)
1753 msg->err = 1;
1754 fprintf(stderr, "%s\n", text);
1757 __dead void
1758 usage(void)
1760 fprintf(stderr, "usage: filter-dkimverify\n");
1761 exit(1);