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