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