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