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