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