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