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