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