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