Blob


1 /*
2 * Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 #include <sys/types.h>
17 #include <sys/socket.h>
19 #include <openssl/evp.h>
20 #include <openssl/pem.h>
21 #include <openssl/sha.h>
22 #include <openssl/err.h>
24 #include <arpa/nameser.h>
26 #include <assert.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <event.h>
30 #include <limits.h>
31 #include <netdb.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <asr.h>
40 #include "opensmtpd.h"
41 #include "unpack_dns.h"
42 #include "ltok.h"
44 /*
45 * Use RFC8601 (Authentication-Results) codes instead of RFC6376 codes,
46 * since they're more expressive.
47 */
48 enum state {
49 DKIM_UNKNOWN,
50 DKIM_PASS,
51 DKIM_FAIL,
52 DKIM_POLICY,
53 DKIM_NEUTRAL,
54 DKIM_TEMPERROR,
55 DKIM_PERMERROR
56 };
58 struct signature {
59 struct header *header;
60 enum state state;
61 const char *state_reason;
62 int v;
63 const char *a;
64 size_t asz;
65 int ak;
66 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 (pledge("tmppath stdio dns", NULL) == -1)
174 osmtpd_err(1, "pledge");
176 if ((ectx = EVP_ENCODE_CTX_new()) == NULL)
177 osmtpd_err(1, "EVP_ENCODE_CTX_new");
179 osmtpd_register_conf(dkim_conf);
180 osmtpd_register_filter_dataline(dkim_dataline);
181 osmtpd_register_filter_commit(dkim_commit);
182 osmtpd_local_message(dkim_message_new, dkim_message_free);
183 osmtpd_run();
185 return 0;
188 void
189 dkim_conf(const char *key, const char *value)
191 const char *end;
193 if (key == NULL) {
194 if (authservid == NULL)
195 osmtpd_errx(1, "Didn't receive admd config option");
196 return;
198 if (strcmp(key, "admd") == 0 && authservid == NULL) {
199 if ((authservid = strdup(value)) == NULL)
200 osmtpd_err(1, "malloc");
201 end = osmtpd_ltok_skip_value(authservid, 0);
202 if (authservid + strlen(authservid) != end)
203 osmtpd_errx(1, "Invalid authservid");
207 void
208 dkim_dataline(struct osmtpd_ctx *ctx, const char *line)
210 struct message *msg = ctx->local_message;
211 size_t i;
213 if (msg->err) {
214 if (line[0] == '.' && line[1] =='\0') {
215 msg->readdone = 1;
216 osmtpd_filter_dataline(ctx, ".");
218 return;
221 if (fprintf(msg->origf, "%s\n", line) < 0) {
222 dkim_err(msg, "Couldn't write to tempfile");
223 return;
225 if (line[0] == '.') {
226 line++;
227 if (line[0] == '\0') {
228 msg->readdone = 1;
229 for (i = 0; i < msg->nheaders; i++) {
230 if (msg->header[i].sig == NULL)
231 continue;
232 dkim_body_verify(msg->header[i].sig);
234 dkim_message_verify(msg);
235 return;
238 if (msg->parsing_headers) {
239 dkim_header_add(ctx, line);
240 if (line[0] == '\0') {
241 msg->parsing_headers = 0;
242 for (i = 0; i < msg->nheaders; i++) {
243 if (msg->header[i].sig == NULL)
244 continue;
245 if (msg->header[i].sig->query == NULL)
246 dkim_signature_verify(
247 msg->header[i].sig);
250 return;
251 } else {
252 dkim_body_parse(msg, line);
256 void
257 dkim_commit(struct osmtpd_ctx *ctx)
259 struct message *msg = ctx->local_message;
261 if (msg->err)
262 osmtpd_filter_disconnect(ctx, "Internal server error");
263 else
264 osmtpd_filter_proceed(ctx);
267 void *
268 dkim_message_new(struct osmtpd_ctx *ctx)
270 struct message *msg;
272 if ((msg = malloc(sizeof(*msg))) == NULL)
273 osmtpd_err(1, NULL);
275 if ((msg->origf = tmpfile()) == NULL) {
276 dkim_err(msg, "Can't open tempfile");
277 return NULL;
279 msg->ctx = ctx;
280 msg->parsing_headers = 1;
281 msg->body_whitelines = 0;
282 msg->has_body = 0;
283 msg->header = NULL;
284 msg->nheaders = 0;
285 msg->err = 0;
286 msg->readdone = 0;
288 return msg;
291 void
292 dkim_message_free(struct osmtpd_ctx *ctx, void *data)
294 struct message *msg = data;
295 size_t i, j;
297 fclose(msg->origf);
298 for (i = 0; i < msg->nheaders; i++) {
299 if (msg->header[i].sig != NULL) {
300 free(msg->header[i].sig->b);
301 EVP_MD_CTX_free(msg->header[i].sig->bhctx);
302 for (j = 0; msg->header[i].sig->h != NULL &&
303 msg->header[i].sig->h[j] != NULL; j++)
304 free(msg->header[i].sig->h[j]);
305 free(msg->header[i].sig->h);
306 EVP_PKEY_free(msg->header[i].sig->p);
308 free(msg->header[i].buf);
309 free(msg->header[i].sig);
311 free(msg->header);
312 free(msg);
315 void
316 dkim_header_add(struct osmtpd_ctx *ctx, const char *line)
318 struct message *msg = ctx->local_message;
319 const char *start, *end, *verify;
320 struct header *headers;
321 size_t i;
323 if (msg->nheaders > 0 &&
324 msg->header[msg->nheaders - 1].readdone == 0) {
325 if (line[0] != ' ' && line[0] != '\t') {
326 msg->header[msg->nheaders - 1].readdone = 1;
327 start = msg->header[msg->nheaders - 1].buf;
328 end = osmtpd_ltok_skip_field_name(start, 0);
329 /* In case someone uses an obs-optional */
330 if (end != NULL)
331 verify = osmtpd_ltok_skip_wsp(end, 1);
332 if (end != NULL &&
333 strncasecmp(
334 start, "DKIM-Signature", end - start) == 0 &&
335 verify[0] == ':')
336 dkim_signature_parse(
337 &msg->header[msg->nheaders - 1]);
338 if (line[0] == '\0')
339 return;
340 } else {
341 dkim_header_cat(ctx, line);
342 return;
345 if (msg->nheaders % 10 == 0) {
346 if ((headers = recallocarray(msg->header, msg->nheaders,
347 msg->nheaders + 10, sizeof(*msg->header))) == NULL) {
348 dkim_err(msg, "malloc");
349 return;
351 msg->header = headers;
352 for (i = 0; i < msg->nheaders; i++) {
353 if (msg->header[i].sig == NULL)
354 continue;
355 msg->header[i].sig->header = &msg->header[i];
358 msg->header[msg->nheaders].msg = msg;
359 msg->nheaders++;
360 dkim_header_cat(ctx, line);
363 void
364 dkim_header_cat(struct osmtpd_ctx *ctx, const char *line)
366 struct message *msg = ctx->local_message;
367 struct header *header = &msg->header[msg->nheaders - 1];
368 char *buf;
370 size_t needed = header->buflen + strlen(line) + 2;
372 if (needed > (header->buflen / 1024) + 1) {
373 buf = reallocarray(header->buf, (needed / 1024) + 1, 1024);
374 if (buf == NULL) {
375 dkim_err(msg, "malloc");
376 return;
378 header->buf = buf;
380 header->buflen += snprintf(header->buf + header->buflen,
381 (((needed / 1024) + 1) * 1024) - header->buflen, "%s%s",
382 header->buflen == 0 ? "" : "\r\n", line);
385 void
386 dkim_signature_parse(struct header *header)
388 struct signature *sig;
389 struct asr_query *query;
390 const char *buf, *i, *end;
391 char tagname[3];
392 char subdomain[HOST_NAME_MAX + 1];
393 size_t ilen, dlen;
395 /* Format checked by dkim_header_add */
396 buf = osmtpd_ltok_skip_field_name(header->buf, 0);
397 buf = osmtpd_ltok_skip_wsp(buf, 1) + 1;
399 if ((header->sig = calloc(1, sizeof(*header->sig))) == NULL) {
400 dkim_err(header->msg, "malloc");
401 return;
403 sig = header->sig;
404 sig->header = header;
405 sig->l = -1;
406 sig->t = -1;
407 sig->x = -1;
409 end = osmtpd_ltok_skip_tag_list(buf, 0);
410 if (end == NULL || end[0] != '\0') {
411 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid tag-list");
412 return;
415 while (buf[0] != '\0') {
416 buf = osmtpd_ltok_skip_fws(buf, 1);
417 end = osmtpd_ltok_skip_tag_name(buf, 0);
419 /* Unknown tag-name */
420 if ((size_t)(end - buf) >= sizeof(tagname))
421 tagname[0] = '\0';
422 else
423 strlcpy(tagname, buf, (end - buf) + 1);
424 buf = osmtpd_ltok_skip_fws(end, 1);
425 /* '=' */
426 buf = osmtpd_ltok_skip_fws(buf + 1, 1);
427 end = osmtpd_ltok_skip_tag_value(buf, 1);
428 if (strcmp(tagname, "v") == 0)
429 dkim_signature_parse_v(sig, buf, end);
430 else if (strcmp(tagname, "a") == 0)
431 dkim_signature_parse_a(sig, buf, end);
432 else if (strcmp(tagname, "b") == 0)
433 dkim_signature_parse_b(sig, buf, end);
434 else if (strcmp(tagname, "bh") == 0)
435 dkim_signature_parse_bh(sig, buf, end);
436 else if (strcmp(tagname, "c") == 0)
437 dkim_signature_parse_c(sig, buf, end);
438 else if (strcmp(tagname, "d") == 0)
439 dkim_signature_parse_d(sig, buf, end);
440 else if (strcmp(tagname, "h") == 0)
441 dkim_signature_parse_h(sig, buf, end);
442 else if (strcmp(tagname, "i") == 0)
443 dkim_signature_parse_i(sig, buf, end);
444 else if (strcmp(tagname, "l") == 0)
445 dkim_signature_parse_l(sig, buf, end);
446 else if (strcmp(tagname, "q") == 0)
447 dkim_signature_parse_q(sig, buf, end);
448 else if (strcmp(tagname, "s") == 0)
449 dkim_signature_parse_s(sig, buf, end);
450 else if (strcmp(tagname, "t") == 0)
451 dkim_signature_parse_t(sig, buf, end);
452 else if (strcmp(tagname, "x") == 0)
453 dkim_signature_parse_x(sig, buf, end);
454 else if (strcmp(tagname, "z") == 0)
455 dkim_signature_parse_z(sig, buf, end);
457 buf = osmtpd_ltok_skip_fws(end, 1);
458 if (buf[0] == ';')
459 buf++;
460 else if (buf[0] != '\0') {
461 dkim_signature_state(sig, DKIM_PERMERROR,
462 "Invalid tag-list");
463 return;
466 if (sig->state != DKIM_UNKNOWN)
467 return;
469 if (sig->v != 1)
470 dkim_signature_state(sig, DKIM_PERMERROR, "Missing v tag");
471 else if (sig->ah == NULL)
472 dkim_signature_state(sig, DKIM_PERMERROR, "Missing a tag");
473 else if (sig->b == NULL)
474 dkim_signature_state(sig, DKIM_PERMERROR, "Missing b tag");
475 else if (sig->bhsz == 0)
476 dkim_signature_state(sig, DKIM_PERMERROR, "Missing bh tag");
477 else if (sig->d[0] == '\0')
478 dkim_signature_state(sig, DKIM_PERMERROR, "Missing d tag");
479 else if (sig->h == NULL)
480 dkim_signature_state(sig, DKIM_PERMERROR, "Missing h tag");
481 else if (sig->s[0] == '\0')
482 dkim_signature_state(sig, DKIM_PERMERROR, "Missing s tag");
483 if (sig->state != DKIM_UNKNOWN)
484 return;
486 if (sig->i != NULL) {
487 i = osmtpd_ltok_skip_local_part(sig->i, 1) + 1;
488 ilen = sig->isz - (size_t)(i - sig->i);
489 dlen = strlen(sig->d);
490 if (ilen < dlen) {
491 dkim_signature_state(sig, DKIM_PERMERROR,
492 "i tag not subdomain of d");
493 return;
495 i += ilen - dlen;
496 if ((i[-1] != '.' && i[-1] != '@') ||
497 strncasecmp(i, sig->d, dlen) != 0) {
498 dkim_signature_state(sig, DKIM_PERMERROR,
499 "i tag not subdomain of d");
500 return;
503 if (sig->t != -1 && sig->x != -1 && sig->t > sig->x) {
504 dkim_signature_state(sig, DKIM_PERMERROR, "t tag after x tag");
505 return;
508 if ((size_t)snprintf(subdomain, sizeof(subdomain), "%s._domainkey.%s",
509 sig->s, sig->d) >= sizeof(subdomain)) {
510 dkim_signature_state(sig, DKIM_PERMERROR,
511 "dns/txt query too long");
512 return;
515 if ((query = res_query_async(subdomain, C_IN, T_TXT, NULL)) == NULL) {
516 dkim_err(header->msg, "res_query_async");
517 return;
519 if ((sig->query = event_asr_run(query, dkim_rr_resolve, sig)) == NULL) {
520 dkim_err(header->msg, "event_asr_run");
521 asr_abort(query);
522 return;
526 void
527 dkim_signature_parse_v(struct signature *sig, const char *start, const char *end)
529 if (sig->v != 0) { /* Duplicate tag */
530 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate v tag");
531 return;
533 /* Unsupported version */
534 if (start[0] != '1' || start + 1 != end)
535 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsupported v tag");
536 else
537 sig->v = 1;
540 void
541 dkim_signature_parse_a(struct signature *sig, const char *start, const char *end)
543 char ah[sizeof("sha256")];
545 if (sig->ah != NULL) {
546 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate a tag");
547 return;
550 if (osmtpd_ltok_skip_sig_a_tag_alg(start, 0) != end) {
551 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid a tag");
552 return;
554 sig->a = start;
555 sig->asz = (size_t)(end - start);
556 if (strncmp(start, "rsa-", 4) == 0) {
557 start += 4;
558 sig->ak = EVP_PKEY_RSA;
559 sig->sephash = 0;
560 #if HAVE_ED25519
561 } else if (strncmp(start, "ed25519-", 8) == 0) {
562 start += 8;
563 sig->ak = EVP_PKEY_ED25519;
564 sig->sephash = 1;
565 #endif
566 } else {
567 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag k");
568 return;
570 if ((size_t)(end - start) >= sizeof(ah)) {
571 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
572 return;
574 strlcpy(ah, start, sizeof(ah));
575 ah[end - start] = '\0';
576 if ((sig->ah = EVP_get_digestbyname(ah)) == NULL) {
577 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
578 return;
580 if ((sig->bhctx = EVP_MD_CTX_new()) == NULL) {
581 dkim_err(sig->header->msg, "EVP_MD_CTX_new");
582 return;
584 if (EVP_DigestInit_ex(sig->bhctx, sig->ah, NULL) <= 0) {
585 dkim_err(sig->header->msg, "EVP_DigestInit_ex");
586 return;
590 void
591 dkim_signature_parse_b(struct signature *sig, const char *start, const char *end)
593 int decodesz;
595 if (sig->b != NULL) {
596 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate b tag");
597 return;
599 sig->bheader = start;
600 if ((sig->b = malloc((((end - start) / 4) + 1) * 3)) == NULL) {
601 dkim_err(sig->header->msg, "malloc");
602 return;
604 /* EVP_DecodeBlock doesn't handle internal whitespace */
605 EVP_DecodeInit(ectx);
606 if (EVP_DecodeUpdate(ectx, sig->b, &decodesz, start,
607 (int)(end - start)) == -1) {
608 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
609 return;
611 sig->bsz = decodesz;
612 if (EVP_DecodeFinal(ectx, sig->b + sig->bsz,
613 &decodesz) == -1) {
614 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
615 return;
617 sig->bsz += decodesz;
620 void
621 dkim_signature_parse_bh(struct signature *sig, const char *start, const char *end)
623 const char *b64;
624 size_t n;
625 int decodesz;
627 if (sig->bhsz != 0) {
628 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate bh tag");
629 return;
631 /*
632 * EVP_Decode* expects sig->bh to be large enough,
633 * so count the actual b64 characters.
634 */
635 b64 = start;
636 n = 0;
637 while (1) {
638 b64 = osmtpd_ltok_skip_fws(b64, 1);
639 if (osmtpd_ltok_skip_alphadigitps(b64, 0) == NULL)
640 break;
641 n++;
642 b64++;
644 if (b64[0] == '=') {
645 n++;
646 b64 = osmtpd_ltok_skip_fws(b64 + 1, 1);
647 if (b64[0] == '=') {
648 n++;
649 b64++;
652 /* Invalid tag value */
653 if (b64 != end || n % 4 != 0 || (n / 4) * 3 > sizeof(sig->bh)) {
654 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
655 return;
657 /* EVP_DecodeBlock doesn't handle internal whitespace */
658 EVP_DecodeInit(ectx);
659 if (EVP_DecodeUpdate(ectx, sig->bh, &decodesz, start,
660 (int)(end - start)) == -1) {
661 /* Paranoia check */
662 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
663 return;
665 sig->bhsz = decodesz;
666 if (EVP_DecodeFinal(ectx, sig->bh + sig->bhsz, &decodesz) == -1) {
667 /* Paranoia check */
668 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
669 return;
671 sig->bhsz += decodesz;
674 void
675 dkim_signature_parse_c(struct signature *sig, const char *start, const char *end)
677 if (sig->c != 0) {
678 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate c tag");
679 return;
681 if (strncmp(start, "simple", 6) == 0) {
682 sig->c = CANON_HEADER_SIMPLE;
683 start += 6;
684 } else if (strncmp(start, "relaxed", 7) == 0) {
685 sig->c = CANON_HEADER_RELAXED;
686 start += 7;
687 } else {
688 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
689 return;
691 if (start[0] == '/') {
692 start++;
693 if (strncmp(start, "simple", 6) == 0) {
694 sig->c |= CANON_BODY_SIMPLE;
695 start += 6;
696 } else if (strncmp(start, "relaxed", 7) == 0) {
697 sig->c |= CANON_BODY_RELAXED;
698 start += 7;
699 } else {
700 dkim_signature_state(sig, DKIM_PERMERROR,
701 "Invalid c tag");
702 return;
706 if (start != end) {
707 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
708 return;
710 sig->c |= CANON_DONE;
713 void
714 dkim_signature_parse_d(struct signature *sig, const char *start, const char *end)
716 if (sig->d[0] != '\0') {
717 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate d tag");
718 return;
720 if (osmtpd_ltok_skip_sig_d_tag_value(start, 0) != end ||
721 (size_t)(end - start) >= sizeof(sig->d)) {
722 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid d tag");
723 return;
725 strlcpy(sig->d, start, end - start + 1);
728 void
729 dkim_signature_parse_h(struct signature *sig, const char *start, const char *end)
731 const char *h;
732 size_t n = 0;
734 if (sig->h != NULL) {
735 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate h tag");
736 return;
738 if (osmtpd_ltok_skip_sig_h_tag_value(start, 0) < end) {
739 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid h tag");
740 return;
742 h = start;
743 while (1) {
744 if ((h = osmtpd_ltok_skip_hdr_name(h, 0)) == NULL) {
745 dkim_signature_state(sig, DKIM_PERMERROR,
746 "Invalid h tag");
747 return;
749 n++;
750 /* ';' is part of hdr-name */
751 if (h > end) {
752 h = end;
753 break;
755 h = osmtpd_ltok_skip_fws(h, 1);
756 if (h[0] != ':')
757 break;
758 h = osmtpd_ltok_skip_fws(h + 1, 1);
760 if ((sig->h = calloc(n + 1, sizeof(*sig->h))) == NULL) {
761 dkim_err(sig->header->msg, "malloc");
762 return;
764 n = 0;
765 h = start;
766 while (1) {
767 h = osmtpd_ltok_skip_hdr_name(start, 0);
768 /* ';' is part of hdr-name */
769 if (h > end) {
770 sig->h[n] = strndup(start, end - start);
771 break;
773 if ((sig->h[n++] = strndup(start, h - start)) == NULL) {
774 dkim_err(sig->header->msg, "malloc");
775 return;
777 start = osmtpd_ltok_skip_fws(h, 1);
778 if (start[0] != ':')
779 break;
780 start = osmtpd_ltok_skip_fws(start + 1, 1);
784 void
785 dkim_signature_parse_i(struct signature *sig, const char *start, const char *end)
787 if (sig->i != NULL) {
788 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate i tag");
789 return;
791 if (osmtpd_ltok_skip_sig_i_tag_value(start, 0) != end) {
792 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
793 return;
795 sig->i = start;
796 sig->isz = (size_t)(end - start);
799 void
800 dkim_signature_parse_l(struct signature *sig, const char *start, const char *end)
802 long long l;
803 char *lend;
805 if (sig->l != -1) { /* Duplicate tag */
806 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate l tag");
807 return;
809 errno = 0;
810 l = strtoll(start, &lend, 10);
811 /* > 76 digits in stroll is an overflow */
812 if (osmtpd_ltok_skip_digit(start, 0) == NULL ||
813 lend != end || errno != 0) {
814 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid l tag");
815 return;
817 if (l > SSIZE_MAX) {
818 dkim_signature_state(sig, DKIM_PERMERROR, "l tag too large");
819 return;
821 sig->l = (ssize_t)l;
824 void
825 dkim_signature_parse_q(struct signature *sig, const char *start, const char *end)
827 const char *qend;
829 if (sig->q != 0) {
830 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate q tag");
831 return;
834 while (1) {
835 start = osmtpd_ltok_skip_fws(start, 1);
836 qend = osmtpd_ltok_skip_sig_q_tag_method(start, 0);
837 if (qend == NULL) {
838 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
839 return;
841 if (strncmp(start, "dns/txt", qend - start) == 0)
842 sig->q = 1;
843 start = osmtpd_ltok_skip_fws(qend, 1);
844 if (start[0] != ':')
845 break;
847 if (start != end) {
848 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
849 return;
851 if (sig->q != 1) {
852 sig->q = 1;
853 dkim_signature_state(sig, DKIM_NEUTRAL, "No useable q found");
854 return;
858 void
859 dkim_signature_parse_s(struct signature *sig, const char *start, const char *end)
861 if (sig->s[0] != '\0') {
862 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate s tag");
863 return;
865 if (osmtpd_ltok_skip_selector(start, 0) != end) {
866 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid s tag");
867 return;
869 strlcpy(sig->s, start, end - start + 1);
872 void
873 dkim_signature_parse_t(struct signature *sig, const char *start, const char *end)
875 char *tend;
877 if (sig->t != -1) {
878 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate t tag");
879 return;
881 errno = 0;
882 sig->t = strtoll(start, &tend, 10);
883 if (osmtpd_ltok_skip_digit(start, 0) == NULL || tend != end ||
884 tend - start > 12 || errno != 0) {
885 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid t tag");
886 return;
890 void
891 dkim_signature_parse_x(struct signature *sig, const char *start, const char *end)
893 char *xend;
895 if (sig->x != -1) {
896 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate x tag");
897 return;
899 errno = 0;
900 sig->x = strtoll(start, &xend, 10);
901 if (osmtpd_ltok_skip_digit(start, 0) == NULL || xend != end ||
902 xend - start > 12 || errno != 0) {
903 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid x tag");
904 return;
908 void
909 dkim_signature_parse_z(struct signature *sig, const char *start, const char *end)
911 if (sig->z != 0) {
912 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate z tag");
913 return;
916 sig->z = 1;
917 if (osmtpd_ltok_skip_sig_z_tag_value(start, 0) != end) {
918 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid z tag");
919 return;
923 void
924 dkim_signature_verify(struct signature *sig)
926 struct message *msg = sig->header->msg;
927 static EVP_MD_CTX *bctx = NULL;
928 char digest[EVP_MAX_MD_SIZE];
929 unsigned int digestsz;
930 const char *end;
931 size_t i, header;
933 if (sig->state != DKIM_UNKNOWN)
934 return;
936 if (bctx == NULL) {
937 if ((bctx = EVP_MD_CTX_new()) == NULL) {
938 dkim_errx(msg, "EVP_MD_CTX_new");
939 return;
942 EVP_MD_CTX_reset(bctx);
943 if (!sig->sephash) {
944 if (EVP_DigestVerifyInit(bctx, NULL, sig->ah, NULL,
945 sig->p) != 1) {
946 dkim_errx(msg, "EVP_DigestVerifyInit");
947 return;
949 } else {
950 if (EVP_DigestInit_ex(bctx, sig->ah, NULL) != 1) {
951 dkim_errx(msg, "EVP_DigestInit_ex");
952 return;
956 for (i = 0; i < msg->nheaders; i++)
957 msg->header[i].parsed = 0;
959 for (header = 0; sig->h[header] != NULL; header++) {
960 for (i = msg->nheaders; i > 0; ) {
961 i--;
962 if (msg->header[i].parsed ||
963 strncasecmp(msg->header[i].buf, sig->h[header],
964 strlen(sig->h[header])) != 0 ||
965 msg->header[i].sig == sig)
966 continue;
967 end = osmtpd_ltok_skip_fws(
968 msg->header[i].buf + strlen(sig->h[header]), 1);
969 if (end[0] != ':')
970 continue;
971 dkim_signature_header(bctx, sig, &(msg->header[i]));
972 msg->header[i].parsed = 1;
975 dkim_signature_header(bctx, sig, sig->header);
976 if (!sig->sephash) {
977 if (EVP_DigestVerifyFinal(bctx, sig->b, sig->bsz) != 1)
978 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
979 } else {
980 if (EVP_DigestFinal_ex(bctx, digest, &digestsz) == 0) {
981 dkim_errx(msg, "EVP_DigestFinal_ex");
982 return;
984 if (EVP_DigestVerifyInit(bctx, NULL, NULL, NULL, sig->p) != 1) {
985 dkim_errx(msg, "EVP_DigestVerifyInit");
986 return;
988 switch (EVP_DigestVerify(bctx, sig->b, sig->bsz, digest,
989 digestsz)) {
990 case 1:
991 break;
992 case 0:
993 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
994 break;
995 default:
996 dkim_errx(msg, "EVP_DigestVerify");
997 return;
1002 /* EVP_DigestVerifyUpdate is a macro, so we can't alias this on a variable */
1003 #define dkim_b_digest_update(a, b, c) \
1004 (sig->sephash ? EVP_DigestUpdate((a), (b), (c)) :\
1005 EVP_DigestVerifyUpdate((a), (b), (c)))
1007 void
1008 dkim_signature_header(EVP_MD_CTX *bctx, struct signature *sig,
1009 struct header *header)
1011 char c;
1012 const char *ptr = header->buf, *end;
1013 int inhdrname = 1;
1014 int canon = sig->c & CANON_HEADER;
1016 for (ptr = header->buf; ptr[0] != '\0'; ptr++) {
1017 if (inhdrname) {
1018 if (canon == CANON_HEADER_RELAXED) {
1019 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1020 c = tolower(ptr[0]);
1021 } else
1022 c = ptr[0];
1023 if (c == ':') {
1024 inhdrname = 0;
1025 if (canon == CANON_HEADER_RELAXED)
1026 ptr = osmtpd_ltok_skip_fws(
1027 ptr + 1, 1) - 1;
1029 if (dkim_b_digest_update(bctx, &c, 1) == 0) {
1030 dkim_errx(sig->header->msg,
1031 "dkim_b_digest_update");
1032 return;
1034 continue;
1036 end = osmtpd_ltok_skip_fws(ptr, 1);
1037 if (end == ptr) {
1038 if (sig->header == header && ptr == sig->bheader) {
1039 ptr = osmtpd_ltok_skip_tag_value(
1040 ptr, 0) - 1;
1041 continue;
1043 if (dkim_b_digest_update(bctx, ptr, 1) == 0) {
1044 dkim_errx(sig->header->msg,
1045 "dkim_b_digest_update");
1046 return;
1048 } else {
1049 if (canon == CANON_HEADER_RELAXED) {
1050 if (end[0] == '\0')
1051 continue;
1052 if (dkim_b_digest_update(bctx, " ", 1) == 0) {
1053 dkim_errx(sig->header->msg,
1054 "dkim_b_digest_update");
1055 return;
1057 } else {
1058 if (dkim_b_digest_update(bctx, ptr,
1059 end - ptr) == 0) {
1060 dkim_errx(sig->header->msg,
1061 "dkim_b_digest_update");
1062 return;
1065 ptr = end - 1;
1069 if (sig->header != header) {
1070 if (dkim_b_digest_update(bctx, "\r\n", 2) == 0) {
1071 dkim_errx(sig->header->msg, "dkim_b_digest_update");
1072 return;
1077 void
1078 dkim_signature_state(struct signature *sig, enum state state,
1079 const char *reason)
1081 if (sig->query != NULL) {
1082 event_asr_abort(sig->query);
1083 sig->query = NULL;
1085 switch (sig->state) {
1086 case DKIM_UNKNOWN:
1087 break;
1088 case DKIM_PASS:
1089 case DKIM_FAIL:
1090 osmtpd_errx(1, "Unexpected transition");
1091 case DKIM_POLICY:
1092 if (state == DKIM_PASS)
1093 return;
1094 break;
1095 case DKIM_NEUTRAL:
1096 if (state == DKIM_PASS)
1097 return;
1098 if (state == DKIM_TEMPERROR || state == DKIM_PERMERROR)
1099 break;
1100 osmtpd_errx(1, "Unexpected transition");
1101 case DKIM_TEMPERROR:
1102 if (state == DKIM_PERMERROR)
1103 break;
1104 return;
1105 case DKIM_PERMERROR:
1106 return;
1108 sig->state = state;
1109 sig->state_reason = reason;
1112 const char *
1113 dkim_state2str(enum state state)
1115 switch (state)
1117 case DKIM_UNKNOWN:
1118 return "unknown";
1119 case DKIM_PASS:
1120 return "pass";
1121 case DKIM_FAIL:
1122 return "fail";
1123 case DKIM_POLICY:
1124 return "policy";
1125 case DKIM_NEUTRAL:
1126 return "neutral";
1127 case DKIM_TEMPERROR:
1128 return "temperror";
1129 case DKIM_PERMERROR:
1130 return "permerror";
1134 void
1135 dkim_rr_resolve(struct asr_result *ar, void *arg)
1137 struct signature *sig = arg;
1138 char key[UINT16_MAX + 1];
1139 const char *rr_txt;
1140 size_t keylen, cstrlen;
1141 struct unpack pack;
1142 struct dns_header h;
1143 struct dns_query q;
1144 struct dns_rr rr;
1146 sig->query = NULL;
1148 if (ar->ar_h_errno == TRY_AGAIN || ar->ar_h_errno == NO_RECOVERY) {
1149 dkim_signature_state(sig, DKIM_TEMPERROR,
1150 hstrerror(ar->ar_h_errno));
1151 goto verify;
1153 if (ar->ar_h_errno != NETDB_SUCCESS) {
1154 dkim_signature_state(sig, DKIM_PERMERROR,
1155 hstrerror(ar->ar_h_errno));
1156 goto verify;
1159 unpack_init(&pack, ar->ar_data, ar->ar_datalen);
1160 if (unpack_header(&pack, &h) != 0 ||
1161 unpack_query(&pack, &q) != 0) {
1162 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid dns/txt");
1163 goto verify;
1165 for (; h.ancount > 0; h.ancount--) {
1166 unpack_rr(&pack, &rr);
1167 if (rr.rr_type != T_TXT)
1168 continue;
1170 keylen = 0;
1171 rr_txt = rr.rr.other.rdata;
1172 while (rr.rr.other.rdlen > 0) {
1173 cstrlen = ((const unsigned char *)rr_txt)[0];
1174 if (cstrlen >= rr.rr.other.rdlen ||
1175 keylen + cstrlen >= sizeof(key))
1176 break;
1178 * RFC 6376 Section 3.6.2.2
1179 * Strings in a TXT RR MUST be concatenated together
1180 * before use with no intervening whitespace.
1182 strlcpy(key + keylen, rr_txt + 1, cstrlen + 1);
1183 rr.rr.other.rdlen -= (cstrlen + 1);
1184 rr_txt += (cstrlen + 1);
1185 keylen += cstrlen;
1187 if (rr.rr.other.rdlen > 0) /* Invalid TXT RDATA */
1188 continue;
1190 if (dkim_key_text_parse(sig, key))
1191 break;
1194 if (h.ancount == 0) {
1195 dkim_signature_state(sig, DKIM_PERMERROR,
1196 "No matching key found");
1197 } else {
1198 /* Only verify if all headers have been read */
1199 if (!sig->header->msg->parsing_headers)
1200 dkim_signature_verify(sig);
1202 verify:
1203 free(ar->ar_data);
1204 dkim_message_verify(sig->header->msg);
1207 int
1208 dkim_key_text_parse(struct signature *sig, const char *key)
1210 char tagname, *hashname;
1211 const char *end, *tagvend, *b64;
1212 char pkraw[UINT16_MAX] = "", pkimp[UINT16_MAX];
1213 size_t pkrawlen = 0, pkoff, linelen, pklen;
1214 int h = 0, k = 0, n = 0, s = 0, t = 0, first = 1, tmp;
1215 BIO *bio;
1217 key = osmtpd_ltok_skip_fws(key, 1);
1218 /* Validate syntax early */
1219 if ((end = osmtpd_ltok_skip_tag_list(key, 0)) == NULL)
1220 return 0;
1222 while (key[0] != '\0') {
1223 key = osmtpd_ltok_skip_fws(key, 1);
1224 if ((end = osmtpd_ltok_skip_tag_name(key, 0)) == NULL)
1225 return 0;
1227 if ((size_t)(end - key) != 1)
1228 tagname = '\0';
1229 else
1230 tagname = key[0];
1231 key = osmtpd_ltok_skip_fws(end, 1);
1232 /* '=' */
1233 if (key[0] != '=')
1234 return 0;
1235 key = osmtpd_ltok_skip_fws(key + 1, 1);
1236 if ((end = osmtpd_ltok_skip_tag_value(key, 0)) == NULL)
1237 return 0;
1238 switch (tagname) {
1239 case 'v':
1241 * RFC 6376 section 3.6.1, v=:
1242 * RECOMMENDED...This tag MUST be the first tag in the
1243 * record.
1245 if (!first ||
1246 osmtpd_ltok_skip_key_v_tag_value(key, 0) != end)
1247 return 0;
1248 key = end;
1249 break;
1250 case 'h':
1251 if (h != 0) /* Duplicate tag */
1252 return 0;
1253 /* Invalid tag value */
1254 if (osmtpd_ltok_skip_key_h_tag_value(key, 0) != end)
1255 return 0;
1256 while (1) {
1257 if ((tagvend = osmtpd_ltok_skip_key_h_tag_alg(
1258 key, 0)) == NULL)
1259 break;
1260 hashname = strndup(key, tagvend - key);
1261 if (hashname == NULL) {
1262 dkim_err(sig->header->msg, "malloc");
1263 return 0;
1265 if (EVP_get_digestbyname(hashname) == sig->ah) {
1266 free(hashname);
1267 h = 1;
1268 break;
1270 free(hashname);
1271 key = osmtpd_ltok_skip_fws(tagvend, 1);
1272 if (key[0] != ':')
1273 break;
1274 key = osmtpd_ltok_skip_fws(key + 1, 1);
1276 if (h != 1)
1277 return 0;
1278 key = end;
1279 break;
1280 case 'k':
1281 if (k != 0) /* Duplicate tag */
1282 return 0;
1283 k = 1;
1284 if (strncmp(key, "rsa", end - key) == 0) {
1285 if (sig->ak != EVP_PKEY_RSA)
1286 return 0;
1287 #if HAVE_ED25519
1288 } else if (strncmp(key, "ed25519", end - key) == 0) {
1289 if (sig->ak != EVP_PKEY_ED25519)
1290 return 0;
1291 #endif
1292 } else
1293 return 0;
1294 key = end;
1295 break;
1296 case 'n':
1297 if (n != 0) /* Duplicate tag */
1298 return 0;
1299 n = 1;
1300 /* semicolon is part of safe-char */
1301 if (osmtpd_ltok_skip_key_n_tag_value(key, 0) < end)
1302 return 0;
1303 key = end;
1304 break;
1305 case 'p':
1306 if (pkrawlen != 0) /* Duplicate tag */
1307 return 0;
1308 tagvend = key;
1309 while (1) {
1310 b64 = osmtpd_ltok_skip_fws(tagvend, 1);
1311 if (osmtpd_ltok_skip_alphadigitps(
1312 tagvend, 0) == NULL)
1313 break;
1314 pkraw[pkrawlen++] = tagvend++[0];
1315 if (pkrawlen >= sizeof(pkraw))
1316 return 0;
1318 if (tagvend[0] == '=') {
1319 pkraw[pkrawlen++] = '=';
1320 tagvend = osmtpd_ltok_skip_fws(b64 + 1, 1);
1321 if (pkrawlen >= sizeof(pkraw))
1322 return 0;
1323 if (tagvend[0] == '=') {
1324 pkraw[pkrawlen++] = '=';
1325 tagvend++;
1326 if (pkrawlen >= sizeof(pkraw))
1327 return 0;
1330 /* Invalid tag value */
1331 if (pkrawlen % 4 != 0 || tagvend != end)
1332 return 0;
1333 key = end;
1334 break;
1335 case 's':
1336 if (s != 0) /* Duplicate tag */
1337 return 0;
1338 /* Invalid tag value */
1339 if (osmtpd_ltok_skip_key_s_tag_value(key, 0) != end)
1340 return 0;
1341 while (1) {
1342 if ((tagvend =
1343 osmtpd_ltok_skip_key_s_tag_type(
1344 key, 0)) == NULL)
1345 break;
1346 if (strncmp(key, "*", tagvend - key) == 0 ||
1347 strncmp(key, "email", tagvend - key) == 0) {
1348 s = 1;
1349 break;
1351 key = osmtpd_ltok_skip_fws(tagvend, 1);
1352 if (key[0] != ':')
1353 break;
1354 key = osmtpd_ltok_skip_fws(key + 1, 1);
1356 if (s != 1)
1357 return 0;
1358 key = end;
1359 break;
1360 case 't':
1361 if (t != 0) /* Duplicate tag */
1362 return 0;
1363 t = 1;
1364 if (osmtpd_ltok_skip_key_t_tag_value(key, 0) != end)
1365 return 0;
1366 while (1) {
1367 tagvend = osmtpd_ltok_skip_key_t_tag_flag(
1368 key, 0);
1369 if (strncmp(key, "y", tagvend - key) == 0)
1370 sig->kt |= KT_Y;
1371 else if (strncmp(key, "s", tagvend - key) == 0)
1372 sig->kt |= KT_S;
1373 key = osmtpd_ltok_skip_fws(tagvend, 1);
1374 if (key[0] != ':')
1375 break;
1376 key = osmtpd_ltok_skip_fws(key + 1, 1);
1378 break;
1379 default:
1380 key = end;
1381 break;
1384 first = 0;
1385 key = osmtpd_ltok_skip_fws(key, 1);
1386 if (key[0] == ';')
1387 key++;
1388 else if (key[0] != '\0')
1389 return 0;
1392 if (pkrawlen == 0) /* Missing tag */
1393 return 0;
1394 if (k == 0 && sig->ak != EVP_PKEY_RSA) /* Default to RSA */
1395 return 0;
1397 if (pkraw[0] == '\0') {
1398 dkim_signature_state(sig, DKIM_PERMERROR, "Key is revoked");
1399 return 1;
1402 switch (sig->ak) {
1403 case EVP_PKEY_RSA:
1404 pkoff = strlcpy(pkimp, "-----BEGIN PUBLIC KEY-----\n",
1405 sizeof(pkimp));
1406 linelen = 0;
1407 for (key = pkraw; key[0] != '\0';) {
1408 if (pkoff + 2 >= sizeof(pkimp))
1409 return 0;
1410 pkimp[pkoff++] = key[0];
1411 if (++linelen == 64) {
1412 pkimp[pkoff++] = '\n';
1413 linelen = 0;
1416 /* Leverage pkoff check in loop */
1417 if (linelen != 0)
1418 pkimp[pkoff++] = '\n';
1419 /* PEM_read_bio_PUBKEY will catch truncated keys */
1420 pkoff += strlcpy(pkimp + pkoff, "-----END PUBLIC KEY-----\n",
1421 sizeof(pkimp) - pkoff);
1422 if ((bio = BIO_new_mem_buf(pkimp, pkoff)) == NULL) {
1423 dkim_err(sig->header->msg, "BIO_new_mem_buf");
1424 return 1;
1426 sig->p = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
1427 BIO_free(bio);
1428 break;
1429 #if HAVE_ED25519
1430 case EVP_PKEY_ED25519:
1431 if ((pkrawlen / 4) * 3 >= sizeof(pkimp))
1432 return 0;
1433 EVP_DecodeInit(ectx);
1434 if (EVP_DecodeUpdate(ectx, pkimp, &tmp, pkraw, pkrawlen) == -1)
1435 return 0;
1436 pklen = tmp;
1437 if (EVP_DecodeFinal(ectx, pkimp, &tmp) == -1)
1438 return 0;
1439 pklen += tmp;
1440 sig->p = EVP_PKEY_new_raw_public_key(sig->ak, NULL, pkimp,
1441 pklen);
1442 break;
1443 #endif
1445 if (sig->p == NULL) {
1447 * XXX No clue how to differentiate between invalid key and
1448 * temporary failure like *alloc.
1449 * Assume invalid key, because it's more likely.
1451 return 0;
1453 return 1;
1456 void
1457 dkim_body_parse(struct message *msg, const char *line)
1459 struct signature *sig;
1460 const char *end = line, *hash, *prev;
1461 size_t hashn, len, i;
1462 int wsp, ret;
1464 if (line[0] == '\0') {
1465 msg->body_whitelines++;
1466 return;
1469 while (msg->body_whitelines-- > 0) {
1470 for (i = 0; i < msg->nheaders; i++) {
1471 if ((sig = msg->header[i].sig) == NULL ||
1472 sig->state != DKIM_UNKNOWN)
1473 continue;
1474 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1475 sig->l -= sig->l == -1 ? 0 : hashn;
1476 if (EVP_DigestUpdate(sig->bhctx, "\r\n", hashn) == 0) {
1477 dkim_errx(msg, "EVP_DigestUpdate");
1478 return;
1482 msg->body_whitelines = 0;
1483 msg->has_body = 1;
1485 while (line[0] != '\0') {
1486 while (1) {
1487 prev = end;
1488 if ((end = osmtpd_ltok_skip_wsp(end, 0)) == NULL)
1489 break;
1491 end = prev;
1492 wsp = end != line;
1493 if (!wsp) {
1494 while (osmtpd_ltok_skip_wsp(end, 0) == NULL &&
1495 end[0] != '\0')
1496 end++;
1498 for (i = 0; i < msg->nheaders; i++) {
1499 sig = msg->header[i].sig;
1500 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1501 continue;
1502 if (wsp &&
1503 (sig->c & CANON_BODY) == CANON_BODY_RELAXED) {
1504 hash = " ";
1505 len = end[0] == '\0' ? 0 : 1;
1506 } else {
1507 hash = line;
1508 len = (size_t)(end - line);
1510 hashn = sig->l == -1 ? len : MIN(len, (size_t)sig->l);
1511 sig->l -= sig->l == -1 ? 0 : hashn;
1512 ret = EVP_DigestUpdate(sig->bhctx, hash, hashn);
1513 if (ret == 0) {
1514 dkim_errx(msg, "EVP_DigestUpdate");
1515 return;
1518 line = end;
1520 for (i = 0; i < msg->nheaders; i++) {
1521 sig = msg->header[i].sig;
1522 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1523 continue;
1524 hashn = sig->l == -1 ? 2 : MIN(2, sig->l);
1525 sig->l -= sig->l == -1 ? 0 : hashn;
1526 ret = EVP_DigestUpdate(sig->bhctx, "\r\n", hashn);
1527 if (ret == 0) {
1528 dkim_errx(msg, "EVP_DigestUpdate");
1529 return;
1534 void
1535 dkim_body_verify(struct signature *sig)
1537 unsigned char digest[EVP_MAX_MD_SIZE];
1538 unsigned int digestsz;
1540 if (sig->state != DKIM_UNKNOWN)
1541 return;
1543 if ((sig->c & CANON_BODY) == CANON_BODY_SIMPLE &&
1544 !sig->header->msg->has_body) {
1545 if (EVP_DigestUpdate(sig->bhctx, "\r\n",
1546 sig->l == -1 ? 2 : MIN(2, sig->l)) <= 0) {
1547 dkim_errx(sig->header->msg,
1548 "Can't update hash context");
1549 return;
1552 if (sig->l > 0) {
1553 dkim_signature_state(sig, DKIM_PERMERROR,
1554 "l tag larger than body");
1555 return;
1558 if (EVP_DigestFinal_ex(sig->bhctx, digest, &digestsz) == 0) {
1559 dkim_errx(sig->header->msg, "EVP_DigestFinal_ex");
1560 return;
1563 if (digestsz != sig->bhsz || memcmp(digest, sig->bh, digestsz) != 0)
1564 dkim_signature_state(sig, DKIM_FAIL, "bh mismatch");
1567 void
1568 dkim_message_verify(struct message *msg)
1570 struct signature *sig;
1571 size_t i;
1572 ssize_t n, aroff = 0;
1573 int found = 0;
1574 char *line = NULL;
1575 size_t linelen = 0;
1577 if (!msg->readdone)
1578 return;
1580 for (i = 0; i < msg->nheaders; i++) {
1581 if (msg->header[i].sig == NULL)
1582 continue;
1583 if (msg->header[i].sig->query != NULL)
1584 return;
1585 if (msg->header[i].sig->state != DKIM_UNKNOWN)
1586 continue;
1587 dkim_signature_state(msg->header[i].sig, DKIM_PASS, NULL);
1590 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1591 "Authentication-Results: %s", authservid)) == -1) {
1592 dkim_err(msg, "malloc");
1593 goto fail;
1595 for (i = 0; i < msg->nheaders; i++) {
1596 sig = msg->header[i].sig;
1597 if (sig == NULL)
1598 continue;
1599 found = 1;
1600 if ((aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=%s",
1601 dkim_state2str(sig->state))) == -1) {
1602 dkim_err(msg, "malloc");
1603 goto fail;
1605 if (sig->state_reason != NULL) {
1606 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1607 " reason=\"%s\"", sig->state_reason)) == -1) {
1608 dkim_err(msg, "malloc");
1609 goto fail;
1612 if (sig->s[0] != '\0') {
1613 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1614 " header.s=%s", sig->s)) == -1) {
1615 dkim_err(msg, "malloc");
1616 goto fail;
1619 if (sig->d[0] != '\0') {
1620 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1621 " header.d=%s", sig->d)) == -1) {
1622 dkim_err(msg, "malloc");
1623 goto fail;
1627 * Don't print i-tag, since localpart can be a quoted-string,
1628 * which can contain FWS and CFWS.
1630 if (sig->a != NULL) {
1631 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1632 " header.a=%.*s", (int)sig->asz, sig->a)) == -1) {
1633 dkim_err(msg, "malloc");
1634 goto fail;
1638 if (!found) {
1639 aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=none");
1640 if (aroff == -1) {
1641 dkim_err(msg, "malloc");
1642 goto fail;
1645 dkim_ar_print(msg->ctx, line);
1647 rewind(msg->origf);
1648 while ((n = getline(&line, &linelen, msg->origf)) != -1) {
1649 line[n - 1] = '\0';
1650 osmtpd_filter_dataline(msg->ctx, "%s", line);
1652 if (ferror(msg->origf))
1653 dkim_err(msg, "getline");
1654 fail:
1655 free(line);
1656 return;
1659 void
1660 dkim_ar_print(struct osmtpd_ctx *ctx, const char *start)
1662 const char *scan, *checkpoint, *ncheckpoint;
1663 size_t arlen = 0;
1664 int first = 1, arid = 1;
1666 checkpoint = start;
1667 ncheckpoint = osmtpd_ltok_skip_hdr_name(start, 0) + 1;
1668 for (scan = start; scan[0] != '\0'; scan++) {
1669 if (scan[0] == '\t')
1670 arlen = (arlen + 8) & ~7;
1671 else
1672 arlen++;
1673 if (arlen >= AUTHENTICATION_RESULTS_LINELEN) {
1674 osmtpd_filter_dataline(ctx, "%s%.*s", first ? "" : "\t",
1675 (int)((checkpoint == start ?
1676 ncheckpoint : checkpoint) - start), start);
1677 start = osmtpd_ltok_skip_cfws(checkpoint, 1);
1678 scan = start;
1679 arlen = 8;
1680 first = 0;
1682 if (scan == ncheckpoint) {
1683 checkpoint = ncheckpoint;
1684 ncheckpoint = osmtpd_ltok_skip_cfws(ncheckpoint, 1);
1685 /* authserv-id */
1686 if (arid) {
1687 ncheckpoint = osmtpd_ltok_skip_value(
1688 ncheckpoint, 0);
1689 arid = 0;
1690 /* methodspec */
1691 } else if (strncmp(ncheckpoint, "dkim",
1692 sizeof("dkim") - 1) == 0) {
1693 ncheckpoint = osmtpd_ltok_skip_keyword(
1694 ncheckpoint + sizeof("dkim"), 0);
1695 /* reasonspec */
1696 } else if (strncmp(ncheckpoint, "reason",
1697 sizeof("reason") - 1) == 0) {
1698 ncheckpoint = osmtpd_ltok_skip_value(
1699 ncheckpoint + sizeof("reason"), 0);
1700 /* propspec */
1701 } else {
1702 ncheckpoint += sizeof("header.x=") - 1;
1703 ncheckpoint = osmtpd_ltok_skip_ar_pvalue(
1704 ncheckpoint, 0);
1705 if (ncheckpoint[0] == ';')
1706 ncheckpoint++;
1710 osmtpd_filter_dataline(ctx, "%s%s", first ? "" : "\t", start);
1713 ssize_t
1714 dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
1716 va_list ap;
1717 char *artmp;
1718 int size;
1719 size_t nn;
1721 assert(*n >= aroff);
1722 va_start(ap, fmt);
1723 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1724 va_end(ap);
1725 if (size + aroff <= *n)
1726 return (ssize_t)size + aroff;
1727 nn = (((aroff + size) / 256) + 1) * 256;
1728 artmp = realloc(*ar, nn);
1729 if (artmp == NULL)
1730 return -1;
1731 *ar = artmp;
1732 *n = nn;
1733 va_start(ap, fmt);
1734 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1735 va_end(ap);
1736 return (ssize_t)size + aroff;
1739 void
1740 dkim_err(struct message *msg, char *text)
1742 msg->err = 1;
1743 fprintf(stderr, "%s: %s\n", text, strerror(errno));
1746 void
1747 dkim_errx(struct message *msg, char *text)
1749 msg->err = 1;
1750 fprintf(stderr, "%s\n", text);
1753 __dead void
1754 usage(void)
1756 fprintf(stderr, "usage: filter-dkimverify\n");
1757 exit(1);