Change note for 445d03d4ea
[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 = p + str->ptr;
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 if (cur_tag && cur_val)
494 {
495 (void) string_from_gstring(cur_val);
496 pdkim_strtrim(cur_val);
497
498 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->s, cur_val->s);
499
500 switch (*cur_tag->s)
501 {
502 case 'b':
503 pdkim_decode_base64(cur_val->s,
504 cur_tag->s[1] == 'h' ? &sig->bodyhash : &sig->sighash);
505 break;
506 case 'v':
507 /* We only support version 1, and that is currently the
508 only version there is. */
509 sig->version =
510 Ustrcmp(cur_val->s, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
511 break;
512 case 'a':
513 {
514 uschar * s = Ustrchr(cur_val->s, '-');
515
516 for(i = 0; i < nelem(pdkim_keytypes); i++)
517 if (Ustrncmp(cur_val->s, pdkim_keytypes[i], s - cur_val->s) == 0)
518 { sig->keytype = i; break; }
519 for (++s, i = 0; i < nelem(pdkim_hashes); i++)
520 if (Ustrcmp(s, pdkim_hashes[i].dkim_hashname) == 0)
521 { sig->hashtype = i; break; }
522 break;
523 }
524
525 case 'c':
526 for (i = 0; pdkim_combined_canons[i].str; i++)
527 if (Ustrcmp(cur_val->s, pdkim_combined_canons[i].str) == 0)
528 {
529 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
530 sig->canon_body = pdkim_combined_canons[i].canon_body;
531 break;
532 }
533 break;
534 case 'q':
535 for (i = 0; pdkim_querymethods[i]; i++)
536 if (Ustrcmp(cur_val->s, pdkim_querymethods[i]) == 0)
537 {
538 sig->querymethod = i;
539 break;
540 }
541 break;
542 case 's':
543 sig->selector = string_copyn(cur_val->s, cur_val->ptr); break;
544 case 'd':
545 sig->domain = string_copyn(cur_val->s, cur_val->ptr); break;
546 case 'i':
547 sig->identity = pdkim_decode_qp(cur_val->s); break;
548 case 't':
549 sig->created = strtoul(CS cur_val->s, NULL, 10); break;
550 case 'x':
551 sig->expires = strtoul(CS cur_val->s, NULL, 10); break;
552 case 'l':
553 sig->bodylength = strtol(CS cur_val->s, NULL, 10); break;
554 case 'h':
555 sig->headernames = string_copyn(cur_val->s, cur_val->ptr); break;
556 case 'z':
557 sig->copiedheaders = pdkim_decode_qp(cur_val->s); break;
558 default:
559 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
560 break;
561 }
562 }
563 cur_tag = cur_val = NULL;
564 in_b_val = FALSE;
565 where = PDKIM_HDR_LIMBO;
566 }
567 else
568 cur_val = string_catn(cur_val, p, 1);
569 }
570
571NEXT_CHAR:
572 if (c == '\0')
573 break;
574
575 if (!in_b_val)
576 *q++ = c;
577 }
578
579*q = '\0';
580/* Chomp raw header. The final newline must not be added to the signature. */
581while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
582 *q = '\0';
583
584DEBUG(D_acl)
585 {
586 debug_printf(
587 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
588 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
589 debug_printf(
590 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sighash.len*8);
591 debug_printf(
592 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
593 }
594
595/*XXX hash method: extend for sha512 */
596if (!exim_sha_init(&sig->body_hash_ctx,
597 pdkim_hashes[sig->hashtype].exim_hashmethod))
598 {
599 DEBUG(D_acl)
600 debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n");
601 return NULL;
602 }
603return sig;
604}
605
606
607/* -------------------------------------------------------------------------- */
608
609static pdkim_pubkey *
610pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
611{
612const uschar * ele;
613int sep = ';';
614pdkim_pubkey * pub;
615
616pub = store_get(sizeof(pdkim_pubkey));
617memset(pub, 0, sizeof(pdkim_pubkey));
618
619while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
620 {
621 const uschar * val;
622
623 if ((val = Ustrchr(ele, '=')))
624 {
625 int taglen = val++ - ele;
626
627 DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
628 switch (ele[0])
629 {
630 case 'v': pub->version = val; break;
631 case 'h': pub->hashes = val; break;
632 case 'k': break;
633 case 'g': pub->granularity = val; break;
634 case 'n': pub->notes = pdkim_decode_qp(val); break;
635 case 'p': pdkim_decode_base64(val, &pub->key); break;
636 case 's': pub->srvtype = val; break;
637 case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
638 if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
639 break;
640 default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
641 }
642 }
643 }
644
645/* Set fallback defaults */
646if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
647else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
648 {
649 DEBUG(D_acl) debug_printf(" Bad v= field\n");
650 return NULL;
651 }
652
653if (!pub->granularity) pub->granularity = US"*";
654/*
655if (!pub->keytype ) pub->keytype = US"rsa";
656*/
657if (!pub->srvtype ) pub->srvtype = US"*";
658
659/* p= is required */
660if (pub->key.data)
661 return pub;
662
663DEBUG(D_acl) debug_printf(" Missing p= field\n");
664return NULL;
665}
666
667
668/* -------------------------------------------------------------------------- */
669
670/* Update the bodyhash for one sig, with some additional data.
671If we have to relax the data for this sig, return our copy of it. */
672
673/*XXX Currently we calculate a hash for each sig. But it is possible
674that multi-signing will be wanted using different signing algos
675(rsa, ec) using the same hash and canonicalization. Consider in future
676hanging the hash+cacnon from the ctx and only referencing from the sig,
677so that it can be calculated only once - being over the body this
678caould be meagbytes, hence expensive. */
679
680static blob *
681pdkim_update_sig_bodyhash(pdkim_signature * sig, blob * orig_data, blob * relaxed_data)
682{
683blob * canon_data = orig_data;
684/* Defaults to simple canon (no further treatment necessary) */
685
686if (sig->canon_body == PDKIM_CANON_RELAXED)
687 {
688 /* Relax the line if not done already */
689 if (!relaxed_data)
690 {
691 BOOL seen_wsp = FALSE;
692 const uschar * p;
693 int q = 0;
694
695 /* We want to be able to free this else we allocate
696 for the entire message which could be many MB. Since
697 we don't know what allocations the SHA routines might
698 do, not safe to use store_get()/store_reset(). */
699
700 relaxed_data = store_malloc(sizeof(blob) + orig_data->len+1);
701 relaxed_data->data = US (relaxed_data+1);
702
703 for (p = orig_data->data; *p; p++)
704 {
705 char c = *p;
706 if (c == '\r')
707 {
708 if (q > 0 && relaxed_data->data[q-1] == ' ')
709 q--;
710 }
711 else if (c == '\t' || c == ' ')
712 {
713 c = ' '; /* Turns WSP into SP */
714 if (seen_wsp)
715 continue;
716 seen_wsp = TRUE;
717 }
718 else
719 seen_wsp = FALSE;
720 relaxed_data->data[q++] = c;
721 }
722 relaxed_data->data[q] = '\0';
723 relaxed_data->len = q;
724 }
725 canon_data = relaxed_data;
726 }
727
728/* Make sure we don't exceed the to-be-signed body length */
729if ( sig->bodylength >= 0
730 && sig->signed_body_bytes + (unsigned long)canon_data->len > sig->bodylength
731 )
732 canon_data->len = sig->bodylength - sig->signed_body_bytes;
733
734if (canon_data->len > 0)
735 {
736 exim_sha_update(&sig->body_hash_ctx, CUS canon_data->data, canon_data->len);
737 sig->signed_body_bytes += canon_data->len;
738 DEBUG(D_acl) pdkim_quoteprint(canon_data->data, canon_data->len);
739 }
740
741return relaxed_data;
742}
743
744
745/* -------------------------------------------------------------------------- */
746
747static void
748pdkim_finish_bodyhash(pdkim_ctx * ctx)
749{
750pdkim_signature * sig;
751
752/* Traverse all signatures */
753for (sig = ctx->sig; sig; sig = sig->next)
754 { /* Finish hashes */
755 blob bh;
756
757 exim_sha_finish(&sig->body_hash_ctx, &bh);
758
759 DEBUG(D_acl)
760 {
761 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
762 "PDKIM [%s] Body %s computed: ",
763 sig->domain, sig->signed_body_bytes,
764 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
765 pdkim_hexprint(CUS bh.data, bh.len);
766 }
767
768 /* SIGNING -------------------------------------------------------------- */
769 if (ctx->flags & PDKIM_MODE_SIGN)
770 {
771 sig->bodyhash = bh;
772
773 /* If bodylength limit is set, and we have received less bytes
774 than the requested amount, effectively remove the limit tag. */
775 if (sig->signed_body_bytes < sig->bodylength)
776 sig->bodylength = -1;
777 }
778
779 else
780 /* VERIFICATION --------------------------------------------------------- */
781 /* Be careful that the header sig included a bodyash */
782
783 if (sig->bodyhash.data && memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
784 {
785 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
786 }
787 else
788 {
789 DEBUG(D_acl)
790 {
791 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain);
792 pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
793 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
794 }
795 sig->verify_status = PDKIM_VERIFY_FAIL;
796 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
797 }
798 }
799}
800
801
802
803static void
804pdkim_body_complete(pdkim_ctx * ctx)
805{
806pdkim_signature * sig;
807
808/* In simple body mode, if any empty lines were buffered,
809replace with one. rfc 4871 3.4.3 */
810/*XXX checking the signed-body-bytes is a gross hack; I think
811it indicates that all linebreaks should be buffered, including
812the one terminating a text line */
813
814for (sig = ctx->sig; sig; sig = sig->next)
815 if ( sig->canon_body == PDKIM_CANON_SIMPLE
816 && sig->signed_body_bytes == 0
817 && sig->num_buffered_blanklines > 0
818 )
819 (void) pdkim_update_sig_bodyhash(sig, &lineending, NULL);
820
821ctx->flags |= PDKIM_SEEN_EOD;
822ctx->linebuf_offset = 0;
823}
824
825
826
827/* -------------------------------------------------------------------------- */
828/* Call from pdkim_feed below for processing complete body lines */
829
830static void
831pdkim_bodyline_complete(pdkim_ctx * ctx)
832{
833blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
834pdkim_signature * sig;
835blob * rnl = NULL;
836blob * rline = NULL;
837
838/* Ignore extra data if we've seen the end-of-data marker */
839if (ctx->flags & PDKIM_SEEN_EOD) goto all_skip;
840
841/* We've always got one extra byte to stuff a zero ... */
842ctx->linebuf[line.len] = '\0';
843
844/* Terminate on EOD marker */
845if (ctx->flags & PDKIM_DOT_TERM)
846 {
847 if (memcmp(line.data, ".\r\n", 3) == 0)
848 { pdkim_body_complete(ctx); return; }
849
850 /* Unstuff dots */
851 if (memcmp(line.data, "..", 2) == 0)
852 { line.data++; line.len--; }
853 }
854
855/* Empty lines need to be buffered until we find a non-empty line */
856if (memcmp(line.data, "\r\n", 2) == 0)
857 {
858 for (sig = ctx->sig; sig; sig = sig->next) sig->num_buffered_blanklines++;
859 goto all_skip;
860 }
861
862/* Process line for each sig separately */
863for (sig = ctx->sig; sig; sig = sig->next)
864 {
865 if (sig->canon_body == PDKIM_CANON_RELAXED)
866 {
867 /* Lines with just spaces need to be buffered too */
868 uschar * cp = line.data;
869 char c;
870
871 while ((c = *cp))
872 {
873 if (c == '\r' && cp[1] == '\n') break;
874 if (c != ' ' && c != '\t') goto sig_process;
875 cp++;
876 }
877
878 sig->num_buffered_blanklines++;
879 goto sig_skip;
880 }
881
882sig_process:
883 /* At this point, we have a non-empty line, so release the buffered ones. */
884
885 while (sig->num_buffered_blanklines)
886 {
887 rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
888 sig->num_buffered_blanklines--;
889 }
890
891 rline = pdkim_update_sig_bodyhash(sig, &line, rline);
892sig_skip: ;
893 }
894
895if (rnl) store_free(rnl);
896if (rline) store_free(rline);
897
898all_skip:
899
900ctx->linebuf_offset = 0;
901return;
902}
903
904
905/* -------------------------------------------------------------------------- */
906/* Callback from pdkim_feed below for processing complete headers */
907#define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
908
909static int
910pdkim_header_complete(pdkim_ctx * ctx)
911{
912pdkim_signature * sig, * last_sig;
913
914/* Special case: The last header can have an extra \r appended */
915if ( (ctx->cur_header->ptr > 1) &&
916 (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
917 --ctx->cur_header->ptr;
918(void) string_from_gstring(ctx->cur_header);
919
920if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
921
922/* SIGNING -------------------------------------------------------------- */
923if (ctx->flags & PDKIM_MODE_SIGN)
924 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
925
926 /* Add header to the signed headers list (in reverse order) */
927 sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s);
928
929/* VERIFICATION ----------------------------------------------------------- */
930/* DKIM-Signature: headers are added to the verification list */
931else
932 {
933#ifdef notdef
934 DEBUG(D_acl)
935 {
936 debug_printf("PDKIM >> raw hdr: ");
937 pdkim_quoteprint(CUS ctx->cur_header->s, ctx->cur_header->ptr);
938 }
939#endif
940 if (strncasecmp(CCS ctx->cur_header->s,
941 DKIM_SIGNATURE_HEADERNAME,
942 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
943 {
944 /* Create and chain new signature block. We could error-check for all
945 required tags here, but prefer to create the internal sig and expicitly
946 fail verification of it later. */
947
948 DEBUG(D_acl) debug_printf(
949 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
950
951 sig = pdkim_parse_sig_header(ctx, ctx->cur_header->s);
952
953 if (!(last_sig = ctx->sig))
954 ctx->sig = sig;
955 else
956 {
957 while (last_sig->next) last_sig = last_sig->next;
958 last_sig->next = sig;
959 }
960 }
961
962 /* all headers are stored for signature verification */
963 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->s);
964 }
965
966BAIL:
967ctx->cur_header->s[ctx->cur_header->ptr = 0] = '\0'; /* leave buffer for reuse */
968return PDKIM_OK;
969}
970
971
972
973/* -------------------------------------------------------------------------- */
974#define HEADER_BUFFER_FRAG_SIZE 256
975
976DLLEXPORT int
977pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
978{
979int p, rc;
980
981/* Alternate EOD signal, used in non-dotstuffing mode */
982if (!data)
983 pdkim_body_complete(ctx);
984
985else for (p = 0; p<len; p++)
986 {
987 uschar c = data[p];
988
989 if (ctx->flags & PDKIM_PAST_HDRS)
990 {
991 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
992 {
993 ctx->linebuf[ctx->linebuf_offset++] = '\r';
994 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
995 return PDKIM_ERR_LONG_LINE;
996 }
997
998 /* Processing body byte */
999 ctx->linebuf[ctx->linebuf_offset++] = c;
1000 if (c == '\r')
1001 ctx->flags |= PDKIM_SEEN_CR;
1002 else if (c == '\n')
1003 {
1004 ctx->flags &= ~PDKIM_SEEN_CR;
1005 pdkim_bodyline_complete(ctx);
1006 }
1007
1008 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1009 return PDKIM_ERR_LONG_LINE;
1010 }
1011 else
1012 {
1013 /* Processing header byte */
1014 if (c == '\r')
1015 ctx->flags |= PDKIM_SEEN_CR;
1016 else if (c == '\n')
1017 {
1018 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1019 ctx->cur_header = string_catn(ctx->cur_header, CUS "\r", 1);
1020
1021 if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */
1022 {
1023 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1024 return rc;
1025
1026 ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS;
1027 DEBUG(D_acl) debug_printf(
1028 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1029 continue;
1030 }
1031 else
1032 ctx->flags = (ctx->flags & ~PDKIM_SEEN_CR) | PDKIM_SEEN_LF;
1033 }
1034 else if (ctx->flags & PDKIM_SEEN_LF)
1035 {
1036 if (!(c == '\t' || c == ' ')) /* End of header */
1037 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1038 return rc;
1039 ctx->flags &= ~PDKIM_SEEN_LF;
1040 }
1041
1042 if (!ctx->cur_header || ctx->cur_header->ptr < PDKIM_MAX_HEADER_LEN)
1043 ctx->cur_header = string_catn(ctx->cur_header, CUS &data[p], 1);
1044 }
1045 }
1046return PDKIM_OK;
1047}
1048
1049
1050
1051/* Extend a growing header with a continuation-linebreak */
1052static gstring *
1053pdkim_hdr_cont(gstring * str, int * col)
1054{
1055*col = 1;
1056return string_catn(str, US"\r\n\t", 3);
1057}
1058
1059
1060
1061/*
1062 * RFC 5322 specifies that header line length SHOULD be no more than 78
1063 * lets make it so!
1064 * pdkim_headcat
1065 *
1066 * returns uschar * (not nul-terminated)
1067 *
1068 * col: this int holds and receives column number (octets since last '\n')
1069 * str: partial string to append to
1070 * pad: padding, split line or space after before or after eg: ";"
1071 * intro: - must join to payload eg "h=", usually the tag name
1072 * payload: eg base64 data - long data can be split arbitrarily.
1073 *
1074 * this code doesn't fold the header in some of the places that RFC4871
1075 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1076 * pairs and inside long values. it also always spaces or breaks after the
1077 * "pad"
1078 *
1079 * no guarantees are made for output given out-of range input. like tag
1080 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1081 */
1082
1083static gstring *
1084pdkim_headcat(int * col, gstring * str,
1085 const uschar * pad, const uschar * intro, const uschar * payload)
1086{
1087size_t l;
1088
1089if (pad)
1090 {
1091 l = Ustrlen(pad);
1092 if (*col + l > 78)
1093 str = pdkim_hdr_cont(str, col);
1094 str = string_catn(str, pad, l);
1095 *col += l;
1096 }
1097
1098l = (pad?1:0) + (intro?Ustrlen(intro):0);
1099
1100if (*col + l > 78)
1101 { /*can't fit intro - start a new line to make room.*/
1102 str = pdkim_hdr_cont(str, col);
1103 l = intro?Ustrlen(intro):0;
1104 }
1105
1106l += payload ? Ustrlen(payload):0 ;
1107
1108while (l>77)
1109 { /* this fragment will not fit on a single line */
1110 if (pad)
1111 {
1112 str = string_catn(str, US" ", 1);
1113 *col += 1;
1114 pad = NULL; /* only want this once */
1115 l--;
1116 }
1117
1118 if (intro)
1119 {
1120 size_t sl = Ustrlen(intro);
1121
1122 str = string_catn(str, intro, sl);
1123 *col += sl;
1124 l -= sl;
1125 intro = NULL; /* only want this once */
1126 }
1127
1128 if (payload)
1129 {
1130 size_t sl = Ustrlen(payload);
1131 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1132
1133 str = string_catn(str, payload, chomp);
1134 *col += chomp;
1135 payload += chomp;
1136 l -= chomp-1;
1137 }
1138
1139 /* the while precondition tells us it didn't fit. */
1140 str = pdkim_hdr_cont(str, col);
1141 }
1142
1143if (*col + l > 78)
1144 {
1145 str = pdkim_hdr_cont(str, col);
1146 pad = NULL;
1147 }
1148
1149if (pad)
1150 {
1151 str = string_catn(str, US" ", 1);
1152 *col += 1;
1153 pad = NULL;
1154 }
1155
1156if (intro)
1157 {
1158 size_t sl = Ustrlen(intro);
1159
1160 str = string_catn(str, intro, sl);
1161 *col += sl;
1162 l -= sl;
1163 intro = NULL;
1164 }
1165
1166if (payload)
1167 {
1168 size_t sl = Ustrlen(payload);
1169
1170 str = string_catn(str, payload, sl);
1171 *col += sl;
1172 }
1173
1174return str;
1175}
1176
1177
1178/* -------------------------------------------------------------------------- */
1179
1180static uschar *
1181pdkim_create_header(pdkim_signature * sig, BOOL final)
1182{
1183uschar * base64_bh;
1184uschar * base64_b;
1185int col = 0;
1186gstring * hdr;
1187gstring * canon_all;
1188
1189canon_all = string_cat (NULL, pdkim_canons[sig->canon_headers]);
1190canon_all = string_catn(canon_all, US"/", 1);
1191canon_all = string_cat (canon_all, pdkim_canons[sig->canon_body]);
1192(void) string_from_gstring(canon_all);
1193
1194hdr = string_cat(NULL, US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1195col = hdr->ptr;
1196
1197/* Required and static bits */
1198hdr = pdkim_headcat(&col, hdr, US";", US"a=", dkim_sig_to_a_tag(sig));
1199hdr = pdkim_headcat(&col, hdr, US";", US"q=", pdkim_querymethods[sig->querymethod]);
1200hdr = pdkim_headcat(&col, hdr, US";", US"c=", canon_all->s);
1201hdr = pdkim_headcat(&col, hdr, US";", US"d=", sig->domain);
1202hdr = pdkim_headcat(&col, hdr, US";", US"s=", sig->selector);
1203
1204/* list of header names can be split between items. */
1205 {
1206 uschar * n = string_copy(sig->headernames);
1207 uschar * i = US"h=";
1208 uschar * s = US";";
1209
1210 while (*n)
1211 {
1212 uschar * c = Ustrchr(n, ':');
1213
1214 if (c) *c ='\0';
1215
1216 if (!i)
1217 hdr = pdkim_headcat(&col, hdr, NULL, NULL, US":");
1218
1219 hdr = pdkim_headcat(&col, hdr, s, i, n);
1220
1221 if (!c)
1222 break;
1223
1224 n = c+1;
1225 s = NULL;
1226 i = NULL;
1227 }
1228 }
1229
1230base64_bh = pdkim_encode_base64(&sig->bodyhash);
1231hdr = pdkim_headcat(&col, hdr, US";", US"bh=", base64_bh);
1232
1233/* Optional bits */
1234if (sig->identity)
1235 hdr = pdkim_headcat(&col, hdr, US";", US"i=", sig->identity);
1236
1237if (sig->created > 0)
1238 {
1239 uschar minibuf[20];
1240
1241 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1242 hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf);
1243}
1244
1245if (sig->expires > 0)
1246 {
1247 uschar minibuf[20];
1248
1249 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1250 hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf);
1251 }
1252
1253if (sig->bodylength >= 0)
1254 {
1255 uschar minibuf[20];
1256
1257 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1258 hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf);
1259 }
1260
1261/* Preliminary or final version? */
1262if (final)
1263 {
1264 base64_b = pdkim_encode_base64(&sig->sighash);
1265 hdr = pdkim_headcat(&col, hdr, US";", US"b=", base64_b);
1266
1267 /* add trailing semicolon: I'm not sure if this is actually needed */
1268 hdr = pdkim_headcat(&col, hdr, NULL, US";", US"");
1269 }
1270else
1271 {
1272 /* To satisfy the rule "all surrounding whitespace [...] deleted"
1273 ( RFC 6376 section 3.7 ) we ensure there is no whitespace here. Otherwise
1274 the headcat routine could insert a linebreak which the relaxer would reduce
1275 to a single space preceding the terminating semicolon, resulting in an
1276 incorrect header-hash. */
1277 hdr = pdkim_headcat(&col, hdr, US";", US"b=;", US"");
1278 }
1279
1280return string_from_gstring(hdr);
1281}
1282
1283
1284/* -------------------------------------------------------------------------- */
1285
1286static pdkim_pubkey *
1287pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1288 const uschar ** errstr)
1289{
1290uschar * dns_txt_name, * dns_txt_reply;
1291pdkim_pubkey * p;
1292
1293/* Fetch public key for signing domain, from DNS */
1294
1295dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1296
1297dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1298memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1299
1300if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1301 || dns_txt_reply[0] == '\0'
1302 )
1303 {
1304 sig->verify_status = PDKIM_VERIFY_INVALID;
1305 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1306 return NULL;
1307 }
1308
1309DEBUG(D_acl)
1310 {
1311 debug_printf(
1312 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1313 " %s\n"
1314 " Raw record: ",
1315 dns_txt_name);
1316 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1317 }
1318
1319if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1320 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1321 )
1322 {
1323 sig->verify_status = PDKIM_VERIFY_INVALID;
1324 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1325
1326 DEBUG(D_acl)
1327 {
1328 if (p)
1329 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1330 else
1331 debug_printf(" Error while parsing public key record\n");
1332 debug_printf(
1333 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1334 }
1335 return NULL;
1336 }
1337
1338DEBUG(D_acl) debug_printf(
1339 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1340
1341/* Import public key */
1342if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
1343 {
1344 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
1345 sig->verify_status = PDKIM_VERIFY_INVALID;
1346 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1347 return NULL;
1348 }
1349
1350return p;
1351}
1352
1353
1354/* -------------------------------------------------------------------------- */
1355
1356DLLEXPORT int
1357pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1358 const uschar ** err)
1359{
1360pdkim_signature * sig;
1361
1362/* Check if we must still flush a (partial) header. If that is the
1363 case, the message has no body, and we must compute a body hash
1364 out of '<CR><LF>' */
1365if (ctx->cur_header && ctx->cur_header->ptr > 0)
1366 {
1367 blob * rnl = NULL;
1368 int rc;
1369
1370 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1371 return rc;
1372
1373 for (sig = ctx->sig; sig; sig = sig->next)
1374 rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
1375 if (rnl) store_free(rnl);
1376 }
1377else
1378 DEBUG(D_acl) debug_printf(
1379 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1380
1381/* Build (and/or evaluate) body hash */
1382pdkim_finish_bodyhash(ctx);
1383
1384for (sig = ctx->sig; sig; sig = sig->next)
1385 {
1386 hctx hhash_ctx;
1387 uschar * sig_hdr = US"";
1388 blob hhash;
1389 gstring * hdata = NULL;
1390
1391 if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
1392 {
1393 DEBUG(D_acl)
1394 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
1395 break;
1396 }
1397
1398 if (ctx->flags & PDKIM_MODE_SIGN)
1399 DEBUG(D_acl) debug_printf(
1400 "PDKIM >> Headers to be signed: >>>>>>>>>>>>\n"
1401 " %s\n",
1402 sig->sign_headers);
1403
1404 DEBUG(D_acl) debug_printf(
1405 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
1406
1407
1408 /* SIGNING ---------------------------------------------------------------- */
1409 /* When signing, walk through our header list and add them to the hash. As we
1410 go, construct a list of the header's names to use for the h= parameter.
1411 Then append to that list any remaining header names for which there was no
1412 header to sign. */
1413
1414 if (ctx->flags & PDKIM_MODE_SIGN)
1415 {
1416 gstring * g = NULL;
1417 pdkim_stringlist *p;
1418 const uschar * l;
1419 uschar * s;
1420 int sep = 0;
1421
1422 sig->headernames = NULL; /* Collected signed header names */
1423
1424 for (p = sig->headers; p; p = p->next)
1425 {
1426 uschar * rh = p->value;
1427
1428 if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
1429 {
1430 /* Collect header names (Note: colon presence is guaranteed here) */
1431 g = string_append_listele_n(g, ':', rh, Ustrchr(rh, ':') - rh);
1432
1433 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1434 rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */
1435
1436 /* Feed header to the hash algorithm */
1437 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1438
1439 /* Remember headers block for signing (when the library cannot do incremental) */
1440 hdata = exim_dkim_data_append(hdata, rh);
1441
1442 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1443 }
1444 }
1445
1446 /* Any headers we wanted to sign but were not present must also be listed.
1447 Ignore elements that have been ticked-off or are marked as never-oversign. */
1448
1449 l = sig->sign_headers;
1450 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1451 {
1452 if (*s == '+') /* skip oversigning marker */
1453 s++;
1454 if (*s != '_' && *s != '=')
1455 g = string_append_listele(g, ':', s);
1456 }
1457 sig->headernames = string_from_gstring(g);
1458
1459 /* Create signature header with b= omitted */
1460 sig_hdr = pdkim_create_header(sig, FALSE);
1461 }
1462
1463 /* VERIFICATION ----------------------------------------------------------- */
1464 /* When verifying, walk through the header name list in the h= parameter and
1465 add the headers to the hash in that order. */
1466 else
1467 {
1468 uschar * p = sig->headernames;
1469 uschar * q;
1470 pdkim_stringlist * hdrs;
1471
1472 if (p)
1473 {
1474 /* clear tags */
1475 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1476 hdrs->tag = 0;
1477
1478 p = string_copy(p);
1479 while(1)
1480 {
1481 if ((q = Ustrchr(p, ':')))
1482 *q = '\0';
1483
1484 /*XXX walk the list of headers in same order as received. */
1485 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1486 if ( hdrs->tag == 0
1487 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
1488 && (hdrs->value)[Ustrlen(p)] == ':'
1489 )
1490 {
1491 /* cook header for relaxed canon, or just copy it for simple */
1492
1493 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1494 ? pdkim_relax_header(hdrs->value, TRUE)
1495 : string_copy(CUS hdrs->value);
1496
1497 /* Feed header to the hash algorithm */
1498 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1499
1500 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1501 hdrs->tag = 1;
1502 break;
1503 }
1504
1505 if (!q) break;
1506 p = q+1;
1507 }
1508
1509 sig_hdr = string_copy(sig->rawsig_no_b_val);
1510 }
1511 }
1512
1513 DEBUG(D_acl) debug_printf(
1514 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1515
1516 DEBUG(D_acl)
1517 {
1518 debug_printf(
1519 "PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
1520 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1521 debug_printf(
1522 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1523 }
1524
1525 /* Relax header if necessary */
1526 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1527 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
1528
1529 DEBUG(D_acl)
1530 {
1531 debug_printf(
1532 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1533 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1534 debug_printf(
1535 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1536 }
1537
1538 /* Finalize header hash */
1539 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1540 exim_sha_finish(&hhash_ctx, &hhash);
1541
1542 DEBUG(D_acl)
1543 {
1544 debug_printf("PDKIM [%s] Header %s computed: ",
1545 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
1546 pdkim_hexprint(hhash.data, hhash.len);
1547 }
1548
1549 /* Remember headers block for signing (when the signing library cannot do
1550 incremental) */
1551 if (ctx->flags & PDKIM_MODE_SIGN)
1552 hdata = exim_dkim_data_append(hdata, US sig_hdr);
1553
1554 /* SIGNING ---------------------------------------------------------------- */
1555 if (ctx->flags & PDKIM_MODE_SIGN)
1556 {
1557 es_ctx sctx;
1558
1559 /* Import private key, including the keytype */
1560/*XXX extend for non-RSA algos */
1561 if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx)))
1562 {
1563 DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
1564 return PDKIM_ERR_RSA_PRIVKEY;
1565 }
1566
1567 /* Do signing. With OpenSSL we are signing the hash of headers just
1568 calculated, with GnuTLS we have to sign an entire block of headers
1569 (due to available interfaces) and it recalculates the hash internally. */
1570
1571#if defined(SIGN_GNUTLS)
1572 hhash.data = hdata->s;
1573 hhash.len = hdata->ptr;
1574#endif
1575
1576/*XXX extend for non-RSA algos */
1577 if ((*err = exim_dkim_sign(&sctx,
1578 pdkim_hashes[sig->hashtype].exim_hashmethod,
1579 &hhash, &sig->sighash)))
1580 {
1581 DEBUG(D_acl) debug_printf("signing: %s\n", *err);
1582 return PDKIM_ERR_RSA_SIGNING;
1583 }
1584
1585 DEBUG(D_acl)
1586 {
1587 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1588 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1589 }
1590
1591 sig->signature_header = pdkim_create_header(sig, TRUE);
1592 }
1593
1594 /* VERIFICATION ----------------------------------------------------------- */
1595 else
1596 {
1597 ev_ctx vctx;
1598
1599 /* Make sure we have all required signature tags */
1600 if (!( sig->domain && *sig->domain
1601 && sig->selector && *sig->selector
1602 && sig->headernames && *sig->headernames
1603 && sig->bodyhash.data
1604 && sig->sighash.data
1605 && sig->keytype >= 0
1606 && sig->hashtype >= 0
1607 && sig->version
1608 ) )
1609 {
1610 sig->verify_status = PDKIM_VERIFY_INVALID;
1611 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1612
1613 DEBUG(D_acl) debug_printf(
1614 " Error in DKIM-Signature header: tags missing or invalid\n"
1615 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1616 goto NEXT_VERIFY;
1617 }
1618
1619 /* Make sure sig uses supported DKIM version (only v1) */
1620 if (sig->version != 1)
1621 {
1622 sig->verify_status = PDKIM_VERIFY_INVALID;
1623 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1624
1625 DEBUG(D_acl) debug_printf(
1626 " Error in DKIM-Signature header: unsupported DKIM version\n"
1627 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1628 goto NEXT_VERIFY;
1629 }
1630
1631 DEBUG(D_acl)
1632 {
1633 debug_printf( "PDKIM [%s] b from mail: ", sig->domain);
1634 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1635 }
1636
1637 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
1638 goto NEXT_VERIFY;
1639
1640 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1641 do not have the hash part of the sig algorithm matching */
1642
1643 if (sig->pubkey->hashes)
1644 {
1645 const uschar * list = sig->pubkey->hashes, * ele;
1646 int sep = ':';
1647 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
1648 if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
1649 if (!ele)
1650 {
1651 DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
1652 sig->pubkey->hashes,
1653 pdkim_keytypes[sig->keytype],
1654 pdkim_hashes[sig->hashtype].dkim_hashname);
1655 sig->verify_status = PDKIM_VERIFY_FAIL;
1656 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1657 goto NEXT_VERIFY;
1658 }
1659 }
1660
1661 /* Check the signature */
1662/*XXX needs extension for non-RSA */
1663 if ((*err = exim_dkim_verify(&vctx,
1664 pdkim_hashes[sig->hashtype].exim_hashmethod,
1665 &hhash, &sig->sighash)))
1666 {
1667 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
1668 sig->verify_status = PDKIM_VERIFY_FAIL;
1669 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1670 goto NEXT_VERIFY;
1671 }
1672
1673
1674 /* We have a winner! (if bodyhash was correct earlier) */
1675 if (sig->verify_status == PDKIM_VERIFY_NONE)
1676 sig->verify_status = PDKIM_VERIFY_PASS;
1677
1678NEXT_VERIFY:
1679
1680 DEBUG(D_acl)
1681 {
1682 debug_printf("PDKIM [%s] signature status: %s",
1683 sig->domain, pdkim_verify_status_str(sig->verify_status));
1684 if (sig->verify_ext_status > 0)
1685 debug_printf(" (%s)\n",
1686 pdkim_verify_ext_status_str(sig->verify_ext_status));
1687 else
1688 debug_printf("\n");
1689 }
1690 }
1691 }
1692
1693/* If requested, set return pointer to signature(s) */
1694if (return_signatures)
1695 *return_signatures = ctx->sig;
1696
1697return PDKIM_OK;
1698}
1699
1700
1701/* -------------------------------------------------------------------------- */
1702
1703DLLEXPORT pdkim_ctx *
1704pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
1705{
1706pdkim_ctx * ctx;
1707
1708ctx = store_get(sizeof(pdkim_ctx));
1709memset(ctx, 0, sizeof(pdkim_ctx));
1710
1711if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1712ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1713ctx->dns_txt_callback = dns_txt_callback;
1714
1715return ctx;
1716}
1717
1718
1719/* -------------------------------------------------------------------------- */
1720
1721/*XXX ? needs extension to cover non-RSA algo? */
1722
1723DLLEXPORT pdkim_signature *
1724pdkim_init_sign(pdkim_ctx * ctx,
1725 uschar * domain, uschar * selector, uschar * privkey,
1726 uschar * hashname, const uschar ** errstr)
1727{
1728int hashtype;
1729pdkim_signature * sig;
1730
1731if (!domain || !selector || !privkey)
1732 return NULL;
1733
1734/* Allocate & init one signature struct */
1735
1736sig = store_get(sizeof(pdkim_signature));
1737memset(sig, 0, sizeof(pdkim_signature));
1738
1739sig->bodylength = -1;
1740
1741sig->domain = string_copy(US domain);
1742sig->selector = string_copy(US selector);
1743sig->privkey = string_copy(US privkey);
1744/*XXX no keytype yet; comes from privkey */
1745
1746for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
1747 if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
1748 { sig->hashtype = hashtype; break; }
1749if (hashtype >= nelem(pdkim_hashes))
1750 {
1751 DEBUG(D_acl)
1752 debug_printf("PDKIM: unrecognised hashname '%s'\n", hashname);
1753 return NULL;
1754 }
1755
1756if (!exim_sha_init(&sig->body_hash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
1757 {
1758 DEBUG(D_acl)
1759 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
1760 return NULL;
1761 }
1762
1763DEBUG(D_acl)
1764 {
1765 pdkim_signature s = *sig;
1766 ev_ctx vctx;
1767
1768 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1769 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
1770 debug_printf("WARNING: bad dkim key in dns\n");
1771 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1772 }
1773return sig;
1774}
1775
1776
1777/* -------------------------------------------------------------------------- */
1778
1779DLLEXPORT void
1780pdkim_set_optional(pdkim_signature * sig,
1781 char * sign_headers,
1782 char * identity,
1783 int canon_headers,
1784 int canon_body,
1785 long bodylength,
1786 unsigned long created,
1787 unsigned long expires)
1788{
1789if (identity)
1790 sig->identity = string_copy(US identity);
1791
1792sig->sign_headers = string_copy(sign_headers
1793 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1794
1795sig->canon_headers = canon_headers;
1796sig->canon_body = canon_body;
1797sig->bodylength = bodylength;
1798sig->created = created;
1799sig->expires = expires;
1800
1801return;
1802}
1803
1804
1805
1806void
1807pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
1808 int(*dns_txt_callback)(char *, char *))
1809{
1810memset(ctx, 0, sizeof(pdkim_ctx));
1811ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1812ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1813DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
1814}
1815
1816
1817void
1818pdkim_init(void)
1819{
1820exim_dkim_init();
1821}
1822
1823
1824
1825#endif /*DISABLE_DKIM*/