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