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