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