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