Compiler quietening
[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
29#ifndef SUPPORT_TLS
30# error Need SUPPORT_TLS for DKIM
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
83 [KEYTYPE_ED25519] = US"ed25519", /* Works for 3.6.0 GnuTLS */
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
617d3932
JH
124int
125pdkim_hashname_to_hashtype(const uschar * s, unsigned len)
126{
127int i;
128if (!len) len = Ustrlen(s);
129for (i = 0; i < nelem(pdkim_hashes); i++)
130 if (Ustrncmp(s, pdkim_hashes[i].dkim_hashname, len) == 0)
131 return i;
132return -1;
133}
134
135void
136pdkim_cstring_to_canons(const uschar * s, unsigned len,
137 int * canon_head, int * canon_body)
138{
139int i;
140if (!len) len = Ustrlen(s);
141for (i = 0; pdkim_combined_canons[i].str; i++)
142 if ( Ustrncmp(s, pdkim_combined_canons[i].str, len) == 0
143 && len == Ustrlen(pdkim_combined_canons[i].str))
144 {
145 *canon_head = pdkim_combined_canons[i].canon_headers;
146 *canon_body = pdkim_combined_canons[i].canon_body;
147 break;
148 }
149}
150
151
f444c2c7
JH
152
153const char *
154pdkim_verify_status_str(int status)
155{
f7302073
JH
156switch(status)
157 {
158 case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE";
159 case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID";
160 case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL";
161 case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS";
162 default: return "PDKIM_VERIFY_UNKNOWN";
ff7ddfd7
TK
163 }
164}
f444c2c7
JH
165
166const char *
167pdkim_verify_ext_status_str(int ext_status)
168{
f7302073
JH
169switch(ext_status)
170 {
171 case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
172 case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
135e9496 173 case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
f7302073
JH
174 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
175 case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
176 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
177 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
178 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
179 case PDKIM_VERIFY_INVALID_DKIM_VERSION: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
180 default: return "PDKIM_VERIFY_UNKNOWN";
181 }
182}
183
b9df1829 184const uschar *
f7302073
JH
185pdkim_errstr(int status)
186{
187switch(status)
188 {
b9df1829
JH
189 case PDKIM_OK: return US"OK";
190 case PDKIM_FAIL: return US"FAIL";
286b9d5f
JH
191 case PDKIM_ERR_RSA_PRIVKEY: return US"PRIVKEY";
192 case PDKIM_ERR_RSA_SIGNING: return US"SIGNING";
193 case PDKIM_ERR_LONG_LINE: return US"LONG_LINE";
b9df1829
JH
194 case PDKIM_ERR_BUFFER_TOO_SMALL: return US"BUFFER_TOO_SMALL";
195 case PDKIM_SIGN_PRIVKEY_WRAP: return US"PRIVKEY_WRAP";
196 case PDKIM_SIGN_PRIVKEY_B64D: return US"PRIVKEY_B64D";
ef698bf6 197 default: return US"(unknown)";
ff7ddfd7
TK
198 }
199}
200
201
80a47a2c
TK
202/* -------------------------------------------------------------------------- */
203/* Print debugging functions */
617d3932 204void
b78006ac 205pdkim_quoteprint(const uschar *data, int len)
3045f050
JH
206{
207int i;
0d04a285 208for (i = 0; i < len; i++)
3045f050 209 {
b78006ac 210 const int c = data[i];
3045f050
JH
211 switch (c)
212 {
0d04a285
JH
213 case ' ' : debug_printf("{SP}"); break;
214 case '\t': debug_printf("{TB}"); break;
215 case '\r': debug_printf("{CR}"); break;
216 case '\n': debug_printf("{LF}"); break;
217 case '{' : debug_printf("{BO}"); break;
218 case '}' : debug_printf("{BC}"); break;
3045f050
JH
219 default:
220 if ( (c < 32) || (c > 127) )
0d04a285 221 debug_printf("{%02x}", c);
3045f050 222 else
0d04a285 223 debug_printf("%c", c);
80a47a2c
TK
224 break;
225 }
226 }
2592e6c0 227debug_printf("\n");
80a47a2c 228}
80a47a2c 229
617d3932 230void
b78006ac 231pdkim_hexprint(const uschar *data, int len)
3045f050
JH
232{
233int i;
02c4f8fb
JH
234if (data) for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
235else debug_printf("<NULL>");
2592e6c0 236debug_printf("\n");
80a47a2c 237}
80a47a2c
TK
238
239
f444c2c7 240
f444c2c7 241static pdkim_stringlist *
ca9cb170 242pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
3045f050 243{
ca9cb170 244pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
3045f050 245
abe1010c 246memset(new_entry, 0, sizeof(pdkim_stringlist));
ca9cb170 247new_entry->value = string_copy(str);
ab9152ff
JH
248if (base) new_entry->next = base;
249return new_entry;
6ab02e3f 250}
80a47a2c
TK
251
252
8ef02a06
JH
253
254/* Trim whitespace fore & aft */
255
ca9cb170 256static void
acec9514 257pdkim_strtrim(gstring * str)
3045f050 258{
acec9514 259uschar * p = str->s;
b2bcdd35 260uschar * q;
acec9514
JH
261
262while (*p == '\t' || *p == ' ') /* dump the leading whitespace */
263 { str->size--; str->ptr--; str->s++; }
264
265while ( str->ptr > 0
81147e20 266 && ((q = str->s + str->ptr - 1), (*q == '\t' || *q == ' '))
acec9514
JH
267 )
268 str->ptr--; /* dump trailing whitespace */
269
270(void) string_from_gstring(str);
8ef02a06
JH
271}
272
273
80a47a2c
TK
274
275/* -------------------------------------------------------------------------- */
3045f050 276
3045f050
JH
277DLLEXPORT void
278pdkim_free_ctx(pdkim_ctx *ctx)
279{
6ab02e3f 280}
80a47a2c
TK
281
282
283/* -------------------------------------------------------------------------- */
284/* Matches the name of the passed raw "header" against
8ef02a06 285 the passed colon-separated "tick", and invalidates
484cc1a9
JH
286 the entry in tick. Entries can be prefixed for multi- or over-signing,
287 in which case do not invalidate.
288
289 Returns OK for a match, or fail-code
290*/
3045f050 291
f444c2c7 292static int
e2e3255a 293header_name_match(const uschar * header, uschar * tick)
3045f050 294{
484cc1a9
JH
295const uschar * ticklist = tick;
296int sep = ':';
297BOOL multisign;
298uschar * hname, * p, * ele;
ca9cb170 299uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
3045f050 300
ca9cb170
JH
301if (!hcolon)
302 return PDKIM_FAIL; /* This isn't a header */
3045f050 303
ca9cb170
JH
304/* if we had strncmpic() we wouldn't need this copy */
305hname = string_copyn(header, hcolon-header);
3045f050 306
484cc1a9 307while (p = US ticklist, ele = string_nextinlist(&ticklist, &sep, NULL, 0))
3045f050 308 {
484cc1a9
JH
309 switch (*ele)
310 {
311 case '=': case '+': multisign = TRUE; ele++; break;
312 default: multisign = FALSE; break;
80a47a2c
TK
313 }
314
484cc1a9
JH
315 if (strcmpic(ele, hname) == 0)
316 {
317 if (!multisign)
318 *p = '_'; /* Invalidate this header name instance in tick-off list */
319 return PDKIM_OK;
320 }
321 }
ca9cb170 322return PDKIM_FAIL;
80a47a2c
TK
323}
324
325
326/* -------------------------------------------------------------------------- */
ca9cb170 327/* Performs "relaxed" canonicalization of a header. */
3045f050 328
617d3932
JH
329uschar *
330pdkim_relax_header_n(const uschar * header, int len, BOOL append_crlf)
3045f050
JH
331{
332BOOL past_field_name = FALSE;
333BOOL seen_wsp = FALSE;
ca9cb170 334const uschar * p;
617d3932 335uschar * relaxed = store_get(len+3);
ca9cb170 336uschar * q = relaxed;
3045f050 337
617d3932 338for (p = header; p - header < len; p++)
3045f050 339 {
ca9cb170 340 uschar c = *p;
ea18931d
JH
341
342 if (c == '\r' || c == '\n') /* Ignore CR & LF */
3045f050
JH
343 continue;
344 if (c == '\t' || c == ' ')
345 {
346 if (seen_wsp)
80a47a2c 347 continue;
3045f050
JH
348 c = ' '; /* Turns WSP into SP */
349 seen_wsp = TRUE;
80a47a2c 350 }
3045f050
JH
351 else
352 if (!past_field_name && c == ':')
353 {
ea18931d
JH
354 if (seen_wsp) q--; /* This removes WSP immediately before the colon */
355 seen_wsp = TRUE; /* This removes WSP immediately after the colon */
3045f050 356 past_field_name = TRUE;
80a47a2c 357 }
3045f050
JH
358 else
359 seen_wsp = FALSE;
360
361 /* Lowercase header name */
362 if (!past_field_name) c = tolower(c);
363 *q++ = c;
80a47a2c 364 }
3045f050
JH
365
366if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
3045f050 367
ea18931d 368if (append_crlf) { *q++ = '\r'; *q++ = '\n'; }
ca9cb170 369*q = '\0';
3045f050 370return relaxed;
6ab02e3f 371}
80a47a2c
TK
372
373
617d3932
JH
374uschar *
375pdkim_relax_header(const uschar * header, BOOL append_crlf)
376{
377return pdkim_relax_header_n(header, Ustrlen(header), append_crlf);
378}
379
380
80a47a2c
TK
381/* -------------------------------------------------------------------------- */
382#define PDKIM_QP_ERROR_DECODE -1
3045f050 383
35cf75e9
JH
384static const uschar *
385pdkim_decode_qp_char(const uschar *qp_p, int *c)
3045f050 386{
35cf75e9 387const uschar *initial_pos = qp_p;
3045f050
JH
388
389/* Advance one char */
390qp_p++;
391
392/* Check for two hex digits and decode them */
393if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
394 {
395 /* Do hex conversion */
396 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
a5840e10 397 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
3045f050 398 return qp_p + 2;
6ab02e3f 399 }
80a47a2c 400
3045f050
JH
401/* Illegal char here */
402*c = PDKIM_QP_ERROR_DECODE;
403return initial_pos;
80a47a2c
TK
404}
405
406
407/* -------------------------------------------------------------------------- */
3045f050 408
e2e3255a 409static uschar *
35cf75e9 410pdkim_decode_qp(const uschar * str)
3045f050
JH
411{
412int nchar = 0;
ca9cb170 413uschar * q;
35cf75e9 414const uschar * p = str;
ca9cb170 415uschar * n = store_get(Ustrlen(str)+1);
3045f050
JH
416
417*n = '\0';
418q = n;
ca9cb170 419while (*p)
3045f050
JH
420 {
421 if (*p == '=')
422 {
423 p = pdkim_decode_qp_char(p, &nchar);
424 if (nchar >= 0)
425 {
426 *q++ = nchar;
427 continue;
80a47a2c
TK
428 }
429 }
3045f050
JH
430 else
431 *q++ = *p;
432 p++;
80a47a2c 433 }
3045f050
JH
434*q = '\0';
435return n;
80a47a2c
TK
436}
437
438
439/* -------------------------------------------------------------------------- */
3045f050 440
617d3932 441void
35cf75e9 442pdkim_decode_base64(const uschar * str, blob * b)
3045f050 443{
617d3932 444int dlen = b64decode(str, &b->data);
2592e6c0
JH
445if (dlen < 0) b->data = NULL;
446b->len = dlen;
80a47a2c
TK
447}
448
617d3932 449uschar *
2592e6c0 450pdkim_encode_base64(blob * b)
3045f050 451{
ca9cb170 452return b64encode(b->data, b->len);
80a47a2c
TK
453}
454
455
456/* -------------------------------------------------------------------------- */
457#define PDKIM_HDR_LIMBO 0
458#define PDKIM_HDR_TAG 1
459#define PDKIM_HDR_VALUE 2
3045f050 460
f444c2c7 461static pdkim_signature *
9e70917d 462pdkim_parse_sig_header(pdkim_ctx * ctx, uschar * raw_hdr)
3045f050 463{
2c0f3ea1 464pdkim_signature * sig;
ca9cb170 465uschar *p, *q;
acec9514
JH
466gstring * cur_tag = NULL;
467gstring * cur_val = NULL;
3045f050
JH
468BOOL past_hname = FALSE;
469BOOL in_b_val = FALSE;
470int where = PDKIM_HDR_LIMBO;
471int i;
472
ca9cb170 473sig = store_get(sizeof(pdkim_signature));
abe1010c 474memset(sig, 0, sizeof(pdkim_signature));
3045f050
JH
475sig->bodylength = -1;
476
07eeb4df 477/* Set so invalid/missing data error display is accurate */
07eeb4df 478sig->version = 0;
d73e45df
JH
479sig->keytype = -1;
480sig->hashtype = -1;
07eeb4df 481
ca9cb170 482q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
80a47a2c 483
3045f050
JH
484for (p = raw_hdr; ; p++)
485 {
486 char c = *p;
80a47a2c 487
3045f050
JH
488 /* Ignore FWS */
489 if (c == '\r' || c == '\n')
490 goto NEXT_CHAR;
80a47a2c 491
3045f050
JH
492 /* Fast-forward through header name */
493 if (!past_hname)
494 {
495 if (c == ':') past_hname = TRUE;
496 goto NEXT_CHAR;
80a47a2c
TK
497 }
498
3045f050
JH
499 if (where == PDKIM_HDR_LIMBO)
500 {
501 /* In limbo, just wait for a tag-char to appear */
502 if (!(c >= 'a' && c <= 'z'))
503 goto NEXT_CHAR;
80a47a2c 504
3045f050 505 where = PDKIM_HDR_TAG;
80a47a2c
TK
506 }
507
3045f050
JH
508 if (where == PDKIM_HDR_TAG)
509 {
3045f050 510 if (c >= 'a' && c <= 'z')
acec9514 511 cur_tag = string_catn(cur_tag, p, 1);
80a47a2c 512
3045f050
JH
513 if (c == '=')
514 {
acec9514 515 if (Ustrcmp(string_from_gstring(cur_tag), "b") == 0)
3045f050 516 {
ca9cb170 517 *q++ = '=';
3045f050
JH
518 in_b_val = TRUE;
519 }
520 where = PDKIM_HDR_VALUE;
521 goto NEXT_CHAR;
80a47a2c
TK
522 }
523 }
524
3045f050
JH
525 if (where == PDKIM_HDR_VALUE)
526 {
3045f050
JH
527 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
528 goto NEXT_CHAR;
529
530 if (c == ';' || c == '\0')
531 {
a05d3e34
JH
532 /* We must have both tag and value, and tags must be one char except
533 for the possibility of "bh". */
534
535 if ( cur_tag && cur_val
536 && (cur_tag->ptr == 1 || *cur_tag->s == 'b')
537 )
3045f050 538 {
acec9514 539 (void) string_from_gstring(cur_val);
3045f050
JH
540 pdkim_strtrim(cur_val);
541
acec9514 542 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->s, cur_val->s);
3045f050 543
acec9514 544 switch (*cur_tag->s)
3045f050 545 {
286b9d5f 546 case 'b': /* sig-data or body-hash */
a05d3e34
JH
547 switch (cur_tag->s[1])
548 {
549 case '\0': pdkim_decode_base64(cur_val->s, &sig->sighash); break;
550 case 'h': if (cur_tag->ptr == 2)
551 pdkim_decode_base64(cur_val->s, &sig->bodyhash);
552 break;
553 default: break;
554 }
3045f050 555 break;
286b9d5f 556 case 'v': /* version */
3045f050
JH
557 /* We only support version 1, and that is currently the
558 only version there is. */
07eeb4df 559 sig->version =
acec9514 560 Ustrcmp(cur_val->s, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
3045f050 561 break;
286b9d5f 562 case 'a': /* algorithm */
d73e45df 563 {
acec9514 564 uschar * s = Ustrchr(cur_val->s, '-');
d73e45df
JH
565
566 for(i = 0; i < nelem(pdkim_keytypes); i++)
acec9514 567 if (Ustrncmp(cur_val->s, pdkim_keytypes[i], s - cur_val->s) == 0)
d73e45df 568 { sig->keytype = i; break; }
286b9d5f
JH
569 if (sig->keytype < 0)
570 log_write(0, LOG_MAIN,
571 "DKIM: ignoring signature due to nonhandled keytype in a=%s",
572 cur_val->s);
573
617d3932 574 sig->hashtype = pdkim_hashname_to_hashtype(++s, 0);
3045f050 575 break;
d73e45df
JH
576 }
577
286b9d5f 578 case 'c': /* canonicalization */
617d3932
JH
579 pdkim_cstring_to_canons(cur_val->s, 0,
580 &sig->canon_headers, &sig->canon_body);
3045f050 581 break;
286b9d5f 582 case 'q': /* Query method (for pubkey)*/
3045f050 583 for (i = 0; pdkim_querymethods[i]; i++)
acec9514 584 if (Ustrcmp(cur_val->s, pdkim_querymethods[i]) == 0)
3045f050 585 {
286b9d5f 586 sig->querymethod = i; /* we never actually use this */
3045f050
JH
587 break;
588 }
589 break;
286b9d5f 590 case 's': /* Selector */
acec9514 591 sig->selector = string_copyn(cur_val->s, cur_val->ptr); break;
286b9d5f 592 case 'd': /* SDID */
acec9514 593 sig->domain = string_copyn(cur_val->s, cur_val->ptr); break;
286b9d5f 594 case 'i': /* AUID */
acec9514 595 sig->identity = pdkim_decode_qp(cur_val->s); break;
286b9d5f 596 case 't': /* Timestamp */
acec9514 597 sig->created = strtoul(CS cur_val->s, NULL, 10); break;
286b9d5f 598 case 'x': /* Expiration */
acec9514 599 sig->expires = strtoul(CS cur_val->s, NULL, 10); break;
286b9d5f 600 case 'l': /* Body length count */
acec9514 601 sig->bodylength = strtol(CS cur_val->s, NULL, 10); break;
286b9d5f 602 case 'h': /* signed header fields */
acec9514 603 sig->headernames = string_copyn(cur_val->s, cur_val->ptr); break;
286b9d5f 604 case 'z': /* Copied headfields */
acec9514 605 sig->copiedheaders = pdkim_decode_qp(cur_val->s); break;
286b9d5f
JH
606/*XXX draft-ietf-dcrup-dkim-crypto-05 would need 'p' tag support
607for rsafp signatures. But later discussion is dropping those. */
3045f050 608 default:
0d04a285 609 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
3045f050
JH
610 break;
611 }
612 }
acec9514 613 cur_tag = cur_val = NULL;
3045f050
JH
614 in_b_val = FALSE;
615 where = PDKIM_HDR_LIMBO;
80a47a2c 616 }
3045f050 617 else
acec9514 618 cur_val = string_catn(cur_val, p, 1);
80a47a2c
TK
619 }
620
3045f050
JH
621NEXT_CHAR:
622 if (c == '\0')
623 break;
80a47a2c 624
3045f050
JH
625 if (!in_b_val)
626 *q++ = c;
80a47a2c
TK
627 }
628
286b9d5f
JH
629if (sig->keytype < 0 || sig->hashtype < 0) /* Cannot verify this signature */
630 return NULL;
631
3045f050
JH
632*q = '\0';
633/* Chomp raw header. The final newline must not be added to the signature. */
37f3dc43
JH
634while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
635 *q = '\0';
80a47a2c 636
0d04a285 637DEBUG(D_acl)
3045f050 638 {
0d04a285 639 debug_printf(
3045f050 640 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
e2e3255a 641 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
0d04a285 642 debug_printf(
dcd03763 643 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sighash.len*8);
0d04a285 644 debug_printf(
3045f050 645 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 646 }
80a47a2c 647
617d3932 648if (!pdkim_set_sig_bodyhash(ctx, sig))
7b83389d 649 return NULL;
cf1cce5e 650
3045f050 651return sig;
80a47a2c
TK
652}
653
654
655/* -------------------------------------------------------------------------- */
80a47a2c 656
617d3932
JH
657pdkim_pubkey *
658pdkim_parse_pubkey_record(const uschar *raw_record)
3045f050 659{
35cf75e9
JH
660const uschar * ele;
661int sep = ';';
662pdkim_pubkey * pub;
80a47a2c 663
ca9cb170 664pub = store_get(sizeof(pdkim_pubkey));
abe1010c 665memset(pub, 0, sizeof(pdkim_pubkey));
80a47a2c 666
35cf75e9
JH
667while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
668 {
669 const uschar * val;
670
671 if ((val = Ustrchr(ele, '=')))
3045f050 672 {
35cf75e9 673 int taglen = val++ - ele;
80a47a2c 674
35cf75e9
JH
675 DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
676 switch (ele[0])
3045f050 677 {
35cf75e9
JH
678 case 'v': pub->version = val; break;
679 case 'h': pub->hashes = val; break;
286b9d5f 680 case 'k': pub->keytype = val; break;
35cf75e9
JH
681 case 'g': pub->granularity = val; break;
682 case 'n': pub->notes = pdkim_decode_qp(val); break;
683 case 'p': pdkim_decode_base64(val, &pub->key); break;
684 case 's': pub->srvtype = val; break;
685 case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
686 if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
e21a4d00 687 break;
35cf75e9 688 default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
80a47a2c 689 }
e21a4d00 690 }
35cf75e9 691 }
80a47a2c 692
3045f050 693/* Set fallback defaults */
fc6fb551
JH
694if (!pub->version)
695 pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
135e9496
JH
696else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
697 {
698 DEBUG(D_acl) debug_printf(" Bad v= field\n");
699 return NULL;
700 }
e21a4d00 701
35cf75e9 702if (!pub->granularity) pub->granularity = US"*";
35cf75e9 703if (!pub->keytype ) pub->keytype = US"rsa";
35cf75e9 704if (!pub->srvtype ) pub->srvtype = US"*";
80a47a2c 705
3045f050 706/* p= is required */
2592e6c0 707if (pub->key.data)
80a47a2c 708 return pub;
3045f050 709
135e9496 710DEBUG(D_acl) debug_printf(" Missing p= field\n");
3045f050 711return NULL;
80a47a2c
TK
712}
713
714
715/* -------------------------------------------------------------------------- */
3045f050 716
cf1cce5e 717/* Update one bodyhash with some additional data.
9e70917d
JH
718If we have to relax the data for this sig, return our copy of it. */
719
9e70917d 720static blob *
cf1cce5e 721pdkim_update_ctx_bodyhash(pdkim_bodyhash * b, blob * orig_data, blob * relaxed_data)
3045f050 722{
9e70917d
JH
723blob * canon_data = orig_data;
724/* Defaults to simple canon (no further treatment necessary) */
3045f050 725
cf1cce5e 726if (b->canon_method == PDKIM_CANON_RELAXED)
3045f050 727 {
9e70917d
JH
728 /* Relax the line if not done already */
729 if (!relaxed_data)
3045f050 730 {
9e70917d 731 BOOL seen_wsp = FALSE;
744976d4 732 const uschar * p, * r;
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
744976d4 743 for (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{
cf1cce5e 790pdkim_bodyhash * b;
9e70917d 791pdkim_signature * sig;
80a47a2c 792
cf1cce5e 793for (b = ctx->bodyhash; b; b = b->next) /* Finish hashes */
617d3932 794 {
0ae2cff6 795 DEBUG(D_acl) debug_printf("PDKIM: finish bodyhash %d/%d/%d len %ld\n",
617d3932 796 b->hashtype, b->canon_method, b->bodylength, b->signed_body_bytes);
cf1cce5e 797 exim_sha_finish(&b->body_hash_ctx, &b->bh);
617d3932 798 }
cf1cce5e 799
3045f050 800/* Traverse all signatures */
f4d091fb 801for (sig = ctx->sig; sig; sig = sig->next)
cf1cce5e
JH
802 {
803 b = sig->calc_body_hash;
3045f050 804
0d04a285 805 DEBUG(D_acl)
3045f050 806 {
4ff848b5 807 debug_printf("PDKIM [%s] Body bytes (%s) hashed: %lu\n"
9e70917d 808 "PDKIM [%s] Body %s computed: ",
4ff848b5
JH
809 sig->domain, pdkim_canons[b->canon_method], b->signed_body_bytes,
810 sig->domain, pdkim_hashes[b->hashtype].dkim_hashname);
cf1cce5e 811 pdkim_hexprint(CUS b->bh.data, b->bh.len);
80a47a2c 812 }
3045f050
JH
813
814 /* SIGNING -------------------------------------------------------------- */
e983e85a 815 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 816 {
3045f050
JH
817 /* If bodylength limit is set, and we have received less bytes
818 than the requested amount, effectively remove the limit tag. */
cf1cce5e 819 if (b->signed_body_bytes < sig->bodylength)
3045f050 820 sig->bodylength = -1;
80a47a2c 821 }
3045f050 822
3045f050 823 else
02c4f8fb
JH
824 /* VERIFICATION --------------------------------------------------------- */
825 /* Be careful that the header sig included a bodyash */
826
cf1cce5e
JH
827 if ( sig->bodyhash.data
828 && memcmp(b->bh.data, sig->bodyhash.data, b->bh.len) == 0)
3045f050 829 {
4ff848b5 830 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash compared OK\n", sig->domain);
80a47a2c 831 }
3045f050
JH
832 else
833 {
0d04a285 834 DEBUG(D_acl)
3045f050 835 {
e21a4d00 836 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain);
dcd03763 837 pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
0d04a285 838 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
3045f050 839 }
3045f050
JH
840 sig->verify_status = PDKIM_VERIFY_FAIL;
841 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
80a47a2c 842 }
80a47a2c 843 }
6ab02e3f 844}
80a47a2c
TK
845
846
847
9e70917d 848static void
e983e85a
JH
849pdkim_body_complete(pdkim_ctx * ctx)
850{
cf1cce5e 851pdkim_bodyhash * b;
e983e85a
JH
852
853/* In simple body mode, if any empty lines were buffered,
854replace with one. rfc 4871 3.4.3 */
855/*XXX checking the signed-body-bytes is a gross hack; I think
856it indicates that all linebreaks should be buffered, including
857the one terminating a text line */
858
cf1cce5e
JH
859for (b = ctx->bodyhash; b; b = b->next)
860 if ( b->canon_method == PDKIM_CANON_SIMPLE
861 && b->signed_body_bytes == 0
862 && b->num_buffered_blanklines > 0
9e70917d 863 )
cf1cce5e 864 (void) pdkim_update_ctx_bodyhash(b, &lineending, NULL);
e983e85a
JH
865
866ctx->flags |= PDKIM_SEEN_EOD;
867ctx->linebuf_offset = 0;
e983e85a
JH
868}
869
870
871
80a47a2c 872/* -------------------------------------------------------------------------- */
e983e85a 873/* Call from pdkim_feed below for processing complete body lines */
744976d4 874/* NOTE: the line is not NUL-terminated; but we have a count */
3045f050 875
9e70917d
JH
876static void
877pdkim_bodyline_complete(pdkim_ctx * ctx)
3045f050 878{
9e70917d 879blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
cf1cce5e 880pdkim_bodyhash * b;
9e70917d
JH
881blob * rnl = NULL;
882blob * rline = NULL;
3045f050
JH
883
884/* Ignore extra data if we've seen the end-of-data marker */
9e70917d 885if (ctx->flags & PDKIM_SEEN_EOD) goto all_skip;
3045f050
JH
886
887/* We've always got one extra byte to stuff a zero ... */
9e70917d 888ctx->linebuf[line.len] = '\0';
3045f050 889
0d04a285 890/* Terminate on EOD marker */
e983e85a 891if (ctx->flags & PDKIM_DOT_TERM)
3045f050 892 {
9e70917d
JH
893 if (memcmp(line.data, ".\r\n", 3) == 0)
894 { pdkim_body_complete(ctx); return; }
0d04a285 895
e983e85a 896 /* Unstuff dots */
9e70917d
JH
897 if (memcmp(line.data, "..", 2) == 0)
898 { line.data++; line.len--; }
80a47a2c
TK
899 }
900
3045f050 901/* Empty lines need to be buffered until we find a non-empty line */
9e70917d 902if (memcmp(line.data, "\r\n", 2) == 0)
3045f050 903 {
cf1cce5e 904 for (b = ctx->bodyhash; b; b = b->next) b->num_buffered_blanklines++;
9e70917d 905 goto all_skip;
80a47a2c
TK
906 }
907
cf1cce5e
JH
908/* Process line for each bodyhash separately */
909for (b = ctx->bodyhash; b; b = b->next)
3045f050 910 {
cf1cce5e 911 if (b->canon_method == PDKIM_CANON_RELAXED)
3045f050 912 {
9e70917d 913 /* Lines with just spaces need to be buffered too */
7845dbb3 914 uschar * cp = line.data;
9e70917d 915 char c;
6a11a9e6 916
9e70917d
JH
917 while ((c = *cp))
918 {
919 if (c == '\r' && cp[1] == '\n') break;
cf1cce5e 920 if (c != ' ' && c != '\t') goto hash_process;
9e70917d
JH
921 cp++;
922 }
923
cf1cce5e
JH
924 b->num_buffered_blanklines++;
925 goto hash_skip;
6a11a9e6
JH
926 }
927
cf1cce5e 928hash_process:
9e70917d 929 /* At this point, we have a non-empty line, so release the buffered ones. */
6a11a9e6 930
cf1cce5e 931 while (b->num_buffered_blanklines)
9e70917d 932 {
cf1cce5e
JH
933 rnl = pdkim_update_ctx_bodyhash(b, &lineending, rnl);
934 b->num_buffered_blanklines--;
9e70917d
JH
935 }
936
cf1cce5e
JH
937 rline = pdkim_update_ctx_bodyhash(b, &line, rline);
938hash_skip: ;
80a47a2c
TK
939 }
940
9e70917d
JH
941if (rnl) store_free(rnl);
942if (rline) store_free(rline);
943
944all_skip:
80a47a2c 945
3045f050 946ctx->linebuf_offset = 0;
9e70917d 947return;
80a47a2c
TK
948}
949
950
951/* -------------------------------------------------------------------------- */
952/* Callback from pdkim_feed below for processing complete headers */
953#define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
3045f050 954
f444c2c7 955static int
2c0f3ea1 956pdkim_header_complete(pdkim_ctx * ctx)
3045f050 957{
2c0f3ea1
JH
958pdkim_signature * sig, * last_sig;
959
3045f050 960/* Special case: The last header can have an extra \r appended */
acec9514
JH
961if ( (ctx->cur_header->ptr > 1) &&
962 (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
963 --ctx->cur_header->ptr;
964(void) string_from_gstring(ctx->cur_header);
80a47a2c 965
617d3932
JH
966#ifdef EXPERIMENTAL_ARC
967/* Feed the header line to ARC processing */
968(void) arc_header_feed(ctx->cur_header, !(ctx->flags & PDKIM_MODE_SIGN));
969#endif
970
2c0f3ea1 971if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
80a47a2c 972
3045f050 973/* SIGNING -------------------------------------------------------------- */
e983e85a 974if (ctx->flags & PDKIM_MODE_SIGN)
0d04a285 975 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
80a47a2c 976
ab9152ff 977 /* Add header to the signed headers list (in reverse order) */
acec9514 978 sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s);
94431adb 979
0d04a285 980/* VERIFICATION ----------------------------------------------------------- */
3045f050 981/* DKIM-Signature: headers are added to the verification list */
e983e85a 982else
3045f050 983 {
f6ee24a2 984#ifdef notdef
bd8fbe36
JH
985 DEBUG(D_acl)
986 {
987 debug_printf("PDKIM >> raw hdr: ");
acec9514 988 pdkim_quoteprint(CUS ctx->cur_header->s, ctx->cur_header->ptr);
bd8fbe36 989 }
f6ee24a2 990#endif
acec9514 991 if (strncasecmp(CCS ctx->cur_header->s,
3045f050 992 DKIM_SIGNATURE_HEADERNAME,
e2e3255a 993 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
3045f050 994 {
02c4f8fb
JH
995 /* Create and chain new signature block. We could error-check for all
996 required tags here, but prefer to create the internal sig and expicitly
997 fail verification of it later. */
80a47a2c 998
0d04a285 999 DEBUG(D_acl) debug_printf(
3045f050 1000 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
3045f050 1001
acec9514 1002 sig = pdkim_parse_sig_header(ctx, ctx->cur_header->s);
02c4f8fb
JH
1003
1004 if (!(last_sig = ctx->sig))
2c0f3ea1 1005 ctx->sig = sig;
02c4f8fb 1006 else
3045f050 1007 {
02c4f8fb 1008 while (last_sig->next) last_sig = last_sig->next;
2c0f3ea1 1009 last_sig->next = sig;
80a47a2c
TK
1010 }
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{
02c4f8fb 1030int p, rc;
3045f050 1031
e983e85a
JH
1032/* Alternate EOD signal, used in non-dotstuffing mode */
1033if (!data)
1034 pdkim_body_complete(ctx);
1035
10c50704 1036else for (p = 0; p<len; p++)
3045f050 1037 {
ca9cb170 1038 uschar c = data[p];
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(
02c4f8fb 1079 "PDKIM >> 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
cd1a5fe0 1339static pdkim_pubkey *
b9df1829
JH
1340pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1341 const uschar ** errstr)
cd1a5fe0
JH
1342{
1343uschar * dns_txt_name, * dns_txt_reply;
1344pdkim_pubkey * p;
cd1a5fe0
JH
1345
1346/* Fetch public key for signing domain, from DNS */
1347
1348dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1349
617d3932 1350if ( !(dns_txt_reply = ctx->dns_txt_callback(dns_txt_name))
cd1a5fe0
JH
1351 || dns_txt_reply[0] == '\0'
1352 )
1353 {
1354 sig->verify_status = PDKIM_VERIFY_INVALID;
1355 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1356 return NULL;
1357 }
1358
1359DEBUG(D_acl)
1360 {
1361 debug_printf(
1362 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
9e70917d
JH
1363 " %s\n"
1364 " Raw record: ",
1365 dns_txt_name);
cd1a5fe0
JH
1366 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1367 }
1368
617d3932 1369if ( !(p = pdkim_parse_pubkey_record(CUS dns_txt_reply))
cd1a5fe0
JH
1370 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1371 )
1372 {
1373 sig->verify_status = PDKIM_VERIFY_INVALID;
1374 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1375
1376 DEBUG(D_acl)
1377 {
1378 if (p)
1379 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1380 else
1381 debug_printf(" Error while parsing public key record\n");
1382 debug_printf(
1383 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1384 }
1385 return NULL;
1386 }
1387
1388DEBUG(D_acl) debug_printf(
1389 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1390
1391/* Import public key */
286b9d5f
JH
1392
1393if ((*errstr = exim_dkim_verify_init(&p->key,
1394 sig->keytype == KEYTYPE_ED25519 ? KEYFMT_ED25519_BARE : KEYFMT_DER,
1395 vctx)))
cd1a5fe0 1396 {
b9df1829 1397 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
cd1a5fe0
JH
1398 sig->verify_status = PDKIM_VERIFY_INVALID;
1399 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1400 return NULL;
1401 }
1402
286b9d5f 1403vctx->keytype = sig->keytype;
cd1a5fe0
JH
1404return p;
1405}
1406
1407
1408/* -------------------------------------------------------------------------- */
1409
3045f050 1410DLLEXPORT int
b9df1829
JH
1411pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1412 const uschar ** err)
3045f050 1413{
cf1cce5e 1414pdkim_bodyhash * b;
9e70917d 1415pdkim_signature * sig;
286b9d5f 1416BOOL verify_pass = FALSE;
3045f050
JH
1417
1418/* Check if we must still flush a (partial) header. If that is the
1419 case, the message has no body, and we must compute a body hash
1420 out of '<CR><LF>' */
acec9514 1421if (ctx->cur_header && ctx->cur_header->ptr > 0)
3045f050 1422 {
9e70917d
JH
1423 blob * rnl = NULL;
1424 int rc;
1425
1426 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1427 return rc;
1428
cf1cce5e
JH
1429 for (b = ctx->bodyhash; b; b = b->next)
1430 rnl = pdkim_update_ctx_bodyhash(b, &lineending, rnl);
9e70917d 1431 if (rnl) store_free(rnl);
80a47a2c 1432 }
3045f050 1433else
0d04a285 1434 DEBUG(D_acl) debug_printf(
3045f050 1435 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1436
617d3932
JH
1437/* Build (and/or evaluate) body hash. Do this even if no DKIM sigs, in case we
1438have a hash to do for ARC. */
1439
1440pdkim_finish_bodyhash(ctx);
1441
286b9d5f
JH
1442if (!ctx->sig)
1443 {
1444 DEBUG(D_acl) debug_printf("PDKIM: no signatures\n");
617d3932 1445 *return_signatures = NULL;
286b9d5f
JH
1446 return PDKIM_OK;
1447 }
1448
9e70917d 1449for (sig = ctx->sig; sig; sig = sig->next)
3045f050 1450 {
2592e6c0 1451 hctx hhash_ctx;
ad6f5499 1452 uschar * sig_hdr = US"";
2592e6c0 1453 blob hhash;
acec9514 1454 gstring * hdata = NULL;
286b9d5f
JH
1455 es_ctx sctx;
1456
617d3932
JH
1457 if ( !(ctx->flags & PDKIM_MODE_SIGN)
1458 && sig->verify_status == PDKIM_VERIFY_FAIL)
1459 {
1460 DEBUG(D_acl)
1461 debug_printf("PDKIM: [%s] abandoning this signature\n", sig->domain);
1462 continue;
1463 }
1464
286b9d5f
JH
1465 /*XXX The hash of the headers is needed for GCrypt (for which we can do RSA
1466 suging only, as it happens) and for either GnuTLS and OpenSSL when we are
1467 signing with EC (specifically, Ed25519). The former is because the GCrypt
1468 signing operation is pure (does not do its own hash) so we must hash. The
1469 latter is because we (stupidly, but this is what the IETF draft is saying)
1470 must hash with the declared hash method, then pass the result to the library
1471 hash-and-sign routine (because that's all the libraries are providing. And
1472 we're stuck with whatever that hidden hash method is, too). We may as well
1473 do this hash incrementally.
1474 We don't need the hash we're calculating here for the GnuTLS and OpenSSL
1475 cases of RSA signing, since those library routines can do hash-and-sign.
1476
1477 Some time in the future we could easily avoid doing the hash here for those
1478 cases (which will be common for a long while. We could also change from
1479 the current copy-all-the-headers-into-one-block, then call the hash-and-sign
1480 implementation - to a proper incremental one. Unfortunately, GnuTLS just
1481 cannot do incremental - either signing or verification. Unsure about GCrypt.
1482 */
1483
1484 /*XXX The header hash is also used (so far) by the verify operation */
2592e6c0 1485
d73e45df 1486 if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
7b83389d 1487 {
286b9d5f
JH
1488 log_write(0, LOG_MAIN|LOG_PANIC,
1489 "PDKIM: hash setup error, possibly nonhandled hashtype");
7b83389d
JH
1490 break;
1491 }
80a47a2c 1492
9e70917d
JH
1493 if (ctx->flags & PDKIM_MODE_SIGN)
1494 DEBUG(D_acl) debug_printf(
1495 "PDKIM >> Headers to be signed: >>>>>>>>>>>>\n"
1496 " %s\n",
1497 sig->sign_headers);
1498
0d04a285 1499 DEBUG(D_acl) debug_printf(
4ff848b5
JH
1500 "PDKIM >> Header data for hash, canonicalized (%-7s), in sequence >>\n",
1501 pdkim_canons[sig->canon_headers]);
3045f050 1502
9e70917d 1503
3045f050
JH
1504 /* SIGNING ---------------------------------------------------------------- */
1505 /* When signing, walk through our header list and add them to the hash. As we
8ef02a06
JH
1506 go, construct a list of the header's names to use for the h= parameter.
1507 Then append to that list any remaining header names for which there was no
1508 header to sign. */
3045f050 1509
e983e85a 1510 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1511 {
acec9514 1512 gstring * g = NULL;
3045f050 1513 pdkim_stringlist *p;
8ef02a06
JH
1514 const uschar * l;
1515 uschar * s;
1516 int sep = 0;
3045f050 1517
286b9d5f
JH
1518 /* Import private key, including the keytype which we need for building
1519 the signature header */
1520
1521/*XXX extend for non-RSA algos */
617d3932 1522 if ((*err = exim_dkim_signing_init(CUS sig->privkey, &sctx)))
286b9d5f
JH
1523 {
1524 log_write(0, LOG_MAIN|LOG_PANIC, "signing_init: %s", *err);
1525 return PDKIM_ERR_RSA_PRIVKEY;
1526 }
1527 sig->keytype = sctx.keytype;
9e70917d 1528
286b9d5f
JH
1529 for (sig->headernames = NULL, /* Collected signed header names */
1530 p = sig->headers; p; p = p->next)
9e70917d
JH
1531 {
1532 uschar * rh = p->value;
1533
1534 if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
ab9152ff 1535 {
ab9152ff 1536 /* Collect header names (Note: colon presence is guaranteed here) */
acec9514 1537 g = string_append_listele_n(g, ':', rh, Ustrchr(rh, ':') - rh);
3045f050 1538
9e70917d
JH
1539 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1540 rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */
3045f050 1541
ab9152ff 1542 /* Feed header to the hash algorithm */
e2e3255a 1543 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
f444c2c7 1544
ab9152ff 1545 /* Remember headers block for signing (when the library cannot do incremental) */
286b9d5f 1546 /*XXX we could avoid doing this for all but the GnuTLS/RSA case */
acec9514 1547 hdata = exim_dkim_data_append(hdata, rh);
3045f050 1548
ab9152ff
JH
1549 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1550 }
9e70917d 1551 }
8ef02a06 1552
484cc1a9
JH
1553 /* Any headers we wanted to sign but were not present must also be listed.
1554 Ignore elements that have been ticked-off or are marked as never-oversign. */
1555
ca9cb170 1556 l = sig->sign_headers;
8ef02a06 1557 while((s = string_nextinlist(&l, &sep, NULL, 0)))
484cc1a9
JH
1558 {
1559 if (*s == '+') /* skip oversigning marker */
1560 s++;
1561 if (*s != '_' && *s != '=')
acec9514 1562 g = string_append_listele(g, ':', s);
484cc1a9 1563 }
acec9514 1564 sig->headernames = string_from_gstring(g);
ca9cb170
JH
1565
1566 /* Create signature header with b= omitted */
1567 sig_hdr = pdkim_create_header(sig, FALSE);
80a47a2c 1568 }
37f8b554 1569
3045f050
JH
1570 /* VERIFICATION ----------------------------------------------------------- */
1571 /* When verifying, walk through the header name list in the h= parameter and
1572 add the headers to the hash in that order. */
1573 else
1574 {
10c50704 1575 uschar * p = sig->headernames;
2592e6c0
JH
1576 uschar * q;
1577 pdkim_stringlist * hdrs;
3045f050 1578
10c50704 1579 if (p)
3045f050 1580 {
10c50704 1581 /* clear tags */
3045f050 1582 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
10c50704 1583 hdrs->tag = 0;
3045f050 1584
10c50704
JH
1585 p = string_copy(p);
1586 while(1)
1587 {
1588 if ((q = Ustrchr(p, ':')))
1589 *q = '\0';
1590
1591 /*XXX walk the list of headers in same order as received. */
1592 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1593 if ( hdrs->tag == 0
4dc2379a 1594 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
10c50704
JH
1595 && (hdrs->value)[Ustrlen(p)] == ':'
1596 )
1597 {
1598 /* cook header for relaxed canon, or just copy it for simple */
1599
1600 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
ea18931d 1601 ? pdkim_relax_header(hdrs->value, TRUE)
10c50704
JH
1602 : string_copy(CUS hdrs->value);
1603
1604 /* Feed header to the hash algorithm */
1605 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1606
1607 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1608 hdrs->tag = 1;
1609 break;
1610 }
3045f050 1611
10c50704
JH
1612 if (!q) break;
1613 p = q+1;
1614 }
3045f050 1615
10c50704 1616 sig_hdr = string_copy(sig->rawsig_no_b_val);
80a47a2c 1617 }
80a47a2c
TK
1618 }
1619
0d04a285 1620 DEBUG(D_acl) debug_printf(
3045f050 1621 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1622
9e70917d
JH
1623 DEBUG(D_acl)
1624 {
1625 debug_printf(
1626 "PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
1627 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1628 debug_printf(
1629 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1630 }
1631
3045f050
JH
1632 /* Relax header if necessary */
1633 if (sig->canon_headers == PDKIM_CANON_RELAXED)
ea18931d 1634 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
80a47a2c 1635
0d04a285 1636 DEBUG(D_acl)
3045f050 1637 {
4ff848b5
JH
1638 debug_printf("PDKIM >> Signed DKIM-Signature header, canonicalized (%-7s) >>>>>>>\n",
1639 pdkim_canons[sig->canon_headers]);
e2e3255a 1640 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
0d04a285 1641 debug_printf(
3045f050 1642 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1643 }
3045f050
JH
1644
1645 /* Finalize header hash */
e2e3255a 1646 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
2592e6c0 1647 exim_sha_finish(&hhash_ctx, &hhash);
3045f050 1648
f444c2c7
JH
1649 DEBUG(D_acl)
1650 {
9e70917d
JH
1651 debug_printf("PDKIM [%s] Header %s computed: ",
1652 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
2592e6c0 1653 pdkim_hexprint(hhash.data, hhash.len);
80a47a2c
TK
1654 }
1655
9e70917d
JH
1656 /* Remember headers block for signing (when the signing library cannot do
1657 incremental) */
e983e85a 1658 if (ctx->flags & PDKIM_MODE_SIGN)
acec9514 1659 hdata = exim_dkim_data_append(hdata, US sig_hdr);
f444c2c7 1660
3045f050 1661 /* SIGNING ---------------------------------------------------------------- */
e983e85a 1662 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1663 {
286b9d5f
JH
1664 hashmethod hm = sig->keytype == KEYTYPE_ED25519
1665 ? HASH_SHA2_512 : pdkim_hashes[sig->hashtype].exim_hashmethod;
f444c2c7 1666
286b9d5f
JH
1667#ifdef SIGN_HAVE_ED25519
1668 /* For GCrypt, and for EC, we pass the hash-of-headers to the signing
1669 routine. For anything else we just pass the headers. */
f444c2c7 1670
286b9d5f 1671 if (sig->keytype != KEYTYPE_ED25519)
f444c2c7 1672#endif
286b9d5f
JH
1673 {
1674 hhash.data = hdata->s;
1675 hhash.len = hdata->ptr;
1676 }
f444c2c7 1677
9b2583c4 1678/*XXX extend for non-RSA algos */
286b9d5f
JH
1679/*- done for GnuTLS */
1680 if ((*err = exim_dkim_sign(&sctx, hm, &hhash, &sig->sighash)))
f444c2c7 1681 {
286b9d5f 1682 log_write(0, LOG_MAIN|LOG_PANIC, "signing: %s", *err);
f444c2c7
JH
1683 return PDKIM_ERR_RSA_SIGNING;
1684 }
80a47a2c 1685
0d04a285 1686 DEBUG(D_acl)
3045f050 1687 {
0d04a285 1688 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
dcd03763 1689 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
80a47a2c 1690 }
80a47a2c 1691
ca9cb170 1692 sig->signature_header = pdkim_create_header(sig, TRUE);
80a47a2c 1693 }
80a47a2c 1694
3045f050
JH
1695 /* VERIFICATION ----------------------------------------------------------- */
1696 else
1697 {
2592e6c0 1698 ev_ctx vctx;
3045f050 1699
07eeb4df 1700 /* Make sure we have all required signature tags */
1701 if (!( sig->domain && *sig->domain
1702 && sig->selector && *sig->selector
1703 && sig->headernames && *sig->headernames
1704 && sig->bodyhash.data
dcd03763 1705 && sig->sighash.data
d73e45df
JH
1706 && sig->keytype >= 0
1707 && sig->hashtype >= 0
07eeb4df 1708 && sig->version
1709 ) )
1710 {
1711 sig->verify_status = PDKIM_VERIFY_INVALID;
1712 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1713
1714 DEBUG(D_acl) debug_printf(
1715 " Error in DKIM-Signature header: tags missing or invalid\n"
1716 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1717 goto NEXT_VERIFY;
1718 }
1719
1720 /* Make sure sig uses supported DKIM version (only v1) */
1721 if (sig->version != 1)
1722 {
1723 sig->verify_status = PDKIM_VERIFY_INVALID;
1724 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1725
1726 DEBUG(D_acl) debug_printf(
1727 " Error in DKIM-Signature header: unsupported DKIM version\n"
1728 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1729 goto NEXT_VERIFY;
1730 }
1731
9e70917d
JH
1732 DEBUG(D_acl)
1733 {
1734 debug_printf( "PDKIM [%s] b from mail: ", sig->domain);
1735 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1736 }
1737
b9df1829 1738 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
286b9d5f
JH
1739 {
1740 log_write(0, LOG_MAIN, "PDKIM: %s%s %s%s [failed key import]",
1741 sig->domain ? "d=" : "", sig->domain ? sig->domain : US"",
1742 sig->selector ? "s=" : "", sig->selector ? sig->selector : US"");
3045f050 1743 goto NEXT_VERIFY;
286b9d5f 1744 }
80a47a2c 1745
135e9496
JH
1746 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1747 do not have the hash part of the sig algorithm matching */
1748
1749 if (sig->pubkey->hashes)
1750 {
1751 const uschar * list = sig->pubkey->hashes, * ele;
1752 int sep = ':';
1753 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
d73e45df 1754 if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
135e9496
JH
1755 if (!ele)
1756 {
d73e45df
JH
1757 DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
1758 sig->pubkey->hashes,
1759 pdkim_keytypes[sig->keytype],
1760 pdkim_hashes[sig->hashtype].dkim_hashname);
135e9496
JH
1761 sig->verify_status = PDKIM_VERIFY_FAIL;
1762 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1763 goto NEXT_VERIFY;
1764 }
1765 }
1766
3045f050 1767 /* Check the signature */
286b9d5f
JH
1768/*XXX extend for non-RSA algos */
1769/*- done for GnuTLS */
d73e45df 1770 if ((*err = exim_dkim_verify(&vctx,
286b9d5f
JH
1771 pdkim_hashes[sig->hashtype].exim_hashmethod,
1772 &hhash, &sig->sighash)))
3045f050 1773 {
b9df1829 1774 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
3045f050
JH
1775 sig->verify_status = PDKIM_VERIFY_FAIL;
1776 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1777 goto NEXT_VERIFY;
ff7ddfd7
TK
1778 }
1779
2592e6c0 1780
4c04137d 1781 /* We have a winner! (if bodyhash was correct earlier) */
3045f050 1782 if (sig->verify_status == PDKIM_VERIFY_NONE)
286b9d5f 1783 {
3045f050 1784 sig->verify_status = PDKIM_VERIFY_PASS;
286b9d5f
JH
1785 verify_pass = TRUE;
1786 }
3045f050
JH
1787
1788NEXT_VERIFY:
1789
0d04a285 1790 DEBUG(D_acl)
3045f050 1791 {
286b9d5f
JH
1792 debug_printf("PDKIM [%s] %s signature status: %s",
1793 sig->domain, dkim_sig_to_a_tag(sig),
1794 pdkim_verify_status_str(sig->verify_status));
3045f050 1795 if (sig->verify_ext_status > 0)
0d04a285 1796 debug_printf(" (%s)\n",
3045f050
JH
1797 pdkim_verify_ext_status_str(sig->verify_ext_status));
1798 else
0d04a285 1799 debug_printf("\n");
80a47a2c 1800 }
80a47a2c 1801 }
80a47a2c
TK
1802 }
1803
3045f050
JH
1804/* If requested, set return pointer to signature(s) */
1805if (return_signatures)
1806 *return_signatures = ctx->sig;
80a47a2c 1807
286b9d5f
JH
1808return ctx->flags & PDKIM_MODE_SIGN || verify_pass
1809 ? PDKIM_OK : PDKIM_FAIL;
80a47a2c
TK
1810}
1811
1812
1813/* -------------------------------------------------------------------------- */
3045f050
JH
1814
1815DLLEXPORT pdkim_ctx *
617d3932 1816pdkim_init_verify(uschar * (*dns_txt_callback)(uschar *), BOOL dot_stuffing)
3045f050 1817{
ca9cb170 1818pdkim_ctx * ctx;
3045f050 1819
ca9cb170 1820ctx = store_get(sizeof(pdkim_ctx));
abe1010c 1821memset(ctx, 0, sizeof(pdkim_ctx));
3045f050 1822
e983e85a 1823if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
ca9cb170 1824ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
3045f050 1825ctx->dns_txt_callback = dns_txt_callback;
80a47a2c 1826
3045f050 1827return ctx;
80a47a2c
TK
1828}
1829
1830
1831/* -------------------------------------------------------------------------- */
80a47a2c 1832
9e70917d
JH
1833DLLEXPORT pdkim_signature *
1834pdkim_init_sign(pdkim_ctx * ctx,
1835 uschar * domain, uschar * selector, uschar * privkey,
1836 uschar * hashname, const uschar ** errstr)
3045f050 1837{
d73e45df 1838int hashtype;
cd1a5fe0 1839pdkim_signature * sig;
80a47a2c 1840
d73e45df 1841if (!domain || !selector || !privkey)
3045f050 1842 return NULL;
80a47a2c 1843
9e70917d 1844/* Allocate & init one signature struct */
80a47a2c 1845
9e70917d 1846sig = store_get(sizeof(pdkim_signature));
abe1010c 1847memset(sig, 0, sizeof(pdkim_signature));
80a47a2c 1848
3045f050 1849sig->bodylength = -1;
80a47a2c 1850
e2e3255a
JH
1851sig->domain = string_copy(US domain);
1852sig->selector = string_copy(US selector);
d73e45df 1853sig->privkey = string_copy(US privkey);
286b9d5f 1854sig->keytype = -1;
cb224393 1855
d73e45df
JH
1856for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
1857 if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
1858 { sig->hashtype = hashtype; break; }
1859if (hashtype >= nelem(pdkim_hashes))
7b83389d 1860 {
286b9d5f
JH
1861 log_write(0, LOG_MAIN|LOG_PANIC,
1862 "PDKIM: unrecognised hashname '%s'", hashname);
d73e45df
JH
1863 return NULL;
1864 }
1865
cd1a5fe0
JH
1866DEBUG(D_acl)
1867 {
1868 pdkim_signature s = *sig;
1869 ev_ctx vctx;
1870
328c5688 1871 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
b9df1829 1872 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
cd1a5fe0 1873 debug_printf("WARNING: bad dkim key in dns\n");
328c5688 1874 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
cd1a5fe0 1875 }
9e70917d 1876return sig;
6ab02e3f 1877}
80a47a2c 1878
f444c2c7 1879
80a47a2c 1880/* -------------------------------------------------------------------------- */
3045f050 1881
9e70917d
JH
1882DLLEXPORT void
1883pdkim_set_optional(pdkim_signature * sig,
1884 char * sign_headers,
1885 char * identity,
80a47a2c
TK
1886 int canon_headers,
1887 int canon_body,
1888 long bodylength,
80a47a2c 1889 unsigned long created,
3045f050
JH
1890 unsigned long expires)
1891{
3045f050 1892if (identity)
e2e3255a 1893 sig->identity = string_copy(US identity);
80a47a2c 1894
ca9cb170
JH
1895sig->sign_headers = string_copy(sign_headers
1896 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
80a47a2c 1897
8ef02a06
JH
1898sig->canon_headers = canon_headers;
1899sig->canon_body = canon_body;
1900sig->bodylength = bodylength;
1901sig->created = created;
1902sig->expires = expires;
80a47a2c 1903
9e70917d
JH
1904return;
1905}
1906
1907
1908
cf1cce5e 1909/* Set up a blob for calculating the bodyhash according to the
617d3932 1910given needs. Use an existing one if possible, or create a new one.
cf1cce5e 1911
617d3932 1912Return: hashblob pointer, or NULL on error
cf1cce5e
JH
1913*/
1914pdkim_bodyhash *
617d3932
JH
1915pdkim_set_bodyhash(pdkim_ctx * ctx, int hashtype, int canon_method,
1916 long bodylength)
cf1cce5e
JH
1917{
1918pdkim_bodyhash * b;
1919
1920for (b = ctx->bodyhash; b; b = b->next)
617d3932
JH
1921 if ( hashtype == b->hashtype
1922 && canon_method == b->canon_method
1923 && bodylength == b->bodylength)
1924 {
0ae2cff6 1925 DEBUG(D_receive) debug_printf("PDKIM: using existing bodyhash %d/%d/%ld\n",
617d3932
JH
1926 hashtype, canon_method, bodylength);
1927 return b;
1928 }
cf1cce5e 1929
0ae2cff6 1930DEBUG(D_receive) debug_printf("PDKIM: new bodyhash %d/%d/%ld\n",
617d3932 1931 hashtype, canon_method, bodylength);
cf1cce5e
JH
1932b = store_get(sizeof(pdkim_bodyhash));
1933b->next = ctx->bodyhash;
617d3932
JH
1934b->hashtype = hashtype;
1935b->canon_method = canon_method;
1936b->bodylength = bodylength;
cf1cce5e 1937if (!exim_sha_init(&b->body_hash_ctx, /*XXX hash method: extend for sha512 */
617d3932 1938 pdkim_hashes[hashtype].exim_hashmethod))
cf1cce5e
JH
1939 {
1940 DEBUG(D_acl)
1941 debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n");
1942 return NULL;
1943 }
1944b->signed_body_bytes = 0;
1945b->num_buffered_blanklines = 0;
1946ctx->bodyhash = b;
617d3932
JH
1947return b;
1948}
1949
cf1cce5e 1950
617d3932
JH
1951/* Set up a blob for calculating the bodyhash according to the
1952needs of this signature. Use an existing one if possible, or
1953create a new one.
1954
1955Return: hashblob pointer, or NULL on error (only used as a boolean).
1956*/
1957pdkim_bodyhash *
1958pdkim_set_sig_bodyhash(pdkim_ctx * ctx, pdkim_signature * sig)
1959{
1960pdkim_bodyhash * b = pdkim_set_bodyhash(ctx,
1961 sig->hashtype, sig->canon_body, sig->bodylength);
cf1cce5e
JH
1962sig->calc_body_hash = b;
1963return b;
1964}
1965
1966
1967/* -------------------------------------------------------------------------- */
1968
1969
9e70917d
JH
1970void
1971pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
617d3932 1972 uschar * (*dns_txt_callback)(uschar *))
9e70917d
JH
1973{
1974memset(ctx, 0, sizeof(pdkim_ctx));
1975ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1976ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1977DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
6ab02e3f 1978}
3045f050 1979
3045f050 1980
2592e6c0
JH
1981void
1982pdkim_init(void)
1983{
9b2583c4 1984exim_dkim_init();
2592e6c0
JH
1985}
1986
1987
1988
f444c2c7 1989#endif /*DISABLE_DKIM*/