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