DKIM: permit verify of sig blocks that sign other sig blocks. Bug 2014
[exim.git] / src / src / pdkim / pdkim.c
1 /*
2 * PDKIM - a RFC4871 (DKIM) implementation
3 *
4 * Copyright (C) 2009 - 2016 Tom Kistner <tom@duncanthrax.net>
5 * Copyright (C) 2016 Jeremy Harris <jgh@exim.org>
6 *
7 * http://duncanthrax.net/pdkim/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 #include "../exim.h"
25
26
27 #ifndef DISABLE_DKIM /* entire file */
28
29 #ifndef SUPPORT_TLS
30 # error Need SUPPORT_TLS for DKIM
31 #endif
32
33 #include "crypt_ver.h"
34
35 #ifdef RSA_OPENSSL
36 # include <openssl/rsa.h>
37 # include <openssl/ssl.h>
38 # include <openssl/err.h>
39 #elif defined(RSA_GNUTLS)
40 # include <gnutls/gnutls.h>
41 # include <gnutls/x509.h>
42 #endif
43
44 #include "pdkim.h"
45 #include "rsa.h"
46
47 #define PDKIM_SIGNATURE_VERSION "1"
48 #define PDKIM_PUB_RECORD_VERSION US "DKIM1"
49
50 #define PDKIM_MAX_HEADER_LEN 65536
51 #define PDKIM_MAX_HEADERS 512
52 #define PDKIM_MAX_BODY_LINE_LEN 16384
53 #define PDKIM_DNS_TXT_MAX_NAMELEN 1024
54 #define PDKIM_DEFAULT_SIGN_HEADERS "From:Sender:Reply-To:Subject:Date:"\
55 "Message-ID:To:Cc:MIME-Version:Content-Type:"\
56 "Content-Transfer-Encoding:Content-ID:"\
57 "Content-Description:Resent-Date:Resent-From:"\
58 "Resent-Sender:Resent-To:Resent-Cc:"\
59 "Resent-Message-ID:In-Reply-To:References:"\
60 "List-Id:List-Help:List-Unsubscribe:"\
61 "List-Subscribe:List-Post:List-Owner:List-Archive"
62
63 /* -------------------------------------------------------------------------- */
64 struct pdkim_stringlist {
65 uschar * value;
66 int tag;
67 void * next;
68 };
69
70 /* -------------------------------------------------------------------------- */
71 /* A bunch of list constants */
72 const uschar * pdkim_querymethods[] = {
73 US"dns/txt",
74 NULL
75 };
76 const uschar * pdkim_algos[] = {
77 US"rsa-sha256",
78 US"rsa-sha1",
79 NULL
80 };
81 const uschar * pdkim_canons[] = {
82 US"simple",
83 US"relaxed",
84 NULL
85 };
86 const uschar * pdkim_hashes[] = {
87 US"sha256",
88 US"sha1",
89 NULL
90 };
91 const uschar * pdkim_keytypes[] = {
92 US"rsa",
93 NULL
94 };
95
96 typedef struct pdkim_combined_canon_entry {
97 const uschar * str;
98 int canon_headers;
99 int canon_body;
100 } pdkim_combined_canon_entry;
101
102 pdkim_combined_canon_entry pdkim_combined_canons[] = {
103 { US"simple/simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
104 { US"simple/relaxed", PDKIM_CANON_SIMPLE, PDKIM_CANON_RELAXED },
105 { US"relaxed/simple", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
106 { US"relaxed/relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_RELAXED },
107 { US"simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
108 { US"relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
109 { NULL, 0, 0 }
110 };
111
112
113 /* -------------------------------------------------------------------------- */
114
115 const char *
116 pdkim_verify_status_str(int status)
117 {
118 switch(status)
119 {
120 case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE";
121 case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID";
122 case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL";
123 case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS";
124 default: return "PDKIM_VERIFY_UNKNOWN";
125 }
126 }
127
128 const char *
129 pdkim_verify_ext_status_str(int ext_status)
130 {
131 switch(ext_status)
132 {
133 case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
134 case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
135 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
136 case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
137 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
138 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
139 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
140 case PDKIM_VERIFY_INVALID_DKIM_VERSION: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
141 default: return "PDKIM_VERIFY_UNKNOWN";
142 }
143 }
144
145 const char *
146 pdkim_errstr(int status)
147 {
148 switch(status)
149 {
150 case PDKIM_OK: return "OK";
151 case PDKIM_FAIL: return "FAIL";
152 case PDKIM_ERR_RSA_PRIVKEY: return "RSA_PRIVKEY";
153 case PDKIM_ERR_RSA_SIGNING: return "RSA SIGNING";
154 case PDKIM_ERR_LONG_LINE: return "RSA_LONG_LINE";
155 case PDKIM_ERR_BUFFER_TOO_SMALL: return "BUFFER_TOO_SMALL";
156 case PDKIM_SIGN_PRIVKEY_WRAP: return "PRIVKEY_WRAP";
157 case PDKIM_SIGN_PRIVKEY_B64D: return "PRIVKEY_B64D";
158 default: return "(unknown)";
159 }
160 }
161
162
163 /* -------------------------------------------------------------------------- */
164 /* Print debugging functions */
165 static void
166 pdkim_quoteprint(const uschar *data, int len)
167 {
168 int i;
169 for (i = 0; i < len; i++)
170 {
171 const int c = data[i];
172 switch (c)
173 {
174 case ' ' : debug_printf("{SP}"); break;
175 case '\t': debug_printf("{TB}"); break;
176 case '\r': debug_printf("{CR}"); break;
177 case '\n': debug_printf("{LF}"); break;
178 case '{' : debug_printf("{BO}"); break;
179 case '}' : debug_printf("{BC}"); break;
180 default:
181 if ( (c < 32) || (c > 127) )
182 debug_printf("{%02x}", c);
183 else
184 debug_printf("%c", c);
185 break;
186 }
187 }
188 debug_printf("\n");
189 }
190
191 static void
192 pdkim_hexprint(const uschar *data, int len)
193 {
194 int i;
195 for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
196 debug_printf("\n");
197 }
198
199
200
201 static pdkim_stringlist *
202 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
203 {
204 pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
205
206 memset(new_entry, 0, sizeof(pdkim_stringlist));
207 new_entry->value = string_copy(str);
208 if (base) new_entry->next = base;
209 return new_entry;
210 }
211
212
213
214 /* Trim whitespace fore & aft */
215
216 static void
217 pdkim_strtrim(uschar * str)
218 {
219 uschar * p = str;
220 uschar * q = str;
221 while (*p == '\t' || *p == ' ') p++; /* skip whitespace */
222 while (*p) {*q = *p; q++; p++;} /* dump the leading whitespace */
223 *q = '\0';
224 while (q != str && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
225 { /* dump trailing whitespace */
226 *q = '\0';
227 q--;
228 }
229 }
230
231
232
233 /* -------------------------------------------------------------------------- */
234
235 DLLEXPORT void
236 pdkim_free_ctx(pdkim_ctx *ctx)
237 {
238 }
239
240
241 /* -------------------------------------------------------------------------- */
242 /* Matches the name of the passed raw "header" against
243 the passed colon-separated "tick", and invalidates
244 the entry in tick. Returns OK or fail-code */
245 /*XXX might be safer done using a pdkim_stringlist for "tick" */
246
247 static int
248 header_name_match(const uschar * header, uschar * tick)
249 {
250 uschar * hname;
251 uschar * lcopy;
252 uschar * p;
253 uschar * q;
254 uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
255
256 if (!hcolon)
257 return PDKIM_FAIL; /* This isn't a header */
258
259 /* if we had strncmpic() we wouldn't need this copy */
260 hname = string_copyn(header, hcolon-header);
261
262 /* Copy tick-off list locally, so we can punch zeroes into it */
263 p = lcopy = string_copy(tick);
264
265 for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':'))
266 {
267 *q = '\0';
268 if (strcmpic(p, hname) == 0)
269 goto found;
270
271 p = q+1;
272 }
273
274 if (strcmpic(p, hname) == 0)
275 goto found;
276
277 return PDKIM_FAIL;
278
279 found:
280 /* Invalidate header name instance in tick-off list */
281 tick[p-lcopy] = '_';
282 return PDKIM_OK;
283 }
284
285
286 /* -------------------------------------------------------------------------- */
287 /* Performs "relaxed" canonicalization of a header. */
288
289 static uschar *
290 pdkim_relax_header(const uschar * header, int crlf)
291 {
292 BOOL past_field_name = FALSE;
293 BOOL seen_wsp = FALSE;
294 const uschar * p;
295 uschar * relaxed = store_get(Ustrlen(header)+3);
296 uschar * q = relaxed;
297
298 for (p = header; *p; p++)
299 {
300 uschar c = *p;
301 /* Ignore CR & LF */
302 if (c == '\r' || c == '\n')
303 continue;
304 if (c == '\t' || c == ' ')
305 {
306 if (seen_wsp)
307 continue;
308 c = ' '; /* Turns WSP into SP */
309 seen_wsp = TRUE;
310 }
311 else
312 if (!past_field_name && c == ':')
313 {
314 if (seen_wsp) q--; /* This removes WSP before the colon */
315 seen_wsp = TRUE; /* This removes WSP after the colon */
316 past_field_name = TRUE;
317 }
318 else
319 seen_wsp = FALSE;
320
321 /* Lowercase header name */
322 if (!past_field_name) c = tolower(c);
323 *q++ = c;
324 }
325
326 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
327
328 if (crlf) { *q++ = '\r'; *q++ = '\n'; }
329 *q = '\0';
330 return relaxed;
331 }
332
333
334 /* -------------------------------------------------------------------------- */
335 #define PDKIM_QP_ERROR_DECODE -1
336
337 static uschar *
338 pdkim_decode_qp_char(uschar *qp_p, int *c)
339 {
340 uschar *initial_pos = qp_p;
341
342 /* Advance one char */
343 qp_p++;
344
345 /* Check for two hex digits and decode them */
346 if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
347 {
348 /* Do hex conversion */
349 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
350 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
351 return qp_p + 2;
352 }
353
354 /* Illegal char here */
355 *c = PDKIM_QP_ERROR_DECODE;
356 return initial_pos;
357 }
358
359
360 /* -------------------------------------------------------------------------- */
361
362 static uschar *
363 pdkim_decode_qp(uschar * str)
364 {
365 int nchar = 0;
366 uschar * q;
367 uschar * p = str;
368 uschar * n = store_get(Ustrlen(str)+1);
369
370 *n = '\0';
371 q = n;
372 while (*p)
373 {
374 if (*p == '=')
375 {
376 p = pdkim_decode_qp_char(p, &nchar);
377 if (nchar >= 0)
378 {
379 *q++ = nchar;
380 continue;
381 }
382 }
383 else
384 *q++ = *p;
385 p++;
386 }
387 *q = '\0';
388 return n;
389 }
390
391
392 /* -------------------------------------------------------------------------- */
393
394 static void
395 pdkim_decode_base64(uschar *str, blob * b)
396 {
397 int dlen;
398 dlen = b64decode(str, &b->data);
399 if (dlen < 0) b->data = NULL;
400 b->len = dlen;
401 }
402
403 static uschar *
404 pdkim_encode_base64(blob * b)
405 {
406 return b64encode(b->data, b->len);
407 }
408
409
410 /* -------------------------------------------------------------------------- */
411 #define PDKIM_HDR_LIMBO 0
412 #define PDKIM_HDR_TAG 1
413 #define PDKIM_HDR_VALUE 2
414
415 static pdkim_signature *
416 pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
417 {
418 pdkim_signature *sig ;
419 uschar *p, *q;
420 uschar * cur_tag = NULL; int ts = 0, tl = 0;
421 uschar * cur_val = NULL; int vs = 0, vl = 0;
422 BOOL past_hname = FALSE;
423 BOOL in_b_val = FALSE;
424 int where = PDKIM_HDR_LIMBO;
425 int i;
426
427 sig = store_get(sizeof(pdkim_signature));
428 memset(sig, 0, sizeof(pdkim_signature));
429 sig->bodylength = -1;
430
431 /* Set so invalid/missing data error display is accurate */
432 sig->algo = -1;
433 sig->version = 0;
434
435 q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
436
437 for (p = raw_hdr; ; p++)
438 {
439 char c = *p;
440
441 /* Ignore FWS */
442 if (c == '\r' || c == '\n')
443 goto NEXT_CHAR;
444
445 /* Fast-forward through header name */
446 if (!past_hname)
447 {
448 if (c == ':') past_hname = TRUE;
449 goto NEXT_CHAR;
450 }
451
452 if (where == PDKIM_HDR_LIMBO)
453 {
454 /* In limbo, just wait for a tag-char to appear */
455 if (!(c >= 'a' && c <= 'z'))
456 goto NEXT_CHAR;
457
458 where = PDKIM_HDR_TAG;
459 }
460
461 if (where == PDKIM_HDR_TAG)
462 {
463 if (c >= 'a' && c <= 'z')
464 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
465
466 if (c == '=')
467 {
468 cur_tag[tl] = '\0';
469 if (Ustrcmp(cur_tag, "b") == 0)
470 {
471 *q++ = '=';
472 in_b_val = TRUE;
473 }
474 where = PDKIM_HDR_VALUE;
475 goto NEXT_CHAR;
476 }
477 }
478
479 if (where == PDKIM_HDR_VALUE)
480 {
481 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
482 goto NEXT_CHAR;
483
484 if (c == ';' || c == '\0')
485 {
486 if (tl && vl)
487 {
488 cur_val[vl] = '\0';
489 pdkim_strtrim(cur_val);
490
491 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
492
493 switch (*cur_tag)
494 {
495 case 'b':
496 if (cur_tag[1] == 'h')
497 pdkim_decode_base64(cur_val, &sig->bodyhash);
498 else
499 pdkim_decode_base64(cur_val, &sig->sigdata);
500 break;
501 case 'v':
502 /* We only support version 1, and that is currently the
503 only version there is. */
504 sig->version =
505 Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
506 break;
507 case 'a':
508 for (i = 0; pdkim_algos[i]; i++)
509 if (Ustrcmp(cur_val, pdkim_algos[i]) == 0)
510 {
511 sig->algo = i;
512 break;
513 }
514 break;
515 case 'c':
516 for (i = 0; pdkim_combined_canons[i].str; i++)
517 if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0)
518 {
519 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
520 sig->canon_body = pdkim_combined_canons[i].canon_body;
521 break;
522 }
523 break;
524 case 'q':
525 for (i = 0; pdkim_querymethods[i]; i++)
526 if (Ustrcmp(cur_val, pdkim_querymethods[i]) == 0)
527 {
528 sig->querymethod = i;
529 break;
530 }
531 break;
532 case 's':
533 sig->selector = string_copy(cur_val); break;
534 case 'd':
535 sig->domain = string_copy(cur_val); break;
536 case 'i':
537 sig->identity = pdkim_decode_qp(cur_val); break;
538 case 't':
539 sig->created = strtoul(CS cur_val, NULL, 10); break;
540 case 'x':
541 sig->expires = strtoul(CS cur_val, NULL, 10); break;
542 case 'l':
543 sig->bodylength = strtol(CS cur_val, NULL, 10); break;
544 case 'h':
545 sig->headernames = string_copy(cur_val); break;
546 case 'z':
547 sig->copiedheaders = pdkim_decode_qp(cur_val); break;
548 default:
549 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
550 break;
551 }
552 }
553 tl = 0;
554 vl = 0;
555 in_b_val = FALSE;
556 where = PDKIM_HDR_LIMBO;
557 }
558 else
559 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
560 }
561
562 NEXT_CHAR:
563 if (c == '\0')
564 break;
565
566 if (!in_b_val)
567 *q++ = c;
568 }
569
570 *q = '\0';
571 /* Chomp raw header. The final newline must not be added to the signature. */
572 while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
573 *q = '\0';
574
575 DEBUG(D_acl)
576 {
577 debug_printf(
578 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
579 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
580 debug_printf(
581 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sigdata.len*8);
582 debug_printf(
583 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
584 }
585
586 exim_sha_init(&sig->body_hash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
587 return sig;
588 }
589
590
591 /* -------------------------------------------------------------------------- */
592
593 static pdkim_pubkey *
594 pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
595 {
596 pdkim_pubkey *pub;
597 const uschar *p;
598 uschar * cur_tag = NULL; int ts = 0, tl = 0;
599 uschar * cur_val = NULL; int vs = 0, vl = 0;
600 int where = PDKIM_HDR_LIMBO;
601
602 pub = store_get(sizeof(pdkim_pubkey));
603 memset(pub, 0, sizeof(pdkim_pubkey));
604
605 for (p = raw_record; ; p++)
606 {
607 uschar c = *p;
608
609 /* Ignore FWS */
610 if (c != '\r' && c != '\n') switch (where)
611 {
612 case PDKIM_HDR_LIMBO: /* In limbo, just wait for a tag-char to appear */
613 if (!(c >= 'a' && c <= 'z'))
614 break;
615 where = PDKIM_HDR_TAG;
616 /*FALLTHROUGH*/
617
618 case PDKIM_HDR_TAG:
619 if (c >= 'a' && c <= 'z')
620 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
621
622 if (c == '=')
623 {
624 cur_tag[tl] = '\0';
625 where = PDKIM_HDR_VALUE;
626 }
627 break;
628
629 case PDKIM_HDR_VALUE:
630 if (c == ';' || c == '\0')
631 {
632 if (tl && vl)
633 {
634 cur_val[vl] = '\0';
635 pdkim_strtrim(cur_val);
636 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
637
638 switch (cur_tag[0])
639 {
640 case 'v':
641 pub->version = string_copy(cur_val); break;
642 case 'h':
643 case 'k':
644 /* This field appears to never be used. Also, unclear why
645 a 'k' (key-type_ would go in this field name. There is a field
646 "keytype", also never used.
647 pub->hashes = string_copy(cur_val);
648 */
649 break;
650 case 'g':
651 pub->granularity = string_copy(cur_val); break;
652 case 'n':
653 pub->notes = pdkim_decode_qp(cur_val); break;
654 case 'p':
655 pdkim_decode_base64(US cur_val, &pub->key); break;
656 case 's':
657 pub->srvtype = string_copy(cur_val); break;
658 case 't':
659 if (Ustrchr(cur_val, 'y') != NULL) pub->testing = 1;
660 if (Ustrchr(cur_val, 's') != NULL) pub->no_subdomaining = 1;
661 break;
662 default:
663 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
664 break;
665 }
666 }
667 tl = 0;
668 vl = 0;
669 where = PDKIM_HDR_LIMBO;
670 }
671 else
672 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
673 break;
674 }
675
676 if (c == '\0') break;
677 }
678
679 /* Set fallback defaults */
680 if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
681 else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0) return NULL;
682
683 if (!pub->granularity) pub->granularity = string_copy(US"*");
684 /*
685 if (!pub->keytype ) pub->keytype = string_copy(US"rsa");
686 */
687 if (!pub->srvtype ) pub->srvtype = string_copy(US"*");
688
689 /* p= is required */
690 if (pub->key.data)
691 return pub;
692
693 return NULL;
694 }
695
696
697 /* -------------------------------------------------------------------------- */
698
699 static int
700 pdkim_update_bodyhash(pdkim_ctx *ctx, const char *data, int len)
701 {
702 pdkim_signature *sig = ctx->sig;
703 /* Cache relaxed version of data */
704 uschar *relaxed_data = NULL;
705 int relaxed_len = 0;
706
707 /* Traverse all signatures, updating their hashes. */
708 while (sig)
709 {
710 /* Defaults to simple canon (no further treatment necessary) */
711 const uschar *canon_data = CUS data;
712 int canon_len = len;
713
714 if (sig->canon_body == PDKIM_CANON_RELAXED)
715 {
716 /* Relax the line if not done already */
717 if (!relaxed_data)
718 {
719 BOOL seen_wsp = FALSE;
720 const char *p;
721 int q = 0;
722
723 /* We want to be able to free this else we allocate
724 for the entire message which could be many MB. Since
725 we don't know what allocations the SHA routines might
726 do, not safe to use store_get()/store_reset(). */
727
728 relaxed_data = store_malloc(len+1);
729
730 for (p = data; *p; p++)
731 {
732 char c = *p;
733 if (c == '\r')
734 {
735 if (q > 0 && relaxed_data[q-1] == ' ')
736 q--;
737 }
738 else if (c == '\t' || c == ' ')
739 {
740 c = ' '; /* Turns WSP into SP */
741 if (seen_wsp)
742 continue;
743 seen_wsp = TRUE;
744 }
745 else
746 seen_wsp = FALSE;
747 relaxed_data[q++] = c;
748 }
749 relaxed_data[q] = '\0';
750 relaxed_len = q;
751 }
752 canon_data = relaxed_data;
753 canon_len = relaxed_len;
754 }
755
756 /* Make sure we don't exceed the to-be-signed body length */
757 if ( sig->bodylength >= 0
758 && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
759 )
760 canon_len = sig->bodylength - sig->signed_body_bytes;
761
762 if (canon_len > 0)
763 {
764 exim_sha_update(&sig->body_hash, CUS canon_data, canon_len);
765 sig->signed_body_bytes += canon_len;
766 DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
767 }
768
769 sig = sig->next;
770 }
771
772 if (relaxed_data) store_free(relaxed_data);
773 return PDKIM_OK;
774 }
775
776
777 /* -------------------------------------------------------------------------- */
778
779 static void
780 pdkim_finish_bodyhash(pdkim_ctx *ctx)
781 {
782 pdkim_signature *sig;
783
784 /* Traverse all signatures */
785 for (sig = ctx->sig; sig; sig = sig->next)
786 { /* Finish hashes */
787 blob bh;
788
789 exim_sha_finish(&sig->body_hash, &bh);
790
791 DEBUG(D_acl)
792 {
793 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
794 "PDKIM [%s] Body hash computed: ",
795 sig->domain, sig->signed_body_bytes, sig->domain);
796 pdkim_hexprint(CUS bh.data, bh.len);
797 }
798
799 /* SIGNING -------------------------------------------------------------- */
800 if (ctx->flags & PDKIM_MODE_SIGN)
801 {
802 sig->bodyhash = bh;
803
804 /* If bodylength limit is set, and we have received less bytes
805 than the requested amount, effectively remove the limit tag. */
806 if (sig->signed_body_bytes < sig->bodylength)
807 sig->bodylength = -1;
808 }
809
810 /* VERIFICATION --------------------------------------------------------- */
811 else
812 {
813 /* Compare bodyhash */
814 if (memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
815 {
816 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
817 }
818 else
819 {
820 DEBUG(D_acl)
821 {
822 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain);
823 pdkim_hexprint(sig->bodyhash.data,
824 exim_sha_hashlen(&sig->body_hash));
825 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
826 }
827 sig->verify_status = PDKIM_VERIFY_FAIL;
828 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
829 }
830 }
831 }
832 }
833
834
835
836 static int
837 pdkim_body_complete(pdkim_ctx * ctx)
838 {
839 pdkim_signature * sig = ctx->sig; /*XXX assumes only one sig */
840
841 /* In simple body mode, if any empty lines were buffered,
842 replace with one. rfc 4871 3.4.3 */
843 /*XXX checking the signed-body-bytes is a gross hack; I think
844 it indicates that all linebreaks should be buffered, including
845 the one terminating a text line */
846
847 if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
848 && sig->signed_body_bytes == 0
849 && ctx->num_buffered_crlf > 0
850 )
851 pdkim_update_bodyhash(ctx, "\r\n", 2);
852
853 ctx->flags |= PDKIM_SEEN_EOD;
854 ctx->linebuf_offset = 0;
855 return PDKIM_OK;
856 }
857
858
859
860 /* -------------------------------------------------------------------------- */
861 /* Call from pdkim_feed below for processing complete body lines */
862
863 static int
864 pdkim_bodyline_complete(pdkim_ctx *ctx)
865 {
866 char *p = ctx->linebuf;
867 int n = ctx->linebuf_offset;
868 pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
869
870 /* Ignore extra data if we've seen the end-of-data marker */
871 if (ctx->flags & PDKIM_SEEN_EOD) goto BAIL;
872
873 /* We've always got one extra byte to stuff a zero ... */
874 ctx->linebuf[ctx->linebuf_offset] = '\0';
875
876 /* Terminate on EOD marker */
877 if (ctx->flags & PDKIM_DOT_TERM)
878 {
879 if (memcmp(p, ".\r\n", 3) == 0)
880 return pdkim_body_complete(ctx);
881
882 /* Unstuff dots */
883 if (memcmp(p, "..", 2) == 0)
884 {
885 p++;
886 n--;
887 }
888 }
889
890 /* Empty lines need to be buffered until we find a non-empty line */
891 if (memcmp(p, "\r\n", 2) == 0)
892 {
893 ctx->num_buffered_crlf++;
894 goto BAIL;
895 }
896
897 if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
898 {
899 /* Lines with just spaces need to be buffered too */
900 char *check = p;
901 while (memcmp(check, "\r\n", 2) != 0)
902 {
903 char c = *check;
904
905 if (c != '\t' && c != ' ')
906 goto PROCESS;
907 check++;
908 }
909
910 ctx->num_buffered_crlf++;
911 goto BAIL;
912 }
913
914 PROCESS:
915 /* At this point, we have a non-empty line, so release the buffered ones. */
916 while (ctx->num_buffered_crlf)
917 {
918 pdkim_update_bodyhash(ctx, "\r\n", 2);
919 ctx->num_buffered_crlf--;
920 }
921
922 pdkim_update_bodyhash(ctx, p, n);
923
924 BAIL:
925 ctx->linebuf_offset = 0;
926 return PDKIM_OK;
927 }
928
929
930 /* -------------------------------------------------------------------------- */
931 /* Callback from pdkim_feed below for processing complete headers */
932 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
933
934 static int
935 pdkim_header_complete(pdkim_ctx *ctx)
936 {
937 /* Special case: The last header can have an extra \r appended */
938 if ( (ctx->cur_header_len > 1) &&
939 (ctx->cur_header[(ctx->cur_header_len)-1] == '\r') )
940 --ctx->cur_header_len;
941 ctx->cur_header[ctx->cur_header_len] = '\0';
942
943 ctx->num_headers++;
944 if (ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
945
946 /* SIGNING -------------------------------------------------------------- */
947 if (ctx->flags & PDKIM_MODE_SIGN)
948 {
949 pdkim_signature *sig;
950
951 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
952
953 /* Add header to the signed headers list (in reverse order) */
954 sig->headers = pdkim_prepend_stringlist(sig->headers,
955 ctx->cur_header);
956 }
957
958 /* VERIFICATION ----------------------------------------------------------- */
959 /* DKIM-Signature: headers are added to the verification list */
960 else
961 {
962 DEBUG(D_acl)
963 {
964 debug_printf("PDKIM >> raw hdr: ");
965 pdkim_quoteprint(CUS ctx->cur_header, Ustrlen(ctx->cur_header));
966 }
967 if (strncasecmp(CCS ctx->cur_header,
968 DKIM_SIGNATURE_HEADERNAME,
969 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
970 {
971 pdkim_signature *new_sig;
972
973 /* Create and chain new signature block */
974 DEBUG(D_acl) debug_printf(
975 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
976
977 if ((new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header)))
978 {
979 pdkim_signature *last_sig = ctx->sig;
980 if (!last_sig)
981 ctx->sig = new_sig;
982 else
983 {
984 while (last_sig->next) last_sig = last_sig->next;
985 last_sig->next = new_sig;
986 }
987 }
988 else
989 DEBUG(D_acl) debug_printf(
990 "Error while parsing signature header\n"
991 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
992 }
993
994 /* all headers are stored for signature verification */
995 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header);
996 }
997
998 BAIL:
999 *ctx->cur_header = '\0';
1000 ctx->cur_header_len = 0; /* leave buffer for reuse */
1001 return PDKIM_OK;
1002 }
1003
1004
1005
1006 /* -------------------------------------------------------------------------- */
1007 #define HEADER_BUFFER_FRAG_SIZE 256
1008
1009 DLLEXPORT int
1010 pdkim_feed(pdkim_ctx *ctx, char *data, int len)
1011 {
1012 int p;
1013
1014 /* Alternate EOD signal, used in non-dotstuffing mode */
1015 if (!data)
1016 pdkim_body_complete(ctx);
1017
1018 else for (p = 0; p<len; p++)
1019 {
1020 uschar c = data[p];
1021
1022 if (ctx->flags & PDKIM_PAST_HDRS)
1023 {
1024 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1025 {
1026 ctx->linebuf[ctx->linebuf_offset++] = '\r';
1027 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1028 return PDKIM_ERR_LONG_LINE;
1029 }
1030
1031 /* Processing body byte */
1032 ctx->linebuf[ctx->linebuf_offset++] = c;
1033 if (c == '\r')
1034 ctx->flags |= PDKIM_SEEN_CR;
1035 else if (c == '\n')
1036 {
1037 int rc;
1038 ctx->flags &= ~PDKIM_SEEN_CR;
1039 if ((rc = pdkim_bodyline_complete(ctx)) != PDKIM_OK)
1040 return rc;
1041 }
1042
1043 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1044 return PDKIM_ERR_LONG_LINE;
1045 }
1046 else
1047 {
1048 /* Processing header byte */
1049 if (c == '\r')
1050 ctx->flags |= PDKIM_SEEN_CR;
1051 else if (c == '\n')
1052 {
1053 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1054 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1055 &ctx->cur_header_len, CUS "\r", 1);
1056
1057 if (ctx->flags & PDKIM_SEEN_LF)
1058 {
1059 int rc = pdkim_header_complete(ctx); /* Seen last header line */
1060 if (rc != PDKIM_OK) return rc;
1061
1062 ctx->flags = ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR) | PDKIM_PAST_HDRS;
1063 DEBUG(D_acl) debug_printf(
1064 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n");
1065 continue;
1066 }
1067 else
1068 ctx->flags = ctx->flags & ~PDKIM_SEEN_CR | PDKIM_SEEN_LF;
1069 }
1070 else if (ctx->flags & PDKIM_SEEN_LF)
1071 {
1072 if (!(c == '\t' || c == ' '))
1073 {
1074 int rc = pdkim_header_complete(ctx); /* End of header */
1075 if (rc != PDKIM_OK) return rc;
1076 }
1077 ctx->flags &= ~PDKIM_SEEN_LF;
1078 }
1079
1080 if (ctx->cur_header_len < PDKIM_MAX_HEADER_LEN)
1081 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1082 &ctx->cur_header_len, CUS &data[p], 1);
1083 }
1084 }
1085 return PDKIM_OK;
1086 }
1087
1088
1089
1090 /* Extend a grwong header with a continuation-linebreak */
1091 static uschar *
1092 pdkim_hdr_cont(uschar * str, int * size, int * ptr, int * col)
1093 {
1094 *col = 1;
1095 return string_catn(str, size, ptr, US"\r\n\t", 3);
1096 }
1097
1098
1099
1100 /*
1101 * RFC 5322 specifies that header line length SHOULD be no more than 78
1102 * lets make it so!
1103 * pdkim_headcat
1104 *
1105 * returns uschar * (not nul-terminated)
1106 *
1107 * col: this int holds and receives column number (octets since last '\n')
1108 * str: partial string to append to
1109 * size: current buffer size for str
1110 * ptr: current tail-pointer for str
1111 * pad: padding, split line or space after before or after eg: ";"
1112 * intro: - must join to payload eg "h=", usually the tag name
1113 * payload: eg base64 data - long data can be split arbitrarily.
1114 *
1115 * this code doesn't fold the header in some of the places that RFC4871
1116 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1117 * pairs and inside long values. it also always spaces or breaks after the
1118 * "pad"
1119 *
1120 * no guarantees are made for output given out-of range input. like tag
1121 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1122 */
1123
1124 static uschar *
1125 pdkim_headcat(int * col, uschar * str, int * size, int * ptr,
1126 const uschar * pad, const uschar * intro, const uschar * payload)
1127 {
1128 size_t l;
1129
1130 if (pad)
1131 {
1132 l = Ustrlen(pad);
1133 if (*col + l > 78)
1134 str = pdkim_hdr_cont(str, size, ptr, col);
1135 str = string_catn(str, size, ptr, pad, l);
1136 *col += l;
1137 }
1138
1139 l = (pad?1:0) + (intro?Ustrlen(intro):0);
1140
1141 if (*col + l > 78)
1142 { /*can't fit intro - start a new line to make room.*/
1143 str = pdkim_hdr_cont(str, size, ptr, col);
1144 l = intro?Ustrlen(intro):0;
1145 }
1146
1147 l += payload ? Ustrlen(payload):0 ;
1148
1149 while (l>77)
1150 { /* this fragment will not fit on a single line */
1151 if (pad)
1152 {
1153 str = string_catn(str, size, ptr, US" ", 1);
1154 *col += 1;
1155 pad = NULL; /* only want this once */
1156 l--;
1157 }
1158
1159 if (intro)
1160 {
1161 size_t sl = Ustrlen(intro);
1162
1163 str = string_catn(str, size, ptr, intro, sl);
1164 *col += sl;
1165 l -= sl;
1166 intro = NULL; /* only want this once */
1167 }
1168
1169 if (payload)
1170 {
1171 size_t sl = Ustrlen(payload);
1172 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1173
1174 str = string_catn(str, size, ptr, payload, chomp);
1175 *col += chomp;
1176 payload += chomp;
1177 l -= chomp-1;
1178 }
1179
1180 /* the while precondition tells us it didn't fit. */
1181 str = pdkim_hdr_cont(str, size, ptr, col);
1182 }
1183
1184 if (*col + l > 78)
1185 {
1186 str = pdkim_hdr_cont(str, size, ptr, col);
1187 pad = NULL;
1188 }
1189
1190 if (pad)
1191 {
1192 str = string_catn(str, size, ptr, US" ", 1);
1193 *col += 1;
1194 pad = NULL;
1195 }
1196
1197 if (intro)
1198 {
1199 size_t sl = Ustrlen(intro);
1200
1201 str = string_catn(str, size, ptr, intro, sl);
1202 *col += sl;
1203 l -= sl;
1204 intro = NULL;
1205 }
1206
1207 if (payload)
1208 {
1209 size_t sl = Ustrlen(payload);
1210
1211 str = string_catn(str, size, ptr, payload, sl);
1212 *col += sl;
1213 }
1214
1215 return str;
1216 }
1217
1218
1219 /* -------------------------------------------------------------------------- */
1220
1221 static uschar *
1222 pdkim_create_header(pdkim_signature *sig, BOOL final)
1223 {
1224 uschar * base64_bh;
1225 uschar * base64_b;
1226 int col = 0;
1227 uschar * hdr; int hdr_size = 0, hdr_len = 0;
1228 uschar * canon_all; int can_size = 0, can_len = 0;
1229
1230 canon_all = string_cat (NULL, &can_size, &can_len,
1231 pdkim_canons[sig->canon_headers]);
1232 canon_all = string_catn(canon_all, &can_size, &can_len, US"/", 1);
1233 canon_all = string_cat (canon_all, &can_size, &can_len,
1234 pdkim_canons[sig->canon_body]);
1235 canon_all[can_len] = '\0';
1236
1237 hdr = string_cat(NULL, &hdr_size, &hdr_len,
1238 US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1239 col = hdr_len;
1240
1241 /* Required and static bits */
1242 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
1243 pdkim_algos[sig->algo]);
1244 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
1245 pdkim_querymethods[sig->querymethod]);
1246 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=",
1247 canon_all);
1248 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"d=",
1249 sig->domain);
1250 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=",
1251 sig->selector);
1252
1253 /* list of header names can be split between items. */
1254 {
1255 uschar * n = string_copy(sig->headernames);
1256 uschar * i = US"h=";
1257 uschar * s = US";";
1258
1259 while (*n)
1260 {
1261 uschar * c = Ustrchr(n, ':');
1262
1263 if (c) *c ='\0';
1264
1265 if (!i)
1266 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, NULL, US":");
1267
1268 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, s, i, n);
1269
1270 if (!c)
1271 break;
1272
1273 n = c+1;
1274 s = NULL;
1275 i = NULL;
1276 }
1277 }
1278
1279 base64_bh = pdkim_encode_base64(&sig->bodyhash);
1280 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"bh=", base64_bh);
1281
1282 /* Optional bits */
1283 if (sig->identity)
1284 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"i=", sig->identity);
1285
1286 if (sig->created > 0)
1287 {
1288 uschar minibuf[20];
1289
1290 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1291 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"t=", minibuf);
1292 }
1293
1294 if (sig->expires > 0)
1295 {
1296 uschar minibuf[20];
1297
1298 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1299 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"x=", minibuf);
1300 }
1301
1302 if (sig->bodylength >= 0)
1303 {
1304 uschar minibuf[20];
1305
1306 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1307 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"l=", minibuf);
1308 }
1309
1310 /* Preliminary or final version? */
1311 base64_b = final ? pdkim_encode_base64(&sig->sigdata) : US"";
1312 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
1313
1314 /* add trailing semicolon: I'm not sure if this is actually needed */
1315 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
1316
1317 hdr[hdr_len] = '\0';
1318 return hdr;
1319 }
1320
1321
1322 /* -------------------------------------------------------------------------- */
1323
1324 static pdkim_pubkey *
1325 pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx)
1326 {
1327 uschar * dns_txt_name, * dns_txt_reply;
1328 pdkim_pubkey * p;
1329 const uschar * errstr;
1330
1331 /* Fetch public key for signing domain, from DNS */
1332
1333 dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1334
1335 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1336 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1337
1338 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1339 || dns_txt_reply[0] == '\0'
1340 )
1341 {
1342 sig->verify_status = PDKIM_VERIFY_INVALID;
1343 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1344 return NULL;
1345 }
1346
1347 DEBUG(D_acl)
1348 {
1349 debug_printf(
1350 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1351 " Raw record: ");
1352 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1353 }
1354
1355 if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1356 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1357 )
1358 {
1359 sig->verify_status = PDKIM_VERIFY_INVALID;
1360 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1361
1362 DEBUG(D_acl)
1363 {
1364 if (p)
1365 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1366 else
1367 debug_printf(" Error while parsing public key record\n");
1368 debug_printf(
1369 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1370 }
1371 return NULL;
1372 }
1373
1374 DEBUG(D_acl) debug_printf(
1375 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1376
1377 /* Import public key */
1378 if ((errstr = exim_rsa_verify_init(&p->key, vctx)))
1379 {
1380 DEBUG(D_acl) debug_printf("verify_init: %s\n", errstr);
1381 sig->verify_status = PDKIM_VERIFY_INVALID;
1382 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1383 return NULL;
1384 }
1385
1386 return p;
1387 }
1388
1389
1390 /* -------------------------------------------------------------------------- */
1391
1392 DLLEXPORT int
1393 pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatures)
1394 {
1395 pdkim_signature *sig = ctx->sig;
1396
1397 /* Check if we must still flush a (partial) header. If that is the
1398 case, the message has no body, and we must compute a body hash
1399 out of '<CR><LF>' */
1400 if (ctx->cur_header && ctx->cur_header_len)
1401 {
1402 int rc = pdkim_header_complete(ctx);
1403 if (rc != PDKIM_OK) return rc;
1404 pdkim_update_bodyhash(ctx, "\r\n", 2);
1405 }
1406 else
1407 DEBUG(D_acl) debug_printf(
1408 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1409
1410 /* Build (and/or evaluate) body hash */
1411 pdkim_finish_bodyhash(ctx);
1412
1413 while (sig)
1414 {
1415 BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
1416 hctx hhash_ctx;
1417 uschar * sig_hdr = US"";
1418 blob hhash;
1419 blob hdata;
1420 int hdata_alloc = 0;
1421
1422 hdata.data = NULL;
1423 hdata.len = 0;
1424
1425 exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256);
1426
1427 DEBUG(D_acl) debug_printf(
1428 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>\n");
1429
1430 /* SIGNING ---------------------------------------------------------------- */
1431 /* When signing, walk through our header list and add them to the hash. As we
1432 go, construct a list of the header's names to use for the h= parameter.
1433 Then append to that list any remaining header names for which there was no
1434 header to sign. */
1435
1436 if (ctx->flags & PDKIM_MODE_SIGN)
1437 {
1438 uschar * headernames = NULL; /* Collected signed header names */
1439 int hs = 0, hl = 0;
1440 pdkim_stringlist *p;
1441 const uschar * l;
1442 uschar * s;
1443 int sep = 0;
1444
1445 for (p = sig->headers; p; p = p->next)
1446 if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
1447 {
1448 uschar * rh;
1449 /* Collect header names (Note: colon presence is guaranteed here) */
1450 uschar * q = Ustrchr(p->value, ':');
1451
1452 headernames = string_catn(headernames, &hs, &hl,
1453 p->value, (q - US p->value) + (p->next ? 1 : 0));
1454
1455 rh = sig->canon_headers == PDKIM_CANON_RELAXED
1456 ? pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
1457 : string_copy(CUS p->value); /* just copy it for simple canon */
1458
1459 /* Feed header to the hash algorithm */
1460 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1461
1462 /* Remember headers block for signing (when the library cannot do incremental) */
1463 (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
1464
1465 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1466 }
1467
1468 l = sig->sign_headers;
1469 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1470 if (*s != '_')
1471 { /*SSS string_append_listele() */
1472 if (hl > 0 && headernames[hl-1] != ':')
1473 headernames = string_catn(headernames, &hs, &hl, US":", 1);
1474
1475 headernames = string_cat(headernames, &hs, &hl, s);
1476 }
1477 headernames[hl] = '\0';
1478
1479 /* Copy headernames to signature struct */
1480 sig->headernames = headernames;
1481
1482 /* Create signature header with b= omitted */
1483 sig_hdr = pdkim_create_header(sig, FALSE);
1484 }
1485
1486 /* VERIFICATION ----------------------------------------------------------- */
1487 /* When verifying, walk through the header name list in the h= parameter and
1488 add the headers to the hash in that order. */
1489 else
1490 {
1491 uschar * p = sig->headernames;
1492 uschar * q;
1493 pdkim_stringlist * hdrs;
1494
1495 if (p)
1496 {
1497 /* clear tags */
1498 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1499 hdrs->tag = 0;
1500
1501 p = string_copy(p);
1502 while(1)
1503 {
1504 if ((q = Ustrchr(p, ':')))
1505 *q = '\0';
1506
1507 /*XXX walk the list of headers in same order as received. */
1508 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1509 if ( hdrs->tag == 0
1510 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
1511 && (hdrs->value)[Ustrlen(p)] == ':'
1512 )
1513 {
1514 /* cook header for relaxed canon, or just copy it for simple */
1515
1516 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1517 ? pdkim_relax_header(hdrs->value, 1)
1518 : string_copy(CUS hdrs->value);
1519
1520 /* Feed header to the hash algorithm */
1521 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1522
1523 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1524 hdrs->tag = 1;
1525 break;
1526 }
1527
1528 if (!q) break;
1529 p = q+1;
1530 }
1531
1532 sig_hdr = string_copy(sig->rawsig_no_b_val);
1533 }
1534 }
1535
1536 DEBUG(D_acl) debug_printf(
1537 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1538
1539 /* Relax header if necessary */
1540 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1541 sig_hdr = pdkim_relax_header(sig_hdr, 0);
1542
1543 DEBUG(D_acl)
1544 {
1545 debug_printf(
1546 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1547 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1548 debug_printf(
1549 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1550 }
1551
1552 /* Finalize header hash */
1553 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1554 exim_sha_finish(&hhash_ctx, &hhash);
1555
1556 DEBUG(D_acl)
1557 {
1558 debug_printf("PDKIM [%s] Header hash computed: ", sig->domain);
1559 pdkim_hexprint(hhash.data, hhash.len);
1560 }
1561
1562 /* Remember headers block for signing (when the library cannot do incremental) */
1563 if (ctx->flags & PDKIM_MODE_SIGN)
1564 (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
1565
1566 /* SIGNING ---------------------------------------------------------------- */
1567 if (ctx->flags & PDKIM_MODE_SIGN)
1568 {
1569 es_ctx sctx;
1570 const uschar * errstr;
1571
1572 /* Import private key */
1573 if ((errstr = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
1574 {
1575 DEBUG(D_acl) debug_printf("signing_init: %s\n", errstr);
1576 return PDKIM_ERR_RSA_PRIVKEY;
1577 }
1578
1579 /* Do signing. With OpenSSL we are signing the hash of headers just
1580 calculated, with GnuTLS we have to sign an entire block of headers
1581 (due to available interfaces) and it recalculates the hash internally. */
1582
1583 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1584 hdata = hhash;
1585 #endif
1586
1587 if ((errstr = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sigdata)))
1588 {
1589 DEBUG(D_acl) debug_printf("signing: %s\n", errstr);
1590 return PDKIM_ERR_RSA_SIGNING;
1591 }
1592
1593 DEBUG(D_acl)
1594 {
1595 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1596 pdkim_hexprint(sig->sigdata.data, sig->sigdata.len);
1597 }
1598
1599 sig->signature_header = pdkim_create_header(sig, TRUE);
1600 }
1601
1602 /* VERIFICATION ----------------------------------------------------------- */
1603 else
1604 {
1605 ev_ctx vctx;
1606 const uschar * errstr;
1607 pdkim_pubkey * p;
1608
1609 /* Make sure we have all required signature tags */
1610 if (!( sig->domain && *sig->domain
1611 && sig->selector && *sig->selector
1612 && sig->headernames && *sig->headernames
1613 && sig->bodyhash.data
1614 && sig->sigdata.data
1615 && sig->algo > -1
1616 && sig->version
1617 ) )
1618 {
1619 sig->verify_status = PDKIM_VERIFY_INVALID;
1620 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1621
1622 DEBUG(D_acl) debug_printf(
1623 " Error in DKIM-Signature header: tags missing or invalid\n"
1624 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1625 goto NEXT_VERIFY;
1626 }
1627
1628 /* Make sure sig uses supported DKIM version (only v1) */
1629 if (sig->version != 1)
1630 {
1631 sig->verify_status = PDKIM_VERIFY_INVALID;
1632 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1633
1634 DEBUG(D_acl) debug_printf(
1635 " Error in DKIM-Signature header: unsupported DKIM version\n"
1636 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1637 goto NEXT_VERIFY;
1638 }
1639
1640 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx)))
1641 goto NEXT_VERIFY;
1642
1643 /* Check the signature */
1644 if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sigdata)))
1645 {
1646 DEBUG(D_acl) debug_printf("headers verify: %s\n", errstr);
1647 sig->verify_status = PDKIM_VERIFY_FAIL;
1648 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1649 goto NEXT_VERIFY;
1650 }
1651
1652
1653 /* We have a winner! (if bodyhash was correct earlier) */
1654 if (sig->verify_status == PDKIM_VERIFY_NONE)
1655 sig->verify_status = PDKIM_VERIFY_PASS;
1656
1657 NEXT_VERIFY:
1658
1659 DEBUG(D_acl)
1660 {
1661 debug_printf("PDKIM [%s] signature status: %s",
1662 sig->domain, pdkim_verify_status_str(sig->verify_status));
1663 if (sig->verify_ext_status > 0)
1664 debug_printf(" (%s)\n",
1665 pdkim_verify_ext_status_str(sig->verify_ext_status));
1666 else
1667 debug_printf("\n");
1668 }
1669 }
1670
1671 sig = sig->next;
1672 }
1673
1674 /* If requested, set return pointer to signature(s) */
1675 if (return_signatures)
1676 *return_signatures = ctx->sig;
1677
1678 return PDKIM_OK;
1679 }
1680
1681
1682 /* -------------------------------------------------------------------------- */
1683
1684 DLLEXPORT pdkim_ctx *
1685 pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
1686 {
1687 pdkim_ctx * ctx;
1688
1689 ctx = store_get(sizeof(pdkim_ctx));
1690 memset(ctx, 0, sizeof(pdkim_ctx));
1691
1692 if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1693 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1694 ctx->dns_txt_callback = dns_txt_callback;
1695
1696 return ctx;
1697 }
1698
1699
1700 /* -------------------------------------------------------------------------- */
1701
1702 DLLEXPORT pdkim_ctx *
1703 pdkim_init_sign(char * domain, char * selector, char * rsa_privkey, int algo,
1704 BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *))
1705 {
1706 pdkim_ctx * ctx;
1707 pdkim_signature * sig;
1708
1709 if (!domain || !selector || !rsa_privkey)
1710 return NULL;
1711
1712 ctx = store_get(sizeof(pdkim_ctx) + PDKIM_MAX_BODY_LINE_LEN + sizeof(pdkim_signature));
1713 memset(ctx, 0, sizeof(pdkim_ctx));
1714
1715 ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1716 ctx->linebuf = CS (ctx+1);
1717
1718 DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
1719
1720 sig = (pdkim_signature *)(ctx->linebuf + PDKIM_MAX_BODY_LINE_LEN);
1721 memset(sig, 0, sizeof(pdkim_signature));
1722
1723 sig->bodylength = -1;
1724 ctx->sig = sig;
1725
1726 sig->domain = string_copy(US domain);
1727 sig->selector = string_copy(US selector);
1728 sig->rsa_privkey = string_copy(US rsa_privkey);
1729 sig->algo = algo;
1730
1731 exim_sha_init(&sig->body_hash, algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
1732
1733 DEBUG(D_acl)
1734 {
1735 pdkim_signature s = *sig;
1736 ev_ctx vctx;
1737
1738 debug_printf("PDKIM (checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1739 if (!pdkim_key_from_dns(ctx, &s, &vctx))
1740 debug_printf("WARNING: bad dkim key in dns\n");
1741 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1742 }
1743
1744 return ctx;
1745 }
1746
1747
1748 /* -------------------------------------------------------------------------- */
1749
1750 DLLEXPORT int
1751 pdkim_set_optional(pdkim_ctx *ctx,
1752 char *sign_headers,
1753 char *identity,
1754 int canon_headers,
1755 int canon_body,
1756 long bodylength,
1757 unsigned long created,
1758 unsigned long expires)
1759 {
1760 pdkim_signature * sig = ctx->sig;
1761
1762 if (identity)
1763 sig->identity = string_copy(US identity);
1764
1765 sig->sign_headers = string_copy(sign_headers
1766 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1767
1768 sig->canon_headers = canon_headers;
1769 sig->canon_body = canon_body;
1770 sig->bodylength = bodylength;
1771 sig->created = created;
1772 sig->expires = expires;
1773
1774 return PDKIM_OK;
1775 }
1776
1777
1778 void
1779 pdkim_init(void)
1780 {
1781 exim_rsa_init();
1782 }
1783
1784
1785
1786 #endif /*DISABLE_DKIM*/