Blob


1 /*
2 * Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 #include <sys/types.h>
17 #include <sys/socket.h>
19 #include <openssl/evp.h>
20 #include <openssl/pem.h>
21 #include <openssl/sha.h>
22 #include <openssl/err.h>
24 #include <arpa/nameser.h>
26 #include <assert.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <event.h>
30 #include <limits.h>
31 #include <netdb.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <asr.h>
40 #include "opensmtpd.h"
41 #include "unpack_dns.h"
42 #include "ltok.h"
44 /*
45 * Use RFC8601 (Authentication-Results) codes instead of RFC6376 codes,
46 * since they're more expressive.
47 */
48 enum state {
49 DKIM_UNKNOWN,
50 DKIM_PASS,
51 DKIM_FAIL,
52 DKIM_POLICY,
53 DKIM_NEUTRAL,
54 DKIM_TEMPERROR,
55 DKIM_PERMERROR
56 };
58 struct signature {
59 struct header *header;
60 enum state state;
61 const char *state_reason;
62 int v;
63 const char *a;
64 size_t asz;
65 int ak;
66 const EVP_MD *ah;
67 char *b;
68 size_t bsz;
69 const char *bheader;
70 /* Make sure padding bits for base64 decoding fit */
71 char bh[EVP_MAX_MD_SIZE + (3 - (EVP_MAX_MD_SIZE % 3))];
72 size_t bhsz;
73 EVP_MD_CTX *bhctx;
74 int c;
75 #define CANON_HEADER_SIMPLE 0
76 #define CANON_HEADER_RELAXED 1
77 #define CANON_HEADER 1
78 #define CANON_BODY_SIMPLE 0
79 #define CANON_BODY_RELAXED 1 << 1
80 #define CANON_BODY 1 << 1
81 #define CANON_DONE 1 << 2
82 char d[HOST_NAME_MAX + 1];
83 char **h;
84 const char *i;
85 size_t isz;
86 ssize_t l;
87 int q;
88 char s[HOST_NAME_MAX + 1];
89 time_t t; /* Signature t=/timestamp */
90 #define KT_Y 1
91 #define KT_S 1 << 1
92 int kt; /* Key t=/Flags */
93 time_t x;
94 int z;
95 struct event_asr *query;
96 EVP_PKEY *p;
97 };
99 struct header {
100 struct message *msg;
101 uint8_t readdone;
102 uint8_t parsed;
103 char *buf;
104 size_t buflen;
105 struct signature *sig;
106 };
108 #define AUTHENTICATION_RESULTS_LINELEN 78
109 #define MIN(a, b) ((a) < (b) ? (a) : (b))
111 struct message {
112 struct osmtpd_ctx *ctx;
113 FILE *origf;
114 int parsing_headers;
115 size_t body_whitelines;
116 int has_body;
117 struct header *header;
118 size_t nheaders;
119 int err;
120 int readdone;
121 };
123 void usage(void);
124 void dkim_err(struct message *, char *);
125 void dkim_errx(struct message *, char *);
126 void dkim_conf(const char *, const char *);
127 void dkim_dataline(struct osmtpd_ctx *, const char *);
128 void dkim_commit(struct osmtpd_ctx *);
129 void *dkim_message_new(struct osmtpd_ctx *);
130 void dkim_message_free(struct osmtpd_ctx *, void *);
131 void dkim_header_add(struct osmtpd_ctx *, const char *);
132 void dkim_signature_parse(struct header *);
133 void dkim_signature_parse_v(struct signature *, const char *, const char *);
134 void dkim_signature_parse_a(struct signature *, const char *, const char *);
135 void dkim_signature_parse_b(struct signature *, const char *, const char *);
136 void dkim_signature_parse_bh(struct signature *, const char *, const char *);
137 void dkim_signature_parse_c(struct signature *, const char *, const char *);
138 void dkim_signature_parse_d(struct signature *, const char *, const char *);
139 void dkim_signature_parse_h(struct signature *, const char *, const char *);
140 void dkim_signature_parse_i(struct signature *, const char *, const char *);
141 void dkim_signature_parse_l(struct signature *, const char *, const char *);
142 void dkim_signature_parse_q(struct signature *, const char *, const char *);
143 void dkim_signature_parse_s(struct signature *, const char *, const char *);
144 void dkim_signature_parse_t(struct signature *, const char *, const char *);
145 void dkim_signature_parse_x(struct signature *, const char *, const char *);
146 void dkim_signature_parse_z(struct signature *, const char *, const char *);
147 void dkim_signature_verify(struct signature *);
148 void dkim_signature_header(EVP_MD_CTX *, struct signature *, struct header *);
149 void dkim_signature_state(struct signature *, enum state, const char *);
150 const char *dkim_state2str(enum state);
151 void dkim_header_cat(struct osmtpd_ctx *, const char *);
152 void dkim_body_parse(struct message *, const char *);
153 void dkim_body_verify(struct signature *);
154 void dkim_rr_resolve(struct asr_result *, void *);
155 void dkim_message_verify(struct message *);
156 ssize_t dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
157 __attribute__((__format__ (printf, 4, 5)));
158 void dkim_ar_print(struct osmtpd_ctx *, const char *);
159 int dkim_key_text_parse(struct signature *, const char *);
161 char *authservid;
162 EVP_ENCODE_CTX *ectx = NULL;
164 int
165 main(int argc, char *argv[])
167 if (argc != 1)
168 osmtpd_errx(1, "Invalid argument count");
170 OpenSSL_add_all_digests();
172 if (pledge("tmppath stdio dns", NULL) == -1)
173 osmtpd_err(1, "pledge");
175 if ((ectx = EVP_ENCODE_CTX_new()) == NULL)
176 osmtpd_err(1, "EVP_ENCODE_CTX_new");
178 osmtpd_register_conf(dkim_conf);
179 osmtpd_register_filter_dataline(dkim_dataline);
180 osmtpd_register_filter_commit(dkim_commit);
181 osmtpd_local_message(dkim_message_new, dkim_message_free);
182 osmtpd_run();
184 return 0;
187 void
188 dkim_conf(const char *key, const char *value)
190 const char *end;
192 if (key == NULL) {
193 if (authservid == NULL)
194 osmtpd_errx(1, "Didn't receive admd config option");
195 return;
197 if (strcmp(key, "admd") == 0 && authservid == NULL) {
198 if ((authservid = strdup(value)) == NULL)
199 osmtpd_err(1, "malloc");
200 end = osmtpd_ltok_skip_value(authservid, 0);
201 if (authservid + strlen(authservid) != end)
202 osmtpd_errx(1, "Invalid authservid");
206 void
207 dkim_dataline(struct osmtpd_ctx *ctx, const char *line)
209 struct message *msg = ctx->local_message;
210 size_t i;
212 if (msg->err) {
213 if (line[0] == '.' && line[1] =='\0') {
214 msg->readdone = 1;
215 osmtpd_filter_dataline(ctx, ".");
217 return;
220 if (fprintf(msg->origf, "%s\n", line) < 0) {
221 dkim_err(msg, "Couldn't write to tempfile");
222 return;
224 if (line[0] == '.') {
225 line++;
226 if (line[0] == '\0') {
227 msg->readdone = 1;
228 for (i = 0; i < msg->nheaders; i++) {
229 if (msg->header[i].sig == NULL)
230 continue;
231 dkim_body_verify(msg->header[i].sig);
233 dkim_message_verify(msg);
234 return;
237 if (msg->parsing_headers) {
238 dkim_header_add(ctx, line);
239 if (line[0] == '\0') {
240 msg->parsing_headers = 0;
241 for (i = 0; i < msg->nheaders; i++) {
242 if (msg->header[i].sig == NULL)
243 continue;
244 if (msg->header[i].sig->query == NULL)
245 dkim_signature_verify(
246 msg->header[i].sig);
249 return;
250 } else {
251 dkim_body_parse(msg, line);
255 void
256 dkim_commit(struct osmtpd_ctx *ctx)
258 struct message *msg = ctx->local_message;
260 if (msg->err)
261 osmtpd_filter_disconnect(ctx, "Internal server error");
262 else
263 osmtpd_filter_proceed(ctx);
266 void *
267 dkim_message_new(struct osmtpd_ctx *ctx)
269 struct message *msg;
271 if ((msg = malloc(sizeof(*msg))) == NULL)
272 osmtpd_err(1, NULL);
274 if ((msg->origf = tmpfile()) == NULL) {
275 dkim_err(msg, "Can't open tempfile");
276 return NULL;
278 msg->ctx = ctx;
279 msg->parsing_headers = 1;
280 msg->body_whitelines = 0;
281 msg->has_body = 0;
282 msg->header = NULL;
283 msg->nheaders = 0;
284 msg->err = 0;
285 msg->readdone = 0;
287 return msg;
290 void
291 dkim_message_free(struct osmtpd_ctx *ctx, void *data)
293 struct message *msg = data;
294 size_t i, j;
296 fclose(msg->origf);
297 for (i = 0; i < msg->nheaders; i++) {
298 if (msg->header[i].sig != NULL) {
299 free(msg->header[i].sig->b);
300 EVP_MD_CTX_free(msg->header[i].sig->bhctx);
301 for (j = 0; msg->header[i].sig->h != NULL &&
302 msg->header[i].sig->h[j] != NULL; j++)
303 free(msg->header[i].sig->h[j]);
304 free(msg->header[i].sig->h);
306 free(msg->header[i].sig);
308 free(msg->header);
309 free(msg);
312 void
313 dkim_header_add(struct osmtpd_ctx *ctx, const char *line)
315 struct message *msg = ctx->local_message;
316 const char *start, *end, *verify;
317 struct header *headers;
318 size_t i;
320 if (msg->nheaders > 0 &&
321 msg->header[msg->nheaders - 1].readdone == 0) {
322 if (line[0] != ' ' && line[0] != '\t') {
323 msg->header[msg->nheaders - 1].readdone = 1;
324 start = msg->header[msg->nheaders - 1].buf;
325 end = osmtpd_ltok_skip_field_name(start, 0);
326 /* In case someone uses an obs-optional */
327 if (end != NULL)
328 verify = osmtpd_ltok_skip_wsp(end, 1);
329 if (end != NULL &&
330 strncasecmp(
331 start, "DKIM-Signature", end - start) == 0 &&
332 verify[0] == ':')
333 dkim_signature_parse(
334 &msg->header[msg->nheaders - 1]);
335 if (line[0] == '\0')
336 return;
337 } else {
338 dkim_header_cat(ctx, line);
339 return;
342 if (msg->nheaders % 10 == 0) {
343 if ((headers = recallocarray(msg->header, msg->nheaders,
344 msg->nheaders + 10, sizeof(*msg->header))) == NULL) {
345 dkim_err(msg, "malloc");
346 return;
348 msg->header = headers;
349 for (i = 0; i < msg->nheaders; i++) {
350 if (msg->header[i].sig == NULL)
351 continue;
352 msg->header[i].sig->header = &msg->header[i];
355 msg->header[msg->nheaders].msg = msg;
356 msg->nheaders++;
357 dkim_header_cat(ctx, line);
360 void
361 dkim_header_cat(struct osmtpd_ctx *ctx, const char *line)
363 struct message *msg = ctx->local_message;
364 struct header *header = &msg->header[msg->nheaders - 1];
365 char *buf;
367 size_t needed = header->buflen + strlen(line) + 2;
369 if (needed > (header->buflen / 1024) + 1) {
370 buf = reallocarray(header->buf, (needed / 1024) + 1, 1024);
371 if (buf == NULL) {
372 dkim_err(msg, "malloc");
373 return;
375 header->buf = buf;
377 header->buflen += snprintf(header->buf + header->buflen,
378 (((needed / 1024) + 1) * 1024) - header->buflen, "%s%s",
379 header->buflen == 0 ? "" : "\r\n", line);
382 void
383 dkim_signature_parse(struct header *header)
385 struct signature *sig;
386 struct asr_query *query;
387 const char *buf, *i, *end;
388 char tagname[3];
389 char subdomain[HOST_NAME_MAX + 1];
390 size_t ilen, dlen;
392 /* Format checked by dkim_header_add */
393 buf = osmtpd_ltok_skip_field_name(header->buf, 0);
394 buf = osmtpd_ltok_skip_wsp(buf, 1) + 1;
396 if ((header->sig = calloc(1, sizeof(*header->sig))) == NULL) {
397 dkim_err(header->msg, "malloc");
398 return;
400 sig = header->sig;
401 sig->header = header;
402 sig->l = -1;
403 sig->t = -1;
404 sig->x = -1;
406 end = osmtpd_ltok_skip_tag_list(buf, 0);
407 if (end == NULL || end[0] != '\0') {
408 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid tag-list");
409 return;
412 while (buf[0] != '\0') {
413 buf = osmtpd_ltok_skip_fws(buf, 1);
414 end = osmtpd_ltok_skip_tag_name(buf, 0);
416 /* Unknown tag-name */
417 if ((size_t)(end - buf) >= sizeof(tagname))
418 tagname[0] = '\0';
419 else
420 strlcpy(tagname, buf, (end - buf) + 1);
421 buf = osmtpd_ltok_skip_fws(end, 1);
422 /* '=' */
423 buf = osmtpd_ltok_skip_fws(buf + 1, 1);
424 end = osmtpd_ltok_skip_tag_value(buf, 1);
425 if (strcmp(tagname, "v") == 0)
426 dkim_signature_parse_v(sig, buf, end);
427 else if (strcmp(tagname, "a") == 0)
428 dkim_signature_parse_a(sig, buf, end);
429 else if (strcmp(tagname, "b") == 0)
430 dkim_signature_parse_b(sig, buf, end);
431 else if (strcmp(tagname, "bh") == 0)
432 dkim_signature_parse_bh(sig, buf, end);
433 else if (strcmp(tagname, "c") == 0)
434 dkim_signature_parse_c(sig, buf, end);
435 else if (strcmp(tagname, "d") == 0)
436 dkim_signature_parse_d(sig, buf, end);
437 else if (strcmp(tagname, "h") == 0)
438 dkim_signature_parse_h(sig, buf, end);
439 else if (strcmp(tagname, "i") == 0)
440 dkim_signature_parse_i(sig, buf, end);
441 else if (strcmp(tagname, "l") == 0)
442 dkim_signature_parse_l(sig, buf, end);
443 else if (strcmp(tagname, "q") == 0)
444 dkim_signature_parse_q(sig, buf, end);
445 else if (strcmp(tagname, "s") == 0)
446 dkim_signature_parse_s(sig, buf, end);
447 else if (strcmp(tagname, "t") == 0)
448 dkim_signature_parse_t(sig, buf, end);
449 else if (strcmp(tagname, "x") == 0)
450 dkim_signature_parse_x(sig, buf, end);
451 else if (strcmp(tagname, "z") == 0)
452 dkim_signature_parse_z(sig, buf, end);
454 buf = osmtpd_ltok_skip_fws(end, 1);
455 if (buf[0] == ';')
456 buf++;
457 else if (buf[0] != '\0') {
458 dkim_signature_state(sig, DKIM_PERMERROR,
459 "Invalid tag-list");
460 return;
463 if (sig->state != DKIM_UNKNOWN)
464 return;
466 if (sig->v != 1)
467 dkim_signature_state(sig, DKIM_PERMERROR, "Missing v tag");
468 else if (sig->ah == NULL)
469 dkim_signature_state(sig, DKIM_PERMERROR, "Missing a tag");
470 else if (sig->b == NULL)
471 dkim_signature_state(sig, DKIM_PERMERROR, "Missing b tag");
472 else if (sig->bhsz == 0)
473 dkim_signature_state(sig, DKIM_PERMERROR, "Missing bh tag");
474 else if (sig->d[0] == '\0')
475 dkim_signature_state(sig, DKIM_PERMERROR, "Missing d tag");
476 else if (sig->h == NULL)
477 dkim_signature_state(sig, DKIM_PERMERROR, "Missing h tag");
478 else if (sig->s[0] == '\0')
479 dkim_signature_state(sig, DKIM_PERMERROR, "Missing s tag");
480 if (sig->state != DKIM_UNKNOWN)
481 return;
483 if (sig->i != NULL) {
484 i = osmtpd_ltok_skip_local_part(sig->i, 1) + 1;
485 ilen = strlen(i);
486 dlen = strlen(sig->d);
487 if (ilen < dlen) {
488 dkim_signature_state(sig, DKIM_PERMERROR,
489 "i tagn not subdomain of d");
490 return;
492 i += ilen - dlen;
493 if ((i[-1] != '.' && i[-1] != '@') || strcmp(i, sig->d) != 0) {
494 dkim_signature_state(sig, DKIM_PERMERROR,
495 "i tagn not subdomain of d");
496 return;
499 if (sig->t != -1 && sig->x != -1 && sig->t > sig->x) {
500 dkim_signature_state(sig, DKIM_PERMERROR, "t tag after x tag");
501 return;
504 if ((size_t)snprintf(subdomain, sizeof(subdomain), "%s._domainkey.%s",
505 sig->s, sig->d) >= sizeof(subdomain)) {
506 dkim_signature_state(sig, DKIM_PERMERROR,
507 "dns/txt query too long");
508 return;
511 if ((query = res_query_async(subdomain, C_IN, T_TXT, NULL)) == NULL) {
512 dkim_err(header->msg, "res_query_async");
513 return;
515 if ((sig->query = event_asr_run(query, dkim_rr_resolve, sig)) == NULL) {
516 dkim_err(header->msg, "event_asr_run");
517 asr_abort(query);
518 return;
522 void
523 dkim_signature_parse_v(struct signature *sig, const char *start, const char *end)
525 if (sig->v != 0) { /* Duplicate tag */
526 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate v tag");
527 return;
529 /* Unsupported version */
530 if (start[0] != '1' || start + 1 != end)
531 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsupported v tag");
532 else
533 sig->v = 1;
536 void
537 dkim_signature_parse_a(struct signature *sig, const char *start, const char *end)
539 char ah[sizeof("sha256")];
541 if (sig->ah != NULL) {
542 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate a tag");
543 return;
546 if (osmtpd_ltok_skip_sig_a_tag_alg(start, 0) != end) {
547 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid a tag");
548 return;
550 sig->a = start;
551 sig->asz = (size_t)(end - start);
552 if (strncmp(start, "rsa-", 4) == 0) {
553 start += 4;
554 sig->ak = EVP_PKEY_RSA;
555 } else {
556 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag k");
557 return;
559 if ((size_t)(end - start) >= sizeof(ah)) {
560 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
561 return;
563 strlcpy(ah, start, sizeof(ah));
564 ah[end - start] = '\0';
565 if ((sig->ah = EVP_get_digestbyname(ah)) == NULL) {
566 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
567 return;
569 if ((sig->bhctx = EVP_MD_CTX_new()) == NULL) {
570 dkim_err(sig->header->msg, "EVP_MD_CTX_new");
571 return;
573 if (EVP_DigestInit_ex(sig->bhctx, sig->ah, NULL) <= 0) {
574 dkim_err(sig->header->msg, "EVP_DigestInit_ex");
575 return;
579 void
580 dkim_signature_parse_b(struct signature *sig, const char *start, const char *end)
582 int decodesz;
584 if (sig->b != NULL) {
585 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate b tag");
586 return;
588 sig->bheader = start;
589 if ((sig->b = malloc((((end - start) / 4) + 1) * 3)) == NULL) {
590 dkim_err(sig->header->msg, "malloc");
591 return;
593 /* EVP_DecodeBlock doesn't handle internal whitespace */
594 EVP_DecodeInit(ectx);
595 if (EVP_DecodeUpdate(ectx, sig->b, &decodesz, start,
596 (int)(end - start)) == -1) {
597 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
598 return;
600 sig->bsz = decodesz;
601 if (EVP_DecodeFinal(ectx, sig->b + sig->bsz,
602 &decodesz) == -1) {
603 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
604 return;
606 sig->bsz += decodesz;
609 void
610 dkim_signature_parse_bh(struct signature *sig, const char *start, const char *end)
612 const char *b64;
613 size_t n;
614 int decodesz;
616 if (sig->bhsz != 0) {
617 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate bh tag");
618 return;
620 /*
621 * EVP_Decode* expects sig->bh to be large enough,
622 * so count the actual b64 characters.
623 */
624 b64 = start;
625 n = 0;
626 while (1) {
627 b64 = osmtpd_ltok_skip_fws(b64, 1);
628 if (osmtpd_ltok_skip_alphadigitps(b64, 0) == NULL)
629 break;
630 n++;
631 b64++;
633 if (b64[0] == '=') {
634 n++;
635 b64 = osmtpd_ltok_skip_fws(b64 + 1, 1);
636 if (b64[0] == '=') {
637 n++;
638 b64++;
641 /* Invalid tag value */
642 if (b64 != end || n % 4 != 0 || (n / 4) * 3 > sizeof(sig->bh)) {
643 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
644 return;
646 /* EVP_DecodeBlock doesn't handle internal whitespace */
647 EVP_DecodeInit(ectx);
648 if (EVP_DecodeUpdate(ectx, sig->bh, &decodesz, start,
649 (int)(end - start)) == -1) {
650 /* Paranoia check */
651 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
652 return;
654 sig->bhsz = decodesz;
655 if (EVP_DecodeFinal(ectx, sig->bh + sig->bhsz, &decodesz) == -1) {
656 /* Paranoia check */
657 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
658 return;
660 sig->bhsz += decodesz;
663 void
664 dkim_signature_parse_c(struct signature *sig, const char *start, const char *end)
666 if (sig->c != 0) {
667 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate c tag");
668 return;
670 if (strncmp(start, "simple", 6) == 0) {
671 sig->c = CANON_HEADER_SIMPLE;
672 start += 6;
673 } else if (strncmp(start, "relaxed", 7) == 0) {
674 sig->c = CANON_HEADER_RELAXED;
675 start += 7;
676 } else {
677 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
678 return;
680 if (start[0] == '/') {
681 start++;
682 if (strncmp(start, "simple", 6) == 0) {
683 sig->c |= CANON_BODY_SIMPLE;
684 start += 6;
685 } else if (strncmp(start, "relaxed", 7) == 0) {
686 sig->c |= CANON_BODY_RELAXED;
687 start += 7;
688 } else {
689 dkim_signature_state(sig, DKIM_PERMERROR,
690 "Invalid c tag");
691 return;
695 if (start != end) {
696 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
697 return;
699 sig->c |= CANON_DONE;
702 void
703 dkim_signature_parse_d(struct signature *sig, const char *start, const char *end)
705 if (sig->d[0] != '\0') {
706 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate d tag");
707 return;
709 if (osmtpd_ltok_skip_domain(start, 0) != end ||
710 (size_t)(end - start) >= sizeof(sig->d)) {
711 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid d tag");
712 return;
714 strlcpy(sig->d, start, end - start + 1);
717 void
718 dkim_signature_parse_h(struct signature *sig, const char *start, const char *end)
720 const char *h;
721 size_t n = 0;
723 if (sig->h != NULL) {
724 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate h tag");
725 return;
727 h = start;
728 while (1) {
729 if ((h = osmtpd_ltok_skip_hdr_name(h, 0)) == NULL) {
730 dkim_signature_state(sig, DKIM_PERMERROR,
731 "Invalid h tag");
732 return;
734 n++;
735 /* ';' is part of hdr-name */
736 if (h > end) {
737 h = end;
738 break;
740 h = osmtpd_ltok_skip_fws(h, 1);
741 if (h[0] != ':')
742 break;
743 h = osmtpd_ltok_skip_fws(h + 1, 1);
745 if (h != end) {
746 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid h tag");
747 return;
749 if ((sig->h = calloc(n + 1, sizeof(*sig->h))) == NULL) {
750 dkim_err(sig->header->msg, "malloc");
751 return;
753 n = 0;
754 h = start;
755 while (1) {
756 h = osmtpd_ltok_skip_hdr_name(start, 0);
757 /* ';' is part of hdr-name */
758 if (h > end) {
759 sig->h[n] = strndup(start, end - start);
760 break;
762 if ((sig->h[n++] = strndup(start, h - start)) == NULL) {
763 dkim_err(sig->header->msg, "malloc");
764 return;
766 start = osmtpd_ltok_skip_fws(h, 1);
767 if (start[0] != ':')
768 break;
769 start = osmtpd_ltok_skip_fws(start + 1, 1);
773 void
774 dkim_signature_parse_i(struct signature *sig, const char *start, const char *end)
776 const char *i;
778 if (sig->i != NULL) {
779 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate i tag");
780 return;
782 i = osmtpd_ltok_skip_local_part(start, 1);
783 if (i[0] != '@') {
784 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
785 return;
787 if (osmtpd_ltok_skip_domain(i + 1, 0) != end) {
788 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
789 return;
791 sig->i = start;
792 sig->isz = (size_t)(end - start);
795 void
796 dkim_signature_parse_l(struct signature *sig, const char *start, const char *end)
798 long long l;
799 char *lend;
801 if (sig->l != -1) { /* Duplicate tag */
802 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate l tag");
803 return;
805 errno = 0;
806 l = strtoll(start, &lend, 10);
807 /* > 76 digits in stroll is an overflow */
808 if (osmtpd_ltok_skip_digit(start, 0) == NULL ||
809 lend != end || errno != 0) {
810 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid l tag");
811 return;
813 if (l > SSIZE_MAX) {
814 dkim_signature_state(sig, DKIM_PERMERROR, "l tag too large");
815 return;
817 sig->l = (ssize_t)l;
820 void
821 dkim_signature_parse_q(struct signature *sig, const char *start, const char *end)
823 const char *qend;
825 if (sig->q != 0) {
826 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate q tag");
827 return;
830 while (1) {
831 start = osmtpd_ltok_skip_fws(start, 1);
832 qend = osmtpd_ltok_skip_sig_q_tag_method(start, 0);
833 if (qend == NULL) {
834 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
835 return;
837 if (strncmp(start, "dns/txt", qend - start) == 0)
838 sig->q = 1;
839 start = osmtpd_ltok_skip_fws(qend, 1);
840 if (start[0] != ':')
841 break;
843 if (start != end) {
844 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
845 return;
847 if (sig->q != 1) {
848 sig->q = 1;
849 dkim_signature_state(sig, DKIM_NEUTRAL, "No useable q found");
850 return;
854 void
855 dkim_signature_parse_s(struct signature *sig, const char *start, const char *end)
857 if (sig->s[0] != '\0') {
858 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate s tag");
859 return;
861 if (osmtpd_ltok_skip_selector(start, 0) != end) {
862 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid s tag");
863 return;
865 strlcpy(sig->s, start, end - start + 1);
868 void
869 dkim_signature_parse_t(struct signature *sig, const char *start, const char *end)
871 char *tend;
873 if (sig->t != -1) {
874 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate t tag");
875 return;
877 errno = 0;
878 sig->t = strtoll(start, &tend, 10);
879 if (osmtpd_ltok_skip_digit(start, 0) == NULL || tend != end ||
880 tend - start > 12 || errno != 0) {
881 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid t tag");
882 return;
886 void
887 dkim_signature_parse_x(struct signature *sig, const char *start, const char *end)
889 char *xend;
891 if (sig->x != -1) {
892 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate x tag");
893 return;
895 errno = 0;
896 sig->x = strtoll(start, &xend, 10);
897 if (osmtpd_ltok_skip_digit(start, 0) == NULL || xend != end ||
898 xend - start > 12 || errno != 0) {
899 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid x tag");
900 return;
904 void
905 dkim_signature_parse_z(struct signature *sig, const char *start, const char *end)
907 if (sig->z != 0) {
908 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate z tag");
909 return;
912 sig->z = 1;
913 if (osmtpd_ltok_skip_sig_z_tag_value(start, 0) != end) {
914 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid z tag");
915 return;
919 void
920 dkim_signature_verify(struct signature *sig)
922 struct message *msg = sig->header->msg;
923 static EVP_MD_CTX *bctx = NULL;
924 const char *end;
925 size_t i, header;
927 if (sig->state != DKIM_UNKNOWN)
928 return;
930 if (bctx == NULL) {
931 if ((bctx = EVP_MD_CTX_new()) == NULL) {
932 dkim_errx(msg, "EVP_MD_CTX_new");
933 return;
936 EVP_MD_CTX_reset(bctx);
937 if (EVP_DigestVerifyInit(bctx, NULL, sig->ah, NULL, sig->p) != 1) {
938 dkim_errx(msg, "EVP_DigestVerifyInit");
939 return;
942 for (i = 0; i < msg->nheaders; i++)
943 msg->header[i].parsed = 0;
945 for (header = 0; sig->h[header] != NULL; header++) {
946 for (i = msg->nheaders; i > 0; ) {
947 i--;
948 if (msg->header[i].parsed ||
949 strncasecmp(msg->header[i].buf, sig->h[header],
950 strlen(sig->h[header])) != 0 ||
951 msg->header[i].sig == sig)
952 continue;
953 end = osmtpd_ltok_skip_fws(
954 msg->header[i].buf + strlen(sig->h[header]), 1);
955 if (end[0] != ':')
956 continue;
957 dkim_signature_header(bctx, sig, &(msg->header[i]));
958 msg->header[i].parsed = 1;
961 dkim_signature_header(bctx, sig, sig->header);
962 if (EVP_DigestVerifyFinal(bctx, sig->b, sig->bsz) != 1)
963 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
966 void
967 dkim_signature_header(EVP_MD_CTX *bctx, struct signature *sig,
968 struct header *header)
970 char c;
971 const char *ptr = header->buf, *end;
972 int inhdrname = 1;
973 int canon = sig->c & CANON_HEADER;
975 for (ptr = header->buf; ptr[0] != '\0'; ptr++) {
976 if (inhdrname) {
977 if (canon == CANON_HEADER_RELAXED) {
978 ptr = osmtpd_ltok_skip_fws(ptr, 1);
979 c = tolower(ptr[0]);
980 } else
981 c = ptr[0];
982 if (c == ':') {
983 inhdrname = 0;
984 if (canon == CANON_HEADER_RELAXED)
985 ptr = osmtpd_ltok_skip_fws(
986 ptr + 1, 1) - 1;
988 if (EVP_DigestVerifyUpdate(bctx, &c, 1) == 0) {
989 dkim_errx(sig->header->msg,
990 "EVP_DigestVerifyUpdate");
991 return;
993 continue;
995 end = osmtpd_ltok_skip_fws(ptr, 1);
996 if (end == ptr) {
997 if (sig->header == header && ptr == sig->bheader) {
998 ptr = osmtpd_ltok_skip_tag_value(
999 ptr, 0) - 1;
1000 continue;
1002 if (EVP_DigestVerifyUpdate(bctx, ptr, 1) == 0) {
1003 dkim_errx(sig->header->msg,
1004 "EVP_DigestVerifyUpdate");
1005 return;
1007 } else {
1008 if (canon == CANON_HEADER_RELAXED) {
1009 if (end[0] == '\0')
1010 continue;
1011 if (EVP_DigestVerifyUpdate(bctx, " ", 1) == 0) {
1012 dkim_errx(sig->header->msg,
1013 "EVP_DigestVerifyUpdate");
1014 return;
1016 } else {
1017 if (EVP_DigestVerifyUpdate(bctx, ptr,
1018 end - ptr) == 0) {
1019 dkim_errx(sig->header->msg,
1020 "EVP_DigestVerifyUpdate");
1021 return;
1024 ptr = end - 1;
1028 if (sig->header != header) {
1029 if (EVP_DigestVerifyUpdate(bctx, "\r\n", 2) == 0) {
1030 dkim_errx(sig->header->msg, "EVP_DigestVerifyUpdate");
1031 return;
1036 void
1037 dkim_signature_state(struct signature *sig, enum state state,
1038 const char *reason)
1040 if (sig->query != NULL) {
1041 event_asr_abort(sig->query);
1042 sig->query = NULL;
1044 switch (sig->state) {
1045 case DKIM_UNKNOWN:
1046 break;
1047 case DKIM_PASS:
1048 case DKIM_FAIL:
1049 osmtpd_errx(1, "Unexpected transition");
1050 case DKIM_POLICY:
1051 if (state == DKIM_PASS)
1052 return;
1053 break;
1054 case DKIM_NEUTRAL:
1055 if (state == DKIM_PASS)
1056 return;
1057 if (state == DKIM_TEMPERROR || state == DKIM_PERMERROR)
1058 break;
1059 osmtpd_errx(1, "Unexpected transition");
1060 case DKIM_TEMPERROR:
1061 if (state == DKIM_PERMERROR)
1062 break;
1063 return;
1064 case DKIM_PERMERROR:
1065 return;
1067 sig->state = state;
1068 sig->state_reason = reason;
1071 const char *
1072 dkim_state2str(enum state state)
1074 switch (state)
1076 case DKIM_UNKNOWN:
1077 return "unknown";
1078 case DKIM_PASS:
1079 return "pass";
1080 case DKIM_FAIL:
1081 return "fail";
1082 case DKIM_POLICY:
1083 return "policy";
1084 case DKIM_NEUTRAL:
1085 return "neutral";
1086 case DKIM_TEMPERROR:
1087 return "temperror";
1088 case DKIM_PERMERROR:
1089 return "permerror";
1093 void
1094 dkim_rr_resolve(struct asr_result *ar, void *arg)
1096 struct signature *sig = arg;
1097 char key[UINT16_MAX + 1];
1098 const char *rr_txt;
1099 size_t keylen, cstrlen;
1100 struct unpack pack;
1101 struct dns_header h;
1102 struct dns_query q;
1103 struct dns_rr rr;
1105 sig->query = NULL;
1107 if (ar->ar_h_errno == TRY_AGAIN || ar->ar_h_errno == NO_RECOVERY) {
1108 dkim_signature_state(sig, DKIM_TEMPERROR,
1109 hstrerror(ar->ar_h_errno));
1110 goto verify;
1112 if (ar->ar_h_errno != NETDB_SUCCESS) {
1113 dkim_signature_state(sig, DKIM_PERMERROR,
1114 hstrerror(ar->ar_h_errno));
1115 goto verify;
1118 unpack_init(&pack, ar->ar_data, ar->ar_datalen);
1119 if (unpack_header(&pack, &h) != 0 ||
1120 unpack_query(&pack, &q) != 0) {
1121 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid dns/txt");
1122 goto verify;
1124 for (; h.ancount > 0; h.ancount--) {
1125 unpack_rr(&pack, &rr);
1126 if (rr.rr_type != T_TXT)
1127 continue;
1129 keylen = 0;
1130 rr_txt = rr.rr.other.rdata;
1131 while (rr.rr.other.rdlen > 0) {
1132 cstrlen = ((const unsigned char *)rr_txt)[0];
1133 if (cstrlen >= rr.rr.other.rdlen ||
1134 keylen + cstrlen >= sizeof(key))
1135 break;
1137 * RFC 6376 Section 3.6.2.2
1138 * Strings in a TXT RR MUST be concatenated together
1139 * before use with no intervening whitespace.
1141 strlcpy(key + keylen, rr_txt + 1, cstrlen + 1);
1142 rr.rr.other.rdlen -= (cstrlen + 1);
1143 rr_txt += (cstrlen + 1);
1144 keylen += cstrlen;
1146 if (rr.rr.other.rdlen > 0) /* Invalid TXT RDATA */
1147 continue;
1149 if (dkim_key_text_parse(sig, key))
1150 break;
1153 if (h.ancount == 0) {
1154 dkim_signature_state(sig, DKIM_PERMERROR,
1155 "No matching key found");
1156 } else {
1157 /* Only verify if all headers have been read */
1158 if (!sig->header->msg->parsing_headers)
1159 dkim_signature_verify(sig);
1161 verify:
1162 dkim_message_verify(sig->header->msg);
1165 int
1166 dkim_key_text_parse(struct signature *sig, const char *key)
1168 char tagname, *hashname;
1169 const char *end, *tagvend;
1170 char pkraw[UINT16_MAX] = "", pkimp[UINT16_MAX];
1171 size_t pkoff, linelen;
1172 int h = 0, k = 0, n = 0, p = 0, s = 0, t = 0;
1173 BIO *bio;
1175 key = osmtpd_ltok_skip_fws(key, 1);
1176 /* Validate syntax early */
1177 if ((end = osmtpd_ltok_skip_tag_list(key, 0)) == NULL)
1178 return 0;
1181 * RFC 6376 section 3.6.1, v=:
1182 * RECOMMENDED...This tag MUST be the first tag in the record.
1184 if (osmtpd_ltok_skip_tag_name(key, 0) - key == 1 &&
1185 key[0] == 'v') {
1186 key = osmtpd_ltok_skip_tag_name(key, 0);
1187 key = osmtpd_ltok_skip_fws(key, 1);
1188 key++; /* = */
1189 key = osmtpd_ltok_skip_fws(key, 1);
1190 end = osmtpd_ltok_skip_tag_value(key, 0);
1191 if (end - key != 5 || strncmp(key, "DKIM1", 5) != 0)
1192 return 0;
1193 key += 5;
1194 key = osmtpd_ltok_skip_fws(key, 1);
1195 if (key[0] == ';')
1196 key++;
1198 while (key[0] != '\0') {
1199 key = osmtpd_ltok_skip_fws(key, 1);
1200 if ((end = osmtpd_ltok_skip_tag_name(key, 0)) == NULL)
1201 return 0;
1203 if ((size_t)(end - key) != 1)
1204 tagname = '\0';
1205 else
1206 tagname = key[0];
1207 key = osmtpd_ltok_skip_fws(end, 1);
1208 /* '=' */
1209 if (key[0] != '=')
1210 return 0;
1211 key = osmtpd_ltok_skip_fws(key + 1, 1);
1212 if ((end = osmtpd_ltok_skip_tag_value(key, 0)) == NULL)
1213 return 0;
1214 switch (tagname) {
1215 case 'v':
1216 /* tagname in wrong position */
1217 return 0;
1218 case 'h':
1219 if (h != 0) /* Duplicate tag */
1220 return 0;
1221 /* Invalid tag value */
1222 if (osmtpd_ltok_skip_key_h_tag_value(
1223 key, 0) != end)
1224 return 0;
1225 while (1) {
1226 if ((tagvend =
1227 osmtpd_ltok_skip_key_h_tag_value(
1228 key, 0)) == NULL)
1229 break;
1230 hashname = strndup(key, tagvend - key);
1231 if (hashname == NULL) {
1232 dkim_err(sig->header->msg, "malloc");
1233 return 0;
1235 if (EVP_get_digestbyname(hashname) == sig->ah) {
1236 free(hashname);
1237 h = 1;
1238 break;
1240 free(hashname);
1241 key = osmtpd_ltok_skip_fws(tagvend, 1);
1242 if (key[0] != ':')
1243 break;
1244 key = osmtpd_ltok_skip_fws(key + 1, 1);
1246 if (h != 1)
1247 return 0;
1248 key = end;
1249 break;
1250 case 'k':
1251 if (k != 0) /* Duplicate tag */
1252 return 0;
1253 k = 1;
1254 if (strncmp(key, "rsa", end - key) != 0)
1255 return 0;
1256 key = end;
1257 break;
1258 case 'n':
1259 if (n != 0) /* Duplicate tag */
1260 return 0;
1261 n = 1;
1262 if (osmtpd_ltok_skip_key_n_tag_value(key, 0) != end)
1263 return 0;
1264 key = end;
1265 break;
1266 case 'p':
1267 if (p != 0) /* Duplicate tag */
1268 return 0;
1269 p = 1;
1270 tagvend = osmtpd_ltok_skip_base64string(key, 1);
1271 /* Invalid tag value */
1272 if (tagvend != end ||
1273 (size_t)(end - key) >= sizeof(pkraw))
1274 return 0;
1275 strlcpy(pkraw, key, tagvend - key + 1);
1276 key = end;
1277 break;
1278 case 's':
1279 if (s != 0) /* Duplicate tag */
1280 return 0;
1281 /* Invalid tag value */
1282 if (osmtpd_ltok_skip_key_s_tag_value(key, 0) !=
1283 end)
1284 return 0;
1285 while (1) {
1286 if ((tagvend =
1287 osmtpd_ltok_skip_key_s_tag_type(
1288 key, 0)) == NULL)
1289 break;
1290 if (strncmp(key, "*", tagvend - key) == 0 ||
1291 strncmp(key, "email", tagvend - key) == 0) {
1292 s = 1;
1293 break;
1295 key = osmtpd_ltok_skip_fws(tagvend, 1);
1296 if (key[0] != ':')
1297 break;
1298 key = osmtpd_ltok_skip_fws(key + 1, 1);
1300 if (s != 1)
1301 return 0;
1302 key = end;
1303 break;
1304 case 't':
1305 if (t != 0) /* Duplicate tag */
1306 return 0;
1307 t = 1;
1308 if (osmtpd_ltok_skip_key_s_tag_type(key, 0) !=
1309 end)
1310 return 0;
1311 while (1) {
1312 tagvend =
1313 osmtpd_ltok_skip_key_t_tag_flag(
1314 key, 0);
1315 if (strncmp(key, "y", tagvend - key) == 0)
1316 sig->kt |= KT_Y;
1317 else if (strncmp(key, "s", tagvend - key) == 0)
1318 sig->kt |= KT_S;
1319 key = osmtpd_ltok_skip_fws(tagvend, 1);
1320 if (key[0] != ':')
1321 break;
1322 key = osmtpd_ltok_skip_fws(key + 1, 1);
1324 break;
1325 default:
1326 key = end;
1327 break;
1330 key = osmtpd_ltok_skip_fws(key, 1);
1331 if (key[0] == ';')
1332 key++;
1333 else if (key[0] != '\0')
1334 return 0;
1337 if (p == 0) /* Missing tag */
1338 return 0;
1339 if (k == 0 && sig->ak != EVP_PKEY_RSA) /* Default to RSA */
1340 return 0;
1342 if (pkraw[0] == '\0') {
1343 dkim_signature_state(sig, DKIM_PERMERROR, "Key is revoked");
1344 return 1;
1347 switch (sig->ak) {
1348 case EVP_PKEY_RSA:
1349 pkoff = strlcpy(pkimp, "-----BEGIN PUBLIC KEY-----\n",
1350 sizeof(pkimp));
1351 linelen = 0;
1352 for (key = pkraw; key[0] != '\0';) {
1353 if (pkoff + 2 >= sizeof(pkimp))
1354 return 0;
1355 pkimp[pkoff++] = key[0];
1356 if (++linelen == 64) {
1357 pkimp[pkoff++] = '\n';
1358 linelen = 0;
1360 key = osmtpd_ltok_skip_fws(key + 1, 1);
1362 /* Leverage pkoff check in loop */
1363 if (linelen != 0)
1364 pkimp[pkoff++] = '\n';
1365 /* PEM_read_bio_PUBKEY will catch truncated keys */
1366 pkoff += strlcpy(pkimp + pkoff, "-----END PUBLIC KEY-----\n",
1367 sizeof(pkimp) - pkoff);
1368 if ((bio = BIO_new_mem_buf(pkimp, pkoff)) == NULL) {
1369 dkim_err(sig->header->msg, "BIO_new_mem_buf");
1370 return 1;
1372 sig->p = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
1373 BIO_free(bio);
1374 if (sig->p == NULL) {
1376 * XXX No clue how to differentiate between invalid key
1377 * and temporary failure like *alloc.
1378 * Assume invalid key, because it's more likely.
1380 return 0;
1382 break;
1384 return 1;
1387 void
1388 dkim_body_parse(struct message *msg, const char *line)
1390 char buf[999]; /* Line limit + 1 */
1391 struct signature *sig;
1392 size_t r, w;
1393 ssize_t linelen;
1394 size_t hashn, hashlf;
1395 size_t i;
1396 int canon = CANON_BODY_SIMPLE;
1398 linelen = (ssize_t)strlcpy(buf, line, sizeof(buf));
1399 if (linelen >= (ssize_t)sizeof(buf)) {
1400 dkim_errx(msg, "Line too long");
1401 return;
1403 if (buf[0] == '\0') {
1404 msg->body_whitelines++;
1405 return;
1408 while (msg->body_whitelines-- > 0) {
1409 for (i = 0; i < msg->nheaders; i++) {
1410 if ((sig = msg->header[i].sig) == NULL)
1411 continue;
1412 hashlf = sig->l == -1 ? 2 : MIN(2, sig->l);
1413 sig->l -= sig->l == -1 ? 0 : hashlf;
1414 if (EVP_DigestUpdate(sig->bhctx, "\r\n", hashlf) == 0) {
1415 dkim_errx(msg, "Can't update hash context");
1416 return;
1420 msg->body_whitelines = 0;
1421 msg->has_body = 1;
1423 hash:
1424 for (i = 0; i < msg->nheaders; i++) {
1425 sig = msg->header[i].sig;
1426 if (sig == NULL || ((sig->c & CANON_BODY) != canon) ||
1427 sig->state != DKIM_UNKNOWN)
1428 continue;
1429 hashn = sig->l == -1 ? linelen : MIN(linelen, sig->l);
1430 sig->l -= sig->l == -1 ? 0 : hashn;
1431 hashlf = sig->l == -1 ? 2 : MIN(2, sig->l);
1432 sig->l -= sig->l == -1 ? 0 : hashlf;
1433 if (EVP_DigestUpdate(sig->bhctx, buf, hashn) == 0 ||
1434 EVP_DigestUpdate(sig->bhctx, "\r\n", hashlf) == 0) {
1435 dkim_errx(msg, "Can't update hash context");
1436 return;
1439 if (canon == CANON_BODY_RELAXED)
1440 return;
1441 canon = CANON_BODY_RELAXED;
1442 for (r = w = 0; buf[r] != '\0'; r++) {
1443 if (buf[r] == ' ' || buf[r] == '\t') {
1444 if (r != 0 && buf[w - 1] == ' ')
1445 continue;
1446 else
1447 buf[w++] = ' ';
1448 } else
1449 buf[w++] = buf[r];
1451 linelen = (w != 0 && buf[w - 1] == ' ') ? w - 1 : w;
1452 buf[linelen] = '\0';
1454 goto hash;
1457 void
1458 dkim_body_verify(struct signature *sig)
1460 unsigned char digest[EVP_MAX_MD_SIZE];
1461 unsigned int digestsz;
1463 if (sig->state != DKIM_UNKNOWN)
1464 return;
1466 if ((sig->c & CANON_BODY) == CANON_BODY_SIMPLE &&
1467 !sig->header->msg->has_body) {
1468 if (EVP_DigestUpdate(sig->bhctx, "\r\n",
1469 sig->l == -1 ? 2 : MIN(2, sig->l)) <= 0) {
1470 dkim_errx(sig->header->msg,
1471 "Can't update hash context");
1472 return;
1475 if (sig->l > 0) {
1476 dkim_signature_state(sig, DKIM_PERMERROR,
1477 "l tag larger than body");
1478 return;
1481 if (EVP_DigestFinal_ex(sig->bhctx, digest, &digestsz) == 0) {
1482 dkim_errx(sig->header->msg, "Can't finalize hash context");
1483 return;
1486 if (digestsz != sig->bhsz || memcmp(digest, sig->bh, digestsz) != 0)
1487 dkim_signature_state(sig, DKIM_FAIL, "bh mismatch");
1490 void
1491 dkim_message_verify(struct message *msg)
1493 struct signature *sig;
1494 size_t i;
1495 ssize_t n, aroff = 0;
1496 int found = 0;
1497 char *line = NULL;
1498 size_t linelen = 0;
1500 if (!msg->readdone)
1501 return;
1503 for (i = 0; i < msg->nheaders; i++) {
1504 if (msg->header[i].sig == NULL)
1505 continue;
1506 if (msg->header[i].sig->query != NULL)
1507 return;
1508 if (msg->header[i].sig->state != DKIM_UNKNOWN)
1509 continue;
1510 dkim_signature_state(msg->header[i].sig, DKIM_PASS, NULL);
1513 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1514 "Authentication-Results: %s", authservid)) == -1) {
1515 dkim_err(msg, "malloc");
1516 goto fail;
1518 for (i = 0; i < msg->nheaders; i++) {
1519 sig = msg->header[i].sig;
1520 if (sig == NULL)
1521 continue;
1522 found = 1;
1523 if ((aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=%s",
1524 dkim_state2str(sig->state))) == -1) {
1525 dkim_err(msg, "malloc");
1526 goto fail;
1528 if (sig->state_reason != NULL) {
1529 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1530 " reason=\"%s\"", sig->state_reason)) == -1) {
1531 dkim_err(msg, "malloc");
1532 goto fail;
1535 if (sig->s[0] != '\0') {
1536 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1537 " header.s=%s", sig->s)) == -1) {
1538 dkim_err(msg, "malloc");
1539 goto fail;
1542 if (sig->d[0] != '\0') {
1543 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1544 " header.d=%s", sig->d)) == -1) {
1545 dkim_err(msg, "malloc");
1546 goto fail;
1550 * Don't print i-tag, since localpart can be a quoted-string,
1551 * which can contain FWS and CFWS.
1553 if (sig->a != NULL) {
1554 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1555 " header.a=%.*s", (int)sig->asz, sig->a)) == -1) {
1556 dkim_err(msg, "malloc");
1557 goto fail;
1561 if (!found) {
1562 aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=none");
1563 if (aroff == -1) {
1564 dkim_err(msg, "malloc");
1565 goto fail;
1568 dkim_ar_print(msg->ctx, line);
1570 rewind(msg->origf);
1571 while ((n = getline(&line, &linelen, msg->origf)) != -1) {
1572 line[n - 1] = '\0';
1573 osmtpd_filter_dataline(msg->ctx, "%s", line);
1575 if (ferror(msg->origf))
1576 dkim_err(msg, "getline");
1577 fail:
1578 free(line);
1579 return;
1582 void
1583 dkim_ar_print(struct osmtpd_ctx *ctx, const char *start)
1585 const char *scan, *checkpoint, *ncheckpoint;
1586 size_t arlen = 0;
1587 int first = 1, arid = 1;
1589 checkpoint = start;
1590 ncheckpoint = osmtpd_ltok_skip_hdr_name(start, 0) + 1;
1591 for (scan = start; scan[0] != '\0'; scan++) {
1592 if (scan[0] == '\t')
1593 arlen = (arlen + 8) & ~7;
1594 else
1595 arlen++;
1596 if (arlen >= AUTHENTICATION_RESULTS_LINELEN) {
1597 osmtpd_filter_dataline(ctx, "%s%.*s", first ? "" : "\t",
1598 (int)((checkpoint == start ?
1599 ncheckpoint : checkpoint) - start), start);
1600 start = osmtpd_ltok_skip_cfws(checkpoint, 1);
1601 scan = start;
1602 arlen = 8;
1603 first = 0;
1605 if (scan == ncheckpoint) {
1606 checkpoint = ncheckpoint;
1607 ncheckpoint = osmtpd_ltok_skip_cfws(ncheckpoint, 1);
1608 /* authserv-id */
1609 if (arid) {
1610 ncheckpoint = osmtpd_ltok_skip_value(
1611 ncheckpoint, 0);
1612 arid = 0;
1613 /* methodspec */
1614 } else if (strncmp(ncheckpoint, "dkim",
1615 sizeof("dkim") - 1) == 0) {
1616 ncheckpoint = osmtpd_ltok_skip_keyword(
1617 ncheckpoint + sizeof("dkim"), 0);
1618 /* reasonspec */
1619 } else if (strncmp(ncheckpoint, "reason",
1620 sizeof("reason") - 1) == 0) {
1621 ncheckpoint = osmtpd_ltok_skip_value(
1622 ncheckpoint + sizeof("reason"), 0);
1623 /* propspec */
1624 } else {
1625 ncheckpoint += sizeof("header.x=") - 1;
1626 ncheckpoint = osmtpd_ltok_skip_ar_pvalue(
1627 ncheckpoint, 0);
1628 if (ncheckpoint[0] == ';')
1629 ncheckpoint++;
1633 osmtpd_filter_dataline(ctx, "%s%s", first ? "" : "\t", start);
1636 ssize_t
1637 dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
1639 va_list ap;
1640 char *artmp;
1641 int size;
1642 size_t nn;
1644 assert(*n >= aroff);
1645 va_start(ap, fmt);
1646 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1647 va_end(ap);
1648 if (size + aroff <= *n)
1649 return (ssize_t)size + aroff;
1650 nn = (((aroff + size) / 256) + 1) * 256;
1651 artmp = realloc(*ar, nn);
1652 if (artmp == NULL)
1653 return -1;
1654 *ar = artmp;
1655 *n = nn;
1656 va_start(ap, fmt);
1657 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1658 va_end(ap);
1659 return (ssize_t)size + aroff;
1662 void
1663 dkim_err(struct message *msg, char *text)
1665 msg->err = 1;
1666 fprintf(stderr, "%s: %s\n", text, strerror(errno));
1669 void
1670 dkim_errx(struct message *msg, char *text)
1672 msg->err = 1;
1673 fprintf(stderr, "%s\n", text);
1676 __dead void
1677 usage(void)
1679 fprintf(stderr, "usage: filter-dkimverify\n");
1680 exit(1);