Testsuite: rework timing of time-dependent testcase
[exim.git] / src / src / pdkim / pdkim.c
... / ...
CommitLineData
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/* -------------------------------------------------------------------------- */
64struct pdkim_stringlist {
65 uschar * value;
66 int tag;
67 void * next;
68};
69
70/* -------------------------------------------------------------------------- */
71/* A bunch of list constants */
72const uschar * pdkim_querymethods[] = {
73 US"dns/txt",
74 NULL
75};
76const uschar * pdkim_algos[] = {
77 US"rsa-sha256",
78 US"rsa-sha1",
79 NULL
80};
81const uschar * pdkim_canons[] = {
82 US"simple",
83 US"relaxed",
84 NULL
85};
86const uschar * pdkim_hashes[] = {
87 US"sha256",
88 US"sha1",
89 NULL
90};
91const uschar * pdkim_keytypes[] = {
92 US"rsa",
93 NULL
94};
95
96typedef struct pdkim_combined_canon_entry {
97 const uschar * str;
98 int canon_headers;
99 int canon_body;
100} pdkim_combined_canon_entry;
101
102pdkim_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
115const char *
116pdkim_verify_status_str(int status)
117{
118switch(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
128const char *
129pdkim_verify_ext_status_str(int ext_status)
130{
131switch(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
145const char *
146pdkim_errstr(int status)
147{
148switch(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 */
165static void
166pdkim_quoteprint(const uschar *data, int len)
167{
168int i;
169for (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 }
188debug_printf("\n");
189}
190
191static void
192pdkim_hexprint(const uschar *data, int len)
193{
194int i;
195for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
196debug_printf("\n");
197}
198
199
200
201static pdkim_stringlist *
202pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
203{
204pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
205
206memset(new_entry, 0, sizeof(pdkim_stringlist));
207new_entry->value = string_copy(str);
208if (base) new_entry->next = base;
209return new_entry;
210}
211
212
213
214/* Trim whitespace fore & aft */
215
216static void
217pdkim_strtrim(uschar * str)
218{
219uschar * p = str;
220uschar * q = str;
221while (*p == '\t' || *p == ' ') p++; /* skip whitespace */
222while (*p) {*q = *p; q++; p++;} /* dump the leading whitespace */
223*q = '\0';
224while (q != str && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
225 { /* dump trailing whitespace */
226 *q = '\0';
227 q--;
228 }
229}
230
231
232
233/* -------------------------------------------------------------------------- */
234
235DLLEXPORT void
236pdkim_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
247static int
248header_name_match(const uschar * header, uschar * tick)
249{
250uschar * hname;
251uschar * lcopy;
252uschar * p;
253uschar * q;
254uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
255
256if (!hcolon)
257 return PDKIM_FAIL; /* This isn't a header */
258
259/* if we had strncmpic() we wouldn't need this copy */
260hname = string_copyn(header, hcolon-header);
261
262/* Copy tick-off list locally, so we can punch zeroes into it */
263p = lcopy = string_copy(tick);
264
265for (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
274if (strcmpic(p, hname) == 0)
275 goto found;
276
277return PDKIM_FAIL;
278
279found:
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
289static uschar *
290pdkim_relax_header(const uschar * header, int crlf)
291{
292BOOL past_field_name = FALSE;
293BOOL seen_wsp = FALSE;
294const uschar * p;
295uschar * relaxed = store_get(Ustrlen(header)+3);
296uschar * q = relaxed;
297
298for (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
326if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
327
328if (crlf) { *q++ = '\r'; *q++ = '\n'; }
329*q = '\0';
330return relaxed;
331}
332
333
334/* -------------------------------------------------------------------------- */
335#define PDKIM_QP_ERROR_DECODE -1
336
337static uschar *
338pdkim_decode_qp_char(uschar *qp_p, int *c)
339{
340uschar *initial_pos = qp_p;
341
342/* Advance one char */
343qp_p++;
344
345/* Check for two hex digits and decode them */
346if (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;
356return initial_pos;
357}
358
359
360/* -------------------------------------------------------------------------- */
361
362static uschar *
363pdkim_decode_qp(uschar * str)
364{
365int nchar = 0;
366uschar * q;
367uschar * p = str;
368uschar * n = store_get(Ustrlen(str)+1);
369
370*n = '\0';
371q = n;
372while (*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';
388return n;
389}
390
391
392/* -------------------------------------------------------------------------- */
393
394static void
395pdkim_decode_base64(uschar *str, blob * b)
396{
397int dlen;
398dlen = b64decode(str, &b->data);
399if (dlen < 0) b->data = NULL;
400b->len = dlen;
401}
402
403static uschar *
404pdkim_encode_base64(blob * b)
405{
406return 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
415static pdkim_signature *
416pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
417{
418pdkim_signature *sig ;
419uschar *p, *q;
420uschar * cur_tag = NULL; int ts = 0, tl = 0;
421uschar * cur_val = NULL; int vs = 0, vl = 0;
422BOOL past_hname = FALSE;
423BOOL in_b_val = FALSE;
424int where = PDKIM_HDR_LIMBO;
425int i;
426
427sig = store_get(sizeof(pdkim_signature));
428memset(sig, 0, sizeof(pdkim_signature));
429sig->bodylength = -1;
430
431/* Set so invalid/missing data error display is accurate */
432sig->algo = -1;
433sig->version = 0;
434
435q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
436
437for (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
562NEXT_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. */
572while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
573 *q = '\0';
574
575DEBUG(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
586exim_sha_init(&sig->body_hash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
587return sig;
588}
589
590
591/* -------------------------------------------------------------------------- */
592
593static pdkim_pubkey *
594pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
595{
596pdkim_pubkey *pub;
597const uschar *p;
598uschar * cur_tag = NULL; int ts = 0, tl = 0;
599uschar * cur_val = NULL; int vs = 0, vl = 0;
600int where = PDKIM_HDR_LIMBO;
601
602pub = store_get(sizeof(pdkim_pubkey));
603memset(pub, 0, sizeof(pdkim_pubkey));
604
605for (p = raw_record; ; p++)
606 {
607 char c = *p;
608
609 /* Ignore FWS */
610 if (c == '\r' || c == '\n')
611 goto NEXT_CHAR;
612
613 if (where == PDKIM_HDR_LIMBO)
614 {
615 /* In limbo, just wait for a tag-char to appear */
616 if (!(c >= 'a' && c <= 'z'))
617 goto NEXT_CHAR;
618
619 where = PDKIM_HDR_TAG;
620 }
621
622 if (where == PDKIM_HDR_TAG)
623 {
624 if (c >= 'a' && c <= 'z')
625 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
626
627 if (c == '=')
628 {
629 cur_tag[tl] = '\0';
630 where = PDKIM_HDR_VALUE;
631 goto NEXT_CHAR;
632 }
633 }
634
635 if (where == PDKIM_HDR_VALUE)
636 {
637 if (c == ';' || c == '\0')
638 {
639 if (tl && vl)
640 {
641 cur_val[vl] = '\0';
642 pdkim_strtrim(cur_val);
643 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
644
645 switch (cur_tag[0])
646 {
647 case 'v':
648 /* This tag isn't evaluated because:
649 - We only support version DKIM1.
650 - Which is the default for this value (set below)
651 - Other versions are currently not specified. */
652 break;
653 case 'h':
654 case 'k':
655 pub->hashes = string_copy(cur_val); break;
656 case 'g':
657 pub->granularity = string_copy(cur_val); break;
658 case 'n':
659 pub->notes = pdkim_decode_qp(cur_val); break;
660 case 'p':
661 pdkim_decode_base64(US cur_val, &pub->key);
662 break;
663 case 's':
664 pub->srvtype = string_copy(cur_val); break;
665 case 't':
666 if (Ustrchr(cur_val, 'y') != NULL) pub->testing = 1;
667 if (Ustrchr(cur_val, 's') != NULL) pub->no_subdomaining = 1;
668 break;
669 default:
670 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
671 break;
672 }
673 }
674 tl = 0;
675 vl = 0;
676 where = PDKIM_HDR_LIMBO;
677 }
678 else
679 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
680 }
681
682NEXT_CHAR:
683 if (c == '\0') break;
684 }
685
686/* Set fallback defaults */
687if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
688if (!pub->granularity) pub->granularity = string_copy(US"*");
689if (!pub->keytype ) pub->keytype = string_copy(US"rsa");
690if (!pub->srvtype ) pub->srvtype = string_copy(US"*");
691
692/* p= is required */
693if (pub->key.data)
694 return pub;
695
696return NULL;
697}
698
699
700/* -------------------------------------------------------------------------- */
701
702static int
703pdkim_update_bodyhash(pdkim_ctx *ctx, const char *data, int len)
704{
705pdkim_signature *sig = ctx->sig;
706/* Cache relaxed version of data */
707uschar *relaxed_data = NULL;
708int relaxed_len = 0;
709
710/* Traverse all signatures, updating their hashes. */
711while (sig)
712 {
713 /* Defaults to simple canon (no further treatment necessary) */
714 const uschar *canon_data = CUS data;
715 int canon_len = len;
716
717 if (sig->canon_body == PDKIM_CANON_RELAXED)
718 {
719 /* Relax the line if not done already */
720 if (!relaxed_data)
721 {
722 BOOL seen_wsp = FALSE;
723 const char *p;
724 int q = 0;
725
726 /* We want to be able to free this else we allocate
727 for the entire message which could be many MB. Since
728 we don't know what allocations the SHA routines might
729 do, not safe to use store_get()/store_reset(). */
730
731 relaxed_data = malloc(len+1);
732
733 for (p = data; *p; p++)
734 {
735 char c = *p;
736 if (c == '\r')
737 {
738 if (q > 0 && relaxed_data[q-1] == ' ')
739 q--;
740 }
741 else if (c == '\t' || c == ' ')
742 {
743 c = ' '; /* Turns WSP into SP */
744 if (seen_wsp)
745 continue;
746 seen_wsp = TRUE;
747 }
748 else
749 seen_wsp = FALSE;
750 relaxed_data[q++] = c;
751 }
752 relaxed_data[q] = '\0';
753 relaxed_len = q;
754 }
755 canon_data = relaxed_data;
756 canon_len = relaxed_len;
757 }
758
759 /* Make sure we don't exceed the to-be-signed body length */
760 if ( sig->bodylength >= 0
761 && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
762 )
763 canon_len = sig->bodylength - sig->signed_body_bytes;
764
765 if (canon_len > 0)
766 {
767 exim_sha_update(&sig->body_hash, CUS canon_data, canon_len);
768 sig->signed_body_bytes += canon_len;
769 DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
770 }
771
772 sig = sig->next;
773 }
774
775if (relaxed_data) free(relaxed_data);
776return PDKIM_OK;
777}
778
779
780/* -------------------------------------------------------------------------- */
781
782static void
783pdkim_finish_bodyhash(pdkim_ctx *ctx)
784{
785pdkim_signature *sig;
786
787/* Traverse all signatures */
788for (sig = ctx->sig; sig; sig = sig->next)
789 { /* Finish hashes */
790 blob bh;
791
792 exim_sha_finish(&sig->body_hash, &bh);
793
794 DEBUG(D_acl)
795 {
796 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
797 "PDKIM [%s] bh computed: ",
798 sig->domain, sig->signed_body_bytes, sig->domain);
799 pdkim_hexprint(CUS bh.data, bh.len);
800 }
801
802 /* SIGNING -------------------------------------------------------------- */
803 if (ctx->flags & PDKIM_MODE_SIGN)
804 {
805 sig->bodyhash = bh;
806
807 /* If bodylength limit is set, and we have received less bytes
808 than the requested amount, effectively remove the limit tag. */
809 if (sig->signed_body_bytes < sig->bodylength)
810 sig->bodylength = -1;
811 }
812
813 /* VERIFICATION --------------------------------------------------------- */
814 else
815 {
816 /* Compare bodyhash */
817 if (memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
818 {
819 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
820 }
821 else
822 {
823 DEBUG(D_acl)
824 {
825 debug_printf("PDKIM [%s] bh signature: ", sig->domain);
826 pdkim_hexprint(sig->bodyhash.data,
827 exim_sha_hashlen(&sig->body_hash));
828 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
829 }
830 sig->verify_status = PDKIM_VERIFY_FAIL;
831 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
832 }
833 }
834 }
835}
836
837
838
839static int
840pdkim_body_complete(pdkim_ctx * ctx)
841{
842pdkim_signature * sig = ctx->sig; /*XXX assumes only one sig */
843
844/* In simple body mode, if any empty lines were buffered,
845replace with one. rfc 4871 3.4.3 */
846/*XXX checking the signed-body-bytes is a gross hack; I think
847it indicates that all linebreaks should be buffered, including
848the one terminating a text line */
849
850if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
851 && sig->signed_body_bytes == 0
852 && ctx->num_buffered_crlf > 0
853 )
854 pdkim_update_bodyhash(ctx, "\r\n", 2);
855
856ctx->flags |= PDKIM_SEEN_EOD;
857ctx->linebuf_offset = 0;
858return PDKIM_OK;
859}
860
861
862
863/* -------------------------------------------------------------------------- */
864/* Call from pdkim_feed below for processing complete body lines */
865
866static int
867pdkim_bodyline_complete(pdkim_ctx *ctx)
868{
869char *p = ctx->linebuf;
870int n = ctx->linebuf_offset;
871pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
872
873/* Ignore extra data if we've seen the end-of-data marker */
874if (ctx->flags & PDKIM_SEEN_EOD) goto BAIL;
875
876/* We've always got one extra byte to stuff a zero ... */
877ctx->linebuf[ctx->linebuf_offset] = '\0';
878
879/* Terminate on EOD marker */
880if (ctx->flags & PDKIM_DOT_TERM)
881 {
882 if ( memcmp(p, ".\r\n", 3) == 0)
883 return pdkim_body_complete(ctx);
884
885 /* Unstuff dots */
886 if (memcmp(p, "..", 2) == 0)
887 {
888 p++;
889 n--;
890 }
891 }
892
893/* Empty lines need to be buffered until we find a non-empty line */
894if (memcmp(p, "\r\n", 2) == 0)
895 {
896 ctx->num_buffered_crlf++;
897 goto BAIL;
898 }
899
900if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
901 {
902 /* Lines with just spaces need to be buffered too */
903 char *check = p;
904 while (memcmp(check, "\r\n", 2) != 0)
905 {
906 char c = *check;
907
908 if (c != '\t' && c != ' ')
909 goto PROCESS;
910 check++;
911 }
912
913 ctx->num_buffered_crlf++;
914 goto BAIL;
915}
916
917PROCESS:
918/* At this point, we have a non-empty line, so release the buffered ones. */
919while (ctx->num_buffered_crlf)
920 {
921 pdkim_update_bodyhash(ctx, "\r\n", 2);
922 ctx->num_buffered_crlf--;
923 }
924
925pdkim_update_bodyhash(ctx, p, n);
926
927BAIL:
928ctx->linebuf_offset = 0;
929return PDKIM_OK;
930}
931
932
933/* -------------------------------------------------------------------------- */
934/* Callback from pdkim_feed below for processing complete headers */
935#define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
936
937static int
938pdkim_header_complete(pdkim_ctx *ctx)
939{
940/* Special case: The last header can have an extra \r appended */
941if ( (ctx->cur_header_len > 1) &&
942 (ctx->cur_header[(ctx->cur_header_len)-1] == '\r') )
943 --ctx->cur_header_len;
944ctx->cur_header[ctx->cur_header_len] = '\0';
945
946ctx->num_headers++;
947if (ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
948
949/* SIGNING -------------------------------------------------------------- */
950if (ctx->flags & PDKIM_MODE_SIGN)
951 {
952 pdkim_signature *sig;
953
954 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
955
956 /* Add header to the signed headers list (in reverse order) */
957 sig->headers = pdkim_prepend_stringlist(sig->headers,
958 ctx->cur_header);
959 }
960
961/* VERIFICATION ----------------------------------------------------------- */
962/* DKIM-Signature: headers are added to the verification list */
963else
964 {
965 if (strncasecmp(CCS ctx->cur_header,
966 DKIM_SIGNATURE_HEADERNAME,
967 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
968 {
969 pdkim_signature *new_sig;
970
971 /* Create and chain new signature block */
972 DEBUG(D_acl) debug_printf(
973 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
974
975 if ((new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header)))
976 {
977 pdkim_signature *last_sig = ctx->sig;
978 if (!last_sig)
979 ctx->sig = new_sig;
980 else
981 {
982 while (last_sig->next) last_sig = last_sig->next;
983 last_sig->next = new_sig;
984 }
985 }
986 else
987 DEBUG(D_acl) debug_printf(
988 "Error while parsing signature header\n"
989 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
990 }
991
992 /* every other header is stored for signature verification */
993 else
994 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header);
995 }
996
997BAIL:
998*ctx->cur_header = '\0';
999ctx->cur_header_len = 0; /* leave buffer for reuse */
1000return PDKIM_OK;
1001}
1002
1003
1004
1005/* -------------------------------------------------------------------------- */
1006#define HEADER_BUFFER_FRAG_SIZE 256
1007
1008DLLEXPORT int
1009pdkim_feed(pdkim_ctx *ctx, char *data, int len)
1010{
1011int p;
1012
1013/* Alternate EOD signal, used in non-dotstuffing mode */
1014if (!data)
1015 pdkim_body_complete(ctx);
1016
1017for (p = 0; p<len; p++)
1018 {
1019 uschar c = data[p];
1020
1021 if (ctx->flags & PDKIM_PAST_HDRS)
1022 {
1023 /* Processing body byte */
1024 ctx->linebuf[ctx->linebuf_offset++] = c;
1025 if (c == '\n')
1026 {
1027 int rc = pdkim_bodyline_complete(ctx); /* End of line */
1028 if (rc != PDKIM_OK) return rc;
1029 }
1030 if (ctx->linebuf_offset == (PDKIM_MAX_BODY_LINE_LEN-1))
1031 return PDKIM_ERR_LONG_LINE;
1032 }
1033 else
1034 {
1035 /* Processing header byte */
1036 if (c != '\r')
1037 {
1038 if (c == '\n')
1039 {
1040 if (ctx->flags & PDKIM_SEEN_LF)
1041 {
1042 int rc = pdkim_header_complete(ctx); /* Seen last header line */
1043 if (rc != PDKIM_OK) return rc;
1044
1045 ctx->flags = ctx->flags & ~PDKIM_SEEN_LF | PDKIM_PAST_HDRS;
1046 DEBUG(D_acl) debug_printf(
1047 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n");
1048 continue;
1049 }
1050 else
1051 ctx->flags |= PDKIM_SEEN_LF;
1052 }
1053 else if (ctx->flags & PDKIM_SEEN_LF)
1054 {
1055 if (!(c == '\t' || c == ' '))
1056 {
1057 int rc = pdkim_header_complete(ctx); /* End of header */
1058 if (rc != PDKIM_OK) return rc;
1059 }
1060 ctx->flags &= ~PDKIM_SEEN_LF;
1061 }
1062 }
1063
1064 if (ctx->cur_header_len < PDKIM_MAX_HEADER_LEN)
1065 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1066 &ctx->cur_header_len, CUS &data[p], 1);
1067 }
1068 }
1069return PDKIM_OK;
1070}
1071
1072
1073
1074/* Extend a grwong header with a continuation-linebreak */
1075static uschar *
1076pdkim_hdr_cont(uschar * str, int * size, int * ptr, int * col)
1077{
1078*col = 1;
1079return string_catn(str, size, ptr, US"\r\n\t", 3);
1080}
1081
1082
1083
1084/*
1085 * RFC 5322 specifies that header line length SHOULD be no more than 78
1086 * lets make it so!
1087 * pdkim_headcat
1088 *
1089 * returns uschar * (not nul-terminated)
1090 *
1091 * col: this int holds and receives column number (octets since last '\n')
1092 * str: partial string to append to
1093 * size: current buffer size for str
1094 * ptr: current tail-pointer for str
1095 * pad: padding, split line or space after before or after eg: ";"
1096 * intro: - must join to payload eg "h=", usually the tag name
1097 * payload: eg base64 data - long data can be split arbitrarily.
1098 *
1099 * this code doesn't fold the header in some of the places that RFC4871
1100 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1101 * pairs and inside long values. it also always spaces or breaks after the
1102 * "pad"
1103 *
1104 * no guarantees are made for output given out-of range input. like tag
1105 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1106 */
1107
1108static uschar *
1109pdkim_headcat(int * col, uschar * str, int * size, int * ptr,
1110 const uschar * pad, const uschar * intro, const uschar * payload)
1111{
1112size_t l;
1113
1114if (pad)
1115 {
1116 l = Ustrlen(pad);
1117 if (*col + l > 78)
1118 str = pdkim_hdr_cont(str, size, ptr, col);
1119 str = string_catn(str, size, ptr, pad, l);
1120 *col += l;
1121 }
1122
1123l = (pad?1:0) + (intro?Ustrlen(intro):0);
1124
1125if (*col + l > 78)
1126 { /*can't fit intro - start a new line to make room.*/
1127 str = pdkim_hdr_cont(str, size, ptr, col);
1128 l = intro?Ustrlen(intro):0;
1129 }
1130
1131l += payload ? Ustrlen(payload):0 ;
1132
1133while (l>77)
1134 { /* this fragment will not fit on a single line */
1135 if (pad)
1136 {
1137 str = string_catn(str, size, ptr, US" ", 1);
1138 *col += 1;
1139 pad = NULL; /* only want this once */
1140 l--;
1141 }
1142
1143 if (intro)
1144 {
1145 size_t sl = Ustrlen(intro);
1146
1147 str = string_catn(str, size, ptr, intro, sl);
1148 *col += sl;
1149 l -= sl;
1150 intro = NULL; /* only want this once */
1151 }
1152
1153 if (payload)
1154 {
1155 size_t sl = Ustrlen(payload);
1156 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1157
1158 str = string_catn(str, size, ptr, payload, chomp);
1159 *col += chomp;
1160 payload += chomp;
1161 l -= chomp-1;
1162 }
1163
1164 /* the while precondition tells us it didn't fit. */
1165 str = pdkim_hdr_cont(str, size, ptr, col);
1166 }
1167
1168if (*col + l > 78)
1169 {
1170 str = pdkim_hdr_cont(str, size, ptr, col);
1171 pad = NULL;
1172 }
1173
1174if (pad)
1175 {
1176 str = string_catn(str, size, ptr, US" ", 1);
1177 *col += 1;
1178 pad = NULL;
1179 }
1180
1181if (intro)
1182 {
1183 size_t sl = Ustrlen(intro);
1184
1185 str = string_catn(str, size, ptr, intro, sl);
1186 *col += sl;
1187 l -= sl;
1188 intro = NULL;
1189 }
1190
1191if (payload)
1192 {
1193 size_t sl = Ustrlen(payload);
1194
1195 str = string_catn(str, size, ptr, payload, sl);
1196 *col += sl;
1197 }
1198
1199return str;
1200}
1201
1202
1203/* -------------------------------------------------------------------------- */
1204
1205static uschar *
1206pdkim_create_header(pdkim_signature *sig, BOOL final)
1207{
1208uschar * base64_bh;
1209uschar * base64_b;
1210int col = 0;
1211uschar * hdr; int hdr_size = 0, hdr_len = 0;
1212uschar * canon_all; int can_size = 0, can_len = 0;
1213
1214canon_all = string_cat (NULL, &can_size, &can_len,
1215 pdkim_canons[sig->canon_headers]);
1216canon_all = string_catn(canon_all, &can_size, &can_len, US"/", 1);
1217canon_all = string_cat (canon_all, &can_size, &can_len,
1218 pdkim_canons[sig->canon_body]);
1219canon_all[can_len] = '\0';
1220
1221hdr = string_cat(NULL, &hdr_size, &hdr_len,
1222 US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1223col = hdr_len;
1224
1225/* Required and static bits */
1226hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
1227 pdkim_algos[sig->algo]);
1228hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
1229 pdkim_querymethods[sig->querymethod]);
1230hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=",
1231 canon_all);
1232hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"d=",
1233 sig->domain);
1234hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=",
1235 sig->selector);
1236
1237/* list of header names can be split between items. */
1238 {
1239 uschar * n = string_copy(sig->headernames);
1240 uschar * i = US"h=";
1241 uschar * s = US";";
1242
1243 while (*n)
1244 {
1245 uschar * c = Ustrchr(n, ':');
1246
1247 if (c) *c ='\0';
1248
1249 if (!i)
1250 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, NULL, US":");
1251
1252 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, s, i, n);
1253
1254 if (!c)
1255 break;
1256
1257 n = c+1;
1258 s = NULL;
1259 i = NULL;
1260 }
1261 }
1262
1263base64_bh = pdkim_encode_base64(&sig->bodyhash);
1264hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"bh=", base64_bh);
1265
1266/* Optional bits */
1267if (sig->identity)
1268 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"i=", sig->identity);
1269
1270if (sig->created > 0)
1271 {
1272 uschar minibuf[20];
1273
1274 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1275 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"t=", minibuf);
1276}
1277
1278if (sig->expires > 0)
1279 {
1280 uschar minibuf[20];
1281
1282 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1283 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"x=", minibuf);
1284 }
1285
1286if (sig->bodylength >= 0)
1287 {
1288 uschar minibuf[20];
1289
1290 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1291 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"l=", minibuf);
1292 }
1293
1294/* Preliminary or final version? */
1295base64_b = final ? pdkim_encode_base64(&sig->sigdata) : US"";
1296hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
1297
1298/* add trailing semicolon: I'm not sure if this is actually needed */
1299hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
1300
1301hdr[hdr_len] = '\0';
1302return hdr;
1303}
1304
1305
1306/* -------------------------------------------------------------------------- */
1307
1308DLLEXPORT int
1309pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatures)
1310{
1311pdkim_signature *sig = ctx->sig;
1312uschar * headernames = NULL; /* Collected signed header names */
1313int hs = 0, hl = 0;
1314
1315/* Check if we must still flush a (partial) header. If that is the
1316 case, the message has no body, and we must compute a body hash
1317 out of '<CR><LF>' */
1318if (ctx->cur_header && ctx->cur_header_len)
1319 {
1320 int rc = pdkim_header_complete(ctx);
1321 if (rc != PDKIM_OK) return rc;
1322 pdkim_update_bodyhash(ctx, "\r\n", 2);
1323 }
1324else
1325 DEBUG(D_acl) debug_printf(
1326 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1327
1328/* Build (and/or evaluate) body hash */
1329pdkim_finish_bodyhash(ctx);
1330
1331while (sig)
1332 {
1333 BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
1334 hctx hhash_ctx;
1335 uschar * sig_hdr;
1336 blob hhash;
1337 blob hdata;
1338 int hdata_alloc = 0;
1339
1340 hdata.data = NULL;
1341 hdata.len = 0;
1342
1343 exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256);
1344
1345 DEBUG(D_acl) debug_printf(
1346 "PDKIM >> Hashed header data, canonicalized, in sequence >>>>>>>>>>>>>>\n");
1347
1348 /* SIGNING ---------------------------------------------------------------- */
1349 /* When signing, walk through our header list and add them to the hash. As we
1350 go, construct a list of the header's names to use for the h= parameter.
1351 Then append to that list any remaining header names for which there was no
1352 header to sign. */
1353
1354 if (ctx->flags & PDKIM_MODE_SIGN)
1355 {
1356 pdkim_stringlist *p;
1357 const uschar * l;
1358 uschar * s;
1359 int sep = 0;
1360
1361 for (p = sig->headers; p; p = p->next)
1362 if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
1363 {
1364 uschar * rh;
1365 /* Collect header names (Note: colon presence is guaranteed here) */
1366 uschar * q = Ustrchr(p->value, ':');
1367
1368 headernames = string_catn(headernames, &hs, &hl,
1369 p->value, (q - US p->value) + (p->next ? 1 : 0));
1370
1371 rh = sig->canon_headers == PDKIM_CANON_RELAXED
1372 ? pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
1373 : string_copy(CUS p->value); /* just copy it for simple canon */
1374
1375 /* Feed header to the hash algorithm */
1376 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1377
1378 /* Remember headers block for signing (when the library cannot do incremental) */
1379 (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
1380
1381 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1382 }
1383
1384 l = sig->sign_headers;
1385 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1386 if (*s != '_')
1387 { /*SSS string_append_listele() */
1388 if (hl > 0 && headernames[hl-1] != ':')
1389 headernames = string_catn(headernames, &hs, &hl, US":", 1);
1390
1391 headernames = string_cat(headernames, &hs, &hl, s);
1392 }
1393 headernames[hl] = '\0';
1394
1395 /* Copy headernames to signature struct */
1396 sig->headernames = headernames;
1397 headernames = NULL, hs = hl = 0;
1398
1399 /* Create signature header with b= omitted */
1400 sig_hdr = pdkim_create_header(sig, FALSE);
1401 }
1402
1403 /* VERIFICATION ----------------------------------------------------------- */
1404 /* When verifying, walk through the header name list in the h= parameter and
1405 add the headers to the hash in that order. */
1406 else
1407 {
1408 uschar * b = string_copy(sig->headernames);
1409 uschar * p = b;
1410 uschar * q;
1411 pdkim_stringlist * hdrs;
1412
1413 /* clear tags */
1414 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1415 hdrs->tag = 0;
1416
1417 while(1)
1418 {
1419 if ((q = Ustrchr(p, ':')))
1420 *q = '\0';
1421
1422/*XXX walk the list of headers in same order as received. */
1423 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1424 if ( hdrs->tag == 0
1425 && strncasecmp(hdrs->value, CS p, Ustrlen(p)) == 0
1426 && (hdrs->value)[Ustrlen(p)] == ':'
1427 )
1428 {
1429 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1430 ? pdkim_relax_header(hdrs->value, 1) /* cook header for relaxed canon */
1431 : string_copy(CUS hdrs->value); /* just copy it for simple canon */
1432
1433 /* Feed header to the hash algorithm */
1434 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1435
1436 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1437 hdrs->tag = 1;
1438 break;
1439 }
1440
1441 if (!q) break;
1442 p = q+1;
1443 }
1444
1445 sig_hdr = string_copy(sig->rawsig_no_b_val);
1446 }
1447
1448 DEBUG(D_acl) debug_printf(
1449 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1450
1451 /* Relax header if necessary */
1452 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1453 sig_hdr = pdkim_relax_header(sig_hdr, 0);
1454
1455 DEBUG(D_acl)
1456 {
1457 debug_printf(
1458 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1459 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1460 debug_printf(
1461 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1462 }
1463
1464 /* Finalize header hash */
1465 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1466 exim_sha_finish(&hhash_ctx, &hhash);
1467
1468 DEBUG(D_acl)
1469 {
1470 debug_printf("PDKIM [%s] hh computed: ", sig->domain);
1471 pdkim_hexprint(hhash.data, hhash.len);
1472 }
1473
1474 /* Remember headers block for signing (when the library cannot do incremental) */
1475 if (ctx->flags & PDKIM_MODE_SIGN)
1476 (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
1477
1478 /* SIGNING ---------------------------------------------------------------- */
1479 if (ctx->flags & PDKIM_MODE_SIGN)
1480 {
1481 es_ctx sctx;
1482 const uschar * errstr;
1483
1484 /* Import private key */
1485 if ((errstr = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
1486 {
1487 DEBUG(D_acl) debug_printf("signing_init: %s\n", errstr);
1488 return PDKIM_ERR_RSA_PRIVKEY;
1489 }
1490
1491 /* Do signing. With OpenSSL we are signing the hash of headers just
1492 calculated, with GnuTLS we have to sign an entire block of headers
1493 (due to available interfaces) and it recalculates the hash internally. */
1494
1495#if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1496 hdata = hhash;
1497#endif
1498
1499 if ((errstr = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sigdata)))
1500 {
1501 DEBUG(D_acl) debug_printf("signing: %s\n", errstr);
1502 return PDKIM_ERR_RSA_SIGNING;
1503 }
1504
1505 DEBUG(D_acl)
1506 {
1507 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1508 pdkim_hexprint(sig->sigdata.data, sig->sigdata.len);
1509 }
1510
1511 sig->signature_header = pdkim_create_header(sig, TRUE);
1512 }
1513
1514 /* VERIFICATION ----------------------------------------------------------- */
1515 else
1516 {
1517 ev_ctx vctx;
1518 const uschar * errstr;
1519
1520 uschar *dns_txt_name, *dns_txt_reply;
1521
1522 /* Make sure we have all required signature tags */
1523 if (!( sig->domain && *sig->domain
1524 && sig->selector && *sig->selector
1525 && sig->headernames && *sig->headernames
1526 && sig->bodyhash.data
1527 && sig->sigdata.data
1528 && sig->algo > -1
1529 && sig->version
1530 ) )
1531 {
1532 sig->verify_status = PDKIM_VERIFY_INVALID;
1533 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1534
1535 DEBUG(D_acl) debug_printf(
1536 " Error in DKIM-Signature header: tags missing or invalid\n"
1537 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1538 goto NEXT_VERIFY;
1539 }
1540
1541 /* Make sure sig uses supported DKIM version (only v1) */
1542 if (sig->version != 1)
1543 {
1544 sig->verify_status = PDKIM_VERIFY_INVALID;
1545 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1546
1547 DEBUG(D_acl) debug_printf(
1548 " Error in DKIM-Signature header: unsupported DKIM version\n"
1549 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1550 goto NEXT_VERIFY;
1551 }
1552
1553 /* Fetch public key for signing domain, from DNS */
1554
1555 dns_txt_name = string_sprintf("%s._domainkey.%s.",
1556 sig->selector, sig->domain);
1557
1558 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1559 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1560
1561 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1562 || dns_txt_reply[0] == '\0')
1563 {
1564 sig->verify_status = PDKIM_VERIFY_INVALID;
1565 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1566 goto NEXT_VERIFY;
1567 }
1568
1569 DEBUG(D_acl)
1570 {
1571 debug_printf(
1572 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1573 " Raw record: ");
1574 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1575 }
1576
1577 if (!(sig->pubkey = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply)))
1578 {
1579 sig->verify_status = PDKIM_VERIFY_INVALID;
1580 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1581
1582 DEBUG(D_acl) debug_printf(
1583 " Error while parsing public key record\n"
1584 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1585 goto NEXT_VERIFY;
1586 }
1587
1588 DEBUG(D_acl) debug_printf(
1589 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1590
1591 /* Import public key */
1592 if ((errstr = exim_rsa_verify_init(&sig->pubkey->key, &vctx)))
1593 {
1594 DEBUG(D_acl) debug_printf("verify_init: %s\n", errstr);
1595 sig->verify_status = PDKIM_VERIFY_INVALID;
1596 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1597 goto NEXT_VERIFY;
1598 }
1599
1600 /* Check the signature */
1601 if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sigdata)))
1602 {
1603 DEBUG(D_acl) debug_printf("headers verify: %s\n", errstr);
1604 sig->verify_status = PDKIM_VERIFY_FAIL;
1605 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1606 goto NEXT_VERIFY;
1607 }
1608
1609
1610 /* We have a winner! (if bodydhash was correct earlier) */
1611 if (sig->verify_status == PDKIM_VERIFY_NONE)
1612 sig->verify_status = PDKIM_VERIFY_PASS;
1613
1614NEXT_VERIFY:
1615
1616 DEBUG(D_acl)
1617 {
1618 debug_printf("PDKIM [%s] signature status: %s",
1619 sig->domain, pdkim_verify_status_str(sig->verify_status));
1620 if (sig->verify_ext_status > 0)
1621 debug_printf(" (%s)\n",
1622 pdkim_verify_ext_status_str(sig->verify_ext_status));
1623 else
1624 debug_printf("\n");
1625 }
1626 }
1627
1628 sig = sig->next;
1629 }
1630
1631/* If requested, set return pointer to signature(s) */
1632if (return_signatures)
1633 *return_signatures = ctx->sig;
1634
1635return PDKIM_OK;
1636}
1637
1638
1639/* -------------------------------------------------------------------------- */
1640
1641DLLEXPORT pdkim_ctx *
1642pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
1643{
1644pdkim_ctx * ctx;
1645
1646ctx = store_get(sizeof(pdkim_ctx));
1647memset(ctx, 0, sizeof(pdkim_ctx));
1648
1649if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1650ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1651ctx->dns_txt_callback = dns_txt_callback;
1652
1653return ctx;
1654}
1655
1656
1657/* -------------------------------------------------------------------------- */
1658
1659DLLEXPORT pdkim_ctx *
1660pdkim_init_sign(char *domain, char *selector, char *rsa_privkey, int algo,
1661 BOOL dot_stuffed)
1662{
1663pdkim_ctx *ctx;
1664pdkim_signature *sig;
1665
1666if (!domain || !selector || !rsa_privkey)
1667 return NULL;
1668
1669ctx = store_get(sizeof(pdkim_ctx));
1670memset(ctx, 0, sizeof(pdkim_ctx));
1671
1672ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1673ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1674
1675sig = store_get(sizeof(pdkim_signature));
1676memset(sig, 0, sizeof(pdkim_signature));
1677
1678sig->bodylength = -1;
1679ctx->sig = sig;
1680
1681sig->domain = string_copy(US domain);
1682sig->selector = string_copy(US selector);
1683sig->rsa_privkey = string_copy(US rsa_privkey);
1684sig->algo = algo;
1685
1686exim_sha_init(&sig->body_hash, algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
1687return ctx;
1688}
1689
1690
1691/* -------------------------------------------------------------------------- */
1692
1693DLLEXPORT int
1694pdkim_set_optional(pdkim_ctx *ctx,
1695 char *sign_headers,
1696 char *identity,
1697 int canon_headers,
1698 int canon_body,
1699 long bodylength,
1700 unsigned long created,
1701 unsigned long expires)
1702{
1703pdkim_signature * sig = ctx->sig;
1704
1705if (identity)
1706 sig->identity = string_copy(US identity);
1707
1708sig->sign_headers = string_copy(sign_headers
1709 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1710
1711sig->canon_headers = canon_headers;
1712sig->canon_body = canon_body;
1713sig->bodylength = bodylength;
1714sig->created = created;
1715sig->expires = expires;
1716
1717return PDKIM_OK;
1718}
1719
1720
1721void
1722pdkim_init(void)
1723{
1724exim_rsa_init();
1725}
1726
1727
1728
1729#endif /*DISABLE_DKIM*/