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;
70 /* Make sure padding bits for base64 decoding fit */
71 char bh[EVP_MAX_MD_SIZE + (3 - (EVP_MAX_MD_SIZE % 3))];
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];
88 char s[HOST_NAME_MAX + 1];
89 time_t t; /* Signature t=/timestamp */
92 int kt; /* Key t=/Flags */
95 struct event_asr *query;
105 struct signature *sig;
108 #define AUTHENTICATION_RESULTS_LINELEN 78
109 #define MIN(a, b) ((a) < (b) ? (a) : (b))
112 struct osmtpd_ctx *ctx;
115 size_t body_whitelines;
117 struct header *header;
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 *);
162 EVP_ENCODE_CTX *ectx = NULL;
165 main(int argc, char *argv[])
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);
188 dkim_conf(const char *key, const char *value)
193 if (authservid == NULL)
194 osmtpd_errx(1, "Didn't receive admd config option");
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");
207 dkim_dataline(struct osmtpd_ctx *ctx, const char *line)
209 struct message *msg = ctx->local_message;
213 if (line[0] == '.' && line[1] =='\0') {
215 osmtpd_filter_dataline(ctx, ".");
220 if (fprintf(msg->origf, "%s\n", line) < 0) {
221 dkim_err(msg, "Couldn't write to tempfile");
224 if (line[0] == '.') {
226 if (line[0] == '\0') {
228 for (i = 0; i < msg->nheaders; i++) {
229 if (msg->header[i].sig == NULL)
231 dkim_body_verify(msg->header[i].sig);
233 dkim_message_verify(msg);
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)
244 if (msg->header[i].sig->query == NULL)
245 dkim_signature_verify(
251 dkim_body_parse(msg, line);
256 dkim_commit(struct osmtpd_ctx *ctx)
258 struct message *msg = ctx->local_message;
261 osmtpd_filter_disconnect(ctx, "Internal server error");
263 osmtpd_filter_proceed(ctx);
267 dkim_message_new(struct osmtpd_ctx *ctx)
271 if ((msg = malloc(sizeof(*msg))) == NULL)
274 if ((msg->origf = tmpfile()) == NULL) {
275 dkim_err(msg, "Can't open tempfile");
279 msg->parsing_headers = 1;
280 msg->body_whitelines = 0;
291 dkim_message_free(struct osmtpd_ctx *ctx, void *data)
293 struct message *msg = data;
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);
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;
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 */
328 verify = osmtpd_ltok_skip_wsp(end, 1);
331 start, "DKIM-Signature", end - start) == 0 &&
333 dkim_signature_parse(
334 &msg->header[msg->nheaders - 1]);
338 dkim_header_cat(ctx, line);
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");
348 msg->header = headers;
349 for (i = 0; i < msg->nheaders; i++) {
350 if (msg->header[i].sig == NULL)
352 msg->header[i].sig->header = &msg->header[i];
355 msg->header[msg->nheaders].msg = msg;
357 dkim_header_cat(ctx, line);
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];
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);
372 dkim_err(msg, "malloc");
377 header->buflen += snprintf(header->buf + header->buflen,
378 (((needed / 1024) + 1) * 1024) - header->buflen, "%s%s",
379 header->buflen == 0 ? "" : "\r\n", line);
383 dkim_signature_parse(struct header *header)
385 struct signature *sig;
386 struct asr_query *query;
387 const char *buf, *i, *end;
389 char subdomain[HOST_NAME_MAX + 1];
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");
401 sig->header = header;
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");
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))
420 strlcpy(tagname, buf, (end - buf) + 1);
421 buf = osmtpd_ltok_skip_fws(end, 1);
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);
457 else if (buf[0] != '\0') {
458 dkim_signature_state(sig, DKIM_PERMERROR,
463 if (sig->state != DKIM_UNKNOWN)
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)
483 if (sig->i != NULL) {
484 i = osmtpd_ltok_skip_local_part(sig->i, 1) + 1;
486 dlen = strlen(sig->d);
488 dkim_signature_state(sig, DKIM_PERMERROR,
489 "i tagn not subdomain of d");
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");
499 if (sig->t != -1 && sig->x != -1 && sig->t > sig->x) {
500 dkim_signature_state(sig, DKIM_PERMERROR, "t tag after x tag");
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");
511 if ((query = res_query_async(subdomain, C_IN, T_TXT, NULL)) == NULL) {
512 dkim_err(header->msg, "res_query_async");
515 if ((sig->query = event_asr_run(query, dkim_rr_resolve, sig)) == NULL) {
516 dkim_err(header->msg, "event_asr_run");
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");
529 /* Unsupported version */
530 if (start[0] != '1' || start + 1 != end)
531 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsupported v tag");
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");
546 if (osmtpd_ltok_skip_sig_a_tag_alg(start, 0) != end) {
547 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid a tag");
551 sig->asz = (size_t)(end - start);
552 if (strncmp(start, "rsa-", 4) == 0) {
554 sig->ak = EVP_PKEY_RSA;
556 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag k");
559 if ((size_t)(end - start) >= sizeof(ah)) {
560 dkim_signature_state(sig, DKIM_NEUTRAL, "Unsuppored a tag h");
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");
569 if ((sig->bhctx = EVP_MD_CTX_new()) == NULL) {
570 dkim_err(sig->header->msg, "EVP_MD_CTX_new");
573 if (EVP_DigestInit_ex(sig->bhctx, sig->ah, NULL) <= 0) {
574 dkim_err(sig->header->msg, "EVP_DigestInit_ex");
580 dkim_signature_parse_b(struct signature *sig, const char *start, const char *end)
584 if (sig->b != NULL) {
585 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate b tag");
588 sig->bheader = start;
589 if ((sig->b = malloc((((end - start) / 4) + 1) * 3)) == NULL) {
590 dkim_err(sig->header->msg, "malloc");
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");
601 if (EVP_DecodeFinal(ectx, sig->b + sig->bsz,
603 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid b tag");
606 sig->bsz += decodesz;
610 dkim_signature_parse_bh(struct signature *sig, const char *start, const char *end)
616 if (sig->bhsz != 0) {
617 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate bh tag");
621 * EVP_Decode* expects sig->bh to be large enough,
622 * so count the actual b64 characters.
627 b64 = osmtpd_ltok_skip_fws(b64, 1);
628 if (osmtpd_ltok_skip_alphadigitps(b64, 0) == NULL)
635 b64 = osmtpd_ltok_skip_fws(b64 + 1, 1);
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");
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) {
651 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
654 sig->bhsz = decodesz;
655 if (EVP_DecodeFinal(ectx, sig->bh + sig->bhsz, &decodesz) == -1) {
657 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid bh tag");
660 sig->bhsz += decodesz;
664 dkim_signature_parse_c(struct signature *sig, const char *start, const char *end)
667 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate c tag");
670 if (strncmp(start, "simple", 6) == 0) {
671 sig->c = CANON_HEADER_SIMPLE;
673 } else if (strncmp(start, "relaxed", 7) == 0) {
674 sig->c = CANON_HEADER_RELAXED;
677 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
680 if (start[0] == '/') {
682 if (strncmp(start, "simple", 6) == 0) {
683 sig->c |= CANON_BODY_SIMPLE;
685 } else if (strncmp(start, "relaxed", 7) == 0) {
686 sig->c |= CANON_BODY_RELAXED;
689 dkim_signature_state(sig, DKIM_PERMERROR,
696 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid c tag");
699 sig->c |= CANON_DONE;
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");
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");
714 strlcpy(sig->d, start, end - start + 1);
718 dkim_signature_parse_h(struct signature *sig, const char *start, const char *end)
723 if (sig->h != NULL) {
724 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate h tag");
729 if ((h = osmtpd_ltok_skip_hdr_name(h, 0)) == NULL) {
730 dkim_signature_state(sig, DKIM_PERMERROR,
735 /* ';' is part of hdr-name */
740 h = osmtpd_ltok_skip_fws(h, 1);
743 h = osmtpd_ltok_skip_fws(h + 1, 1);
746 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid h tag");
749 if ((sig->h = calloc(n + 1, sizeof(*sig->h))) == NULL) {
750 dkim_err(sig->header->msg, "malloc");
756 h = osmtpd_ltok_skip_hdr_name(start, 0);
757 /* ';' is part of hdr-name */
759 sig->h[n] = strndup(start, end - start);
762 if ((sig->h[n++] = strndup(start, h - start)) == NULL) {
763 dkim_err(sig->header->msg, "malloc");
766 start = osmtpd_ltok_skip_fws(h, 1);
769 start = osmtpd_ltok_skip_fws(start + 1, 1);
774 dkim_signature_parse_i(struct signature *sig, const char *start, const char *end)
778 if (sig->i != NULL) {
779 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate i tag");
782 i = osmtpd_ltok_skip_local_part(start, 1);
784 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
787 if (osmtpd_ltok_skip_domain(i + 1, 0) != end) {
788 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid i tag");
792 sig->isz = (size_t)(end - start);
796 dkim_signature_parse_l(struct signature *sig, const char *start, const char *end)
801 if (sig->l != -1) { /* Duplicate tag */
802 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate l tag");
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");
814 dkim_signature_state(sig, DKIM_PERMERROR, "l tag too large");
821 dkim_signature_parse_q(struct signature *sig, const char *start, const char *end)
826 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate q tag");
831 start = osmtpd_ltok_skip_fws(start, 1);
832 qend = osmtpd_ltok_skip_sig_q_tag_method(start, 0);
834 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
837 if (strncmp(start, "dns/txt", qend - start) == 0)
839 start = osmtpd_ltok_skip_fws(qend, 1);
844 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid q tag");
849 dkim_signature_state(sig, DKIM_NEUTRAL, "No useable q found");
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");
861 if (osmtpd_ltok_skip_selector(start, 0) != end) {
862 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid s tag");
865 strlcpy(sig->s, start, end - start + 1);
869 dkim_signature_parse_t(struct signature *sig, const char *start, const char *end)
874 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate t tag");
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");
887 dkim_signature_parse_x(struct signature *sig, const char *start, const char *end)
892 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate x tag");
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");
905 dkim_signature_parse_z(struct signature *sig, const char *start, const char *end)
908 dkim_signature_state(sig, DKIM_PERMERROR, "Duplicate z tag");
913 if (osmtpd_ltok_skip_sig_z_tag_value(start, 0) != end) {
914 dkim_signature_state(sig, DKIM_PERMERROR, "Invalid z tag");
920 dkim_signature_verify(struct signature *sig)
922 struct message *msg = sig->header->msg;
923 static EVP_MD_CTX *bctx = NULL;
927 if (sig->state != DKIM_UNKNOWN)
931 if ((bctx = EVP_MD_CTX_new()) == NULL) {
932 dkim_errx(msg, "EVP_MD_CTX_new");
936 EVP_MD_CTX_reset(bctx);
937 if (EVP_DigestVerifyInit(bctx, NULL, sig->ah, NULL, sig->p) != 1) {
938 dkim_errx(msg, "EVP_DigestVerifyInit");
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; ) {
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)
953 end = osmtpd_ltok_skip_fws(
954 msg->header[i].buf + strlen(sig->h[header]), 1);
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");
967 dkim_signature_header(EVP_MD_CTX *bctx, struct signature *sig,
968 struct header *header)
971 const char *ptr = header->buf, *end;
973 int canon = sig->c & CANON_HEADER;
975 for (ptr = header->buf; ptr[0] != '\0'; ptr++) {
977 if (canon == CANON_HEADER_RELAXED) {
978 ptr = osmtpd_ltok_skip_fws(ptr, 1);
984 if (canon == CANON_HEADER_RELAXED)
985 ptr = osmtpd_ltok_skip_fws(
988 if (EVP_DigestVerifyUpdate(bctx, &c, 1) == 0) {
989 dkim_errx(sig->header->msg,
990 "EVP_DigestVerifyUpdate");
995 end = osmtpd_ltok_skip_fws(ptr, 1);
997 if (sig->header == header && ptr == sig->bheader) {
998 ptr = osmtpd_ltok_skip_tag_value(
1002 if (EVP_DigestVerifyUpdate(bctx, ptr, 1) == 0) {
1003 dkim_errx(sig->header->msg,
1004 "EVP_DigestVerifyUpdate");
1008 if (canon == CANON_HEADER_RELAXED) {
1011 if (EVP_DigestVerifyUpdate(bctx, " ", 1) == 0) {
1012 dkim_errx(sig->header->msg,
1013 "EVP_DigestVerifyUpdate");
1017 if (EVP_DigestVerifyUpdate(bctx, ptr,
1019 dkim_errx(sig->header->msg,
1020 "EVP_DigestVerifyUpdate");
1028 if (sig->header != header) {
1029 if (EVP_DigestVerifyUpdate(bctx, "\r\n", 2) == 0) {
1030 dkim_errx(sig->header->msg, "EVP_DigestVerifyUpdate");
1037 dkim_signature_state(struct signature *sig, enum state state,
1040 if (sig->query != NULL) {
1041 event_asr_abort(sig->query);
1044 switch (sig->state) {
1049 osmtpd_errx(1, "Unexpected transition");
1051 if (state == DKIM_PASS)
1055 if (state == DKIM_PASS)
1057 if (state == DKIM_TEMPERROR || state == DKIM_PERMERROR)
1059 osmtpd_errx(1, "Unexpected transition");
1060 case DKIM_TEMPERROR:
1061 if (state == DKIM_PERMERROR)
1064 case DKIM_PERMERROR:
1068 sig->state_reason = reason;
1072 dkim_state2str(enum state state)
1086 case DKIM_TEMPERROR:
1088 case DKIM_PERMERROR:
1094 dkim_rr_resolve(struct asr_result *ar, void *arg)
1096 struct signature *sig = arg;
1097 char key[UINT16_MAX + 1];
1099 size_t keylen, cstrlen;
1101 struct dns_header h;
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));
1112 if (ar->ar_h_errno != NETDB_SUCCESS) {
1113 dkim_signature_state(sig, DKIM_PERMERROR,
1114 hstrerror(ar->ar_h_errno));
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");
1124 for (; h.ancount > 0; h.ancount--) {
1125 unpack_rr(&pack, &rr);
1126 if (rr.rr_type != T_TXT)
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))
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);
1146 if (rr.rr.other.rdlen > 0) /* Invalid TXT RDATA */
1149 if (dkim_key_text_parse(sig, key))
1153 if (h.ancount == 0) {
1154 dkim_signature_state(sig, DKIM_PERMERROR,
1155 "No matching key found");
1157 /* Only verify if all headers have been read */
1158 if (!sig->header->msg->parsing_headers)
1159 dkim_signature_verify(sig);
1162 dkim_message_verify(sig->header->msg);
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, first = 1;
1175 key = osmtpd_ltok_skip_fws(key, 1);
1176 /* Validate syntax early */
1177 if ((end = osmtpd_ltok_skip_tag_list(key, 0)) == NULL)
1180 while (key[0] != '\0') {
1181 key = osmtpd_ltok_skip_fws(key, 1);
1182 if ((end = osmtpd_ltok_skip_tag_name(key, 0)) == NULL)
1185 if ((size_t)(end - key) != 1)
1189 key = osmtpd_ltok_skip_fws(end, 1);
1193 key = osmtpd_ltok_skip_fws(key + 1, 1);
1194 if ((end = osmtpd_ltok_skip_tag_value(key, 0)) == NULL)
1199 * RFC 6376 section 3.6.1, v=:
1200 * RECOMMENDED...This tag MUST be the first tag in the
1204 osmtpd_ltok_skip_key_v_tag_value(key, 0) != end)
1208 if (h != 0) /* Duplicate tag */
1210 /* Invalid tag value */
1211 if (osmtpd_ltok_skip_key_h_tag_value(key, 0) != end)
1214 if ((tagvend = osmtpd_ltok_skip_key_h_tag_alg(
1217 hashname = strndup(key, tagvend - key);
1218 if (hashname == NULL) {
1219 dkim_err(sig->header->msg, "malloc");
1222 if (EVP_get_digestbyname(hashname) == sig->ah) {
1228 key = osmtpd_ltok_skip_fws(tagvend, 1);
1231 key = osmtpd_ltok_skip_fws(key + 1, 1);
1238 if (k != 0) /* Duplicate tag */
1241 if (strncmp(key, "rsa", end - key) != 0)
1246 if (n != 0) /* Duplicate tag */
1249 if (osmtpd_ltok_skip_key_n_tag_value(key, 0) != end)
1254 if (p != 0) /* Duplicate tag */
1257 tagvend = osmtpd_ltok_skip_base64string(key, 1);
1258 /* Invalid tag value */
1259 if (tagvend != end ||
1260 (size_t)(end - key) >= sizeof(pkraw))
1262 strlcpy(pkraw, key, tagvend - key + 1);
1266 if (s != 0) /* Duplicate tag */
1268 /* Invalid tag value */
1269 if (osmtpd_ltok_skip_key_s_tag_value(key, 0) != end)
1273 osmtpd_ltok_skip_key_s_tag_type(
1276 if (strncmp(key, "*", tagvend - key) == 0 ||
1277 strncmp(key, "email", tagvend - key) == 0) {
1281 key = osmtpd_ltok_skip_fws(tagvend, 1);
1284 key = osmtpd_ltok_skip_fws(key + 1, 1);
1291 if (t != 0) /* Duplicate tag */
1294 if (osmtpd_ltok_skip_key_t_tag_value(key, 0) != end)
1297 tagvend = osmtpd_ltok_skip_key_t_tag_flag(
1299 if (strncmp(key, "y", tagvend - key) == 0)
1301 else if (strncmp(key, "s", tagvend - key) == 0)
1303 key = osmtpd_ltok_skip_fws(tagvend, 1);
1306 key = osmtpd_ltok_skip_fws(key + 1, 1);
1315 key = osmtpd_ltok_skip_fws(key, 1);
1318 else if (key[0] != '\0')
1322 if (p == 0) /* Missing tag */
1324 if (k == 0 && sig->ak != EVP_PKEY_RSA) /* Default to RSA */
1327 if (pkraw[0] == '\0') {
1328 dkim_signature_state(sig, DKIM_PERMERROR, "Key is revoked");
1334 pkoff = strlcpy(pkimp, "-----BEGIN PUBLIC KEY-----\n",
1337 for (key = pkraw; key[0] != '\0';) {
1338 if (pkoff + 2 >= sizeof(pkimp))
1340 pkimp[pkoff++] = key[0];
1341 if (++linelen == 64) {
1342 pkimp[pkoff++] = '\n';
1345 key = osmtpd_ltok_skip_fws(key + 1, 1);
1347 /* Leverage pkoff check in loop */
1349 pkimp[pkoff++] = '\n';
1350 /* PEM_read_bio_PUBKEY will catch truncated keys */
1351 pkoff += strlcpy(pkimp + pkoff, "-----END PUBLIC KEY-----\n",
1352 sizeof(pkimp) - pkoff);
1353 if ((bio = BIO_new_mem_buf(pkimp, pkoff)) == NULL) {
1354 dkim_err(sig->header->msg, "BIO_new_mem_buf");
1357 sig->p = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
1359 if (sig->p == NULL) {
1361 * XXX No clue how to differentiate between invalid key
1362 * and temporary failure like *alloc.
1363 * Assume invalid key, because it's more likely.
1373 dkim_body_parse(struct message *msg, const char *line)
1375 char buf[999]; /* Line limit + 1 */
1376 struct signature *sig;
1379 size_t hashn, hashlf;
1381 int canon = CANON_BODY_SIMPLE;
1383 linelen = (ssize_t)strlcpy(buf, line, sizeof(buf));
1384 if (linelen >= (ssize_t)sizeof(buf)) {
1385 dkim_errx(msg, "Line too long");
1388 if (buf[0] == '\0') {
1389 msg->body_whitelines++;
1393 while (msg->body_whitelines-- > 0) {
1394 for (i = 0; i < msg->nheaders; i++) {
1395 if ((sig = msg->header[i].sig) == NULL)
1397 hashlf = sig->l == -1 ? 2 : MIN(2, sig->l);
1398 sig->l -= sig->l == -1 ? 0 : hashlf;
1399 if (EVP_DigestUpdate(sig->bhctx, "\r\n", hashlf) == 0) {
1400 dkim_errx(msg, "Can't update hash context");
1405 msg->body_whitelines = 0;
1409 for (i = 0; i < msg->nheaders; i++) {
1410 sig = msg->header[i].sig;
1411 if (sig == NULL || ((sig->c & CANON_BODY) != canon) ||
1412 sig->state != DKIM_UNKNOWN)
1414 hashn = sig->l == -1 ? linelen : MIN(linelen, sig->l);
1415 sig->l -= sig->l == -1 ? 0 : hashn;
1416 hashlf = sig->l == -1 ? 2 : MIN(2, sig->l);
1417 sig->l -= sig->l == -1 ? 0 : hashlf;
1418 if (EVP_DigestUpdate(sig->bhctx, buf, hashn) == 0 ||
1419 EVP_DigestUpdate(sig->bhctx, "\r\n", hashlf) == 0) {
1420 dkim_errx(msg, "Can't update hash context");
1424 if (canon == CANON_BODY_RELAXED)
1426 canon = CANON_BODY_RELAXED;
1427 for (r = w = 0; buf[r] != '\0'; r++) {
1428 if (buf[r] == ' ' || buf[r] == '\t') {
1429 if (r != 0 && buf[w - 1] == ' ')
1436 linelen = (w != 0 && buf[w - 1] == ' ') ? w - 1 : w;
1437 buf[linelen] = '\0';
1443 dkim_body_verify(struct signature *sig)
1445 unsigned char digest[EVP_MAX_MD_SIZE];
1446 unsigned int digestsz;
1448 if (sig->state != DKIM_UNKNOWN)
1451 if ((sig->c & CANON_BODY) == CANON_BODY_SIMPLE &&
1452 !sig->header->msg->has_body) {
1453 if (EVP_DigestUpdate(sig->bhctx, "\r\n",
1454 sig->l == -1 ? 2 : MIN(2, sig->l)) <= 0) {
1455 dkim_errx(sig->header->msg,
1456 "Can't update hash context");
1461 dkim_signature_state(sig, DKIM_PERMERROR,
1462 "l tag larger than body");
1466 if (EVP_DigestFinal_ex(sig->bhctx, digest, &digestsz) == 0) {
1467 dkim_errx(sig->header->msg, "Can't finalize hash context");
1471 if (digestsz != sig->bhsz || memcmp(digest, sig->bh, digestsz) != 0)
1472 dkim_signature_state(sig, DKIM_FAIL, "bh mismatch");
1476 dkim_message_verify(struct message *msg)
1478 struct signature *sig;
1480 ssize_t n, aroff = 0;
1488 for (i = 0; i < msg->nheaders; i++) {
1489 if (msg->header[i].sig == NULL)
1491 if (msg->header[i].sig->query != NULL)
1493 if (msg->header[i].sig->state != DKIM_UNKNOWN)
1495 dkim_signature_state(msg->header[i].sig, DKIM_PASS, NULL);
1498 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1499 "Authentication-Results: %s", authservid)) == -1) {
1500 dkim_err(msg, "malloc");
1503 for (i = 0; i < msg->nheaders; i++) {
1504 sig = msg->header[i].sig;
1508 if ((aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=%s",
1509 dkim_state2str(sig->state))) == -1) {
1510 dkim_err(msg, "malloc");
1513 if (sig->state_reason != NULL) {
1514 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1515 " reason=\"%s\"", sig->state_reason)) == -1) {
1516 dkim_err(msg, "malloc");
1520 if (sig->s[0] != '\0') {
1521 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1522 " header.s=%s", sig->s)) == -1) {
1523 dkim_err(msg, "malloc");
1527 if (sig->d[0] != '\0') {
1528 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1529 " header.d=%s", sig->d)) == -1) {
1530 dkim_err(msg, "malloc");
1535 * Don't print i-tag, since localpart can be a quoted-string,
1536 * which can contain FWS and CFWS.
1538 if (sig->a != NULL) {
1539 if ((aroff = dkim_ar_cat(&line, &linelen, aroff,
1540 " header.a=%.*s", (int)sig->asz, sig->a)) == -1) {
1541 dkim_err(msg, "malloc");
1547 aroff = dkim_ar_cat(&line, &linelen, aroff, "; dkim=none");
1549 dkim_err(msg, "malloc");
1553 dkim_ar_print(msg->ctx, line);
1556 while ((n = getline(&line, &linelen, msg->origf)) != -1) {
1558 osmtpd_filter_dataline(msg->ctx, "%s", line);
1560 if (ferror(msg->origf))
1561 dkim_err(msg, "getline");
1568 dkim_ar_print(struct osmtpd_ctx *ctx, const char *start)
1570 const char *scan, *checkpoint, *ncheckpoint;
1572 int first = 1, arid = 1;
1575 ncheckpoint = osmtpd_ltok_skip_hdr_name(start, 0) + 1;
1576 for (scan = start; scan[0] != '\0'; scan++) {
1577 if (scan[0] == '\t')
1578 arlen = (arlen + 8) & ~7;
1581 if (arlen >= AUTHENTICATION_RESULTS_LINELEN) {
1582 osmtpd_filter_dataline(ctx, "%s%.*s", first ? "" : "\t",
1583 (int)((checkpoint == start ?
1584 ncheckpoint : checkpoint) - start), start);
1585 start = osmtpd_ltok_skip_cfws(checkpoint, 1);
1590 if (scan == ncheckpoint) {
1591 checkpoint = ncheckpoint;
1592 ncheckpoint = osmtpd_ltok_skip_cfws(ncheckpoint, 1);
1595 ncheckpoint = osmtpd_ltok_skip_value(
1599 } else if (strncmp(ncheckpoint, "dkim",
1600 sizeof("dkim") - 1) == 0) {
1601 ncheckpoint = osmtpd_ltok_skip_keyword(
1602 ncheckpoint + sizeof("dkim"), 0);
1604 } else if (strncmp(ncheckpoint, "reason",
1605 sizeof("reason") - 1) == 0) {
1606 ncheckpoint = osmtpd_ltok_skip_value(
1607 ncheckpoint + sizeof("reason"), 0);
1610 ncheckpoint += sizeof("header.x=") - 1;
1611 ncheckpoint = osmtpd_ltok_skip_ar_pvalue(
1613 if (ncheckpoint[0] == ';')
1618 osmtpd_filter_dataline(ctx, "%s%s", first ? "" : "\t", start);
1622 dkim_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
1629 assert(*n >= aroff);
1631 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1633 if (size + aroff <= *n)
1634 return (ssize_t)size + aroff;
1635 nn = (((aroff + size) / 256) + 1) * 256;
1636 artmp = realloc(*ar, nn);
1642 size = vsnprintf(*ar + aroff, *n - aroff, fmt, ap);
1644 return (ssize_t)size + aroff;
1648 dkim_err(struct message *msg, char *text)
1651 fprintf(stderr, "%s: %s\n", text, strerror(errno));
1655 dkim_errx(struct message *msg, char *text)
1658 fprintf(stderr, "%s\n", text);
1664 fprintf(stderr, "usage: filter-dkimverify\n");