1 /* This file is part of Mailfromd.
2 Copyright (C) 2020-2021 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <nettle/sha2.h>
25 #include <nettle/buffer.h>
26 #include <nettle/rsa.h>
27 #include <nettle/base64.h>
28 #include <nettle/asn1.h>
29 #include "mailfromd.h"
30 #include <mailutils/imaputil.h>
31 #include "dkim.h"
32
33 /*
34 * Read public and private rsa keys from file.
35 * Matching code derived from pkcs1-conv.c in Nettle.
36 */
37
38 static const uint8_t pem_start_pattern[] = "-----BEGIN ";
39 static int pem_start_pattern_length = sizeof(pem_start_pattern) - 1;
40 static const uint8_t pem_end_pattern[] = "-----END ";
41 static int pem_end_pattern_length = sizeof(pem_end_pattern) - 1;
42 static const uint8_t pem_trailer_pattern[] = "-----";
43 static int pem_trailer_pattern_length = sizeof(pem_trailer_pattern) - 1;
44
45 enum {
46 READ_PEM_OK,
47 READ_PEM_ERROR,
48 READ_PEM_EOF
49 };
50
51 /* Returns READ_PEM_OK on match. */
52 static int
match_pem_start(size_t length,const uint8_t * line,size_t * marker_start,size_t * marker_length)53 match_pem_start(size_t length, const uint8_t *line,
54 size_t *marker_start,
55 size_t *marker_length)
56 {
57 while (length > 0 && mu_isspace(line[length - 1]))
58 length--;
59
60 if (length > (pem_start_pattern_length + pem_trailer_pattern_length)
61 && memcmp(line, pem_start_pattern, pem_start_pattern_length) == 0
62 && memcmp(line + length - pem_trailer_pattern_length,
63 pem_trailer_pattern, pem_trailer_pattern_length) == 0) {
64 *marker_start = pem_start_pattern_length;
65 *marker_length = length -
66 (pem_start_pattern_length + pem_trailer_pattern_length);
67 return READ_PEM_OK;
68 }
69 return READ_PEM_ERROR;
70 }
71
72 /* Returns READ_PEM_OK on match, READ_PEM_EOF if the line is of the right
73 form except for the marker, otherwise READ_PEM_ERROR. */
74 static int
match_pem_end(size_t length,const uint8_t * line,size_t marker_length,const uint8_t * marker)75 match_pem_end(size_t length, const uint8_t *line,
76 size_t marker_length,
77 const uint8_t *marker)
78 {
79 while (length > 0 && mu_isspace(line[length - 1]))
80 length--;
81
82 if (length > (pem_end_pattern_length + pem_trailer_pattern_length)
83 && memcmp(line, pem_end_pattern, pem_end_pattern_length) == 0
84 && memcmp(line + length - pem_trailer_pattern_length,
85 pem_trailer_pattern, pem_trailer_pattern_length) == 0) {
86 if (length == marker_length +
87 (pem_end_pattern_length + pem_trailer_pattern_length)
88 && memcmp(line + pem_end_pattern_length, marker,
89 marker_length) == 0)
90 return READ_PEM_OK;
91 else
92 return READ_PEM_EOF;
93 }
94
95 return READ_PEM_ERROR;
96 }
97
98 struct pem_info {
99 size_t marker_start;
100 size_t marker_length;
101 size_t data_start;
102 size_t data_length;
103 };
104
105 /* Read a single line from file into buffer. */
106 static int
read_line(FILE * fp,struct nettle_buffer * buffer)107 read_line(FILE *fp, struct nettle_buffer *buffer)
108 {
109 int c;
110
111 while ((c = getc(fp)) != EOF) {
112 if (!NETTLE_BUFFER_PUTC(buffer, c))
113 return READ_PEM_ERROR;
114
115 if (c == '\n')
116 return READ_PEM_OK;
117 }
118 if (ferror(fp))
119 return READ_PEM_ERROR;
120
121 return READ_PEM_EOF;
122 }
123
124 /* Read PEM file into buffer and parse it. Arguments:
125 *
126 * fp input file.
127 * buffer buffer to read PEM into.
128 * info fill this structure with information about PEM structure.
129 */
130 static int
read_pem(FILE * fp,struct nettle_buffer * buffer,struct pem_info * info)131 read_pem(FILE *fp, struct nettle_buffer *buffer, struct pem_info *info)
132 {
133 int rc;
134
135 /* Find start line */
136 for (;;) {
137 nettle_buffer_reset(buffer);
138 rc = read_line(fp, buffer);
139 if (rc != READ_PEM_OK)
140 return rc;
141
142 if (match_pem_start(buffer->size, buffer->contents,
143 &info->marker_start,
144 &info->marker_length) == READ_PEM_OK)
145 break;
146 }
147
148 buffer->contents[info->marker_start + info->marker_length] = 0;
149
150 info->data_start = buffer->size;
151
152 for (;;) {
153 size_t line_start = buffer->size;
154
155 if ((rc = read_line(fp, buffer)) != READ_PEM_OK)
156 return rc;
157
158 switch (match_pem_end(buffer->size - line_start,
159 buffer->contents + line_start,
160 info->marker_length,
161 buffer->contents + info->marker_start)) {
162 case READ_PEM_OK:
163 info->data_length = line_start - info->data_start;
164 return READ_PEM_OK;
165 case READ_PEM_ERROR:
166 break;
167 case READ_PEM_EOF:
168 return READ_PEM_EOF;
169 }
170 }
171 return READ_PEM_ERROR;
172 }
173
174 static inline int
base64_decode_in_place(struct base64_decode_ctx * ctx,size_t * dst_length,size_t length,uint8_t * data)175 base64_decode_in_place (struct base64_decode_ctx *ctx, size_t *dst_length,
176 size_t length, uint8_t *data)
177 {
178 return base64_decode_update(ctx, dst_length,
179 data, length,
180 (const uint8_t *) data);
181 }
182
183 static int
decode_base64(struct nettle_buffer * buffer,size_t start,size_t * length)184 decode_base64(struct nettle_buffer *buffer, size_t start, size_t *length)
185 {
186 struct base64_decode_ctx ctx;
187
188 base64_decode_init(&ctx);
189
190 /* Decode in place */
191 if (base64_decode_in_place(&ctx, length, *length,
192 buffer->contents + start)
193 && base64_decode_final(&ctx))
194 return READ_PEM_OK;
195 return READ_PEM_ERROR;
196 }
197
198 static int
convert_rsa_private_key(uint8_t * buffer,size_t size,struct rsa_public_key * pub,struct rsa_private_key * priv)199 convert_rsa_private_key(uint8_t *buffer, size_t size,
200 struct rsa_public_key *pub,
201 struct rsa_private_key *priv)
202 {
203 rsa_public_key_init(pub);
204 rsa_private_key_init(priv);
205 return rsa_keypair_from_der(pub, priv, 0, size, buffer)
206 ? READ_PEM_OK : READ_PEM_ERROR;
207 }
208
209 /* Read a private key PEM file and return RSA key pair. */
210 static int
read_keys(FILE * fp,struct rsa_public_key * pub,struct rsa_private_key * priv)211 read_keys(FILE *fp, struct rsa_public_key *pub, struct rsa_private_key *priv)
212 {
213 struct nettle_buffer buffer;
214 struct pem_info info;
215 static char privkey_marker[] = "RSA PRIVATE KEY";
216 static size_t privkey_marker_length = sizeof(privkey_marker) - 1;
217 int rc;
218
219 nettle_buffer_init_realloc(&buffer, NULL, nettle_xrealloc);//FIXME
220 rc = read_pem(fp, &buffer, &info);
221 if (info.marker_length == privkey_marker_length
222 && memcmp(buffer.contents + info.marker_start, privkey_marker,
223 privkey_marker_length) == 0
224 && decode_base64(&buffer, info.data_start,
225 &info.data_length) == READ_PEM_OK
226 && convert_rsa_private_key(buffer.contents + info.data_start,
227 info.data_length,
228 pub, priv) == READ_PEM_OK)
229 rc = READ_PEM_OK;
230 else
231 rc = READ_PEM_ERROR;
232 nettle_buffer_clear(&buffer);
233
234 return rc;
235 }
236
237 static int
pubkey_from_base64(struct rsa_public_key * pub,const char * str)238 pubkey_from_base64(struct rsa_public_key *pub, const char *str)
239 {
240 struct nettle_buffer buffer;
241 size_t length = strlen(str);
242 struct asn1_der_iterator i, j;
243 int result = READ_PEM_ERROR;
244
245 nettle_buffer_init_realloc(&buffer, NULL, nettle_xrealloc);
246 nettle_buffer_write(&buffer, strlen(str), (const uint8_t*) str);
247 if (decode_base64(&buffer, 0, &length) == READ_PEM_OK
248
249 /* SubjectPublicKeyInfo ::= SEQUENCE {
250 algorithm AlgorithmIdentifier,
251 subjectPublicKey BIT STRING
252 }
253
254 AlgorithmIdentifier ::= SEQUENCE {
255 algorithm OBJECT IDENTIFIER,
256 parameters OPTIONAL
257 }
258 */
259
260 && asn1_der_iterator_first(&i, length, buffer.contents) == ASN1_ITERATOR_CONSTRUCTED
261 && i.type == ASN1_SEQUENCE
262 && asn1_der_decode_constructed_last(&i) == ASN1_ITERATOR_CONSTRUCTED
263 && i.type == ASN1_SEQUENCE
264
265 /* Use the j iterator to parse the algorithm identifier */
266 && asn1_der_decode_constructed(&i, &j) == ASN1_ITERATOR_PRIMITIVE
267 && j.type == ASN1_IDENTIFIER
268 && asn1_der_iterator_next(&i) == ASN1_ITERATOR_PRIMITIVE
269 && i.type == ASN1_BITSTRING
270
271 /* Use i to parse the object wrapped in the bit string.*/
272 && asn1_der_decode_bitstring_last(&i)) {
273 /* pkcs-1 {
274 iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
275 pkcs-1(1) modules(0) pkcs-1(1)
276 }
277
278 --
279 -- When rsaEncryption is used in an AlgorithmIdentifier the
280 -- parameters MUST be present and MUST be NULL.
281 --
282 rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }
283 */
284 static const uint8_t id_rsaEncryption[9] =
285 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
286
287 if (j.length == sizeof(id_rsaEncryption)
288 && memcmp(j.data, id_rsaEncryption,
289 sizeof(id_rsaEncryption)) == 0
290 && asn1_der_iterator_next(&j) == ASN1_ITERATOR_PRIMITIVE
291 && j.type == ASN1_NULL
292 && j.length == 0
293 && asn1_der_iterator_next(&j) == ASN1_ITERATOR_END) {
294 rsa_public_key_init(pub);
295
296 if (rsa_public_key_from_der_iterator(pub, 0, &i))
297 result = READ_PEM_OK;
298 }
299 }
300 nettle_buffer_clear(&buffer);
301 return result;
302 }
303
304 /* State of iteratiom over a colon-separated list of headers. */
305 struct h_list_buf {
306 char const *ptr; /* Current position in the header list. */
307 char *base; /* Return memory pointer. */
308 size_t size; /* Size of memory allocated for base. */
309 };
310
311 /*
312 * dkim_header_list_next(SAVE)
313 * ---------------------------
314 * Free the state buffer allocated by dkim_header_list_first.
315 */
316 void
dkim_header_list_end(void * save)317 dkim_header_list_end(void *save)
318 {
319 struct h_list_buf *hbuf = save;
320 free(hbuf->base);
321 free(hbuf);
322 }
323
324 /*
325 * Return next header from the header list, or NULL if the list is exhausted.
326 * SAVE is the iteration state pointer returned by dkim_header_list_first.
327 */
328 static char *
dkim_header_list_next(void * save)329 dkim_header_list_next(void *save)
330 {
331 struct h_list_buf *hbuf = save;
332 char const *hp = hbuf->ptr;
333
334 while (*hp && (*hp == ' ' || *hp == '\t' || *hp == ':'))
335 hp++;
336 if (*hp) {
337 size_t len = strcspn(hp, " \t:");
338 if (len + 1 > hbuf->size) {
339 hbuf->base = mu_realloc(hbuf->base, len + 1);
340 hbuf->size = len + 1;
341 }
342 memcpy(hbuf->base, hp, len);
343 hbuf->base[len] = 0;
344 hbuf->ptr = hp + len;
345 } else {
346 hbuf->ptr = hp;
347 return NULL;
348 }
349 return hbuf->base;
350 }
351
352 /*
353 * Start iteration over a list of header names (H_LIST), delimited by
354 * colons with optional whitespace around them. Return first header
355 * name and save the state in the memory location pointed to by SAVE.
356 * No matter the return value, dkim_header_list_end must be called to
357 * reclaim the allocated memory.
358 */
359 char *
dkim_header_list_first(char const * h_list,void * save)360 dkim_header_list_first(char const *h_list, void *save)
361 {
362 struct h_list_buf *hbuf, **hbuf_ptr = save;
363
364 hbuf = mu_alloc(sizeof(hbuf[0]));
365 hbuf->ptr = h_list;
366 hbuf->base = NULL;
367 hbuf->size = 0;
368 *hbuf_ptr = hbuf;
369 return dkim_header_list_next(hbuf);
370 }
371
372 int
dkim_header_list_match(char const * h_list,char const * h)373 dkim_header_list_match(char const *h_list, char const *h)
374 {
375 size_t len = strlen (h);
376 while (*h_list) {
377 size_t n;
378
379 while (*h_list && (*h_list == ' ' || *h_list == '\t'))
380 h_list++;
381 if (*h_list == 0)
382 break;
383
384 n = strcspn(h_list, " \t:");
385 if (n == len && mu_c_strncasecmp (h_list, h, len) == 0)
386 return 1;
387 h_list += n;
388
389 while (*h_list && (*h_list == ' ' || *h_list == '\t'))
390 h_list++;
391 if (*h_list != ':')
392 break;
393 ++h_list;
394 }
395 return 0;
396 }
397
398 /*
399 * SHA256 hashing functions.
400 */
401
402 #define BUF_SIZE 1024
403
404 /* Hash the contents read from the mailutils stream STR starting from
405 * the current position and up to the end of file.
406 */
407 static int
hash_stream(mu_stream_t str,struct sha256_ctx * ctx)408 hash_stream(mu_stream_t str, struct sha256_ctx *ctx)
409 {
410 uint8_t buffer[BUF_SIZE];
411 size_t count;
412 int rc;
413
414 while ((rc = mu_stream_read(str, buffer, sizeof(buffer), &count)) == 0
415 && count > 0) {
416 // mu_error("READ %*.*s", (int)count, (int)count, buffer);
417 sha256_update(ctx, count, buffer);
418 }
419
420 if (rc) {
421 mu_diag_funcall(MU_DIAG_ERROR, "mu_stream_read", NULL, rc);
422 return -1;
423 }
424
425 return 0;
426 }
427
428 /* Hash LEN bytes from the current position in stream STR. */
429 static int
hash_stream_segment(mu_stream_t str,size_t len,struct sha256_ctx * ctx)430 hash_stream_segment(mu_stream_t str, size_t len, struct sha256_ctx *ctx)
431 {
432 while (len) {
433 uint8_t buffer[BUF_SIZE];
434 int rc;
435 size_t n = sizeof(buffer), count;
436 if (n > len)
437 n = len;
438 rc = mu_stream_read(str, buffer, n, &count);
439 //printf("HASH %*.*s\n",(int)count,(int)count,buffer);
440 if (rc) {
441 mu_diag_funcall(MU_DIAG_ERROR, "mu_stream_read", NULL,
442 rc);
443 return -1;
444 }
445 if (count == 0) {
446 mu_error(_("unexpected end of file in canonical stream"));
447 return -1;
448 }
449 sha256_update(ctx, count, buffer);
450 len -= count;
451 }
452
453 return 0;
454 }
455
456 /* Hash the remaining content of the stream from the current position
457 * and store a nul-terminated base64 encoded result in outbuf.
458 * Outbuf must have at least BASE64_ENCODE_RAW_LENGTH(SHA256_DIGEST_SIZE) + 1
459 * bytes of capacity,
460 */
461 static int
dkim_body_hash(mu_stream_t str,size_t len,uint8_t * outbuf)462 dkim_body_hash(mu_stream_t str, size_t len, uint8_t *outbuf)
463 {
464 struct sha256_ctx ctx;
465 uint8_t body_digest[SHA256_DIGEST_SIZE];
466
467 sha256_init(&ctx);
468 if (len == DKIM_LENGTH_ALL)
469 hash_stream(str, &ctx);
470 else
471 hash_stream_segment(str, len, &ctx);
472 sha256_digest(&ctx, sizeof(body_digest), body_digest);
473 base64_encode_raw(outbuf, sizeof(body_digest), body_digest);
474
475 return 0;
476 }
477
478 /*
479 * RSA SHA256 digest.
480 */
481
482 /* Given the RSA private key and a pointer to SHA256 context, create the
483 * RSA digest in base64. Return value is stored in RET_B64 (malloced).
484 */
485 int
dkim_rsa_sha256_sign(struct rsa_private_key * priv,struct sha256_ctx * ctx,uint8_t ** ret_b64)486 dkim_rsa_sha256_sign(struct rsa_private_key *priv, struct sha256_ctx *ctx,
487 uint8_t **ret_b64)
488 {
489 int rc;
490 mpz_t sig;
491 size_t i;
492 struct nettle_buffer buffer;
493 uint8_t *outbuf;
494
495 mpz_init(sig);
496 rc = rsa_sha256_sign(priv, ctx, sig);
497 if (!rc)
498 return -1;
499
500 nettle_buffer_init_realloc(&buffer, NULL, nettle_xrealloc);//FIXME
501 for (i = mpz_size(sig); i > 0; i--) {
502 mp_limb_t limb = mpz_getlimbn(sig, i - 1);
503 size_t j;
504 uint8_t *p = nettle_buffer_space(&buffer, sizeof(mp_limb_t))
505 + sizeof(mp_limb_t) - 1;
506 for (j = 0; j < sizeof(mp_limb_t); j++) {
507 *p-- = limb & 0xff;
508 limb >>= 8;
509 }
510 }
511 mpz_clear(sig);
512
513 outbuf = malloc(BASE64_ENCODE_RAW_LENGTH(buffer.size) + 1);
514 if (!outbuf) {
515 nettle_buffer_clear(&buffer);
516 return -1;
517 }
518
519 base64_encode_raw(outbuf, buffer.size, buffer.contents);
520 outbuf[BASE64_ENCODE_RAW_LENGTH(buffer.size)] = 0;
521 nettle_buffer_clear(&buffer);
522
523 *ret_b64 = outbuf;
524
525 return 0;
526 }
527
528 /*
529 * Canonicalization names
530 * re. "DKIM-Signature Canonicalization Header" IANA registry.
531 */
532 static char const *dkim_canon_string[] = { "simple", "relaxed", NULL };
533 #define DKIM_CANON_STRING_MAX (sizeof(dkim_canon_string[DKIM_CANON_RELAXED])-1)
534 /*
535 * Convert STR to a DKIM_CANON_* constant (return DKIM_CANON_ERR on error).
536 * If ENDP is NULL, STR must be one of the strings from dkim_canon_string.
537 * Otherwise, STR may be followed by '\0' or '/'. The pointer to that
538 * character will be returned in the memory location pointed to by ENDP.
539 */
540 int
dkim_str_to_canon_type(char const * str,char ** endp)541 dkim_str_to_canon_type(char const *str, char **endp)
542 {
543 int i;
544 size_t len = strcspn(str, "/");
545 if (endp || str[len] == 0) {
546 for (i = 0; dkim_canon_string[i]; i++)
547 if (len == strlen(dkim_canon_string[i]) &&
548 memcmp(str, dkim_canon_string[i], len) == 0) {
549 if (endp)
550 *endp = (char*)(str + len);
551 return i;
552 }
553 }
554 return DKIM_CANON_ERR;
555 }
556
557 /* Format a struct dkim_signature as a DKIM-Signature header. */
558
559 #define MAX_LINE_LEN 78
560
561 struct dkim_format_buf {
562 mu_stream_t str;
563 mu_stream_stat_buffer stat;
564 int crlf;
565 };
566
567 static inline void
dkim_format_nl(struct dkim_format_buf * fb)568 dkim_format_nl(struct dkim_format_buf *fb)
569 {
570 if (fb->crlf)
571 mu_stream_write(fb->str, "\r\n ", 3, NULL);
572 else
573 mu_stream_write(fb->str, "\n ", 2, NULL);
574 fb->stat[MU_STREAM_STAT_OUT] = 0;
575 }
576
577 static inline int
dkim_format_wrap(struct dkim_format_buf * fb,size_t len)578 dkim_format_wrap(struct dkim_format_buf *fb, size_t len)
579 {
580 if (fb->stat[MU_STREAM_STAT_OUT]
581 && fb->stat[MU_STREAM_STAT_OUT] + len > MAX_LINE_LEN) {
582 dkim_format_nl(fb);
583 return 1;
584 }
585 return 0;
586 }
587
588 static void
dkim_format_tag(struct dkim_format_buf * fb,char const * tag,char const * val)589 dkim_format_tag(struct dkim_format_buf *fb, char const *tag, char const *val)
590 {
591 if (!val)
592 return;
593 if (!dkim_format_wrap(fb, strlen(tag) + strlen(val) + 2))
594 dkim_format_wrap(fb, strlen(tag) + 1);
595 mu_stream_write(fb->str, tag, strlen(tag), NULL);
596 mu_stream_write(fb->str, "=", 1, NULL);
597 dkim_format_wrap(fb, strlen(val) + 1);
598 mu_stream_write(fb->str, val, strlen(val), NULL);
599 mu_stream_write(fb->str, ";", 1, NULL);
600 }
601
602 static void
dkim_format_tag_base64(struct dkim_format_buf * fb,char const * tag,char const * val)603 dkim_format_tag_base64(struct dkim_format_buf *fb, char const *tag,
604 char const *val)
605 {
606 size_t len = strlen(val);
607
608 if (!dkim_format_wrap(fb, strlen(tag) + strlen(val) + 2))
609 dkim_format_wrap(fb, strlen(tag) + 1);
610 mu_stream_write(fb->str, tag, strlen(tag), NULL);
611 mu_stream_write(fb->str, "=", 1, NULL);
612
613 while (len > 0) {
614 size_t n = MAX_LINE_LEN - fb->stat[MU_STREAM_STAT_OUT];
615 if (len < n)
616 n = len;
617 mu_stream_write(fb->str, val, n, NULL);
618 dkim_format_wrap(fb, 1);
619 val += n;
620 len -= n;
621 }
622 mu_stream_write(fb->str, ";", 1, NULL);
623 }
624
625 void
dkim_signature_free(struct dkim_signature * sig)626 dkim_signature_free(struct dkim_signature *sig)
627 {
628 free(sig->a);
629 free(sig->b);
630 free(sig->bh);
631 free(sig->d);
632 free(sig->s);
633 free(sig->h);
634 free(sig->i);
635 free(sig->q);
636 free(sig->v);
637 }
638
639 /*
640 * Auxiliary functions for parsing and formatting dkim_signature fields.
641 *
642 * Each parser is declared as
643 * int P(char const *value, void *data)
644 * Its arguments are:
645 * value - actual tag value obtained from the header.
646 * data - pointer to the member of struct dkim_signature.
647 * The parser returns 0 on success and non-zero on error. It is not supposed
648 * to emit any diagnostic messages.
649 *
650 * Each formatter is declared as
651 * int F(struct dkim_format_buf *fb, char const *tag, void *data)
652 * Its arguments are:
653 * fb - formatting buffer,
654 * tag - the tag name,
655 * value - pointer to the member of struct dkim_signature.
656 */
657
658 /* General purpose parser for char* (or uint8_t*) fields */
659 static int
dkim_tag_char_parser(char const * value,void * data)660 dkim_tag_char_parser(char const *value, void *data)
661 {
662 char **cptr = data;
663 *cptr = mu_strdup(value);
664 return 0;
665 }
666
667 /* General purpose formatter for char* (or uint8_t*) fields */
668 static void
dkim_tag_char_formatter(struct dkim_format_buf * fb,char const * tag,void * data)669 dkim_tag_char_formatter(struct dkim_format_buf *fb,
670 char const *tag,
671 void *data)
672 {
673 char **cptr = data;
674 dkim_format_tag(fb, tag, *cptr);
675 }
676
677 /* Formatter for the a= tag */
678 static void
dkim_tag_a_formatter(struct dkim_format_buf * fb,char const * tag,void * data)679 dkim_tag_a_formatter(struct dkim_format_buf *fb,
680 char const *tag,
681 void *data)
682 {
683 char **cptr = data;
684 dkim_format_tag(fb, tag, *cptr ? *cptr : DKIM_ALGORITHM);
685 }
686
687 /* Formatter for the q= tag */
688 static void
dkim_tag_q_formatter(struct dkim_format_buf * fb,char const * tag,void * data)689 dkim_tag_q_formatter(struct dkim_format_buf *fb,
690 char const *tag,
691 void *data)
692 {
693 char **cptr = data;
694 dkim_format_tag(fb, tag, *cptr ? *cptr : DKIM_QUERY_METHOD);
695 }
696
697 /* Special formatter for the h= tag, that ensures proper wrapping. */
698 static void
dkim_tag_h_formatter(struct dkim_format_buf * fb,char const * tag,void * data)699 dkim_tag_h_formatter(struct dkim_format_buf *fb,
700 char const *tag,
701 void *data)
702 {
703 char **cptr = data;
704 void *save;
705 char const *hval;
706
707 if (!dkim_format_wrap(fb, 2))
708 dkim_format_wrap(fb, strlen(*cptr) + 3);
709
710 mu_stream_write(fb->str, "h=", 2, NULL);
711
712 if ((hval = dkim_header_list_first(*cptr, &save)) != NULL) {
713 dkim_format_wrap(fb, strlen(hval));
714 mu_stream_write(fb->str, hval, strlen(hval), NULL);
715 while ((hval = dkim_header_list_next(save)) != NULL) {
716 dkim_format_wrap(fb, strlen(hval) + 1);
717 mu_stream_write(fb->str, ":", 1, NULL);
718 mu_stream_write(fb->str, hval, strlen(hval), NULL);
719 }
720 }
721 dkim_header_list_end(save);
722 dkim_format_wrap(fb, 1);
723 mu_stream_write(fb->str, ";", 1, NULL);
724 }
725
726 /* Parser and formatter for the c= tag. */
727 static int
dkim_tag_c_parser(char const * value,void * data)728 dkim_tag_c_parser(char const *value, void *data)
729 {
730 int *canon = data;
731 char *s;
732
733 if ((canon[0] = dkim_str_to_canon_type(value, &s)) == DKIM_CANON_ERR)
734 return -1;
735 if (*s == 0)
736 canon[1] = canon[0];
737 else if (*s != '/' ||
738 (canon[1] = dkim_str_to_canon_type(s + 1, NULL)) == DKIM_CANON_ERR)
739 return -1;
740 return 0;
741 }
742
743 static void
dkim_tag_c_formatter(struct dkim_format_buf * fb,char const * tag,void * data)744 dkim_tag_c_formatter(struct dkim_format_buf *fb,
745 char const *tag,
746 void *data)
747 {
748 int *canon = data;
749 char v[(DKIM_CANON_STRING_MAX+1)*2];
750 strcpy(v, dkim_canon_string[canon[0]]);
751 strcat(v, "/");
752 strcat(v, dkim_canon_string[canon[1]]);
753 dkim_format_tag(fb, tag, v);
754 }
755
756 /* General-purpose parser and formatter for time_t members (t and x) */
757 static int
dkim_tag_time_parser(char const * value,void * data)758 dkim_tag_time_parser(char const *value, void *data)
759 {
760 time_t *tptr = data;
761 unsigned long n;
762 char *p;
763 errno = 0;
764 n = strtoul(value, &p, 10);
765 if (errno || *p)
766 return -1;
767 *tptr = n;
768 return 0;
769 }
770
771 static void
dkim_tag_time_formatter(struct dkim_format_buf * fb,char const * tag,void * data)772 dkim_tag_time_formatter(struct dkim_format_buf *fb,
773 char const *tag,
774 void *data)
775 {
776 time_t *tptr = data;
777
778 if (*tptr) {
779 char tbuf[80];
780 snprintf(tbuf, sizeof(tbuf), "%lu", (long unsigned) *tptr);
781 dkim_format_tag(fb, tag, tbuf);
782 }
783 }
784
785 /* Parser and formatter for the l= tag */
786 static int
dkim_tag_l_parser(char const * value,void * data)787 dkim_tag_l_parser(char const *value, void *data)
788 {
789 size_t *sptr = data;
790 unsigned long n;
791 char *endp;
792 errno = 0;
793 n = strtoul(value, &endp, 10);
794 if (errno || *endp)
795 return -1;
796 *sptr = n;
797 return 0;
798 }
799
800 static void
dkim_tag_l_formatter(struct dkim_format_buf * fb,char const * tag,void * data)801 dkim_tag_l_formatter(struct dkim_format_buf *fb,
802 char const *tag,
803 void *data)
804 {
805 size_t *sptr = data;
806 char tbuf[80];
807 if (*sptr != DKIM_LENGTH_ALL) {
808 snprintf(tbuf, sizeof(tbuf), "%zu", *sptr);
809 dkim_format_tag(fb, tag, tbuf);
810 }
811 }
812
813 /* Formatter for the bh= tag. */
814 static void
dkim_tag_bh_formatter(struct dkim_format_buf * fb,char const * tag,void * data)815 dkim_tag_bh_formatter(struct dkim_format_buf *fb,
816 char const *tag,
817 void *data)
818 {
819 char **sptr = data;
820 dkim_format_tag_base64(fb, tag, *sptr);
821 }
822
823 /* Formatter for the b= tag. */
824 static void
dkim_tag_b_formatter(struct dkim_format_buf * fb,char const * tag,void * data)825 dkim_tag_b_formatter(struct dkim_format_buf *fb,
826 char const *tag,
827 void *data)
828 {
829 char **sptr = data;
830 dkim_format_nl(fb);
831 dkim_format_tag_base64(fb, tag, *sptr ? *sptr : "");
832 }
833
834 /* Tag definition structure */
835 struct dkim_tag_descr {
836 char *tag; /* Tag name. */
837 size_t off; /* Field offset in struct dkim_signature. */
838 int (*parser)(char const *, void *);
839 /* Parser function. */
840 void (*formatter)(struct dkim_format_buf *, char const *, void *);
841 /* Formatter function. */
842 };
843
844 /* Order of entries in this array defines the order in which tags are
845 formatted.
846 */
847 static struct dkim_tag_descr tag_descr[] = {
848 {
849 "v",
850 offsetof(struct dkim_signature, v),
851 dkim_tag_char_parser,
852 dkim_tag_char_formatter,
853 },
854 {
855 "a",
856 offsetof(struct dkim_signature, a),
857 dkim_tag_char_parser,
858 dkim_tag_a_formatter
859 },
860 {
861 "d",
862 offsetof(struct dkim_signature, d),
863 dkim_tag_char_parser,
864 dkim_tag_char_formatter,
865 },
866 {
867 "s",
868 offsetof(struct dkim_signature, s),
869 dkim_tag_char_parser,
870 dkim_tag_char_formatter,
871 },
872 {
873 "c",
874 offsetof(struct dkim_signature, canon),
875 dkim_tag_c_parser,
876 dkim_tag_c_formatter
877 },
878 {
879 "q",
880 offsetof(struct dkim_signature, q),
881 dkim_tag_char_parser,
882 dkim_tag_q_formatter
883 },
884 {
885 "h",
886 offsetof(struct dkim_signature, h),
887 dkim_tag_char_parser,
888 dkim_tag_h_formatter,
889 },
890 {
891 "i",
892 offsetof(struct dkim_signature, i),
893 dkim_tag_char_parser,
894 dkim_tag_char_formatter,
895 },
896 {
897 "l",
898 offsetof(struct dkim_signature, l),
899 dkim_tag_l_parser,
900 dkim_tag_l_formatter
901 },
902 {
903 "t",
904 offsetof(struct dkim_signature, t),
905 dkim_tag_time_parser,
906 dkim_tag_time_formatter
907 },
908 {
909 "x",
910 offsetof(struct dkim_signature, x),
911 dkim_tag_time_parser,
912 dkim_tag_time_formatter
913 },
914 {
915 "bh",
916 offsetof(struct dkim_signature, bh),
917 dkim_tag_char_parser,
918 dkim_tag_bh_formatter
919 },
920 {
921 "b",
922 offsetof(struct dkim_signature, b),
923 dkim_tag_char_parser,
924 dkim_tag_b_formatter
925 },
926 { NULL }
927 };
928
929 /* Table-driven DKIM-Signature parser. */
930 int
dkim_signature_parse(char * str,struct dkim_signature * ret_sig)931 dkim_signature_parse(char *str, struct dkim_signature *ret_sig)
932 {
933 struct mu_wordsplit ws;
934 int i;
935 int rc = 0;
936 struct dkim_signature sig;
937
938 /*
939 * tag-list = tag-spec *( ";" tag-spec ) [ ";" ]
940 * tag-spec = [FWS] tag-name [FWS] "=" [FWS] tag-value [FWS]
941 *
942 * The mu_wordsplit call splits the value on ';' and removes
943 * whitespace at both sides of each token. Internal FWS (around
944 * the equals sign) is removed later.
945 */
946 ws.ws_delim = ";";
947 rc = mu_wordsplit(str,
948 &ws,
949 MU_WRDSF_DELIM |
950 MU_WRDSF_NOVAR |
951 MU_WRDSF_WS |
952 MU_WRDSF_NOCMD);
953 if (rc) {
954 mu_wordsplit_free(&ws);
955 return rc;
956 }
957
958 memset(&sig, 0, sizeof(sig));
959 sig.canon[0] = sig.canon[1] = DKIM_CANON_SIMPLE;
960 sig.l = DKIM_LENGTH_ALL;
961 for (i = 0; i < ws.ws_wordc; i++) {
962 struct dkim_tag_descr *tg;
963 char *k = ws.ws_wordv[i];
964 char *p = strchr(k, '=');
965 if (!p) {
966 rc = -1;
967 goto end;
968 }
969 *p++ = 0;
970 /* Remove internal FWS */
971 mu_rtrim_class(k, MU_CTYPE_BLANK);
972 mu_ltrim_class(p, MU_CTYPE_BLANK);
973 /* Handle known tags */
974 for (tg = tag_descr; tg->tag; tg++) {
975 if (strcmp(k, tg->tag) == 0) {
976 rc = tg->parser(p, (char*)&sig + tg->off);
977 if (rc)
978 goto end;
979 break;
980 }
981 }
982 }
983 end:
984 mu_wordsplit_free(&ws);
985 if (rc)
986 dkim_signature_free(&sig);
987 else
988 *ret_sig = sig;
989 return rc;
990 }
991
992 /*
993 * Table-driven DKIM-Signature formatter.
994 * The CRLF parameter defines what delimiter to use for wrapping.
995 */
996 int
dkim_signature_format(struct dkim_signature * sig,int crlf,char ** result)997 dkim_signature_format(struct dkim_signature *sig, int crlf, char **result)
998 {
999 struct dkim_format_buf fb;
1000 int rc;
1001 static char header_field[] = DKIM_SIGNATURE_HEADER ": ";
1002 mu_off_t off;
1003 size_t size;
1004 char *text;
1005 struct dkim_tag_descr *tg;
1006
1007 /* Initialize format buffer */
1008 fb.crlf = crlf;
1009 rc = mu_memory_stream_create(&fb.str, MU_STREAM_RDWR);
1010 if (rc) {
1011 mu_diag_funcall(MU_DIAG_ERROR,
1012 "mu_memory_stream_create",
1013 NULL, rc);
1014 return rc;
1015 }
1016 mu_stream_set_stat(fb.str,
1017 MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT),
1018 fb.stat);
1019 mu_stream_write(fb.str, header_field, strlen(header_field), NULL);
1020 for (tg = tag_descr; tg->tag; tg++) {
1021 tg->formatter(&fb, tg->tag, ((char*)sig + tg->off));
1022 }
1023
1024 if (mu_stream_err(fb.str)) {
1025 rc = mu_stream_last_error(fb.str);
1026 mu_diag_funcall(MU_DIAG_ERROR,
1027 "dkim_signature_format", NULL, rc);
1028 } else {
1029 rc = 0;
1030 mu_stream_seek(fb.str, 0, MU_SEEK_CUR, &off);
1031
1032 //FIXME: assert(size < (size_t)~0)
1033 size = off;
1034 text = mu_alloc(size + 1);
1035
1036 mu_stream_seek(fb.str, 0, MU_SEEK_SET, NULL);
1037
1038 mu_stream_read(fb.str, text, size, NULL);
1039 text[size] = 0;
1040 *result = text;
1041 }
1042 mu_stream_destroy(&fb.str);
1043
1044 return rc;
1045 }
1046
1047 /* Canonicalize the message into a stream.
1048 * Arguments:
1049 *
1050 * msg input message.
1051 * canon canonicalization algorithms for header and body.
1052 * canon_str output stream.
1053 */
1054 int
canonicalize(mu_message_t msg,int canon[2],mu_stream_t * canon_str)1055 canonicalize(mu_message_t msg, int canon[2], mu_stream_t *canon_str)
1056 {
1057 mu_stream_t mstr, flt, in;
1058 int rc;
1059
1060 rc = mu_temp_file_stream_create(&mstr, NULL, 0);
1061 if (rc) {
1062 mu_diag_funcall(MU_DIAG_ERROR,
1063 "mu_temp_file_stream_create",
1064 NULL, rc);
1065 return -1;
1066 }
1067
1068 rc = mu_message_get_streamref(msg, &in);
1069 if (rc) {
1070 mu_diag_funcall(MU_DIAG_ERROR,
1071 "mu_message_get_streamref",
1072 NULL, rc);
1073 mu_stream_destroy(&mstr);
1074 return -1;
1075 }
1076
1077 rc = dkim_canonicalizer_create(&flt, in,
1078 canon[0],
1079 canon[1],
1080 MU_STREAM_READ);
1081 mu_stream_unref(in);
1082 if (rc) {
1083 mu_error("dkim_canonicalizer_create: %s",
1084 mu_strerror(rc));
1085 mu_stream_destroy(&mstr);
1086 return -1;
1087 }
1088
1089 in = flt;
1090 rc = mu_filter_create(&flt, in, "CRLF",
1091 MU_FILTER_ENCODE, MU_STREAM_READ);
1092 mu_stream_unref(in);
1093 if (rc) {
1094 mu_error("mu_filter_stream_create: %s", mu_strerror(rc));
1095 mu_stream_destroy(&mstr);
1096 return -1;
1097 }
1098
1099 rc = mu_stream_copy(mstr, flt, 0, NULL);
1100 mu_stream_unref(flt);
1101 if (rc) {
1102 mu_error("mu_stream_copy: %s", mu_strerror(rc));
1103 mu_stream_destroy(&mstr);
1104 return -1;
1105 }
1106 mu_stream_seek(mstr, 0, MU_SEEK_SET, NULL);
1107 *canon_str = mstr;
1108 return 0;
1109 }
1110
1111 /*
1112 * Header maps.
1113 *
1114 * Message headers form a doubly-linked list of struct header_map
1115 * pointers. The list itself is referenced by its head structure,
1116 * which is a regular header_map where only prev and next pointers
1117 * are valid. In a header, next points to the first and prev to the
1118 * last element in the list.
1119 */
1120 struct header_map {
1121 struct header_map *prev, *next; /* List of elements */
1122 char *header; /* Header name */
1123 mu_off_t start; /* Header start offset */
1124 mu_off_t end; /* Header end offset (points past the
1125 final CRLF) */
1126 };
1127
1128 /* Header_map is initialized using this macro. */
1129 #define HEADER_MAP_INITIALIZER(h) { &(h), &(h) }
1130
1131 /* Remove the header_map from the list */
1132 static inline void
header_map_remove(struct header_map * hp)1133 header_map_remove(struct header_map *hp)
1134 {
1135 hp->prev->next = hp->next;
1136 hp->next->prev = hp->prev;
1137 }
1138
1139 /* Insert header_map B to the list after A. */
1140 static inline void
header_map_insert_after(struct header_map * a,struct header_map * b)1141 header_map_insert_after(struct header_map *a, struct header_map *b)
1142 {
1143 a->next->prev = b;
1144 b->next = a->next;
1145 a->next = b;
1146 b->prev = a;
1147 }
1148
1149 /* Append header_map to the end of the list. */
1150 static inline void
header_map_append(struct header_map * link,struct header_map * hp)1151 header_map_append(struct header_map *link, struct header_map *hp)
1152 {
1153 header_map_insert_after(link->prev, hp);
1154 }
1155
1156 /* Free the list. List head is not freed. */
1157 static inline void
header_map_free(struct header_map * link)1158 header_map_free(struct header_map *link)
1159 {
1160 struct header_map *hmap = link->next;
1161 while (hmap != link) {
1162 header_map_remove(hmap);
1163 free(hmap);
1164 hmap = link->next;
1165 }
1166 }
1167
1168 /*
1169 * Two iterators.
1170 *
1171 * Arguments:
1172 * link the head element of the list.
1173 * h iteration variable
1174 */
1175
1176 /* Iterate over the list in natural direction. */
1177 #define HEADER_MAP_FOREACH(h,link) \
1178 for (h = (link)->next; h != (link); h = (h)->next)
1179 /* Iterate over the list in reverse direction. */
1180 #define HEADER_MAP_FOREACH_REV(h,link) \
1181 for (h = (link)->prev; h != (link); h = (h)->prev)
1182
1183 /* Return true if a message can have multiple instances of the named header.
1184 *
1185 * RFC 6376 mandates that such headers be processed in reverse order.
1186 * Refer to subsection 5.4.2. "Signatures Involving Multiple Instances of
1187 * a Field" on page 41 for details.
1188 */
1189 static int
is_rev_header(char const * name)1190 is_rev_header(char const *name)
1191 {
1192 static char *rev_headers[] = {
1193 "Received",
1194 DKIM_SIGNATURE_HEADER,
1195 "Resent-*",
1196 NULL
1197 };
1198 int i;
1199
1200 for (i = 0; rev_headers[i]; i++) {
1201 if (mu_imap_wildmatch_ci(rev_headers[i], name, ':') == 0)
1202 return 1;
1203 }
1204 return 0;
1205 }
1206
1207 static int
dkim_tag_find(char const * sigstr,char const * tag,size_t * ret_len)1208 dkim_tag_find(char const *sigstr, char const *tag, size_t *ret_len)
1209 {
1210 int i;
1211 size_t tag_len = strlen(tag);
1212 size_t sig_len = strlen(sigstr);
1213
1214 for (i = 0; i + tag_len + 1 < sig_len; i++) {
1215 if (!(sigstr[i] == ' ' || sigstr[i] == '\t' ||
1216 sigstr[i] == '\r' || sigstr[i] == '\n')) {
1217 size_t n = strcspn(sigstr + i, ";");
1218 if (memcmp(sigstr + i, tag, tag_len) == 0 &&
1219 sigstr[i + tag_len] == '=') {
1220 *ret_len = n - tag_len - 1;
1221 return i;
1222 }
1223 i += n;
1224 }
1225 }
1226 return -1;
1227 }
1228
1229 enum {
1230 DKIM_HASH_ERR = -1,
1231 DKIM_HASH_OK,
1232 DKIM_HASH_DIFF
1233 };
1234
1235 #define BH_SIZE (BASE64_ENCODE_RAW_LENGTH(SHA256_DIGEST_SIZE))
1236
1237 /*
1238 * dkim_hash(MSG, SIG, SIGSTR, CTX)
1239 * --------------------------------
1240 * Compute a message hash of MSG as per RFC 6376 section 3.7.
1241 *
1242 * Parameters:
1243 * MSG - (input) message
1244 * SIG - (input/output) parsed out DKIM signature
1245 * SIGSTR - (input) original value of the DKIM signature header.
1246 * CTX - (output) SHA256 context to leave the hash in.
1247 *
1248 * The function is used both for message signing and verification.
1249 *
1250 * When signing, SIGSTR is NULL. Before return, the malloced copy
1251 * of the computed body hash is left in SIG->bh. The caller is
1252 * responsible for freeing it when no longer needed. In this mode,
1253 * the function returns DKIM_HASH_OK on success and DKIM_HASH_ERR
1254 * on error.
1255 *
1256 * When verifying, SIGSTR is not NULL and SIG is the validated broken
1257 * out DKIM signature obtained from SIGSTR. In this case, the function
1258 * does not modify SIG in any way. Instead, it checks whether the computed
1259 * body hash matches SIG->bh and returns DKIM_HASH_DIFF if it does not.
1260 */
1261 static int
dkim_hash(mu_message_t msg,struct dkim_signature * sig,char const * sigstr,struct sha256_ctx * ctx)1262 dkim_hash(mu_message_t msg, struct dkim_signature *sig, char const *sigstr,
1263 struct sha256_ctx *ctx)
1264 {
1265 mu_stream_t canon_stream = NULL;
1266 char *hp;
1267 void *hstate;
1268 struct header_map h_all = HEADER_MAP_INITIALIZER(h_all);
1269 struct header_map h_sel = HEADER_MAP_INITIALIZER(h_sel);
1270 struct header_map *hmap;
1271 uint8_t bh[BH_SIZE];
1272 mu_opool_t op = NULL;
1273 char c;
1274 int rc;
1275 int result = DKIM_HASH_ERR;
1276 size_t count;
1277 enum { H_INIT, H_HEADER, H_CR1, H_CR2, H_NL } state = H_INIT;
1278 mu_stream_t sigcanon, str;
1279 char *sig_str_buf;
1280
1281 /* Create a canonical representation of the message */
1282 if (canonicalize(msg, sig->canon, &canon_stream))
1283 goto err;
1284
1285 /*
1286 * Scan the header part of the canonicalized stream and record
1287 * the headers in the h_all list.
1288 *
1289 * Header names its elements refer to are stored in the object
1290 * pool.
1291 */
1292 mu_opool_create(&op, MU_OPOOL_DEFAULT);
1293 hmap = NULL;
1294
1295 while ((rc = mu_stream_read(canon_stream, &c, 1, &count)) == 0 &&
1296 count == 1) {
1297 switch (state) {
1298 case H_INIT:
1299 if (c == ':') {
1300 c = 0;
1301 mu_opool_append(op, &c, 1);
1302 hmap = calloc(1, sizeof(hmap[0]));
1303 hmap->header = mu_opool_finish(op, NULL);
1304 mu_strlower(hmap->header);
1305 mu_stream_seek(canon_stream, 0, MU_SEEK_CUR,
1306 &hmap->start);
1307 hmap->start -= strlen(hmap->header) + 1;
1308 header_map_append(&h_all, hmap);
1309 state = H_HEADER;
1310 } else
1311 mu_opool_append(op, &c, 1);
1312 break;
1313
1314 case H_HEADER:
1315 if (c == '\r')
1316 state = H_CR1;
1317 break;
1318
1319 case H_CR1:
1320 if (c == '\n')
1321 state = H_NL;
1322 break;
1323
1324 case H_NL:
1325 if (mu_isblank(c))
1326 state = H_HEADER;
1327 else {
1328 mu_stream_seek(canon_stream, 0, MU_SEEK_CUR,
1329 &hmap->end);
1330 hmap->end--;
1331 if (c == '\r')
1332 state = H_CR2;
1333 else {
1334 state = H_INIT;
1335 mu_opool_append(op, &c, 1);
1336 }
1337 }
1338 break;
1339
1340 case H_CR2:
1341 if (c != '\n') {
1342 goto badstream;
1343 }
1344 goto end;
1345 }
1346 }
1347
1348 /* Error exit from the above loop */
1349 if (rc)
1350 mu_diag_funcall(MU_DIAG_ERROR, "mu_stream_read", NULL, rc);
1351 badstream:
1352 mu_error(_("malformed canonical stream"));
1353 goto err;
1354
1355 end:
1356 /*
1357 * Scanning terminated successfully. Current position in the
1358 * canon_stream is left at the start of the body, which will come
1359 * handy later.
1360 *
1361 * Select headers to hash according to the h= tag. Selected headers
1362 * are removed from the h_all and added to the h_sel list.
1363 */
1364 for (hp = dkim_header_list_first(sig->h, &hstate); hp;
1365 hp = dkim_header_list_next(hstate)) {
1366 if (is_rev_header(hp)) {
1367 HEADER_MAP_FOREACH_REV(hmap, &h_all) {
1368 if (mu_c_strcasecmp(hmap->header, hp) == 0) {
1369 header_map_remove(hmap);
1370 header_map_append(&h_sel, hmap);
1371 break;
1372 }
1373 }
1374 } else {
1375 HEADER_MAP_FOREACH(hmap, &h_all) {
1376 if (mu_c_strcasecmp(hmap->header, hp) == 0) {
1377 header_map_remove(hmap);
1378 header_map_append(&h_sel, hmap);
1379 break;
1380 }
1381 }
1382 }
1383 }
1384 dkim_header_list_end(hstate);
1385
1386 /* Hash the body */
1387 if (dkim_body_hash(canon_stream, sig->l, bh))
1388 goto err;
1389 if (sig->bh) {
1390 if (memcmp(sig->bh, bh, BH_SIZE)) {
1391 result = DKIM_HASH_DIFF;
1392 goto err;
1393 }
1394 } else {
1395 sig->bh = malloc(BH_SIZE + 1);
1396 if (!sig->bh)
1397 goto err;
1398 memcpy(sig->bh, bh, BH_SIZE);
1399 sig->bh[BH_SIZE] = 0;
1400 }
1401
1402 /* Hash the selected headers */
1403 HEADER_MAP_FOREACH(hmap, &h_sel) {
1404 mu_stream_seek(canon_stream, hmap->start, MU_SEEK_SET, NULL);
1405 hash_stream_segment(canon_stream, hmap->end - hmap->start,
1406 ctx);
1407 }
1408
1409 /* Add to the hash the DKIM-Signature header with empty b= tag. */
1410 if (sigstr) {
1411 size_t len, blen;
1412 char *vp;
1413 int n = dkim_tag_find(sigstr, "b", &blen);
1414 if (n == -1)
1415 goto err;
1416 len = strlen(sigstr);
1417 sig_str_buf = malloc(sizeof(DKIM_SIGNATURE_HEADER) + 1
1418 + len - blen + 1);
1419 if (!sig_str_buf)
1420 goto err;
1421 strcpy(sig_str_buf, DKIM_SIGNATURE_HEADER ": ");
1422 vp = sig_str_buf + sizeof(DKIM_SIGNATURE_HEADER) + 1;
1423 memcpy(vp, sigstr, n);
1424 memcpy(vp + n, "b=", 2);
1425 strcpy(vp + n + 2, sigstr + n + 2 + blen);
1426 } else {
1427 dkim_signature_format(sig, 0, &sig_str_buf);
1428 }
1429 mu_fixed_memory_stream_create(&str, sig_str_buf, strlen(sig_str_buf),
1430 MU_STREAM_RDWR|MU_STREAM_SEEK);
1431 rc = dkim_canonicalizer_create(&sigcanon, str,
1432 sig->canon[0], sig->canon[1],
1433 MU_STREAM_READ);
1434 mu_stream_unref(str);
1435 if (rc) {
1436 mu_error("dkim_canonicalizer_create: %s", mu_strerror(rc));
1437 goto err;
1438 }
1439
1440 rc = mu_filter_create(&str, sigcanon, "CRLF", MU_FILTER_ENCODE,
1441 MU_STREAM_READ);
1442 mu_stream_unref(sigcanon);
1443 if (rc) {
1444 mu_diag_funcall(MU_DIAG_ERROR,
1445 "mu_filter_stream_create", NULL, c);
1446 goto err;
1447 }
1448 sigcanon = str;
1449
1450 hash_stream(sigcanon, ctx);
1451 mu_stream_unref(sigcanon);
1452 free(sig_str_buf);
1453 result = DKIM_HASH_OK;
1454 err:
1455 /* Reclaim the allocated memory. */
1456 mu_opool_destroy(&op);
1457 header_map_free(&h_all);
1458 header_map_free(&h_sel);
1459 mu_stream_destroy(&canon_stream);
1460 return result;
1461 }
1462
1463
1464 /* Sign the message. Arguments:
1465 *
1466 * msg message to sign.
1467 * sig initialized struct dkim_signature.
1468 * priv_file name of a disk file with the RSA private key in PEM format.
1469 * ret_sighdr return pointer.
1470 *
1471 * On success, a malloced copy of DKIM-Signature header line will be stored
1472 * in ret_sighdr and 0 will be returned.
1473 *
1474 * Side effects: sig->bh is filled with SHA256 digest of the message body.
1475 */
1476 int
mfd_dkim_sign(mu_message_t msg,struct dkim_signature * sig,char * priv_file,char ** ret_sighdr)1477 mfd_dkim_sign(mu_message_t msg, struct dkim_signature *sig,
1478 char *priv_file,
1479 char **ret_sighdr)
1480 {
1481 int rc;
1482 struct rsa_private_key priv;
1483 struct rsa_public_key pub;
1484 FILE *fp;
1485 struct sha256_ctx ctx;
1486 int result = -1;
1487
1488 fp = fopen(priv_file, "r");
1489 if (!fp) {
1490 mu_error(_("can't open %s: %s"), priv_file, strerror(errno));
1491 return -1;
1492 }
1493
1494 rc = read_keys(fp, &pub, &priv);
1495 fclose(fp);
1496 if (rc != READ_PEM_OK) {
1497 mu_error(_("can't read private key from %s: %s"),
1498 priv_file, strerror(errno));
1499 return -1;
1500 }
1501 rsa_public_key_clear(&pub);
1502
1503 sha256_init(&ctx);
1504 if (dkim_hash(msg, sig, NULL, &ctx) == DKIM_HASH_OK) {
1505 /* Create the RSA-SHA256 signature in b */
1506 dkim_rsa_sha256_sign(&priv, &ctx, &sig->b);
1507
1508 /* Create the header */
1509 dkim_signature_format(sig, 1, ret_sighdr);
1510 result = 0;
1511 }
1512 /* Reclaim the allocated memory. */
1513 free(sig->b);
1514 sig->b = NULL;
1515 free(sig->bh);
1516 sig->bh = NULL;
1517 rsa_private_key_clear(&priv);
1518 return result;
1519 }
1520
1521 char const *dkim_explanation_str[] = {
1522 [DKIM_EXPL_OK] = "DKIM verification passed",
1523 [DKIM_EXPL_NO_SIG] = "No DKIM signature",
1524 [DKIM_EXPL_INTERNAL_ERROR] = "internal error",
1525 [DKIM_EXPL_SIG_SYNTAX] = "signature syntax error",
1526 [DKIM_EXPL_SIG_MISS] = "signature is missing required tag",
1527 [DKIM_EXPL_DOMAIN_MISMATCH] = "domain mismatch",
1528 [DKIM_EXPL_BAD_VERSION] = "incompatible version",
1529 [DKIM_EXPL_BAD_ALGORITHM] = "unsupported algorithm",
1530 [DKIM_EXPL_BAD_QUERY] = "unsupported query method",
1531 [DKIM_EXPL_FROM] = "From field not signed",
1532 [DKIM_EXPL_EXPIRED] = "signature expired",
1533 [DKIM_EXPL_DNS_UNAVAIL] = "public key unavailable",
1534 [DKIM_EXPL_DNS_NOTFOUND] = "public key not found",
1535 [DKIM_EXPL_KEY_SYNTAX] = "key syntax error",
1536 [DKIM_EXPL_KEY_REVOKED] = "key revoked",
1537 [DKIM_EXPL_BAD_BODY] = "body hash did not verify",
1538 [DKIM_EXPL_BAD_BASE64] = "can't decode b= tag",
1539 [DKIM_EXPL_BAD_SIG] = "signature did not verify",
1540 };
1541
1542 int dkim_result_trans[] = {
1543 [DKIM_EXPL_OK] = DKIM_VERIFY_OK,
1544 [DKIM_EXPL_BAD_ALGORITHM] = DKIM_VERIFY_PERMFAIL,
1545 [DKIM_EXPL_BAD_BASE64] = DKIM_VERIFY_PERMFAIL,
1546 [DKIM_EXPL_BAD_BODY] = DKIM_VERIFY_PERMFAIL,
1547 [DKIM_EXPL_BAD_SIG] = DKIM_VERIFY_PERMFAIL,
1548 [DKIM_EXPL_BAD_QUERY] = DKIM_VERIFY_PERMFAIL,
1549 [DKIM_EXPL_BAD_VERSION] = DKIM_VERIFY_PERMFAIL,
1550 [DKIM_EXPL_DNS_NOTFOUND] = DKIM_VERIFY_PERMFAIL,
1551 [DKIM_EXPL_DOMAIN_MISMATCH] = DKIM_VERIFY_PERMFAIL,
1552 [DKIM_EXPL_EXPIRED] = DKIM_VERIFY_PERMFAIL,
1553 [DKIM_EXPL_FROM] = DKIM_VERIFY_PERMFAIL,
1554 [DKIM_EXPL_KEY_REVOKED] = DKIM_VERIFY_PERMFAIL,
1555 [DKIM_EXPL_KEY_SYNTAX] = DKIM_VERIFY_PERMFAIL,
1556 [DKIM_EXPL_SIG_MISS] = DKIM_VERIFY_PERMFAIL,
1557 [DKIM_EXPL_SIG_SYNTAX] = DKIM_VERIFY_PERMFAIL,
1558 [DKIM_EXPL_NO_SIG] = DKIM_VERIFY_TEMPFAIL,
1559 [DKIM_EXPL_DNS_UNAVAIL] = DKIM_VERIFY_TEMPFAIL,
1560 [DKIM_EXPL_INTERNAL_ERROR] = DKIM_VERIFY_TEMPFAIL,
1561 };
1562
1563 static int
dkim_sig_validate(struct dkim_signature * sig)1564 dkim_sig_validate(struct dkim_signature *sig)
1565 {
1566 if (!sig->a
1567 || !sig->b
1568 || !sig->bh
1569 || !sig->d
1570 || !sig->h
1571 || !sig->s
1572 || !sig->v) {
1573 return DKIM_EXPL_SIG_MISS;
1574 }
1575
1576 if (strcmp(sig->v, DKIM_VERSION))
1577 return DKIM_EXPL_BAD_VERSION;
1578
1579 if (strcmp(sig->a, DKIM_ALGORITHM))
1580 return DKIM_EXPL_BAD_ALGORITHM;
1581
1582 if (!sig->q)
1583 sig->q = mu_strdup(DKIM_QUERY_METHOD);
1584 else if (strcmp(sig->q, DKIM_QUERY_METHOD))
1585 return DKIM_EXPL_BAD_QUERY;
1586
1587 if (sig->i) {
1588 char *p = strchr(sig->i, '@');
1589 size_t ilen, dlen;
1590 if (!p)
1591 return DKIM_EXPL_SIG_SYNTAX;
1592 p++;
1593 ilen = strlen(p);
1594 dlen = strlen(sig->d);
1595 if (!(dlen <= ilen &&
1596 mu_c_strcasecmp(sig->d, p + ilen - dlen) == 0 &&
1597 (p[ilen - dlen - 1] == '.' || p[ilen - dlen - 1] == '@')))
1598 return DKIM_EXPL_DOMAIN_MISMATCH;
1599 }
1600
1601 if (!dkim_header_list_match(sig->h, MU_HEADER_FROM))
1602 return DKIM_EXPL_FROM;
1603
1604 if (sig->x && time(NULL) > sig->x)
1605 return DKIM_EXPL_EXPIRED;
1606
1607 return DKIM_EXPL_OK;
1608 }
1609
1610 static int
dnsrec_parse(char * rec,mu_assoc_t * pa)1611 dnsrec_parse(char *rec, mu_assoc_t *pa)
1612 {
1613 mu_assoc_t a;
1614 struct mu_wordsplit ws;
1615 int result;
1616
1617 if (mu_assoc_create (&a, 0))
1618 mu_alloc_die ();
1619 mu_assoc_set_destroy_item (a, mu_list_free_item);
1620
1621 ws.ws_delim = ";";
1622 if (mu_wordsplit(rec,
1623 &ws,
1624 MU_WRDSF_DELIM |
1625 MU_WRDSF_NOVAR |
1626 MU_WRDSF_WS |
1627 MU_WRDSF_NOCMD)) {
1628 result = 1;
1629 } else {
1630 size_t i;
1631
1632 for (i = 0; i < ws.ws_wordc; i++) {
1633 char *p = strchr(ws.ws_wordv[i], '=');
1634 char **slot;
1635 int rc;
1636
1637 if (!p) {
1638 result = 1;
1639 break;
1640 }
1641 *p++ = 0;
1642 mu_rtrim_class(ws.ws_wordv[i], MU_CTYPE_BLANK);
1643 mu_ltrim_class(p, MU_CTYPE_BLANK);
1644
1645 rc = mu_assoc_install_ref(a, ws.ws_wordv[i], &slot);
1646 if (rc == ENOMEM)
1647 mu_alloc_die ();
1648 else if (rc) {
1649 result = 1;
1650 break;
1651 } else
1652 result = 0;
1653 *slot = mu_strdup(p);
1654 }
1655 }
1656
1657 mu_wordsplit_free(&ws);
1658 if (result)
1659 mu_assoc_destroy (&a);
1660 else
1661 *pa = a;
1662 return result;
1663 }
1664
1665 static int
pubkey_validate(mu_assoc_t a,struct dkim_signature const * sig)1666 pubkey_validate(mu_assoc_t a, struct dkim_signature const *sig)
1667 {
1668 char *s;
1669 size_t n;
1670
1671 if ((s = mu_assoc_get(a, "v")) != NULL &&
1672 strcmp(s, DKIM_KEYRECORD_VERSION))
1673 return DKIM_EXPL_KEY_SYNTAX;
1674
1675 if ((s = mu_assoc_get(a, "p")) == NULL)
1676 return DKIM_EXPL_KEY_SYNTAX;
1677
1678 if (s[0] == 0)
1679 return DKIM_EXPL_KEY_REVOKED;
1680
1681 n = strcspn(sig->a, "-");
1682 if ((s = mu_assoc_get(a, "k")) != NULL &&
1683 !(n == strlen(s) && memcmp(s, sig->a, n) == 0))
1684 return DKIM_EXPL_BAD_ALGORITHM;
1685
1686 if ((s = mu_assoc_get(a, "h")) != NULL &&
1687 !dkim_header_list_match(s, sig->a + n + 1))
1688 return DKIM_EXPL_BAD_ALGORITHM;
1689 return DKIM_EXPL_OK;
1690 }
1691
1692 static int
dkim_sig_key_verify(mu_message_t msg,struct dkim_signature * sig,struct rsa_public_key * pub)1693 dkim_sig_key_verify(mu_message_t msg, struct dkim_signature *sig,
1694 struct rsa_public_key *pub)
1695 {
1696 struct sha256_ctx ctx;
1697 mpz_t bs;
1698 int rc;
1699 struct nettle_buffer buffer;
1700 size_t length;
1701 mu_header_t hdr;
1702 char const *sigstr;
1703
1704 rc = mu_message_get_header(msg, &hdr);
1705 if (rc) {
1706 mu_diag_funcall(MU_DIAG_ERROR,
1707 "mu_message_get_header", NULL, rc);
1708 return DKIM_EXPL_INTERNAL_ERROR;
1709 }
1710 rc = mu_header_sget_value(hdr, DKIM_SIGNATURE_HEADER, &sigstr);
1711 if (rc) {
1712 mu_diag_funcall(MU_DIAG_ERROR,
1713 "mu_header_sget_value",
1714 DKIM_SIGNATURE_HEADER, rc);
1715 return DKIM_EXPL_INTERNAL_ERROR;
1716 }
1717
1718 sha256_init(&ctx);
1719 switch (dkim_hash(msg, sig, sigstr, &ctx)) {
1720 case DKIM_HASH_OK:
1721 break;
1722
1723 case DKIM_HASH_DIFF:
1724 return DKIM_EXPL_BAD_BODY;
1725
1726 case DKIM_HASH_ERR:
1727 return DKIM_EXPL_INTERNAL_ERROR;
1728 }
1729
1730 length = strlen((char*)sig->b);
1731 nettle_buffer_init_realloc(&buffer, NULL, nettle_xrealloc);
1732 nettle_buffer_write(&buffer, length, sig->b);
1733 if (decode_base64(&buffer, 0, &length) != READ_PEM_OK)
1734 return DKIM_EXPL_BAD_BASE64;
1735
1736 nettle_mpz_init_set_str_256_u(bs, length, buffer.contents);
1737 rc = rsa_sha256_verify (pub, &ctx, bs);
1738 nettle_buffer_clear(&buffer);
1739 mpz_clear(bs);
1740
1741 return rc ? DKIM_EXPL_OK : DKIM_EXPL_BAD_SIG;
1742 }
1743
1744 static int
dkim_sig_verify(mu_message_t msg,struct dkim_signature * sig)1745 dkim_sig_verify(mu_message_t msg, struct dkim_signature *sig)
1746 {
1747 char **dnsrec;
1748 int i;
1749 int result;
1750
1751 /* Get the DKIM DNS record */
1752 switch (dkim_lookup(sig->d, sig->s, &dnsrec)) {
1753 case dns_success:
1754 break;
1755
1756 case dns_not_found:
1757 return DKIM_EXPL_DNS_NOTFOUND;
1758
1759 default:
1760 return DKIM_EXPL_DNS_UNAVAIL;
1761 }
1762
1763 for (i = 0; dnsrec[i]; i++) {
1764 mu_assoc_t a;
1765 struct rsa_public_key pub;
1766 int rc;
1767
1768 if (dnsrec_parse(dnsrec[i], &a))
1769 continue;
1770
1771 if ((rc = pubkey_validate(a, sig)) != DKIM_EXPL_OK) {
1772 result = rc;
1773 } else if (pubkey_from_base64(&pub, mu_assoc_get(a, "p"))
1774 != READ_PEM_OK) {
1775 result = DKIM_EXPL_KEY_SYNTAX;
1776 } else {
1777 result = dkim_sig_key_verify(msg, sig, &pub);
1778 rsa_public_key_clear(&pub);
1779 }
1780 mu_assoc_destroy(&a);
1781
1782 if (result == DKIM_EXPL_OK)
1783 break;
1784 }
1785
1786 for (i = 0; dnsrec[i]; i++)
1787 free(dnsrec[i]);
1788 free(dnsrec);
1789
1790 return result;
1791 }
1792
1793 static void
wselim(char * s)1794 wselim(char *s)
1795 {
1796 char *p = s; /* current destination pointer */
1797 char *q = s; /* q - current source pointer */
1798 while (*q) {
1799 size_t len = strcspn(q, " \t");
1800 if (p != q)
1801 memmove(p, q, len);
1802 p += len;
1803 q += len;
1804 q += strspn(q, " \t");
1805 }
1806 *p = 0;
1807 }
1808
1809 int
mfd_dkim_verify(mu_message_t msg,char ** ret_sig)1810 mfd_dkim_verify(mu_message_t msg, char **ret_sig)
1811 {
1812 mu_header_t hdr;
1813 int rc;
1814 int result = DKIM_EXPL_NO_SIG;
1815 size_t i;
1816
1817 /* Get the DKIM-Signature header from the message */
1818 rc = mu_message_get_header(msg, &hdr);
1819 if (rc) {
1820 mu_diag_funcall(MU_DIAG_ERROR,
1821 "mu_message_get_header", NULL, rc);
1822 return DKIM_EXPL_INTERNAL_ERROR;
1823 }
1824
1825 for (i = 1; result != DKIM_EXPL_OK; i++) {
1826 struct dkim_signature sig;
1827 char *sig_str;
1828
1829 rc = mu_header_aget_value_unfold_n(hdr,
1830 DKIM_SIGNATURE_HEADER,
1831 i,
1832 &sig_str);
1833 if (rc == MU_ERR_NOENT)
1834 break;
1835 else if (rc) {
1836 mu_diag_funcall(MU_DIAG_ERROR,
1837 "mu_header_aget_value_unfold",
1838 NULL, rc);
1839 result = DKIM_EXPL_INTERNAL_ERROR;
1840 break;
1841 }
1842 wselim(sig_str);
1843
1844 /* Parse the DKIM signature */
1845 if (dkim_signature_parse(sig_str, &sig)) {
1846 result = DKIM_EXPL_SIG_SYNTAX;
1847 } else {
1848 /* Validate the signature */
1849 result = dkim_sig_validate(&sig);
1850 if (result == DKIM_EXPL_OK)
1851 result = dkim_sig_verify(msg, &sig);
1852 if (result == DKIM_EXPL_OK && ret_sig) {
1853 *ret_sig = sig_str;
1854 sig_str = NULL;
1855 }
1856 dkim_signature_free(&sig);
1857 }
1858 free(sig_str);
1859 }
1860 return result;
1861 }
1862
1863