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