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