Copyright updates:
[exim.git] / src / src / pdkim / pdkim.c
CommitLineData
80a47a2c
TK
1/*
2 * PDKIM - a RFC4871 (DKIM) implementation
3 *
f444c2c7 4 * Copyright (C) 2009 - 2016 Tom Kistner <tom@duncanthrax.net>
1e1ddfac 5 * Copyright (C) 2016 - 2020 Jeremy Harris <jgh@exim.org>
80a47a2c
TK
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
0d04a285 24#include "../exim.h"
80a47a2c 25
f444c2c7
JH
26
27#ifndef DISABLE_DKIM /* entire file */
28
01603eec
JH
29#ifdef DISABLE_TLS
30# error Must not DISABLE_TLS, for DKIM
f444c2c7
JH
31#endif
32
cb224393 33#include "crypt_ver.h"
f444c2c7 34
d73e45df 35#ifdef SIGN_OPENSSL
cb224393
JH
36# include <openssl/rsa.h>
37# include <openssl/ssl.h>
38# include <openssl/err.h>
d73e45df 39#elif defined(SIGN_GNUTLS)
f444c2c7
JH
40# include <gnutls/gnutls.h>
41# include <gnutls/x509.h>
f444c2c7
JH
42#endif
43
44#include "pdkim.h"
9b2583c4 45#include "signing.h"
80a47a2c
TK
46
47#define PDKIM_SIGNATURE_VERSION "1"
e2e3255a 48#define PDKIM_PUB_RECORD_VERSION US "DKIM1"
80a47a2c
TK
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
80a47a2c
TK
54
55/* -------------------------------------------------------------------------- */
56struct pdkim_stringlist {
e2e3255a
JH
57 uschar * value;
58 int tag;
59 void * next;
80a47a2c
TK
60};
61
80a47a2c
TK
62/* -------------------------------------------------------------------------- */
63/* A bunch of list constants */
e2e3255a
JH
64const uschar * pdkim_querymethods[] = {
65 US"dns/txt",
80a47a2c
TK
66 NULL
67};
e2e3255a
JH
68const uschar * pdkim_canons[] = {
69 US"simple",
70 US"relaxed",
80a47a2c
TK
71 NULL
72};
d73e45df 73
617d3932 74const pdkim_hashtype pdkim_hashes[] = {
d73e45df
JH
75 { US"sha1", HASH_SHA1 },
76 { US"sha256", HASH_SHA2_256 },
77 { US"sha512", HASH_SHA2_512 }
80a47a2c 78};
d73e45df 79
e2e3255a 80const uschar * pdkim_keytypes[] = {
286b9d5f
JH
81 [KEYTYPE_RSA] = US"rsa",
82#ifdef SIGN_HAVE_ED25519
321ef002 83 [KEYTYPE_ED25519] = US"ed25519", /* Works for 3.6.0 GnuTLS, OpenSSL 1.1.1 */
286b9d5f
JH
84#endif
85
86#ifdef notyet_EC_dkim_extensions /* https://tools.ietf.org/html/draft-srose-dkim-ecc-00 */
87 US"eccp256",
88 US"eccp348",
89 US"ed448",
90#endif
80a47a2c
TK
91};
92
93typedef struct pdkim_combined_canon_entry {
286b9d5f
JH
94 const uschar * str;
95 int canon_headers;
96 int canon_body;
80a47a2c 97} pdkim_combined_canon_entry;
f444c2c7 98
80a47a2c 99pdkim_combined_canon_entry pdkim_combined_canons[] = {
e2e3255a
JH
100 { US"simple/simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
101 { US"simple/relaxed", PDKIM_CANON_SIMPLE, PDKIM_CANON_RELAXED },
102 { US"relaxed/simple", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
103 { US"relaxed/relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_RELAXED },
104 { US"simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
105 { US"relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
106 { NULL, 0, 0 }
80a47a2c
TK
107};
108
109
9e70917d
JH
110static blob lineending = {.data = US"\r\n", .len = 2};
111
f444c2c7 112/* -------------------------------------------------------------------------- */
d73e45df 113uschar *
9e70917d 114dkim_sig_to_a_tag(const pdkim_signature * sig)
d73e45df
JH
115{
116if ( sig->keytype < 0 || sig->keytype > nelem(pdkim_keytypes)
117 || sig->hashtype < 0 || sig->hashtype > nelem(pdkim_hashes))
118 return US"err";
119return string_sprintf("%s-%s",
120 pdkim_keytypes[sig->keytype], pdkim_hashes[sig->hashtype].dkim_hashname);
121}
122
123
042e558f
JH
124static int
125pdkim_keyname_to_keytype(const uschar * s)
126{
127for (int i = 0; i < nelem(pdkim_keytypes); i++)
128 if (Ustrcmp(s, pdkim_keytypes[i]) == 0) return i;
129return -1;
130}
131
617d3932
JH
132int
133pdkim_hashname_to_hashtype(const uschar * s, unsigned len)
134{
617d3932 135if (!len) len = Ustrlen(s);
d7978c0f 136for (int i = 0; i < nelem(pdkim_hashes); i++)
617d3932
JH
137 if (Ustrncmp(s, pdkim_hashes[i].dkim_hashname, len) == 0)
138 return i;
139return -1;
140}
141
142void
143pdkim_cstring_to_canons(const uschar * s, unsigned len,
144 int * canon_head, int * canon_body)
145{
617d3932 146if (!len) len = Ustrlen(s);
d7978c0f 147for (int i = 0; pdkim_combined_canons[i].str; i++)
617d3932
JH
148 if ( Ustrncmp(s, pdkim_combined_canons[i].str, len) == 0
149 && len == Ustrlen(pdkim_combined_canons[i].str))
150 {
151 *canon_head = pdkim_combined_canons[i].canon_headers;
152 *canon_body = pdkim_combined_canons[i].canon_body;
153 break;
154 }
155}
156
157
f444c2c7
JH
158
159const char *
160pdkim_verify_status_str(int status)
161{
f7302073
JH
162switch(status)
163 {
164 case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE";
165 case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID";
166 case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL";
167 case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS";
168 default: return "PDKIM_VERIFY_UNKNOWN";
ff7ddfd7
TK
169 }
170}
f444c2c7
JH
171
172const char *
173pdkim_verify_ext_status_str(int ext_status)
174{
f7302073
JH
175switch(ext_status)
176 {
177 case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
178 case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
135e9496 179 case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
f7302073
JH
180 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
181 case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
182 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
183 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
be24b950 184 case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return "PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE";
f7302073
JH
185 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
186 case PDKIM_VERIFY_INVALID_DKIM_VERSION: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
187 default: return "PDKIM_VERIFY_UNKNOWN";
188 }
189}
190
b9df1829 191const uschar *
f7302073
JH
192pdkim_errstr(int status)
193{
194switch(status)
195 {
b9df1829
JH
196 case PDKIM_OK: return US"OK";
197 case PDKIM_FAIL: return US"FAIL";
286b9d5f
JH
198 case PDKIM_ERR_RSA_PRIVKEY: return US"PRIVKEY";
199 case PDKIM_ERR_RSA_SIGNING: return US"SIGNING";
200 case PDKIM_ERR_LONG_LINE: return US"LONG_LINE";
b9df1829 201 case PDKIM_ERR_BUFFER_TOO_SMALL: return US"BUFFER_TOO_SMALL";
64b67b65 202 case PDKIM_ERR_EXCESS_SIGS: return US"EXCESS_SIGS";
b9df1829
JH
203 case PDKIM_SIGN_PRIVKEY_WRAP: return US"PRIVKEY_WRAP";
204 case PDKIM_SIGN_PRIVKEY_B64D: return US"PRIVKEY_B64D";
ef698bf6 205 default: return US"(unknown)";
ff7ddfd7
TK
206 }
207}
208
209
80a47a2c
TK
210/* -------------------------------------------------------------------------- */
211/* Print debugging functions */
617d3932 212void
b78006ac 213pdkim_quoteprint(const uschar *data, int len)
3045f050 214{
d7978c0f 215for (int i = 0; i < len; i++)
3045f050 216 {
b78006ac 217 const int c = data[i];
3045f050
JH
218 switch (c)
219 {
0d04a285
JH
220 case ' ' : debug_printf("{SP}"); break;
221 case '\t': debug_printf("{TB}"); break;
222 case '\r': debug_printf("{CR}"); break;
223 case '\n': debug_printf("{LF}"); break;
224 case '{' : debug_printf("{BO}"); break;
225 case '}' : debug_printf("{BC}"); break;
3045f050
JH
226 default:
227 if ( (c < 32) || (c > 127) )
0d04a285 228 debug_printf("{%02x}", c);
3045f050 229 else
0d04a285 230 debug_printf("%c", c);
80a47a2c
TK
231 break;
232 }
233 }
2592e6c0 234debug_printf("\n");
80a47a2c 235}
80a47a2c 236
617d3932 237void
b78006ac 238pdkim_hexprint(const uschar *data, int len)
3045f050 239{
d7978c0f 240if (data) for (int i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
02c4f8fb 241else debug_printf("<NULL>");
2592e6c0 242debug_printf("\n");
80a47a2c 243}
80a47a2c
TK
244
245
f444c2c7 246
f444c2c7 247static pdkim_stringlist *
ca9cb170 248pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
3045f050 249{
f3ebb786 250pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist), FALSE);
3045f050 251
abe1010c 252memset(new_entry, 0, sizeof(pdkim_stringlist));
ca9cb170 253new_entry->value = string_copy(str);
ab9152ff
JH
254if (base) new_entry->next = base;
255return new_entry;
6ab02e3f 256}
80a47a2c
TK
257
258
8ef02a06
JH
259
260/* Trim whitespace fore & aft */
261
ca9cb170 262static void
acec9514 263pdkim_strtrim(gstring * str)
3045f050 264{
acec9514 265uschar * p = str->s;
b2bcdd35 266uschar * q;
acec9514
JH
267
268while (*p == '\t' || *p == ' ') /* dump the leading whitespace */
269 { str->size--; str->ptr--; str->s++; }
270
271while ( str->ptr > 0
81147e20 272 && ((q = str->s + str->ptr - 1), (*q == '\t' || *q == ' '))
acec9514
JH
273 )
274 str->ptr--; /* dump trailing whitespace */
275
276(void) string_from_gstring(str);
8ef02a06
JH
277}
278
279
80a47a2c
TK
280
281/* -------------------------------------------------------------------------- */
3045f050 282
3045f050
JH
283DLLEXPORT void
284pdkim_free_ctx(pdkim_ctx *ctx)
285{
6ab02e3f 286}
80a47a2c
TK
287
288
289/* -------------------------------------------------------------------------- */
290/* Matches the name of the passed raw "header" against
8ef02a06 291 the passed colon-separated "tick", and invalidates
484cc1a9
JH
292 the entry in tick. Entries can be prefixed for multi- or over-signing,
293 in which case do not invalidate.
294
295 Returns OK for a match, or fail-code
296*/
3045f050 297
f444c2c7 298static int
e2e3255a 299header_name_match(const uschar * header, uschar * tick)
3045f050 300{
484cc1a9
JH
301const uschar * ticklist = tick;
302int sep = ':';
303BOOL multisign;
304uschar * hname, * p, * ele;
ca9cb170 305uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
3045f050 306
ca9cb170
JH
307if (!hcolon)
308 return PDKIM_FAIL; /* This isn't a header */
3045f050 309
ca9cb170
JH
310/* if we had strncmpic() we wouldn't need this copy */
311hname = string_copyn(header, hcolon-header);
3045f050 312
484cc1a9 313while (p = US ticklist, ele = string_nextinlist(&ticklist, &sep, NULL, 0))
3045f050 314 {
484cc1a9
JH
315 switch (*ele)
316 {
317 case '=': case '+': multisign = TRUE; ele++; break;
318 default: multisign = FALSE; break;
80a47a2c
TK
319 }
320
484cc1a9
JH
321 if (strcmpic(ele, hname) == 0)
322 {
323 if (!multisign)
324 *p = '_'; /* Invalidate this header name instance in tick-off list */
325 return PDKIM_OK;
326 }
327 }
ca9cb170 328return PDKIM_FAIL;
80a47a2c
TK
329}
330
331
332/* -------------------------------------------------------------------------- */
ca9cb170 333/* Performs "relaxed" canonicalization of a header. */
3045f050 334
617d3932
JH
335uschar *
336pdkim_relax_header_n(const uschar * header, int len, BOOL append_crlf)
3045f050
JH
337{
338BOOL past_field_name = FALSE;
339BOOL seen_wsp = FALSE;
f3ebb786 340uschar * relaxed = store_get(len+3, TRUE); /* tainted */
ca9cb170 341uschar * q = relaxed;
3045f050 342
d7978c0f 343for (const uschar * p = header; p - header < len; p++)
3045f050 344 {
ca9cb170 345 uschar c = *p;
ea18931d
JH
346
347 if (c == '\r' || c == '\n') /* Ignore CR & LF */
3045f050
JH
348 continue;
349 if (c == '\t' || c == ' ')
350 {
351 if (seen_wsp)
80a47a2c 352 continue;
3045f050
JH
353 c = ' '; /* Turns WSP into SP */
354 seen_wsp = TRUE;
80a47a2c 355 }
3045f050
JH
356 else
357 if (!past_field_name && c == ':')
358 {
ea18931d
JH
359 if (seen_wsp) q--; /* This removes WSP immediately before the colon */
360 seen_wsp = TRUE; /* This removes WSP immediately after the colon */
3045f050 361 past_field_name = TRUE;
80a47a2c 362 }
3045f050
JH
363 else
364 seen_wsp = FALSE;
365
366 /* Lowercase header name */
367 if (!past_field_name) c = tolower(c);
368 *q++ = c;
80a47a2c 369 }
3045f050
JH
370
371if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
3045f050 372
ea18931d 373if (append_crlf) { *q++ = '\r'; *q++ = '\n'; }
ca9cb170 374*q = '\0';
3045f050 375return relaxed;
6ab02e3f 376}
80a47a2c
TK
377
378
617d3932
JH
379uschar *
380pdkim_relax_header(const uschar * header, BOOL append_crlf)
381{
382return pdkim_relax_header_n(header, Ustrlen(header), append_crlf);
383}
384
385
80a47a2c
TK
386/* -------------------------------------------------------------------------- */
387#define PDKIM_QP_ERROR_DECODE -1
3045f050 388
35cf75e9
JH
389static const uschar *
390pdkim_decode_qp_char(const uschar *qp_p, int *c)
3045f050 391{
35cf75e9 392const uschar *initial_pos = qp_p;
3045f050
JH
393
394/* Advance one char */
395qp_p++;
396
397/* Check for two hex digits and decode them */
398if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
399 {
400 /* Do hex conversion */
401 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
a5840e10 402 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
3045f050 403 return qp_p + 2;
6ab02e3f 404 }
80a47a2c 405
3045f050
JH
406/* Illegal char here */
407*c = PDKIM_QP_ERROR_DECODE;
408return initial_pos;
80a47a2c
TK
409}
410
411
412/* -------------------------------------------------------------------------- */
3045f050 413
e2e3255a 414static uschar *
35cf75e9 415pdkim_decode_qp(const uschar * str)
3045f050
JH
416{
417int nchar = 0;
ca9cb170 418uschar * q;
35cf75e9 419const uschar * p = str;
f3ebb786 420uschar * n = store_get(Ustrlen(str)+1, TRUE);
3045f050
JH
421
422*n = '\0';
423q = n;
ca9cb170 424while (*p)
3045f050
JH
425 {
426 if (*p == '=')
427 {
428 p = pdkim_decode_qp_char(p, &nchar);
429 if (nchar >= 0)
430 {
431 *q++ = nchar;
432 continue;
80a47a2c
TK
433 }
434 }
3045f050
JH
435 else
436 *q++ = *p;
437 p++;
80a47a2c 438 }
3045f050
JH
439*q = '\0';
440return n;
80a47a2c
TK
441}
442
443
444/* -------------------------------------------------------------------------- */
3045f050 445
617d3932 446void
35cf75e9 447pdkim_decode_base64(const uschar * str, blob * b)
3045f050 448{
617d3932 449int dlen = b64decode(str, &b->data);
2592e6c0
JH
450if (dlen < 0) b->data = NULL;
451b->len = dlen;
80a47a2c
TK
452}
453
617d3932 454uschar *
2592e6c0 455pdkim_encode_base64(blob * b)
3045f050 456{
1f20760b 457return b64encode(CUS b->data, b->len);
80a47a2c
TK
458}
459
460
461/* -------------------------------------------------------------------------- */
462#define PDKIM_HDR_LIMBO 0
463#define PDKIM_HDR_TAG 1
464#define PDKIM_HDR_VALUE 2
3045f050 465
f444c2c7 466static pdkim_signature *
9e70917d 467pdkim_parse_sig_header(pdkim_ctx * ctx, uschar * raw_hdr)
3045f050 468{
2c0f3ea1 469pdkim_signature * sig;
d7978c0f 470uschar *q;
acec9514
JH
471gstring * cur_tag = NULL;
472gstring * cur_val = NULL;
3045f050
JH
473BOOL past_hname = FALSE;
474BOOL in_b_val = FALSE;
475int where = PDKIM_HDR_LIMBO;
3045f050 476
f3ebb786 477sig = store_get(sizeof(pdkim_signature), FALSE);
abe1010c 478memset(sig, 0, sizeof(pdkim_signature));
3045f050
JH
479sig->bodylength = -1;
480
07eeb4df 481/* Set so invalid/missing data error display is accurate */
07eeb4df 482sig->version = 0;
d73e45df
JH
483sig->keytype = -1;
484sig->hashtype = -1;
07eeb4df 485
f3ebb786 486q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1, TRUE); /* tainted */
80a47a2c 487
d7978c0f 488for (uschar * p = raw_hdr; ; p++)
3045f050
JH
489 {
490 char c = *p;
80a47a2c 491
3045f050
JH
492 /* Ignore FWS */
493 if (c == '\r' || c == '\n')
494 goto NEXT_CHAR;
80a47a2c 495
3045f050
JH
496 /* Fast-forward through header name */
497 if (!past_hname)
498 {
499 if (c == ':') past_hname = TRUE;
500 goto NEXT_CHAR;
80a47a2c
TK
501 }
502
3045f050
JH
503 if (where == PDKIM_HDR_LIMBO)
504 {
505 /* In limbo, just wait for a tag-char to appear */
506 if (!(c >= 'a' && c <= 'z'))
507 goto NEXT_CHAR;
80a47a2c 508
3045f050 509 where = PDKIM_HDR_TAG;
80a47a2c
TK
510 }
511
3045f050
JH
512 if (where == PDKIM_HDR_TAG)
513 {
3045f050 514 if (c >= 'a' && c <= 'z')
acec9514 515 cur_tag = string_catn(cur_tag, p, 1);
80a47a2c 516
3045f050
JH
517 if (c == '=')
518 {
acec9514 519 if (Ustrcmp(string_from_gstring(cur_tag), "b") == 0)
3045f050 520 {
ca9cb170 521 *q++ = '=';
3045f050
JH
522 in_b_val = TRUE;
523 }
524 where = PDKIM_HDR_VALUE;
525 goto NEXT_CHAR;
80a47a2c
TK
526 }
527 }
528
3045f050
JH
529 if (where == PDKIM_HDR_VALUE)
530 {
3045f050
JH
531 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
532 goto NEXT_CHAR;
533
534 if (c == ';' || c == '\0')
535 {
a05d3e34
JH
536 /* We must have both tag and value, and tags must be one char except
537 for the possibility of "bh". */
538
539 if ( cur_tag && cur_val
540 && (cur_tag->ptr == 1 || *cur_tag->s == 'b')
541 )
3045f050 542 {
acec9514 543 (void) string_from_gstring(cur_val);
3045f050
JH
544 pdkim_strtrim(cur_val);
545
acec9514 546 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->s, cur_val->s);
3045f050 547
acec9514 548 switch (*cur_tag->s)
3045f050 549 {
286b9d5f 550 case 'b': /* sig-data or body-hash */
a05d3e34
JH
551 switch (cur_tag->s[1])
552 {
553 case '\0': pdkim_decode_base64(cur_val->s, &sig->sighash); break;
554 case 'h': if (cur_tag->ptr == 2)
555 pdkim_decode_base64(cur_val->s, &sig->bodyhash);
556 break;
557 default: break;
558 }
3045f050 559 break;
286b9d5f 560 case 'v': /* version */
3045f050
JH
561 /* We only support version 1, and that is currently the
562 only version there is. */
07eeb4df 563 sig->version =
acec9514 564 Ustrcmp(cur_val->s, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
3045f050 565 break;
286b9d5f 566 case 'a': /* algorithm */
d73e45df 567 {
e220ba1d
JH
568 const uschar * list = cur_val->s;
569 int sep = '-';
570 uschar * elem;
571
572 if ((elem = string_nextinlist(&list, &sep, NULL, 0)))
042e558f 573 sig->keytype = pdkim_keyname_to_keytype(elem);
e220ba1d 574 if ((elem = string_nextinlist(&list, &sep, NULL, 0)))
d7978c0f 575 for (int i = 0; i < nelem(pdkim_hashes); i++)
e220ba1d
JH
576 if (Ustrcmp(elem, pdkim_hashes[i].dkim_hashname) == 0)
577 { sig->hashtype = i; break; }
d73e45df
JH
578 }
579
286b9d5f 580 case 'c': /* canonicalization */
617d3932
JH
581 pdkim_cstring_to_canons(cur_val->s, 0,
582 &sig->canon_headers, &sig->canon_body);
3045f050 583 break;
286b9d5f 584 case 'q': /* Query method (for pubkey)*/
d7978c0f 585 for (int i = 0; pdkim_querymethods[i]; i++)
acec9514 586 if (Ustrcmp(cur_val->s, pdkim_querymethods[i]) == 0)
3045f050 587 {
286b9d5f 588 sig->querymethod = i; /* we never actually use this */
3045f050
JH
589 break;
590 }
591 break;
286b9d5f 592 case 's': /* Selector */
acec9514 593 sig->selector = string_copyn(cur_val->s, cur_val->ptr); break;
286b9d5f 594 case 'd': /* SDID */
acec9514 595 sig->domain = string_copyn(cur_val->s, cur_val->ptr); break;
286b9d5f 596 case 'i': /* AUID */
acec9514 597 sig->identity = pdkim_decode_qp(cur_val->s); break;
286b9d5f 598 case 't': /* Timestamp */
acec9514 599 sig->created = strtoul(CS cur_val->s, NULL, 10); break;
286b9d5f 600 case 'x': /* Expiration */
acec9514 601 sig->expires = strtoul(CS cur_val->s, NULL, 10); break;
286b9d5f 602 case 'l': /* Body length count */
acec9514 603 sig->bodylength = strtol(CS cur_val->s, NULL, 10); break;
286b9d5f 604 case 'h': /* signed header fields */
acec9514 605 sig->headernames = string_copyn(cur_val->s, cur_val->ptr); break;
286b9d5f 606 case 'z': /* Copied headfields */
acec9514 607 sig->copiedheaders = pdkim_decode_qp(cur_val->s); break;
286b9d5f
JH
608/*XXX draft-ietf-dcrup-dkim-crypto-05 would need 'p' tag support
609for rsafp signatures. But later discussion is dropping those. */
3045f050 610 default:
0d04a285 611 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
3045f050
JH
612 break;
613 }
614 }
acec9514 615 cur_tag = cur_val = NULL;
3045f050
JH
616 in_b_val = FALSE;
617 where = PDKIM_HDR_LIMBO;
80a47a2c 618 }
3045f050 619 else
acec9514 620 cur_val = string_catn(cur_val, p, 1);
80a47a2c
TK
621 }
622
3045f050
JH
623NEXT_CHAR:
624 if (c == '\0')
625 break;
80a47a2c 626
3045f050
JH
627 if (!in_b_val)
628 *q++ = c;
80a47a2c
TK
629 }
630
286b9d5f
JH
631if (sig->keytype < 0 || sig->hashtype < 0) /* Cannot verify this signature */
632 return NULL;
633
3045f050
JH
634*q = '\0';
635/* Chomp raw header. The final newline must not be added to the signature. */
37f3dc43
JH
636while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
637 *q = '\0';
80a47a2c 638
0d04a285 639DEBUG(D_acl)
3045f050 640 {
0d04a285 641 debug_printf(
305f8921 642 "DKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
e2e3255a 643 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
0d04a285 644 debug_printf(
305f8921 645 "DKIM >> Sig size: %4u bits\n", (unsigned) sig->sighash.len*8);
0d04a285 646 debug_printf(
305f8921 647 "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 648 }
80a47a2c 649
617d3932 650if (!pdkim_set_sig_bodyhash(ctx, sig))
7b83389d 651 return NULL;
cf1cce5e 652
3045f050 653return sig;
80a47a2c
TK
654}
655
656
657/* -------------------------------------------------------------------------- */
80a47a2c 658
617d3932
JH
659pdkim_pubkey *
660pdkim_parse_pubkey_record(const uschar *raw_record)
3045f050 661{
35cf75e9
JH
662const uschar * ele;
663int sep = ';';
664pdkim_pubkey * pub;
80a47a2c 665
f3ebb786 666pub = store_get(sizeof(pdkim_pubkey), TRUE); /* tainted */
abe1010c 667memset(pub, 0, sizeof(pdkim_pubkey));
80a47a2c 668
35cf75e9
JH
669while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
670 {
671 const uschar * val;
672
673 if ((val = Ustrchr(ele, '=')))
3045f050 674 {
35cf75e9 675 int taglen = val++ - ele;
80a47a2c 676
35cf75e9
JH
677 DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
678 switch (ele[0])
3045f050 679 {
35cf75e9
JH
680 case 'v': pub->version = val; break;
681 case 'h': pub->hashes = val; break;
286b9d5f 682 case 'k': pub->keytype = val; break;
35cf75e9
JH
683 case 'g': pub->granularity = val; break;
684 case 'n': pub->notes = pdkim_decode_qp(val); break;
685 case 'p': pdkim_decode_base64(val, &pub->key); break;
686 case 's': pub->srvtype = val; break;
687 case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
688 if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
e21a4d00 689 break;
35cf75e9 690 default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
80a47a2c 691 }
e21a4d00 692 }
35cf75e9 693 }
80a47a2c 694
3045f050 695/* Set fallback defaults */
fc6fb551
JH
696if (!pub->version)
697 pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
135e9496
JH
698else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
699 {
700 DEBUG(D_acl) debug_printf(" Bad v= field\n");
701 return NULL;
702 }
e21a4d00 703
35cf75e9 704if (!pub->granularity) pub->granularity = US"*";
35cf75e9 705if (!pub->keytype ) pub->keytype = US"rsa";
35cf75e9 706if (!pub->srvtype ) pub->srvtype = US"*";
80a47a2c 707
3045f050 708/* p= is required */
2592e6c0 709if (pub->key.data)
80a47a2c 710 return pub;
3045f050 711
135e9496 712DEBUG(D_acl) debug_printf(" Missing p= field\n");
3045f050 713return NULL;
80a47a2c
TK
714}
715
716
717/* -------------------------------------------------------------------------- */
3045f050 718
cf1cce5e 719/* Update one bodyhash with some additional data.
9e70917d
JH
720If we have to relax the data for this sig, return our copy of it. */
721
9e70917d 722static blob *
cf1cce5e 723pdkim_update_ctx_bodyhash(pdkim_bodyhash * b, blob * orig_data, blob * relaxed_data)
3045f050 724{
9e70917d
JH
725blob * canon_data = orig_data;
726/* Defaults to simple canon (no further treatment necessary) */
3045f050 727
cf1cce5e 728if (b->canon_method == PDKIM_CANON_RELAXED)
3045f050 729 {
9e70917d
JH
730 /* Relax the line if not done already */
731 if (!relaxed_data)
3045f050 732 {
9e70917d 733 BOOL seen_wsp = FALSE;
9e70917d 734 int q = 0;
3045f050 735
9e70917d
JH
736 /* We want to be able to free this else we allocate
737 for the entire message which could be many MB. Since
738 we don't know what allocations the SHA routines might
739 do, not safe to use store_get()/store_reset(). */
d5bccfc8 740
9e70917d
JH
741 relaxed_data = store_malloc(sizeof(blob) + orig_data->len+1);
742 relaxed_data->data = US (relaxed_data+1);
3045f050 743
d7978c0f 744 for (const uschar * p = orig_data->data, * r = p + orig_data->len; p < r; p++)
9e70917d
JH
745 {
746 char c = *p;
747 if (c == '\r')
748 {
749 if (q > 0 && relaxed_data->data[q-1] == ' ')
750 q--;
751 }
752 else if (c == '\t' || c == ' ')
753 {
754 c = ' '; /* Turns WSP into SP */
755 if (seen_wsp)
756 continue;
757 seen_wsp = TRUE;
3045f050 758 }
9e70917d
JH
759 else
760 seen_wsp = FALSE;
761 relaxed_data->data[q++] = c;
80a47a2c 762 }
9e70917d
JH
763 relaxed_data->data[q] = '\0';
764 relaxed_data->len = q;
80a47a2c 765 }
9e70917d
JH
766 canon_data = relaxed_data;
767 }
80a47a2c 768
9e70917d 769/* Make sure we don't exceed the to-be-signed body length */
cf1cce5e
JH
770if ( b->bodylength >= 0
771 && b->signed_body_bytes + (unsigned long)canon_data->len > b->bodylength
9e70917d 772 )
cf1cce5e 773 canon_data->len = b->bodylength - b->signed_body_bytes;
80a47a2c 774
9e70917d
JH
775if (canon_data->len > 0)
776 {
cf1cce5e
JH
777 exim_sha_update(&b->body_hash_ctx, CUS canon_data->data, canon_data->len);
778 b->signed_body_bytes += canon_data->len;
9e70917d 779 DEBUG(D_acl) pdkim_quoteprint(canon_data->data, canon_data->len);
80a47a2c
TK
780 }
781
9e70917d 782return relaxed_data;
6ab02e3f 783}
80a47a2c
TK
784
785
786/* -------------------------------------------------------------------------- */
80a47a2c 787
ca9cb170 788static void
9e70917d 789pdkim_finish_bodyhash(pdkim_ctx * ctx)
3045f050 790{
d7978c0f 791for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next) /* Finish hashes */
617d3932 792 {
305f8921 793 DEBUG(D_acl) debug_printf("DKIM: finish bodyhash %d/%d/%ld len %ld\n",
617d3932 794 b->hashtype, b->canon_method, b->bodylength, b->signed_body_bytes);
cf1cce5e 795 exim_sha_finish(&b->body_hash_ctx, &b->bh);
617d3932 796 }
cf1cce5e 797
3045f050 798/* Traverse all signatures */
d7978c0f 799for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next)
cf1cce5e 800 {
d7978c0f 801 pdkim_bodyhash * b = sig->calc_body_hash;
3045f050 802
0d04a285 803 DEBUG(D_acl)
3045f050 804 {
305f8921
HSHR
805 debug_printf("DKIM [%s] Body bytes (%s) hashed: %lu\n"
806 "DKIM [%s] Body %s computed: ",
4ff848b5
JH
807 sig->domain, pdkim_canons[b->canon_method], b->signed_body_bytes,
808 sig->domain, pdkim_hashes[b->hashtype].dkim_hashname);
cf1cce5e 809 pdkim_hexprint(CUS b->bh.data, b->bh.len);
80a47a2c 810 }
3045f050
JH
811
812 /* SIGNING -------------------------------------------------------------- */
e983e85a 813 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 814 {
3045f050
JH
815 /* If bodylength limit is set, and we have received less bytes
816 than the requested amount, effectively remove the limit tag. */
cf1cce5e 817 if (b->signed_body_bytes < sig->bodylength)
3045f050 818 sig->bodylength = -1;
80a47a2c 819 }
3045f050 820
3045f050 821 else
02c4f8fb
JH
822 /* VERIFICATION --------------------------------------------------------- */
823 /* Be careful that the header sig included a bodyash */
824
cf1cce5e
JH
825 if ( sig->bodyhash.data
826 && memcmp(b->bh.data, sig->bodyhash.data, b->bh.len) == 0)
3045f050 827 {
305f8921 828 DEBUG(D_acl) debug_printf("DKIM [%s] Body hash compared OK\n", sig->domain);
80a47a2c 829 }
3045f050
JH
830 else
831 {
0d04a285 832 DEBUG(D_acl)
3045f050 833 {
305f8921 834 debug_printf("DKIM [%s] Body hash signature from headers: ", sig->domain);
dcd03763 835 pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
305f8921 836 debug_printf("DKIM [%s] Body hash did NOT verify\n", sig->domain);
3045f050 837 }
3045f050
JH
838 sig->verify_status = PDKIM_VERIFY_FAIL;
839 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
80a47a2c 840 }
80a47a2c 841 }
6ab02e3f 842}
80a47a2c
TK
843
844
845
9e70917d 846static void
e983e85a
JH
847pdkim_body_complete(pdkim_ctx * ctx)
848{
e983e85a
JH
849/* In simple body mode, if any empty lines were buffered,
850replace with one. rfc 4871 3.4.3 */
851/*XXX checking the signed-body-bytes is a gross hack; I think
852it indicates that all linebreaks should be buffered, including
853the one terminating a text line */
854
d7978c0f 855for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)
cf1cce5e
JH
856 if ( b->canon_method == PDKIM_CANON_SIMPLE
857 && b->signed_body_bytes == 0
858 && b->num_buffered_blanklines > 0
9e70917d 859 )
cf1cce5e 860 (void) pdkim_update_ctx_bodyhash(b, &lineending, NULL);
e983e85a
JH
861
862ctx->flags |= PDKIM_SEEN_EOD;
863ctx->linebuf_offset = 0;
e983e85a
JH
864}
865
866
867
80a47a2c 868/* -------------------------------------------------------------------------- */
e983e85a 869/* Call from pdkim_feed below for processing complete body lines */
744976d4 870/* NOTE: the line is not NUL-terminated; but we have a count */
3045f050 871
9e70917d
JH
872static void
873pdkim_bodyline_complete(pdkim_ctx * ctx)
3045f050 874{
9e70917d 875blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
9e70917d
JH
876blob * rnl = NULL;
877blob * rline = NULL;
3045f050
JH
878
879/* Ignore extra data if we've seen the end-of-data marker */
9e70917d 880if (ctx->flags & PDKIM_SEEN_EOD) goto all_skip;
3045f050
JH
881
882/* We've always got one extra byte to stuff a zero ... */
9e70917d 883ctx->linebuf[line.len] = '\0';
3045f050 884
0d04a285 885/* Terminate on EOD marker */
e983e85a 886if (ctx->flags & PDKIM_DOT_TERM)
3045f050 887 {
9e70917d
JH
888 if (memcmp(line.data, ".\r\n", 3) == 0)
889 { pdkim_body_complete(ctx); return; }
0d04a285 890
e983e85a 891 /* Unstuff dots */
9e70917d
JH
892 if (memcmp(line.data, "..", 2) == 0)
893 { line.data++; line.len--; }
80a47a2c
TK
894 }
895
3045f050 896/* Empty lines need to be buffered until we find a non-empty line */
9e70917d 897if (memcmp(line.data, "\r\n", 2) == 0)
3045f050 898 {
d7978c0f
JH
899 for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)
900 b->num_buffered_blanklines++;
9e70917d 901 goto all_skip;
80a47a2c
TK
902 }
903
cf1cce5e 904/* Process line for each bodyhash separately */
d7978c0f 905for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)
3045f050 906 {
cf1cce5e 907 if (b->canon_method == PDKIM_CANON_RELAXED)
3045f050 908 {
9e70917d 909 /* Lines with just spaces need to be buffered too */
7845dbb3 910 uschar * cp = line.data;
9e70917d 911 char c;
6a11a9e6 912
9e70917d
JH
913 while ((c = *cp))
914 {
915 if (c == '\r' && cp[1] == '\n') break;
cf1cce5e 916 if (c != ' ' && c != '\t') goto hash_process;
9e70917d
JH
917 cp++;
918 }
919
cf1cce5e
JH
920 b->num_buffered_blanklines++;
921 goto hash_skip;
6a11a9e6
JH
922 }
923
cf1cce5e 924hash_process:
9e70917d 925 /* At this point, we have a non-empty line, so release the buffered ones. */
6a11a9e6 926
cf1cce5e 927 while (b->num_buffered_blanklines)
9e70917d 928 {
cf1cce5e
JH
929 rnl = pdkim_update_ctx_bodyhash(b, &lineending, rnl);
930 b->num_buffered_blanklines--;
9e70917d
JH
931 }
932
cf1cce5e
JH
933 rline = pdkim_update_ctx_bodyhash(b, &line, rline);
934hash_skip: ;
80a47a2c
TK
935 }
936
9e70917d
JH
937if (rnl) store_free(rnl);
938if (rline) store_free(rline);
939
940all_skip:
80a47a2c 941
3045f050 942ctx->linebuf_offset = 0;
9e70917d 943return;
80a47a2c
TK
944}
945
946
947/* -------------------------------------------------------------------------- */
948/* Callback from pdkim_feed below for processing complete headers */
949#define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
3045f050 950
f444c2c7 951static int
2c0f3ea1 952pdkim_header_complete(pdkim_ctx * ctx)
3045f050 953{
acec9514
JH
954if ( (ctx->cur_header->ptr > 1) &&
955 (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
956 --ctx->cur_header->ptr;
957(void) string_from_gstring(ctx->cur_header);
80a47a2c 958
617d3932
JH
959#ifdef EXPERIMENTAL_ARC
960/* Feed the header line to ARC processing */
961(void) arc_header_feed(ctx->cur_header, !(ctx->flags & PDKIM_MODE_SIGN));
962#endif
963
2c0f3ea1 964if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
80a47a2c 965
3045f050 966/* SIGNING -------------------------------------------------------------- */
e983e85a 967if (ctx->flags & PDKIM_MODE_SIGN)
d7978c0f 968 for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
80a47a2c 969
ab9152ff 970 /* Add header to the signed headers list (in reverse order) */
acec9514 971 sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s);
94431adb 972
0d04a285 973/* VERIFICATION ----------------------------------------------------------- */
3045f050 974/* DKIM-Signature: headers are added to the verification list */
e983e85a 975else
3045f050 976 {
f6ee24a2 977#ifdef notdef
bd8fbe36
JH
978 DEBUG(D_acl)
979 {
305f8921 980 debug_printf("DKIM >> raw hdr: ");
acec9514 981 pdkim_quoteprint(CUS ctx->cur_header->s, ctx->cur_header->ptr);
bd8fbe36 982 }
f6ee24a2 983#endif
acec9514 984 if (strncasecmp(CCS ctx->cur_header->s,
3045f050 985 DKIM_SIGNATURE_HEADERNAME,
e2e3255a 986 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
3045f050 987 {
d7978c0f 988 pdkim_signature * sig, * last_sig;
02c4f8fb
JH
989 /* Create and chain new signature block. We could error-check for all
990 required tags here, but prefer to create the internal sig and expicitly
991 fail verification of it later. */
80a47a2c 992
0d04a285 993 DEBUG(D_acl) debug_printf(
305f8921 994 "DKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
3045f050 995
acec9514 996 sig = pdkim_parse_sig_header(ctx, ctx->cur_header->s);
02c4f8fb
JH
997
998 if (!(last_sig = ctx->sig))
2c0f3ea1 999 ctx->sig = sig;
02c4f8fb 1000 else
3045f050 1001 {
02c4f8fb 1002 while (last_sig->next) last_sig = last_sig->next;
2c0f3ea1 1003 last_sig->next = sig;
80a47a2c 1004 }
64b67b65
JH
1005
1006 if (--dkim_collect_input == 0)
1007 {
1008 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->s);
1009 ctx->cur_header->s[ctx->cur_header->ptr = 0] = '\0';
1010 return PDKIM_ERR_EXCESS_SIGS;
1011 }
80a47a2c 1012 }
37f8b554 1013
eea19017 1014 /* all headers are stored for signature verification */
acec9514 1015 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->s);
80a47a2c
TK
1016 }
1017
3045f050 1018BAIL:
acec9514 1019ctx->cur_header->s[ctx->cur_header->ptr = 0] = '\0'; /* leave buffer for reuse */
3045f050 1020return PDKIM_OK;
6ab02e3f 1021}
80a47a2c
TK
1022
1023
1024
1025/* -------------------------------------------------------------------------- */
1026#define HEADER_BUFFER_FRAG_SIZE 256
3045f050
JH
1027
1028DLLEXPORT int
ef698bf6 1029pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
3045f050 1030{
e983e85a
JH
1031/* Alternate EOD signal, used in non-dotstuffing mode */
1032if (!data)
1033 pdkim_body_complete(ctx);
1034
d7978c0f 1035else for (int p = 0; p < len; p++)
3045f050 1036 {
ca9cb170 1037 uschar c = data[p];
d7978c0f 1038 int rc;
3045f050 1039
e983e85a 1040 if (ctx->flags & PDKIM_PAST_HDRS)
3045f050 1041 {
b895f4b2
JH
1042 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1043 {
1044 ctx->linebuf[ctx->linebuf_offset++] = '\r';
1045 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1046 return PDKIM_ERR_LONG_LINE;
1047 }
1048
3045f050 1049 /* Processing body byte */
0d04a285 1050 ctx->linebuf[ctx->linebuf_offset++] = c;
b895f4b2
JH
1051 if (c == '\r')
1052 ctx->flags |= PDKIM_SEEN_CR;
1053 else if (c == '\n')
3045f050 1054 {
b895f4b2 1055 ctx->flags &= ~PDKIM_SEEN_CR;
9e70917d 1056 pdkim_bodyline_complete(ctx);
80a47a2c 1057 }
b895f4b2
JH
1058
1059 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
3045f050 1060 return PDKIM_ERR_LONG_LINE;
80a47a2c 1061 }
3045f050
JH
1062 else
1063 {
1064 /* Processing header byte */
b895f4b2
JH
1065 if (c == '\r')
1066 ctx->flags |= PDKIM_SEEN_CR;
1067 else if (c == '\n')
3045f050 1068 {
b895f4b2 1069 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
acec9514 1070 ctx->cur_header = string_catn(ctx->cur_header, CUS "\r", 1);
b895f4b2 1071
02c4f8fb 1072 if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */
b895f4b2 1073 {
02c4f8fb
JH
1074 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1075 return rc;
b895f4b2 1076
863bd541 1077 ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS;
b895f4b2 1078 DEBUG(D_acl) debug_printf(
305f8921 1079 "DKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
b895f4b2 1080 continue;
3045f050 1081 }
b895f4b2 1082 else
863bd541 1083 ctx->flags = (ctx->flags & ~PDKIM_SEEN_CR) | PDKIM_SEEN_LF;
b895f4b2
JH
1084 }
1085 else if (ctx->flags & PDKIM_SEEN_LF)
1086 {
02c4f8fb
JH
1087 if (!(c == '\t' || c == ' ')) /* End of header */
1088 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1089 return rc;
b895f4b2 1090 ctx->flags &= ~PDKIM_SEEN_LF;
80a47a2c 1091 }
3045f050 1092
acec9514
JH
1093 if (!ctx->cur_header || ctx->cur_header->ptr < PDKIM_MAX_HEADER_LEN)
1094 ctx->cur_header = string_catn(ctx->cur_header, CUS &data[p], 1);
80a47a2c
TK
1095 }
1096 }
3045f050 1097return PDKIM_OK;
6ab02e3f 1098}
80a47a2c 1099
ca9cb170
JH
1100
1101
acec9514
JH
1102/* Extend a growing header with a continuation-linebreak */
1103static gstring *
1104pdkim_hdr_cont(gstring * str, int * col)
ca9cb170
JH
1105{
1106*col = 1;
acec9514 1107return string_catn(str, US"\r\n\t", 3);
ca9cb170
JH
1108}
1109
1110
1111
05b7d6de
JB
1112/*
1113 * RFC 5322 specifies that header line length SHOULD be no more than 78
1114 * lets make it so!
1115 * pdkim_headcat
ca9cb170
JH
1116 *
1117 * returns uschar * (not nul-terminated)
05b7d6de
JB
1118 *
1119 * col: this int holds and receives column number (octets since last '\n')
1120 * str: partial string to append to
94431adb 1121 * pad: padding, split line or space after before or after eg: ";"
05b7d6de
JB
1122 * intro: - must join to payload eg "h=", usually the tag name
1123 * payload: eg base64 data - long data can be split arbitrarily.
1124 *
1125 * this code doesn't fold the header in some of the places that RFC4871
1126 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1127 * pairs and inside long values. it also always spaces or breaks after the
94431adb 1128 * "pad"
05b7d6de
JB
1129 *
1130 * no guarantees are made for output given out-of range input. like tag
f444c2c7 1131 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
05b7d6de
JB
1132 */
1133
acec9514
JH
1134static gstring *
1135pdkim_headcat(int * col, gstring * str,
ca9cb170 1136 const uschar * pad, const uschar * intro, const uschar * payload)
3045f050
JH
1137{
1138size_t l;
1139
1140if (pad)
05b7d6de 1141 {
ca9cb170 1142 l = Ustrlen(pad);
3045f050 1143 if (*col + l > 78)
acec9514
JH
1144 str = pdkim_hdr_cont(str, col);
1145 str = string_catn(str, pad, l);
3045f050 1146 *col += l;
05b7d6de
JB
1147 }
1148
ca9cb170 1149l = (pad?1:0) + (intro?Ustrlen(intro):0);
05b7d6de 1150
3045f050 1151if (*col + l > 78)
05b7d6de 1152 { /*can't fit intro - start a new line to make room.*/
acec9514 1153 str = pdkim_hdr_cont(str, col);
ca9cb170 1154 l = intro?Ustrlen(intro):0;
05b7d6de
JB
1155 }
1156
ca9cb170 1157l += payload ? Ustrlen(payload):0 ;
05b7d6de 1158
3045f050 1159while (l>77)
05b7d6de 1160 { /* this fragment will not fit on a single line */
3045f050 1161 if (pad)
05b7d6de 1162 {
acec9514 1163 str = string_catn(str, US" ", 1);
3045f050
JH
1164 *col += 1;
1165 pad = NULL; /* only want this once */
1166 l--;
05b7d6de 1167 }
3045f050
JH
1168
1169 if (intro)
05b7d6de 1170 {
ca9cb170 1171 size_t sl = Ustrlen(intro);
3045f050 1172
acec9514 1173 str = string_catn(str, intro, sl);
3045f050
JH
1174 *col += sl;
1175 l -= sl;
1176 intro = NULL; /* only want this once */
05b7d6de 1177 }
3045f050
JH
1178
1179 if (payload)
05b7d6de 1180 {
ca9cb170 1181 size_t sl = Ustrlen(payload);
3045f050
JH
1182 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1183
acec9514 1184 str = string_catn(str, payload, chomp);
3045f050
JH
1185 *col += chomp;
1186 payload += chomp;
1187 l -= chomp-1;
05b7d6de 1188 }
3045f050
JH
1189
1190 /* the while precondition tells us it didn't fit. */
acec9514 1191 str = pdkim_hdr_cont(str, col);
05b7d6de 1192 }
3045f050
JH
1193
1194if (*col + l > 78)
05b7d6de 1195 {
acec9514 1196 str = pdkim_hdr_cont(str, col);
3045f050 1197 pad = NULL;
05b7d6de
JB
1198 }
1199
3045f050 1200if (pad)
05b7d6de 1201 {
acec9514 1202 str = string_catn(str, US" ", 1);
3045f050
JH
1203 *col += 1;
1204 pad = NULL;
05b7d6de
JB
1205 }
1206
3045f050 1207if (intro)
05b7d6de 1208 {
ca9cb170 1209 size_t sl = Ustrlen(intro);
3045f050 1210
acec9514 1211 str = string_catn(str, intro, sl);
3045f050
JH
1212 *col += sl;
1213 l -= sl;
1214 intro = NULL;
05b7d6de 1215 }
3045f050
JH
1216
1217if (payload)
05b7d6de 1218 {
ca9cb170 1219 size_t sl = Ustrlen(payload);
3045f050 1220
acec9514 1221 str = string_catn(str, payload, sl);
3045f050 1222 *col += sl;
05b7d6de
JB
1223 }
1224
ca9cb170 1225return str;
05b7d6de 1226}
80a47a2c 1227
3045f050 1228
80a47a2c 1229/* -------------------------------------------------------------------------- */
3045f050 1230
cf1cce5e
JH
1231/* Signing: create signature header
1232*/
ca9cb170 1233static uschar *
9e70917d 1234pdkim_create_header(pdkim_signature * sig, BOOL final)
3045f050 1235{
ca9cb170
JH
1236uschar * base64_bh;
1237uschar * base64_b;
3045f050 1238int col = 0;
acec9514
JH
1239gstring * hdr;
1240gstring * canon_all;
3045f050 1241
acec9514
JH
1242canon_all = string_cat (NULL, pdkim_canons[sig->canon_headers]);
1243canon_all = string_catn(canon_all, US"/", 1);
1244canon_all = string_cat (canon_all, pdkim_canons[sig->canon_body]);
1245(void) string_from_gstring(canon_all);
3045f050 1246
acec9514
JH
1247hdr = string_cat(NULL, US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1248col = hdr->ptr;
3045f050
JH
1249
1250/* Required and static bits */
acec9514
JH
1251hdr = pdkim_headcat(&col, hdr, US";", US"a=", dkim_sig_to_a_tag(sig));
1252hdr = pdkim_headcat(&col, hdr, US";", US"q=", pdkim_querymethods[sig->querymethod]);
1253hdr = pdkim_headcat(&col, hdr, US";", US"c=", canon_all->s);
1254hdr = pdkim_headcat(&col, hdr, US";", US"d=", sig->domain);
1255hdr = pdkim_headcat(&col, hdr, US";", US"s=", sig->selector);
ca9cb170
JH
1256
1257/* list of header names can be split between items. */
3045f050 1258 {
e2e3255a 1259 uschar * n = string_copy(sig->headernames);
ca9cb170
JH
1260 uschar * i = US"h=";
1261 uschar * s = US";";
1262
1263 while (*n)
05b7d6de 1264 {
ca9cb170 1265 uschar * c = Ustrchr(n, ':');
3045f050 1266
ca9cb170 1267 if (c) *c ='\0';
05b7d6de 1268
ca9cb170 1269 if (!i)
acec9514 1270 hdr = pdkim_headcat(&col, hdr, NULL, NULL, US":");
05b7d6de 1271
acec9514 1272 hdr = pdkim_headcat(&col, hdr, s, i, n);
3045f050 1273
ca9cb170
JH
1274 if (!c)
1275 break;
3045f050 1276
ca9cb170
JH
1277 n = c+1;
1278 s = NULL;
1279 i = NULL;
80a47a2c 1280 }
ca9cb170 1281 }
05b7d6de 1282
cf1cce5e 1283base64_bh = pdkim_encode_base64(&sig->calc_body_hash->bh);
acec9514 1284hdr = pdkim_headcat(&col, hdr, US";", US"bh=", base64_bh);
3045f050 1285
ca9cb170
JH
1286/* Optional bits */
1287if (sig->identity)
acec9514 1288 hdr = pdkim_headcat(&col, hdr, US";", US"i=", sig->identity);
3045f050 1289
ca9cb170
JH
1290if (sig->created > 0)
1291 {
e2e3255a 1292 uschar minibuf[20];
3045f050 1293
e2e3255a 1294 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
acec9514 1295 hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf);
ca9cb170 1296}
3045f050 1297
ca9cb170
JH
1298if (sig->expires > 0)
1299 {
e2e3255a 1300 uschar minibuf[20];
3045f050 1301
e2e3255a 1302 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
acec9514 1303 hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf);
ca9cb170 1304 }
3045f050 1305
ca9cb170
JH
1306if (sig->bodylength >= 0)
1307 {
e2e3255a 1308 uschar minibuf[20];
80a47a2c 1309
e2e3255a 1310 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
acec9514 1311 hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf);
3045f050 1312 }
05b7d6de 1313
ca9cb170 1314/* Preliminary or final version? */
ea18931d
JH
1315if (final)
1316 {
1317 base64_b = pdkim_encode_base64(&sig->sighash);
acec9514 1318 hdr = pdkim_headcat(&col, hdr, US";", US"b=", base64_b);
80a47a2c 1319
ea18931d 1320 /* add trailing semicolon: I'm not sure if this is actually needed */
acec9514 1321 hdr = pdkim_headcat(&col, hdr, NULL, US";", US"");
ea18931d
JH
1322 }
1323else
1324 {
1325 /* To satisfy the rule "all surrounding whitespace [...] deleted"
1326 ( RFC 6376 section 3.7 ) we ensure there is no whitespace here. Otherwise
1327 the headcat routine could insert a linebreak which the relaxer would reduce
1328 to a single space preceding the terminating semicolon, resulting in an
1329 incorrect header-hash. */
acec9514 1330 hdr = pdkim_headcat(&col, hdr, US";", US"b=;", US"");
ea18931d 1331 }
80a47a2c 1332
acec9514 1333return string_from_gstring(hdr);
80a47a2c
TK
1334}
1335
1336
1337/* -------------------------------------------------------------------------- */
3045f050 1338
321ef002
JH
1339/* According to draft-ietf-dcrup-dkim-crypto-07 "keys are 256 bits" (referring
1340to DNS, hence the pubkey). Check for more than 32 bytes; if so assume the
1341alternate possible representation (still) being discussed: a
1342SubjectPublickeyInfo wrapped key - and drop all but the trailing 32-bytes (it
1343should be a DER, with exactly 12 leading bytes - but we could accept a BER also,
1344which could be any size). We still rely on the crypto library for checking for
1345undersize.
1346
1347When the RFC is published this should be re-addressed. */
1348
1349static void
1350check_bare_ed25519_pubkey(pdkim_pubkey * p)
1351{
1352int excess = p->key.len - 32;
1353if (excess > 0)
1354 {
305f8921 1355 DEBUG(D_acl) debug_printf("DKIM: unexpected pubkey len %lu\n", p->key.len);
321ef002
JH
1356 p->key.data += excess; p->key.len = 32;
1357 }
1358}
1359
1360
cd1a5fe0 1361static pdkim_pubkey *
b9df1829
JH
1362pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1363 const uschar ** errstr)
cd1a5fe0
JH
1364{
1365uschar * dns_txt_name, * dns_txt_reply;
1366pdkim_pubkey * p;
cd1a5fe0
JH
1367
1368/* Fetch public key for signing domain, from DNS */
1369
1370dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1371
617d3932 1372if ( !(dns_txt_reply = ctx->dns_txt_callback(dns_txt_name))
cd1a5fe0
JH
1373 || dns_txt_reply[0] == '\0'
1374 )
1375 {
1376 sig->verify_status = PDKIM_VERIFY_INVALID;
1377 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1378 return NULL;
1379 }
1380
1381DEBUG(D_acl)
1382 {
1383 debug_printf(
305f8921 1384 "DKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
9e70917d
JH
1385 " %s\n"
1386 " Raw record: ",
1387 dns_txt_name);
cd1a5fe0
JH
1388 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1389 }
1390
617d3932 1391if ( !(p = pdkim_parse_pubkey_record(CUS dns_txt_reply))
cd1a5fe0
JH
1392 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1393 )
1394 {
1395 sig->verify_status = PDKIM_VERIFY_INVALID;
1396 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1397
1398 DEBUG(D_acl)
1399 {
1400 if (p)
1401 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1402 else
1403 debug_printf(" Error while parsing public key record\n");
1404 debug_printf(
305f8921 1405 "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
cd1a5fe0
JH
1406 }
1407 return NULL;
1408 }
1409
1410DEBUG(D_acl) debug_printf(
305f8921 1411 "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
cd1a5fe0
JH
1412
1413/* Import public key */
286b9d5f 1414
cb78c1a8
JH
1415/* Normally we use the signature a= tag to tell us the pubkey format.
1416When signing under debug we do a test-import of the pubkey, and at that
1417time we do not have a signature so we must interpret the pubkey k= tag
1418instead. Assume writing on the sig is ok in that case. */
1419
1420if (sig->keytype < 0)
042e558f
JH
1421 if ((sig->keytype = pdkim_keyname_to_keytype(p->keytype)) < 0)
1422 {
1423 DEBUG(D_acl) debug_printf("verify_init: unhandled keytype %s\n", p->keytype);
1424 sig->verify_status = PDKIM_VERIFY_INVALID;
1425 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1426 return NULL;
1427 }
cb78c1a8 1428
321ef002
JH
1429if (sig->keytype == KEYTYPE_ED25519)
1430 check_bare_ed25519_pubkey(p);
1431
286b9d5f
JH
1432if ((*errstr = exim_dkim_verify_init(&p->key,
1433 sig->keytype == KEYTYPE_ED25519 ? KEYFMT_ED25519_BARE : KEYFMT_DER,
a841a6ec 1434 vctx, &sig->keybits)))
cd1a5fe0 1435 {
b9df1829 1436 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
cd1a5fe0
JH
1437 sig->verify_status = PDKIM_VERIFY_INVALID;
1438 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1439 return NULL;
1440 }
1441
286b9d5f 1442vctx->keytype = sig->keytype;
cd1a5fe0
JH
1443return p;
1444}
1445
1446
1447/* -------------------------------------------------------------------------- */
042e558f
JH
1448/* Sort and filter the sigs developed from the message */
1449
1450static pdkim_signature *
1451sort_sig_methods(pdkim_signature * siglist)
1452{
1453pdkim_signature * yield, ** ss;
1454const uschar * prefs;
1455uschar * ele;
1456int sep;
1457
1458if (!siglist) return NULL;
1459
1460/* first select in order of hashtypes */
305f8921 1461DEBUG(D_acl) debug_printf("DKIM: dkim_verify_hashes '%s'\n", dkim_verify_hashes);
042e558f
JH
1462for (prefs = dkim_verify_hashes, sep = 0, yield = NULL, ss = &yield;
1463 ele = string_nextinlist(&prefs, &sep, NULL, 0); )
1464 {
1465 int i = pdkim_hashname_to_hashtype(CUS ele, 0);
1466 for (pdkim_signature * s = siglist, * next, ** prev = &siglist; s;
1467 s = next)
1468 {
1469 next = s->next;
1470 if (s->hashtype == i)
1471 { *prev = next; s->next = NULL; *ss = s; ss = &s->next; }
1472 else
1473 prev = &s->next;
1474 }
1475 }
1476
1477/* then in order of keytypes */
1478siglist = yield;
305f8921 1479DEBUG(D_acl) debug_printf("DKIM: dkim_verify_keytypes '%s'\n", dkim_verify_keytypes);
042e558f
JH
1480for (prefs = dkim_verify_keytypes, sep = 0, yield = NULL, ss = &yield;
1481 ele = string_nextinlist(&prefs, &sep, NULL, 0); )
1482 {
1483 int i = pdkim_keyname_to_keytype(CUS ele);
1484 for (pdkim_signature * s = siglist, * next, ** prev = &siglist; s;
1485 s = next)
1486 {
1487 next = s->next;
1488 if (s->keytype == i)
1489 { *prev = next; s->next = NULL; *ss = s; ss = &s->next; }
1490 else
1491 prev = &s->next;
1492 }
1493 }
1494
1495DEBUG(D_acl) for (pdkim_signature * s = yield; s; s = s->next)
1496 debug_printf(" retain d=%s s=%s a=%s\n",
1497 s->domain, s->selector, dkim_sig_to_a_tag(s));
1498return yield;
1499}
1500
1501
1502/* -------------------------------------------------------------------------- */
cd1a5fe0 1503
3045f050 1504DLLEXPORT int
b9df1829
JH
1505pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1506 const uschar ** err)
3045f050 1507{
286b9d5f 1508BOOL verify_pass = FALSE;
3045f050
JH
1509
1510/* Check if we must still flush a (partial) header. If that is the
1511 case, the message has no body, and we must compute a body hash
1512 out of '<CR><LF>' */
acec9514 1513if (ctx->cur_header && ctx->cur_header->ptr > 0)
3045f050 1514 {
9e70917d
JH
1515 blob * rnl = NULL;
1516 int rc;
1517
1518 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1519 return rc;
1520
d7978c0f 1521 for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)
cf1cce5e 1522 rnl = pdkim_update_ctx_bodyhash(b, &lineending, rnl);
9e70917d 1523 if (rnl) store_free(rnl);
80a47a2c 1524 }
3045f050 1525else
0d04a285 1526 DEBUG(D_acl) debug_printf(
305f8921 1527 "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1528
617d3932
JH
1529/* Build (and/or evaluate) body hash. Do this even if no DKIM sigs, in case we
1530have a hash to do for ARC. */
1531
1532pdkim_finish_bodyhash(ctx);
1533
042e558f
JH
1534/* Sort and filter the recived signatures */
1535
1536if (!(ctx->flags & PDKIM_MODE_SIGN))
1537 ctx->sig = sort_sig_methods(ctx->sig);
1538
286b9d5f
JH
1539if (!ctx->sig)
1540 {
305f8921 1541 DEBUG(D_acl) debug_printf("DKIM: no signatures\n");
617d3932 1542 *return_signatures = NULL;
286b9d5f
JH
1543 return PDKIM_OK;
1544 }
1545
d7978c0f 1546for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next)
3045f050 1547 {
2592e6c0 1548 hctx hhash_ctx;
ad6f5499 1549 uschar * sig_hdr = US"";
2592e6c0 1550 blob hhash;
acec9514 1551 gstring * hdata = NULL;
286b9d5f
JH
1552 es_ctx sctx;
1553
617d3932
JH
1554 if ( !(ctx->flags & PDKIM_MODE_SIGN)
1555 && sig->verify_status == PDKIM_VERIFY_FAIL)
1556 {
1557 DEBUG(D_acl)
305f8921 1558 debug_printf("DKIM: [%s] abandoning this signature\n", sig->domain);
617d3932
JH
1559 continue;
1560 }
1561
286b9d5f 1562 /*XXX The hash of the headers is needed for GCrypt (for which we can do RSA
042e558f 1563 signing only, as it happens) and for either GnuTLS and OpenSSL when we are
286b9d5f
JH
1564 signing with EC (specifically, Ed25519). The former is because the GCrypt
1565 signing operation is pure (does not do its own hash) so we must hash. The
1566 latter is because we (stupidly, but this is what the IETF draft is saying)
1567 must hash with the declared hash method, then pass the result to the library
1568 hash-and-sign routine (because that's all the libraries are providing. And
1569 we're stuck with whatever that hidden hash method is, too). We may as well
1570 do this hash incrementally.
1571 We don't need the hash we're calculating here for the GnuTLS and OpenSSL
1572 cases of RSA signing, since those library routines can do hash-and-sign.
305f8921 1573
286b9d5f
JH
1574 Some time in the future we could easily avoid doing the hash here for those
1575 cases (which will be common for a long while. We could also change from
1576 the current copy-all-the-headers-into-one-block, then call the hash-and-sign
1577 implementation - to a proper incremental one. Unfortunately, GnuTLS just
1578 cannot do incremental - either signing or verification. Unsure about GCrypt.
1579 */
1580
1581 /*XXX The header hash is also used (so far) by the verify operation */
2592e6c0 1582
d73e45df 1583 if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
7b83389d 1584 {
286b9d5f 1585 log_write(0, LOG_MAIN|LOG_PANIC,
305f8921 1586 "DKIM: hash setup error, possibly nonhandled hashtype");
7b83389d
JH
1587 break;
1588 }
80a47a2c 1589
9e70917d
JH
1590 if (ctx->flags & PDKIM_MODE_SIGN)
1591 DEBUG(D_acl) debug_printf(
305f8921 1592 "DKIM >> Headers to be signed: >>>>>>>>>>>>\n"
9e70917d
JH
1593 " %s\n",
1594 sig->sign_headers);
1595
0d04a285 1596 DEBUG(D_acl) debug_printf(
305f8921 1597 "DKIM >> Header data for hash, canonicalized (%-7s), in sequence >>\n",
4ff848b5 1598 pdkim_canons[sig->canon_headers]);
3045f050 1599
9e70917d 1600
3045f050
JH
1601 /* SIGNING ---------------------------------------------------------------- */
1602 /* When signing, walk through our header list and add them to the hash. As we
8ef02a06
JH
1603 go, construct a list of the header's names to use for the h= parameter.
1604 Then append to that list any remaining header names for which there was no
1605 header to sign. */
3045f050 1606
e983e85a 1607 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1608 {
acec9514 1609 gstring * g = NULL;
8ef02a06
JH
1610 const uschar * l;
1611 uschar * s;
1612 int sep = 0;
3045f050 1613
286b9d5f
JH
1614 /* Import private key, including the keytype which we need for building
1615 the signature header */
1616
617d3932 1617 if ((*err = exim_dkim_signing_init(CUS sig->privkey, &sctx)))
286b9d5f
JH
1618 {
1619 log_write(0, LOG_MAIN|LOG_PANIC, "signing_init: %s", *err);
1620 return PDKIM_ERR_RSA_PRIVKEY;
1621 }
1622 sig->keytype = sctx.keytype;
9e70917d 1623
d7978c0f
JH
1624 sig->headernames = NULL; /* Collected signed header names */
1625 for (pdkim_stringlist * p = sig->headers; p; p = p->next)
9e70917d
JH
1626 {
1627 uschar * rh = p->value;
1628
1629 if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
ab9152ff 1630 {
ab9152ff 1631 /* Collect header names (Note: colon presence is guaranteed here) */
acec9514 1632 g = string_append_listele_n(g, ':', rh, Ustrchr(rh, ':') - rh);
3045f050 1633
9e70917d
JH
1634 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1635 rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */
3045f050 1636
ab9152ff 1637 /* Feed header to the hash algorithm */
e2e3255a 1638 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
f444c2c7 1639
ab9152ff 1640 /* Remember headers block for signing (when the library cannot do incremental) */
286b9d5f 1641 /*XXX we could avoid doing this for all but the GnuTLS/RSA case */
acec9514 1642 hdata = exim_dkim_data_append(hdata, rh);
3045f050 1643
ab9152ff
JH
1644 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1645 }
9e70917d 1646 }
8ef02a06 1647
484cc1a9
JH
1648 /* Any headers we wanted to sign but were not present must also be listed.
1649 Ignore elements that have been ticked-off or are marked as never-oversign. */
1650
ca9cb170 1651 l = sig->sign_headers;
8ef02a06 1652 while((s = string_nextinlist(&l, &sep, NULL, 0)))
484cc1a9
JH
1653 {
1654 if (*s == '+') /* skip oversigning marker */
1655 s++;
1656 if (*s != '_' && *s != '=')
acec9514 1657 g = string_append_listele(g, ':', s);
484cc1a9 1658 }
acec9514 1659 sig->headernames = string_from_gstring(g);
ca9cb170
JH
1660
1661 /* Create signature header with b= omitted */
1662 sig_hdr = pdkim_create_header(sig, FALSE);
80a47a2c 1663 }
37f8b554 1664
3045f050
JH
1665 /* VERIFICATION ----------------------------------------------------------- */
1666 /* When verifying, walk through the header name list in the h= parameter and
1667 add the headers to the hash in that order. */
1668 else
1669 {
10c50704 1670 uschar * p = sig->headernames;
2592e6c0 1671 uschar * q;
3045f050 1672
10c50704 1673 if (p)
3045f050 1674 {
10c50704 1675 /* clear tags */
d7978c0f 1676 for (pdkim_stringlist * hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
10c50704 1677 hdrs->tag = 0;
3045f050 1678
10c50704
JH
1679 p = string_copy(p);
1680 while(1)
1681 {
1682 if ((q = Ustrchr(p, ':')))
1683 *q = '\0';
1684
1685 /*XXX walk the list of headers in same order as received. */
d7978c0f 1686 for (pdkim_stringlist * hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
10c50704 1687 if ( hdrs->tag == 0
4dc2379a 1688 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
10c50704
JH
1689 && (hdrs->value)[Ustrlen(p)] == ':'
1690 )
1691 {
1692 /* cook header for relaxed canon, or just copy it for simple */
1693
1694 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
ea18931d 1695 ? pdkim_relax_header(hdrs->value, TRUE)
10c50704
JH
1696 : string_copy(CUS hdrs->value);
1697
1698 /* Feed header to the hash algorithm */
1699 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1700
1701 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1702 hdrs->tag = 1;
1703 break;
1704 }
3045f050 1705
10c50704
JH
1706 if (!q) break;
1707 p = q+1;
1708 }
3045f050 1709
10c50704 1710 sig_hdr = string_copy(sig->rawsig_no_b_val);
80a47a2c 1711 }
80a47a2c
TK
1712 }
1713
0d04a285 1714 DEBUG(D_acl) debug_printf(
305f8921 1715 "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1716
9e70917d
JH
1717 DEBUG(D_acl)
1718 {
1719 debug_printf(
305f8921 1720 "DKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
9e70917d
JH
1721 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1722 debug_printf(
305f8921 1723 "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
9e70917d
JH
1724 }
1725
3045f050
JH
1726 /* Relax header if necessary */
1727 if (sig->canon_headers == PDKIM_CANON_RELAXED)
ea18931d 1728 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
80a47a2c 1729
0d04a285 1730 DEBUG(D_acl)
3045f050 1731 {
305f8921 1732 debug_printf("DKIM >> Signed DKIM-Signature header, canonicalized (%-7s) >>>>>>>\n",
4ff848b5 1733 pdkim_canons[sig->canon_headers]);
e2e3255a 1734 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
0d04a285 1735 debug_printf(
305f8921 1736 "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1737 }
3045f050
JH
1738
1739 /* Finalize header hash */
e2e3255a 1740 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
2592e6c0 1741 exim_sha_finish(&hhash_ctx, &hhash);
3045f050 1742
f444c2c7
JH
1743 DEBUG(D_acl)
1744 {
305f8921 1745 debug_printf("DKIM [%s] Header %s computed: ",
9e70917d 1746 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
2592e6c0 1747 pdkim_hexprint(hhash.data, hhash.len);
80a47a2c
TK
1748 }
1749
9e70917d
JH
1750 /* Remember headers block for signing (when the signing library cannot do
1751 incremental) */
e983e85a 1752 if (ctx->flags & PDKIM_MODE_SIGN)
acec9514 1753 hdata = exim_dkim_data_append(hdata, US sig_hdr);
f444c2c7 1754
3045f050 1755 /* SIGNING ---------------------------------------------------------------- */
e983e85a 1756 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1757 {
286b9d5f 1758 hashmethod hm = sig->keytype == KEYTYPE_ED25519
cb78c1a8
JH
1759#if defined(SIGN_OPENSSL)
1760 ? HASH_NULL
1761#else
1762 ? HASH_SHA2_512
1763#endif
1764 : pdkim_hashes[sig->hashtype].exim_hashmethod;
f444c2c7 1765
286b9d5f
JH
1766#ifdef SIGN_HAVE_ED25519
1767 /* For GCrypt, and for EC, we pass the hash-of-headers to the signing
1768 routine. For anything else we just pass the headers. */
f444c2c7 1769
286b9d5f 1770 if (sig->keytype != KEYTYPE_ED25519)
f444c2c7 1771#endif
286b9d5f
JH
1772 {
1773 hhash.data = hdata->s;
1774 hhash.len = hdata->ptr;
1775 }
f444c2c7 1776
286b9d5f 1777 if ((*err = exim_dkim_sign(&sctx, hm, &hhash, &sig->sighash)))
f444c2c7 1778 {
286b9d5f 1779 log_write(0, LOG_MAIN|LOG_PANIC, "signing: %s", *err);
f444c2c7
JH
1780 return PDKIM_ERR_RSA_SIGNING;
1781 }
80a47a2c 1782
0d04a285 1783 DEBUG(D_acl)
3045f050 1784 {
305f8921 1785 debug_printf( "DKIM [%s] b computed: ", sig->domain);
dcd03763 1786 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
80a47a2c 1787 }
80a47a2c 1788
ca9cb170 1789 sig->signature_header = pdkim_create_header(sig, TRUE);
80a47a2c 1790 }
80a47a2c 1791
3045f050
JH
1792 /* VERIFICATION ----------------------------------------------------------- */
1793 else
1794 {
2592e6c0 1795 ev_ctx vctx;
cb78c1a8 1796 hashmethod hm;
3045f050 1797
07eeb4df 1798 /* Make sure we have all required signature tags */
1799 if (!( sig->domain && *sig->domain
1800 && sig->selector && *sig->selector
1801 && sig->headernames && *sig->headernames
1802 && sig->bodyhash.data
dcd03763 1803 && sig->sighash.data
d73e45df
JH
1804 && sig->keytype >= 0
1805 && sig->hashtype >= 0
07eeb4df 1806 && sig->version
1807 ) )
1808 {
1809 sig->verify_status = PDKIM_VERIFY_INVALID;
1810 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1811
1812 DEBUG(D_acl) debug_printf(
d9604f37 1813 " Error in DKIM-Signature header: tags missing or invalid (%s)\n"
305f8921 1814 "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
d9604f37
JH
1815 !(sig->domain && *sig->domain) ? "d="
1816 : !(sig->selector && *sig->selector) ? "s="
1817 : !(sig->headernames && *sig->headernames) ? "h="
1818 : !sig->bodyhash.data ? "bh="
1819 : !sig->sighash.data ? "b="
1820 : sig->keytype < 0 || sig->hashtype < 0 ? "a="
1821 : "v="
1822 );
07eeb4df 1823 goto NEXT_VERIFY;
1824 }
305f8921 1825
07eeb4df 1826 /* Make sure sig uses supported DKIM version (only v1) */
1827 if (sig->version != 1)
1828 {
1829 sig->verify_status = PDKIM_VERIFY_INVALID;
1830 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1831
1832 DEBUG(D_acl) debug_printf(
1833 " Error in DKIM-Signature header: unsupported DKIM version\n"
305f8921 1834 "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
07eeb4df 1835 goto NEXT_VERIFY;
1836 }
1837
9e70917d
JH
1838 DEBUG(D_acl)
1839 {
305f8921 1840 debug_printf( "DKIM [%s] b from mail: ", sig->domain);
9e70917d
JH
1841 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1842 }
1843
b9df1829 1844 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
286b9d5f 1845 {
305f8921 1846 log_write(0, LOG_MAIN, "DKIM: %s%s %s%s [failed key import]",
286b9d5f
JH
1847 sig->domain ? "d=" : "", sig->domain ? sig->domain : US"",
1848 sig->selector ? "s=" : "", sig->selector ? sig->selector : US"");
3045f050 1849 goto NEXT_VERIFY;
286b9d5f 1850 }
80a47a2c 1851
135e9496
JH
1852 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1853 do not have the hash part of the sig algorithm matching */
1854
1855 if (sig->pubkey->hashes)
1856 {
1857 const uschar * list = sig->pubkey->hashes, * ele;
1858 int sep = ':';
1859 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
d73e45df 1860 if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
135e9496
JH
1861 if (!ele)
1862 {
d73e45df
JH
1863 DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
1864 sig->pubkey->hashes,
1865 pdkim_keytypes[sig->keytype],
1866 pdkim_hashes[sig->hashtype].dkim_hashname);
135e9496
JH
1867 sig->verify_status = PDKIM_VERIFY_FAIL;
1868 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1869 goto NEXT_VERIFY;
1870 }
1871 }
1872
cb78c1a8
JH
1873 hm = sig->keytype == KEYTYPE_ED25519
1874#if defined(SIGN_OPENSSL)
1875 ? HASH_NULL
1876#else
1877 ? HASH_SHA2_512
1878#endif
1879 : pdkim_hashes[sig->hashtype].exim_hashmethod;
1880
3045f050 1881 /* Check the signature */
cb78c1a8
JH
1882
1883 if ((*err = exim_dkim_verify(&vctx, hm, &hhash, &sig->sighash)))
3045f050 1884 {
b9df1829 1885 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
3045f050
JH
1886 sig->verify_status = PDKIM_VERIFY_FAIL;
1887 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1888 goto NEXT_VERIFY;
ff7ddfd7 1889 }
be24b950
JH
1890 if (*dkim_verify_min_keysizes)
1891 {
1892 unsigned minbits;
1893 uschar * ss = expand_getkeyed(US pdkim_keytypes[sig->keytype],
1894 dkim_verify_min_keysizes);
1895 if (ss && (minbits = atoi(CS ss)) > sig->keybits)
1896 {
1897 DEBUG(D_acl) debug_printf("Key too short: Actual: %s %u Minima '%s'\n",
1898 pdkim_keytypes[sig->keytype], sig->keybits, dkim_verify_min_keysizes);
1899 sig->verify_status = PDKIM_VERIFY_FAIL;
1900 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE;
1901 }
1902 }
ff7ddfd7 1903
2592e6c0 1904
4c04137d 1905 /* We have a winner! (if bodyhash was correct earlier) */
3045f050 1906 if (sig->verify_status == PDKIM_VERIFY_NONE)
286b9d5f 1907 {
3045f050 1908 sig->verify_status = PDKIM_VERIFY_PASS;
286b9d5f 1909 verify_pass = TRUE;
042e558f 1910 if (dkim_verify_minimal) break;
286b9d5f 1911 }
3045f050
JH
1912
1913NEXT_VERIFY:
1914
0d04a285 1915 DEBUG(D_acl)
3045f050 1916 {
305f8921 1917 debug_printf("DKIM [%s] %s signature status: %s",
286b9d5f
JH
1918 sig->domain, dkim_sig_to_a_tag(sig),
1919 pdkim_verify_status_str(sig->verify_status));
3045f050 1920 if (sig->verify_ext_status > 0)
0d04a285 1921 debug_printf(" (%s)\n",
3045f050
JH
1922 pdkim_verify_ext_status_str(sig->verify_ext_status));
1923 else
0d04a285 1924 debug_printf("\n");
80a47a2c 1925 }
80a47a2c 1926 }
80a47a2c
TK
1927 }
1928
3045f050
JH
1929/* If requested, set return pointer to signature(s) */
1930if (return_signatures)
1931 *return_signatures = ctx->sig;
80a47a2c 1932
286b9d5f
JH
1933return ctx->flags & PDKIM_MODE_SIGN || verify_pass
1934 ? PDKIM_OK : PDKIM_FAIL;
80a47a2c
TK
1935}
1936
1937
1938/* -------------------------------------------------------------------------- */
3045f050
JH
1939
1940DLLEXPORT pdkim_ctx *
fc2ba7b9 1941pdkim_init_verify(uschar * (*dns_txt_callback)(const uschar *), BOOL dot_stuffing)
3045f050 1942{
ca9cb170 1943pdkim_ctx * ctx;
3045f050 1944
f3ebb786 1945ctx = store_get(sizeof(pdkim_ctx), FALSE);
abe1010c 1946memset(ctx, 0, sizeof(pdkim_ctx));
3045f050 1947
e983e85a 1948if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
f3ebb786
JH
1949/* The line-buffer is for message data, hence tainted */
1950ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE);
3045f050 1951ctx->dns_txt_callback = dns_txt_callback;
80a47a2c 1952
3045f050 1953return ctx;
80a47a2c
TK
1954}
1955
1956
1957/* -------------------------------------------------------------------------- */
80a47a2c 1958
9e70917d
JH
1959DLLEXPORT pdkim_signature *
1960pdkim_init_sign(pdkim_ctx * ctx,
1961 uschar * domain, uschar * selector, uschar * privkey,
1962 uschar * hashname, const uschar ** errstr)
3045f050 1963{
d73e45df 1964int hashtype;
cd1a5fe0 1965pdkim_signature * sig;
80a47a2c 1966
d73e45df 1967if (!domain || !selector || !privkey)
3045f050 1968 return NULL;
80a47a2c 1969
9e70917d 1970/* Allocate & init one signature struct */
80a47a2c 1971
f3ebb786 1972sig = store_get(sizeof(pdkim_signature), FALSE);
abe1010c 1973memset(sig, 0, sizeof(pdkim_signature));
80a47a2c 1974
3045f050 1975sig->bodylength = -1;
80a47a2c 1976
e2e3255a
JH
1977sig->domain = string_copy(US domain);
1978sig->selector = string_copy(US selector);
d73e45df 1979sig->privkey = string_copy(US privkey);
286b9d5f 1980sig->keytype = -1;
cb224393 1981
d73e45df
JH
1982for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
1983 if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
1984 { sig->hashtype = hashtype; break; }
1985if (hashtype >= nelem(pdkim_hashes))
7b83389d 1986 {
286b9d5f 1987 log_write(0, LOG_MAIN|LOG_PANIC,
305f8921 1988 "DKIM: unrecognised hashname '%s'", hashname);
d73e45df
JH
1989 return NULL;
1990 }
1991
cd1a5fe0
JH
1992DEBUG(D_acl)
1993 {
1994 pdkim_signature s = *sig;
1995 ev_ctx vctx;
1996
305f8921 1997 debug_printf("DKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
b9df1829 1998 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
cd1a5fe0 1999 debug_printf("WARNING: bad dkim key in dns\n");
305f8921 2000 debug_printf("DKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
cd1a5fe0 2001 }
9e70917d 2002return sig;
6ab02e3f 2003}
80a47a2c 2004
f444c2c7 2005
80a47a2c 2006/* -------------------------------------------------------------------------- */
3045f050 2007
9e70917d
JH
2008DLLEXPORT void
2009pdkim_set_optional(pdkim_signature * sig,
2010 char * sign_headers,
2011 char * identity,
80a47a2c
TK
2012 int canon_headers,
2013 int canon_body,
2014 long bodylength,
80a47a2c 2015 unsigned long created,
3045f050
JH
2016 unsigned long expires)
2017{
3045f050 2018if (identity)
e2e3255a 2019 sig->identity = string_copy(US identity);
80a47a2c 2020
ca9cb170
JH
2021sig->sign_headers = string_copy(sign_headers
2022 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
80a47a2c 2023
8ef02a06
JH
2024sig->canon_headers = canon_headers;
2025sig->canon_body = canon_body;
2026sig->bodylength = bodylength;
2027sig->created = created;
2028sig->expires = expires;
80a47a2c 2029
9e70917d
JH
2030return;
2031}
2032
2033
2034
cf1cce5e 2035/* Set up a blob for calculating the bodyhash according to the
617d3932 2036given needs. Use an existing one if possible, or create a new one.
cf1cce5e 2037
617d3932 2038Return: hashblob pointer, or NULL on error
cf1cce5e
JH
2039*/
2040pdkim_bodyhash *
617d3932
JH
2041pdkim_set_bodyhash(pdkim_ctx * ctx, int hashtype, int canon_method,
2042 long bodylength)
cf1cce5e
JH
2043{
2044pdkim_bodyhash * b;
2045
6f47da8d
JH
2046if (hashtype == -1 || canon_method == -1) return NULL;
2047
cf1cce5e 2048for (b = ctx->bodyhash; b; b = b->next)
617d3932
JH
2049 if ( hashtype == b->hashtype
2050 && canon_method == b->canon_method
2051 && bodylength == b->bodylength)
2052 {
305f8921 2053 DEBUG(D_receive) debug_printf("DKIM: using existing bodyhash %d/%d/%ld\n",
617d3932
JH
2054 hashtype, canon_method, bodylength);
2055 return b;
2056 }
cf1cce5e 2057
305f8921 2058DEBUG(D_receive) debug_printf("DKIM: new bodyhash %d/%d/%ld\n",
617d3932 2059 hashtype, canon_method, bodylength);
f3ebb786 2060b = store_get(sizeof(pdkim_bodyhash), FALSE);
cf1cce5e 2061b->next = ctx->bodyhash;
617d3932
JH
2062b->hashtype = hashtype;
2063b->canon_method = canon_method;
2064b->bodylength = bodylength;
cf1cce5e 2065if (!exim_sha_init(&b->body_hash_ctx, /*XXX hash method: extend for sha512 */
617d3932 2066 pdkim_hashes[hashtype].exim_hashmethod))
cf1cce5e
JH
2067 {
2068 DEBUG(D_acl)
305f8921 2069 debug_printf("DKIM: hash init error, possibly nonhandled hashtype\n");
cf1cce5e
JH
2070 return NULL;
2071 }
2072b->signed_body_bytes = 0;
2073b->num_buffered_blanklines = 0;
2074ctx->bodyhash = b;
617d3932
JH
2075return b;
2076}
2077
cf1cce5e 2078
617d3932
JH
2079/* Set up a blob for calculating the bodyhash according to the
2080needs of this signature. Use an existing one if possible, or
2081create a new one.
2082
2083Return: hashblob pointer, or NULL on error (only used as a boolean).
2084*/
2085pdkim_bodyhash *
2086pdkim_set_sig_bodyhash(pdkim_ctx * ctx, pdkim_signature * sig)
2087{
2088pdkim_bodyhash * b = pdkim_set_bodyhash(ctx,
2089 sig->hashtype, sig->canon_body, sig->bodylength);
cf1cce5e
JH
2090sig->calc_body_hash = b;
2091return b;
2092}
2093
2094
2095/* -------------------------------------------------------------------------- */
2096
2097
9e70917d
JH
2098void
2099pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
fc2ba7b9 2100 uschar * (*dns_txt_callback)(const uschar *))
9e70917d
JH
2101{
2102memset(ctx, 0, sizeof(pdkim_ctx));
2103ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
f3ebb786
JH
2104/* The line buffer is for message data, hence tainted */
2105ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE);
9e70917d 2106DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
6ab02e3f 2107}
3045f050 2108
3045f050 2109
2592e6c0
JH
2110void
2111pdkim_init(void)
2112{
9b2583c4 2113exim_dkim_init();
2592e6c0
JH
2114}
2115
2116
2117
f444c2c7 2118#endif /*DISABLE_DKIM*/