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