2 * Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org>
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.
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.
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>
40 #include "opensmtpd.h"
41 #include "unpack_dns.h"
45 * Use RFC8601 (Authentication-Results) codes instead of RFC6376 codes,
46 * since they're more expressive.
59 struct header *header;
61 const char *state_reason;
71 /* Make sure padding bits for base64 decoding fit */
72 char bh[EVP_MAX_MD_SIZE + (3 - (EVP_MAX_MD_SIZE % 3))];
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];
89 char s[HOST_NAME_MAX + 1];
90 time_t t; /* Signature t=/timestamp */
93 int kt; /* Key t=/Flags */
96 struct event_asr *query;
106 struct signature *sig;
109 #define AUTHENTICATION_RESULTS_LINELEN 78
110 #define MIN(a, b) ((a) < (b) ? (a) : (b))
113 struct osmtpd_ctx *ctx;
116 size_t body_whitelines;
118 struct header *header;
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 *);
163 EVP_ENCODE_CTX *ectx = NULL;
166 main(int argc, char *argv[])
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);
189 dkim_conf(const char *key, const char *value)
194 if (authservid == NULL)
195 osmtpd_errx(1, "Didn't receive admd config option");
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");
208 dkim_dataline(struct osmtpd_ctx *ctx, const char *line)
210 struct message *msg = ctx->local_message;
214 if (line[0] == '.' && line[1] =='\0') {
216 osmtpd_filter_dataline(ctx, ".");
221 if (fprintf(msg->origf, "%s\n", line) < 0) {
222 dkim_err(msg, "Couldn't write to tempfile");
225 if (line[0] == '.') {
227 if (line[0] == '\0') {
229 for (i = 0; i < msg->nheaders; i++) {
230 if (msg->header[i].sig == NULL)
232 dkim_body_verify(msg->header[i].sig);
234 dkim_message_verify(msg);
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)
245 if (msg->header[i].sig->query == NULL)
246 dkim_signature_verify(
252 dkim_body_parse(msg, line);
257 dkim_commit(struct osmtpd_ctx *ctx)
259 struct message *msg = ctx->local_message;
262 osmtpd_filter_disconnect(ctx, "Internal server error");
264 osmtpd_filter_proceed(ctx);
268 dkim_message_new(struct osmtpd_ctx *ctx)
272 if ((msg = malloc(sizeof(*msg))) == NULL)
275 if ((msg->origf = tmpfile()) == NULL) {
276 dkim_err(msg, "Can't open tempfile");
280 msg->parsing_headers = 1;
281 msg->body_whitelines = 0;
292 dkim_message_free(struct osmtpd_ctx *ctx, void *data)
294 struct message *msg = data;
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);
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;
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 */
331 verify = osmtpd_ltok_skip_wsp(end, 1);
334 start, "DKIM-Signature", end - start) == 0 &&
336 dkim_signature_parse(
337 &msg->header[msg->nheaders - 1]);
341 dkim_header_cat(ctx, line);
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");
351 msg->header = headers;
352 for (i = 0; i < msg->nheaders; i++) {
353 if (msg->header[i].sig == NULL)
355 msg->header[i].sig->header = &msg->header[i];
358 msg->header[msg->nheaders].msg = msg;
360 dkim_header_cat(ctx, line);
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];
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);
375 dkim_err(msg, "malloc");
380 header->buflen += snprintf(header->buf + header->buflen,
381 (((needed / 1024) + 1) * 1024) - header->buflen, "%s%s",
382 header->buflen == 0 ? "" : "\r\n", line);
386 dkim_signature_parse(struct header *header)
388 struct signature *sig;
389 struct asr_query *query;
390 const char *buf, *i, *end;
392 char subdomain[HOST_NAME_MAX + 1];
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");
404 sig->header = header;
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");
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))
423 strlcpy(tagname, buf, (end - buf) + 1);
424 buf = osmtpd_ltok_skip_fws(end, 1);
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);
460 else if (buf[0] != '\0') {
461 dkim_signature_state(sig, DKIM_PERMERROR,
466 if (sig->state != DKIM_UNKNOWN)
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)
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);
491 dkim_signature_state(sig, DKIM_PERMERROR,
492 "i tag not subdomain of d");
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");
503 if (sig->t != -1 && sig->x != -1 && sig->t > sig->x) {
504 dkim_signature_state(sig, DKIM_PERMERROR, "t tag after x tag");
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");
515 if ((query = res_query_async(subdomain, C_IN, T_TXT, NULL)) == NULL) {
516 dkim_err(header->msg, "res_query_async");
519 if ((sig->query = event_asr_run(query, dkim_rr_resolve, sig)) == NULL) {
520 dkim_err(header->msg, "event_asr_run");
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");
533 /* Unsupported version */
534 if (start[0] != '1' || start + 1 != end)
535 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsupported v tag");
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");
550 if (osmtpd_ltok_skip_sig_a_tag_alg(start, 0) != end) {
551 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid a tag");
555 sig->asz = (size_t)(end - start);
556 if (strncmp(start, "rsa-", 4) == 0) {
558 sig->ak = EVP_PKEY_RSA;
561 } else if (strncmp(start, "ed25519-", 8) == 0) {
563 sig->ak = EVP_PKEY_ED25519;
567 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag k");
570 if ((size_t)(end - start) >= sizeof(ah)) {
571 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
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");
580 if ((sig->bhctx = EVP_MD_CTX_new()) == NULL) {
581 dkim_err(sig->header->msg, "EVP_MD_CTX_new");
584 if (EVP_DigestInit_ex(sig->bhctx, sig->ah, NULL) <= 0) {
585 dkim_err(sig->header->msg, "EVP_DigestInit_ex");
591 dkim_signature_parse_b(struct signature *sig, const char *start, const char *end)
595 if (sig->b != NULL) {
596 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate b tag");
599 sig->bheader = start;
600 if ((sig->b = malloc((((end - start) / 4) + 1) * 3)) == NULL) {
601 dkim_err(sig->header->msg, "malloc");
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");
612 if (EVP_DecodeFinal(ectx, sig->b + sig->bsz,
614 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
617 sig->bsz += decodesz;
621 dkim_signature_parse_bh(struct signature *sig, const char *start, const char *end)
627 if (sig->bhsz != 0) {
628 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate bh tag");
632 * EVP_Decode* expects sig->bh to be large enough,
633 * so count the actual b64 characters.
638 b64 = osmtpd_ltok_skip_fws(b64, 1);
639 if (osmtpd_ltok_skip_alphadigitps(b64, 0) == NULL)
646 b64 = osmtpd_ltok_skip_fws(b64 + 1, 1);
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");
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) {
662 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
665 sig->bhsz = decodesz;
666 if (EVP_DecodeFinal(ectx, sig->bh + sig->bhsz, &decodesz) == -1) {
668 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
671 sig->bhsz += decodesz;
675 dkim_signature_parse_c(struct signature *sig, const char *start, const char *end)
678 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate c tag");
681 if (strncmp(start, "simple", 6) == 0) {
682 sig->c = CANON_HEADER_SIMPLE;
684 } else if (strncmp(start, "relaxed", 7) == 0) {
685 sig->c = CANON_HEADER_RELAXED;
688 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
691 if (start[0] == '/') {
693 if (strncmp(start, "simple", 6) == 0) {
694 sig->c |= CANON_BODY_SIMPLE;
696 } else if (strncmp(start, "relaxed", 7) == 0) {
697 sig->c |= CANON_BODY_RELAXED;
700 dkim_signature_state(sig, DKIM_PERMERROR,
707 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
710 sig->c |= CANON_DONE;
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");
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");
725 strlcpy(sig->d, start, end - start + 1);
729 dkim_signature_parse_h(struct signature *sig, const char *start, const char *end)
734 if (sig->h != NULL) {
735 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate h tag");
738 if (osmtpd_ltok_skip_sig_h_tag_value(start, 0) < end) {
739 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid h tag");
744 if ((h = osmtpd_ltok_skip_hdr_name(h, 0)) == NULL) {
745 dkim_signature_state(sig, DKIM_PERMERROR,
750 /* ';' is part of hdr-name */
755 h = osmtpd_ltok_skip_fws(h, 1);
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");
767 h = osmtpd_ltok_skip_hdr_name(start, 0);
768 /* ';' is part of hdr-name */
770 sig->h[n] = strndup(start, end - start);
773 if ((sig->h[n++] = strndup(start, h - start)) == NULL) {
774 dkim_err(sig->header->msg, "malloc");
777 start = osmtpd_ltok_skip_fws(h, 1);
780 start = osmtpd_ltok_skip_fws(start + 1, 1);
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");
791 if (osmtpd_ltok_skip_sig_i_tag_value(start, 0) != end) {
792 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
796 sig->isz = (size_t)(end - start);
800 dkim_signature_parse_l(struct signature *sig, const char *start, const char *end)
805 if (sig->l != -1) { /* Duplicate tag */
806 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate l tag");
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");
818 dkim_signature_state(sig, DKIM_PERMERROR, "l tag too large");
825 dkim_signature_parse_q(struct signature *sig, const char *start, const char *end)
830 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate q tag");
835 start = osmtpd_ltok_skip_fws(start, 1);
836 qend = osmtpd_ltok_skip_sig_q_tag_method(start, 0);
838 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
841 if (strncmp(start, "dns/txt", qend - start) == 0)
843 start = osmtpd_ltok_skip_fws(qend, 1);
848 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
853 dkim_signature_state(sig, DKIM_NEUTRAL, "No useable q found");
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");
865 if (osmtpd_ltok_skip_selector(start, 0) != end) {
866 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid s tag");
869 strlcpy(sig->s, start, end - start + 1);
873 dkim_signature_parse_t(struct signature *sig, const char *start, const char *end)
878 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate t tag");
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");
891 dkim_signature_parse_x(struct signature *sig, const char *start, const char *end)
896 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate x tag");
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");
909 dkim_signature_parse_z(struct signature *sig, const char *start, const char *end)
912 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate z tag");
917 if (osmtpd_ltok_skip_sig_z_tag_value(start, 0) != end) {
918 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid z tag");
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;
933 if (sig->state != DKIM_UNKNOWN)
937 if ((bctx = EVP_MD_CTX_new()) == NULL) {
938 dkim_errx(msg, "EVP_MD_CTX_new");
942 EVP_MD_CTX_reset(bctx);
944 if (EVP_DigestVerifyInit(bctx, NULL, sig->ah, NULL,
946 dkim_errx(msg, "EVP_DigestVerifyInit");
950 if (EVP_DigestInit_ex(bctx, sig->ah, NULL) != 1) {
951 dkim_errx(msg, "EVP_DigestInit_ex");
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; ) {
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)
967 end = osmtpd_ltok_skip_fws(
968 msg->header[i].buf + strlen(sig->h[header]), 1);
971 dkim_signature_header(bctx, sig, &(msg->header[i]));
972 msg->header[i].parsed = 1;
975 dkim_signature_header(bctx, sig, sig->header);
977 if (EVP_DigestVerifyFinal(bctx, sig->b, sig->bsz) != 1)
978 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
980 if (EVP_DigestFinal_ex(bctx, digest, &digestsz) == 0) {
981 dkim_errx(msg, "EVP_DigestFinal_ex");
984 if (EVP_DigestVerifyInit(bctx, NULL, NULL, NULL, sig->p) != 1) {
985 dkim_errx(msg, "EVP_DigestVerifyInit");
988 switch (EVP_DigestVerify(bctx, sig->b, sig->bsz, digest,
993 dkim_signature_state(sig, DKIM_FAIL, "b mismatch");
996 dkim_errx(msg, "EVP_DigestVerify");
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)))
1008 dkim_signature_header(EVP_MD_CTX *bctx, struct signature *sig,
1009 struct header *header)
1012 const char *ptr = header->buf, *end;
1014 int canon = sig->c & CANON_HEADER;
1016 for (ptr = header->buf; ptr[0] != '\0'; ptr++) {
1018 if (canon == CANON_HEADER_RELAXED) {
1019 ptr = osmtpd_ltok_skip_fws(ptr, 1);
1020 c = tolower(ptr[0]);
1025 if (canon == CANON_HEADER_RELAXED)
1026 ptr = osmtpd_ltok_skip_fws(
1029 if (dkim_b_digest_update(bctx, &c, 1) == 0) {
1030 dkim_errx(sig->header->msg,
1031 "dkim_b_digest_update");
1036 end = osmtpd_ltok_skip_fws(ptr, 1);
1038 if (sig->header == header && ptr == sig->bheader) {
1039 ptr = osmtpd_ltok_skip_tag_value(
1043 if (dkim_b_digest_update(bctx, ptr, 1) == 0) {
1044 dkim_errx(sig->header->msg,
1045 "dkim_b_digest_update");
1049 if (canon == CANON_HEADER_RELAXED) {
1052 if (dkim_b_digest_update(bctx, " ", 1) == 0) {
1053 dkim_errx(sig->header->msg,
1054 "dkim_b_digest_update");
1058 if (dkim_b_digest_update(bctx, ptr,
1060 dkim_errx(sig->header->msg,
1061 "dkim_b_digest_update");
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");
1078 dkim_signature_state(struct signature *sig, enum state state,
1081 if (sig->query != NULL) {
1082 event_asr_abort(sig->query);
1085 switch (sig->state) {
1090 osmtpd_errx(1, "Unexpected transition");
1092 if (state == DKIM_PASS)
1096 if (state == DKIM_PASS)
1098 if (state == DKIM_TEMPERROR || state == DKIM_PERMERROR)
1100 osmtpd_errx(1, "Unexpected transition");
1101 case DKIM_TEMPERROR:
1102 if (state == DKIM_PERMERROR)
1105 case DKIM_PERMERROR:
1109 sig->state_reason = reason;
1113 dkim_state2str(enum state state)
1127 case DKIM_TEMPERROR:
1129 case DKIM_PERMERROR:
1135 dkim_rr_resolve(struct asr_result *ar, void *arg)
1137 struct signature *sig = arg;
1138 char key[UINT16_MAX + 1];
1140 size_t keylen, cstrlen;
1142 struct dns_header h;
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));
1153 if (ar->ar_h_errno != NETDB_SUCCESS) {
1154 dkim_signature_state(sig, DKIM_PERMERROR,
1155 hstrerror(ar->ar_h_errno));
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");
1165 for (; h.ancount > 0; h.ancount--) {
1166 unpack_rr(&pack, &rr);
1167 if (rr.rr_type != T_TXT)
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))
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);
1187 if (rr.rr.other.rdlen > 0) /* Invalid TXT RDATA */
1190 if (dkim_key_text_parse(sig, key))
1194 if (h.ancount == 0) {
1195 dkim_signature_state(sig, DKIM_PERMERROR,
1196 "No matching key found");
1198 /* Only verify if all headers have been read */
1199 if (!sig->header->msg->parsing_headers)
1200 dkim_signature_verify(sig);
1204 dkim_message_verify(sig->header->msg);
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;
1217 key = osmtpd_ltok_skip_fws(key, 1);
1218 /* Validate syntax early */
1219 if ((end = osmtpd_ltok_skip_tag_list(key, 0)) == NULL)
1222 while (key[0] != '\0') {
1223 key = osmtpd_ltok_skip_fws(key, 1);
1224 if ((end = osmtpd_ltok_skip_tag_name(key, 0)) == NULL)
1227 if ((size_t)(end - key) != 1)
1231 key = osmtpd_ltok_skip_fws(end, 1);
1235 key = osmtpd_ltok_skip_fws(key + 1, 1);
1236 if ((end = osmtpd_ltok_skip_tag_value(key, 0)) == NULL)
1241 * RFC 6376 section 3.6.1, v=:
1242 * RECOMMENDED...This tag MUST be the first tag in the
1246 osmtpd_ltok_skip_key_v_tag_value(key, 0) != end)
1251 if (h != 0) /* Duplicate tag */
1253 /* Invalid tag value */
1254 if (osmtpd_ltok_skip_key_h_tag_value(key, 0) != end)
1257 if ((tagvend = osmtpd_ltok_skip_key_h_tag_alg(
1260 hashname = strndup(key, tagvend - key);
1261 if (hashname == NULL) {
1262 dkim_err(sig->header->msg, "malloc");
1265 if (EVP_get_digestbyname(hashname) == sig->ah) {
1271 key = osmtpd_ltok_skip_fws(tagvend, 1);
1274 key = osmtpd_ltok_skip_fws(key + 1, 1);
1281 if (k != 0) /* Duplicate tag */
1284 if (strncmp(key, "rsa", end - key) == 0) {
1285 if (sig->ak != EVP_PKEY_RSA)
1288 } else if (strncmp(key, "ed25519", end - key) == 0) {
1289 if (sig->ak != EVP_PKEY_ED25519)
1297 if (n != 0) /* Duplicate tag */
1300 /* semicolon is part of safe-char */
1301 if (osmtpd_ltok_skip_key_n_tag_value(key, 0) < end)
1306 if (pkrawlen != 0) /* Duplicate tag */
1310 b64 = osmtpd_ltok_skip_fws(tagvend, 1);
1311 if (osmtpd_ltok_skip_alphadigitps(
1312 tagvend, 0) == NULL)
1314 pkraw[pkrawlen++] = tagvend++[0];
1315 if (pkrawlen >= sizeof(pkraw))
1318 if (tagvend[0] == '=') {
1319 pkraw[pkrawlen++] = '=';
1320 tagvend = osmtpd_ltok_skip_fws(b64 + 1, 1);
1321 if (pkrawlen >= sizeof(pkraw))
1323 if (tagvend[0] == '=') {
1324 pkraw[pkrawlen++] = '=';
1326 if (pkrawlen >= sizeof(pkraw))
1330 /* Invalid tag value */
1331 if (pkrawlen % 4 != 0 || tagvend != end)
1336 if (s != 0) /* Duplicate tag */
1338 /* Invalid tag value */
1339 if (osmtpd_ltok_skip_key_s_tag_value(key, 0) != end)
1343 osmtpd_ltok_skip_key_s_tag_type(
1346 if (strncmp(key, "*", tagvend - key) == 0 ||
1347 strncmp(key, "email", tagvend - key) == 0) {
1351 key = osmtpd_ltok_skip_fws(tagvend, 1);
1354 key = osmtpd_ltok_skip_fws(key + 1, 1);
1361 if (t != 0) /* Duplicate tag */
1364 if (osmtpd_ltok_skip_key_t_tag_value(key, 0) != end)
1367 tagvend = osmtpd_ltok_skip_key_t_tag_flag(
1369 if (strncmp(key, "y", tagvend - key) == 0)
1371 else if (strncmp(key, "s", tagvend - key) == 0)
1373 key = osmtpd_ltok_skip_fws(tagvend, 1);
1376 key = osmtpd_ltok_skip_fws(key + 1, 1);
1385 key = osmtpd_ltok_skip_fws(key, 1);
1388 else if (key[0] != '\0')
1392 if (pkrawlen == 0) /* Missing tag */
1394 if (k == 0 && sig->ak != EVP_PKEY_RSA) /* Default to RSA */
1397 if (pkraw[0] == '\0') {
1398 dkim_signature_state(sig, DKIM_PERMERROR, "Key is revoked");
1404 pkoff = strlcpy(pkimp, "-----BEGIN PUBLIC KEY-----\n",
1407 for (key = pkraw; key[0] != '\0';) {
1408 if (pkoff + 2 >= sizeof(pkimp))
1410 pkimp[pkoff++] = key[0];
1411 if (++linelen == 64) {
1412 pkimp[pkoff++] = '\n';
1416 /* Leverage pkoff check in loop */
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");
1426 sig->p = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
1430 case EVP_PKEY_ED25519:
1431 if ((pkrawlen / 4) * 3 >= sizeof(pkimp))
1433 EVP_DecodeInit(ectx);
1434 if (EVP_DecodeUpdate(ectx, pkimp, &tmp, pkraw, pkrawlen) == -1)
1437 if (EVP_DecodeFinal(ectx, pkimp, &tmp) == -1)
1440 sig->p = EVP_PKEY_new_raw_public_key(sig->ak, NULL, pkimp,
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.
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;
1464 if (line[0] == '\0') {
1465 msg->body_whitelines++;
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)
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");
1482 msg->body_whitelines = 0;
1485 while (line[0] != '\0') {
1488 if ((end = osmtpd_ltok_skip_wsp(end, 0)) == NULL)
1494 while (osmtpd_ltok_skip_wsp(end, 0) == NULL &&
1498 for (i = 0; i < msg->nheaders; i++) {
1499 sig = msg->header[i].sig;
1500 if (sig == NULL || sig->state != DKIM_UNKNOWN)
1503 (sig->c & CANON_BODY) == CANON_BODY_RELAXED) {
1505 len = end[0] == '\0' ? 0 : 1;
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);
1514 dkim_errx(msg, "EVP_DigestUpdate");
1520 for (i = 0; i < msg->nheaders; i++) {
1521 sig = msg->header[i].sig;
1522 if (sig == NULL || sig->state != DKIM_UNKNOWN)
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);
1528 dkim_errx(msg, "EVP_DigestUpdate");
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)
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");
1553 dkim_signature_state(sig, DKIM_PERMERROR,
1554 "l tag larger than body");
1558 if (EVP_DigestFinal_ex(sig->bhctx, digest, &digestsz) == 0) {
1559 dkim_errx(sig->header->msg, "EVP_DigestFinal_ex");
1563 if (digestsz != sig->bhsz || memcmp(digest, sig->bh, digestsz) != 0)
1564 dkim_signature_state(sig, DKIM_FAIL, "bh mismatch");
1568 dkim_message_verify(struct message *msg)
1570 struct signature *sig;
1572 ssize_t n, aroff = 0;
1580 for (i = 0; i < msg->nheaders; i++) {
1581 if (msg->header[i].sig == NULL)
1583 if (msg->header[i].sig->query != NULL)
1585 if (msg->header[i].sig->state != DKIM_UNKNOWN)
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");
1595 for (i = 0; i < msg->nheaders; i++) {
1596 sig = msg->header[i].sig;
1600 if ((aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=%s",
1601 dkim_state2str(sig->state))) == -1) {
1602 dkim_err(msg, "malloc");
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");
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");
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");
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");
1639 aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=none");
1641 dkim_err(msg, "malloc");
1645 dkim_ar_print(msg->ctx, line);
1648 while ((n = getline(&line, &linelen, msg->origf)) != -1) {
1650 osmtpd_filter_dataline(msg->ctx, "%s", line);
1652 if (ferror(msg->origf))
1653 dkim_err(msg, "getline");
1660 dkim_ar_print(struct osmtpd_ctx *ctx, const char *start)
1662 const char *scan, *checkpoint, *ncheckpoint;
1664 int first = 1, arid = 1;
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;
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);
1682 if (scan == ncheckpoint) {
1683 checkpoint = ncheckpoint;
1684 ncheckpoint = osmtpd_ltok_skip_cfws(ncheckpoint, 1);
1687 ncheckpoint = osmtpd_ltok_skip_value(
1691 } else if (strncmp(ncheckpoint, "dkim",
1692 sizeof("dkim") - 1) == 0) {
1693 ncheckpoint = osmtpd_ltok_skip_keyword(
1694 ncheckpoint + sizeof("dkim"), 0);
1696 } else if (strncmp(ncheckpoint, "reason",
1697 sizeof("reason") - 1) == 0) {
1698 ncheckpoint = osmtpd_ltok_skip_value(
1699 ncheckpoint + sizeof("reason"), 0);
1702 ncheckpoint += sizeof("header.x=") - 1;
1703 ncheckpoint = osmtpd_ltok_skip_ar_pvalue(
1705 if (ncheckpoint[0] == ';')
1710 osmtpd_filter_dataline(ctx, "%s%s", first ? "" : "\t", start);
1714 dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
1721 assert(*n >= aroff);
1723 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1725 if (size + aroff <= *n)
1726 return (ssize_t)size + aroff;
1727 nn = (((aroff + size) / 256) + 1) * 256;
1728 artmp = realloc(*ar, nn);
1734 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1736 return (ssize_t)size + aroff;
1740 dkim_err(struct message *msg, char *text)
1743 fprintf(stderr, "%s: %s\n", text, strerror(errno));
1747 dkim_errx(struct message *msg, char *text)
1750 fprintf(stderr, "%s\n", text);
1756 fprintf(stderr, "usage: filter-dkimverify\n");