Blame


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