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