Cutthrough: silently ignore ACL control when the message cannot be cutthrough-routed
[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>
d4e5e70b 5 * Copyright (C) 2016 - 2017 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;
7845dbb3 713 const uschar * p;
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
9e70917d
JH
724 for (p = orig_data->data; *p; p++)
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 */
3045f050 851
9e70917d
JH
852static void
853pdkim_bodyline_complete(pdkim_ctx * ctx)
3045f050 854{
9e70917d 855blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
cf1cce5e 856pdkim_bodyhash * b;
9e70917d
JH
857blob * rnl = NULL;
858blob * rline = NULL;
3045f050
JH
859
860/* Ignore extra data if we've seen the end-of-data marker */
9e70917d 861if (ctx->flags & PDKIM_SEEN_EOD) goto all_skip;
3045f050
JH
862
863/* We've always got one extra byte to stuff a zero ... */
9e70917d 864ctx->linebuf[line.len] = '\0';
3045f050 865
0d04a285 866/* Terminate on EOD marker */
e983e85a 867if (ctx->flags & PDKIM_DOT_TERM)
3045f050 868 {
9e70917d
JH
869 if (memcmp(line.data, ".\r\n", 3) == 0)
870 { pdkim_body_complete(ctx); return; }
0d04a285 871
e983e85a 872 /* Unstuff dots */
9e70917d
JH
873 if (memcmp(line.data, "..", 2) == 0)
874 { line.data++; line.len--; }
80a47a2c
TK
875 }
876
3045f050 877/* Empty lines need to be buffered until we find a non-empty line */
9e70917d 878if (memcmp(line.data, "\r\n", 2) == 0)
3045f050 879 {
cf1cce5e 880 for (b = ctx->bodyhash; b; b = b->next) b->num_buffered_blanklines++;
9e70917d 881 goto all_skip;
80a47a2c
TK
882 }
883
cf1cce5e
JH
884/* Process line for each bodyhash separately */
885for (b = ctx->bodyhash; b; b = b->next)
3045f050 886 {
cf1cce5e 887 if (b->canon_method == PDKIM_CANON_RELAXED)
3045f050 888 {
9e70917d 889 /* Lines with just spaces need to be buffered too */
7845dbb3 890 uschar * cp = line.data;
9e70917d 891 char c;
6a11a9e6 892
9e70917d
JH
893 while ((c = *cp))
894 {
895 if (c == '\r' && cp[1] == '\n') break;
cf1cce5e 896 if (c != ' ' && c != '\t') goto hash_process;
9e70917d
JH
897 cp++;
898 }
899
cf1cce5e
JH
900 b->num_buffered_blanklines++;
901 goto hash_skip;
6a11a9e6
JH
902 }
903
cf1cce5e 904hash_process:
9e70917d 905 /* At this point, we have a non-empty line, so release the buffered ones. */
6a11a9e6 906
cf1cce5e 907 while (b->num_buffered_blanklines)
9e70917d 908 {
cf1cce5e
JH
909 rnl = pdkim_update_ctx_bodyhash(b, &lineending, rnl);
910 b->num_buffered_blanklines--;
9e70917d
JH
911 }
912
cf1cce5e
JH
913 rline = pdkim_update_ctx_bodyhash(b, &line, rline);
914hash_skip: ;
80a47a2c
TK
915 }
916
9e70917d
JH
917if (rnl) store_free(rnl);
918if (rline) store_free(rline);
919
920all_skip:
80a47a2c 921
3045f050 922ctx->linebuf_offset = 0;
9e70917d 923return;
80a47a2c
TK
924}
925
926
927/* -------------------------------------------------------------------------- */
928/* Callback from pdkim_feed below for processing complete headers */
929#define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
3045f050 930
f444c2c7 931static int
2c0f3ea1 932pdkim_header_complete(pdkim_ctx * ctx)
3045f050 933{
2c0f3ea1
JH
934pdkim_signature * sig, * last_sig;
935
3045f050 936/* Special case: The last header can have an extra \r appended */
acec9514
JH
937if ( (ctx->cur_header->ptr > 1) &&
938 (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
939 --ctx->cur_header->ptr;
940(void) string_from_gstring(ctx->cur_header);
80a47a2c 941
2c0f3ea1 942if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
80a47a2c 943
3045f050 944/* SIGNING -------------------------------------------------------------- */
e983e85a 945if (ctx->flags & PDKIM_MODE_SIGN)
0d04a285 946 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
80a47a2c 947
ab9152ff 948 /* Add header to the signed headers list (in reverse order) */
acec9514 949 sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s);
94431adb 950
0d04a285 951/* VERIFICATION ----------------------------------------------------------- */
3045f050 952/* DKIM-Signature: headers are added to the verification list */
e983e85a 953else
3045f050 954 {
f6ee24a2 955#ifdef notdef
bd8fbe36
JH
956 DEBUG(D_acl)
957 {
958 debug_printf("PDKIM >> raw hdr: ");
acec9514 959 pdkim_quoteprint(CUS ctx->cur_header->s, ctx->cur_header->ptr);
bd8fbe36 960 }
f6ee24a2 961#endif
acec9514 962 if (strncasecmp(CCS ctx->cur_header->s,
3045f050 963 DKIM_SIGNATURE_HEADERNAME,
e2e3255a 964 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
3045f050 965 {
02c4f8fb
JH
966 /* Create and chain new signature block. We could error-check for all
967 required tags here, but prefer to create the internal sig and expicitly
968 fail verification of it later. */
80a47a2c 969
0d04a285 970 DEBUG(D_acl) debug_printf(
3045f050 971 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
3045f050 972
acec9514 973 sig = pdkim_parse_sig_header(ctx, ctx->cur_header->s);
02c4f8fb
JH
974
975 if (!(last_sig = ctx->sig))
2c0f3ea1 976 ctx->sig = sig;
02c4f8fb 977 else
3045f050 978 {
02c4f8fb 979 while (last_sig->next) last_sig = last_sig->next;
2c0f3ea1 980 last_sig->next = sig;
80a47a2c
TK
981 }
982 }
37f8b554 983
eea19017 984 /* all headers are stored for signature verification */
acec9514 985 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->s);
80a47a2c
TK
986 }
987
3045f050 988BAIL:
acec9514 989ctx->cur_header->s[ctx->cur_header->ptr = 0] = '\0'; /* leave buffer for reuse */
3045f050 990return PDKIM_OK;
6ab02e3f 991}
80a47a2c
TK
992
993
994
995/* -------------------------------------------------------------------------- */
996#define HEADER_BUFFER_FRAG_SIZE 256
3045f050
JH
997
998DLLEXPORT int
ef698bf6 999pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
3045f050 1000{
02c4f8fb 1001int p, rc;
3045f050 1002
e983e85a
JH
1003/* Alternate EOD signal, used in non-dotstuffing mode */
1004if (!data)
1005 pdkim_body_complete(ctx);
1006
10c50704 1007else for (p = 0; p<len; p++)
3045f050 1008 {
ca9cb170 1009 uschar c = data[p];
3045f050 1010
e983e85a 1011 if (ctx->flags & PDKIM_PAST_HDRS)
3045f050 1012 {
b895f4b2
JH
1013 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1014 {
1015 ctx->linebuf[ctx->linebuf_offset++] = '\r';
1016 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1017 return PDKIM_ERR_LONG_LINE;
1018 }
1019
3045f050 1020 /* Processing body byte */
0d04a285 1021 ctx->linebuf[ctx->linebuf_offset++] = c;
b895f4b2
JH
1022 if (c == '\r')
1023 ctx->flags |= PDKIM_SEEN_CR;
1024 else if (c == '\n')
3045f050 1025 {
b895f4b2 1026 ctx->flags &= ~PDKIM_SEEN_CR;
9e70917d 1027 pdkim_bodyline_complete(ctx);
80a47a2c 1028 }
b895f4b2
JH
1029
1030 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
3045f050 1031 return PDKIM_ERR_LONG_LINE;
80a47a2c 1032 }
3045f050
JH
1033 else
1034 {
1035 /* Processing header byte */
b895f4b2
JH
1036 if (c == '\r')
1037 ctx->flags |= PDKIM_SEEN_CR;
1038 else if (c == '\n')
3045f050 1039 {
b895f4b2 1040 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
acec9514 1041 ctx->cur_header = string_catn(ctx->cur_header, CUS "\r", 1);
b895f4b2 1042
02c4f8fb 1043 if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */
b895f4b2 1044 {
02c4f8fb
JH
1045 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1046 return rc;
b895f4b2 1047
863bd541 1048 ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS;
b895f4b2 1049 DEBUG(D_acl) debug_printf(
02c4f8fb 1050 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
b895f4b2 1051 continue;
3045f050 1052 }
b895f4b2 1053 else
863bd541 1054 ctx->flags = (ctx->flags & ~PDKIM_SEEN_CR) | PDKIM_SEEN_LF;
b895f4b2
JH
1055 }
1056 else if (ctx->flags & PDKIM_SEEN_LF)
1057 {
02c4f8fb
JH
1058 if (!(c == '\t' || c == ' ')) /* End of header */
1059 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1060 return rc;
b895f4b2 1061 ctx->flags &= ~PDKIM_SEEN_LF;
80a47a2c 1062 }
3045f050 1063
acec9514
JH
1064 if (!ctx->cur_header || ctx->cur_header->ptr < PDKIM_MAX_HEADER_LEN)
1065 ctx->cur_header = string_catn(ctx->cur_header, CUS &data[p], 1);
80a47a2c
TK
1066 }
1067 }
3045f050 1068return PDKIM_OK;
6ab02e3f 1069}
80a47a2c 1070
ca9cb170
JH
1071
1072
acec9514
JH
1073/* Extend a growing header with a continuation-linebreak */
1074static gstring *
1075pdkim_hdr_cont(gstring * str, int * col)
ca9cb170
JH
1076{
1077*col = 1;
acec9514 1078return string_catn(str, US"\r\n\t", 3);
ca9cb170
JH
1079}
1080
1081
1082
05b7d6de
JB
1083/*
1084 * RFC 5322 specifies that header line length SHOULD be no more than 78
1085 * lets make it so!
1086 * pdkim_headcat
ca9cb170
JH
1087 *
1088 * returns uschar * (not nul-terminated)
05b7d6de
JB
1089 *
1090 * col: this int holds and receives column number (octets since last '\n')
1091 * str: partial string to append to
94431adb 1092 * pad: padding, split line or space after before or after eg: ";"
05b7d6de
JB
1093 * intro: - must join to payload eg "h=", usually the tag name
1094 * payload: eg base64 data - long data can be split arbitrarily.
1095 *
1096 * this code doesn't fold the header in some of the places that RFC4871
1097 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1098 * pairs and inside long values. it also always spaces or breaks after the
94431adb 1099 * "pad"
05b7d6de
JB
1100 *
1101 * no guarantees are made for output given out-of range input. like tag
f444c2c7 1102 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
05b7d6de
JB
1103 */
1104
acec9514
JH
1105static gstring *
1106pdkim_headcat(int * col, gstring * str,
ca9cb170 1107 const uschar * pad, const uschar * intro, const uschar * payload)
3045f050
JH
1108{
1109size_t l;
1110
1111if (pad)
05b7d6de 1112 {
ca9cb170 1113 l = Ustrlen(pad);
3045f050 1114 if (*col + l > 78)
acec9514
JH
1115 str = pdkim_hdr_cont(str, col);
1116 str = string_catn(str, pad, l);
3045f050 1117 *col += l;
05b7d6de
JB
1118 }
1119
ca9cb170 1120l = (pad?1:0) + (intro?Ustrlen(intro):0);
05b7d6de 1121
3045f050 1122if (*col + l > 78)
05b7d6de 1123 { /*can't fit intro - start a new line to make room.*/
acec9514 1124 str = pdkim_hdr_cont(str, col);
ca9cb170 1125 l = intro?Ustrlen(intro):0;
05b7d6de
JB
1126 }
1127
ca9cb170 1128l += payload ? Ustrlen(payload):0 ;
05b7d6de 1129
3045f050 1130while (l>77)
05b7d6de 1131 { /* this fragment will not fit on a single line */
3045f050 1132 if (pad)
05b7d6de 1133 {
acec9514 1134 str = string_catn(str, US" ", 1);
3045f050
JH
1135 *col += 1;
1136 pad = NULL; /* only want this once */
1137 l--;
05b7d6de 1138 }
3045f050
JH
1139
1140 if (intro)
05b7d6de 1141 {
ca9cb170 1142 size_t sl = Ustrlen(intro);
3045f050 1143
acec9514 1144 str = string_catn(str, intro, sl);
3045f050
JH
1145 *col += sl;
1146 l -= sl;
1147 intro = NULL; /* only want this once */
05b7d6de 1148 }
3045f050
JH
1149
1150 if (payload)
05b7d6de 1151 {
ca9cb170 1152 size_t sl = Ustrlen(payload);
3045f050
JH
1153 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1154
acec9514 1155 str = string_catn(str, payload, chomp);
3045f050
JH
1156 *col += chomp;
1157 payload += chomp;
1158 l -= chomp-1;
05b7d6de 1159 }
3045f050
JH
1160
1161 /* the while precondition tells us it didn't fit. */
acec9514 1162 str = pdkim_hdr_cont(str, col);
05b7d6de 1163 }
3045f050
JH
1164
1165if (*col + l > 78)
05b7d6de 1166 {
acec9514 1167 str = pdkim_hdr_cont(str, col);
3045f050 1168 pad = NULL;
05b7d6de
JB
1169 }
1170
3045f050 1171if (pad)
05b7d6de 1172 {
acec9514 1173 str = string_catn(str, US" ", 1);
3045f050
JH
1174 *col += 1;
1175 pad = NULL;
05b7d6de
JB
1176 }
1177
3045f050 1178if (intro)
05b7d6de 1179 {
ca9cb170 1180 size_t sl = Ustrlen(intro);
3045f050 1181
acec9514 1182 str = string_catn(str, intro, sl);
3045f050
JH
1183 *col += sl;
1184 l -= sl;
1185 intro = NULL;
05b7d6de 1186 }
3045f050
JH
1187
1188if (payload)
05b7d6de 1189 {
ca9cb170 1190 size_t sl = Ustrlen(payload);
3045f050 1191
acec9514 1192 str = string_catn(str, payload, sl);
3045f050 1193 *col += sl;
05b7d6de
JB
1194 }
1195
ca9cb170 1196return str;
05b7d6de 1197}
80a47a2c 1198
3045f050 1199
80a47a2c 1200/* -------------------------------------------------------------------------- */
3045f050 1201
cf1cce5e
JH
1202/* Signing: create signature header
1203*/
ca9cb170 1204static uschar *
9e70917d 1205pdkim_create_header(pdkim_signature * sig, BOOL final)
3045f050 1206{
ca9cb170
JH
1207uschar * base64_bh;
1208uschar * base64_b;
3045f050 1209int col = 0;
acec9514
JH
1210gstring * hdr;
1211gstring * canon_all;
3045f050 1212
acec9514
JH
1213canon_all = string_cat (NULL, pdkim_canons[sig->canon_headers]);
1214canon_all = string_catn(canon_all, US"/", 1);
1215canon_all = string_cat (canon_all, pdkim_canons[sig->canon_body]);
1216(void) string_from_gstring(canon_all);
3045f050 1217
acec9514
JH
1218hdr = string_cat(NULL, US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1219col = hdr->ptr;
3045f050
JH
1220
1221/* Required and static bits */
acec9514
JH
1222hdr = pdkim_headcat(&col, hdr, US";", US"a=", dkim_sig_to_a_tag(sig));
1223hdr = pdkim_headcat(&col, hdr, US";", US"q=", pdkim_querymethods[sig->querymethod]);
1224hdr = pdkim_headcat(&col, hdr, US";", US"c=", canon_all->s);
1225hdr = pdkim_headcat(&col, hdr, US";", US"d=", sig->domain);
1226hdr = pdkim_headcat(&col, hdr, US";", US"s=", sig->selector);
ca9cb170
JH
1227
1228/* list of header names can be split between items. */
3045f050 1229 {
e2e3255a 1230 uschar * n = string_copy(sig->headernames);
ca9cb170
JH
1231 uschar * i = US"h=";
1232 uschar * s = US";";
1233
1234 while (*n)
05b7d6de 1235 {
ca9cb170 1236 uschar * c = Ustrchr(n, ':');
3045f050 1237
ca9cb170 1238 if (c) *c ='\0';
05b7d6de 1239
ca9cb170 1240 if (!i)
acec9514 1241 hdr = pdkim_headcat(&col, hdr, NULL, NULL, US":");
05b7d6de 1242
acec9514 1243 hdr = pdkim_headcat(&col, hdr, s, i, n);
3045f050 1244
ca9cb170
JH
1245 if (!c)
1246 break;
3045f050 1247
ca9cb170
JH
1248 n = c+1;
1249 s = NULL;
1250 i = NULL;
80a47a2c 1251 }
ca9cb170 1252 }
05b7d6de 1253
cf1cce5e 1254base64_bh = pdkim_encode_base64(&sig->calc_body_hash->bh);
acec9514 1255hdr = pdkim_headcat(&col, hdr, US";", US"bh=", base64_bh);
3045f050 1256
ca9cb170
JH
1257/* Optional bits */
1258if (sig->identity)
acec9514 1259 hdr = pdkim_headcat(&col, hdr, US";", US"i=", sig->identity);
3045f050 1260
ca9cb170
JH
1261if (sig->created > 0)
1262 {
e2e3255a 1263 uschar minibuf[20];
3045f050 1264
e2e3255a 1265 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
acec9514 1266 hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf);
ca9cb170 1267}
3045f050 1268
ca9cb170
JH
1269if (sig->expires > 0)
1270 {
e2e3255a 1271 uschar minibuf[20];
3045f050 1272
e2e3255a 1273 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
acec9514 1274 hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf);
ca9cb170 1275 }
3045f050 1276
ca9cb170
JH
1277if (sig->bodylength >= 0)
1278 {
e2e3255a 1279 uschar minibuf[20];
80a47a2c 1280
e2e3255a 1281 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
acec9514 1282 hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf);
3045f050 1283 }
05b7d6de 1284
ca9cb170 1285/* Preliminary or final version? */
ea18931d
JH
1286if (final)
1287 {
1288 base64_b = pdkim_encode_base64(&sig->sighash);
acec9514 1289 hdr = pdkim_headcat(&col, hdr, US";", US"b=", base64_b);
80a47a2c 1290
ea18931d 1291 /* add trailing semicolon: I'm not sure if this is actually needed */
acec9514 1292 hdr = pdkim_headcat(&col, hdr, NULL, US";", US"");
ea18931d
JH
1293 }
1294else
1295 {
1296 /* To satisfy the rule "all surrounding whitespace [...] deleted"
1297 ( RFC 6376 section 3.7 ) we ensure there is no whitespace here. Otherwise
1298 the headcat routine could insert a linebreak which the relaxer would reduce
1299 to a single space preceding the terminating semicolon, resulting in an
1300 incorrect header-hash. */
acec9514 1301 hdr = pdkim_headcat(&col, hdr, US";", US"b=;", US"");
ea18931d 1302 }
80a47a2c 1303
acec9514 1304return string_from_gstring(hdr);
80a47a2c
TK
1305}
1306
1307
cd1a5fe0
JH
1308/* -------------------------------------------------------------------------- */
1309
1310static pdkim_pubkey *
b9df1829
JH
1311pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1312 const uschar ** errstr)
cd1a5fe0
JH
1313{
1314uschar * dns_txt_name, * dns_txt_reply;
1315pdkim_pubkey * p;
cd1a5fe0
JH
1316
1317/* Fetch public key for signing domain, from DNS */
1318
1319dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1320
1eedc10f 1321if ( !(dns_txt_reply = ctx->dns_txt_callback(CS dns_txt_name))
cd1a5fe0
JH
1322 || dns_txt_reply[0] == '\0'
1323 )
1324 {
1325 sig->verify_status = PDKIM_VERIFY_INVALID;
1326 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1327 return NULL;
1328 }
1329
1330DEBUG(D_acl)
1331 {
1332 debug_printf(
1333 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
9e70917d
JH
1334 " %s\n"
1335 " Raw record: ",
1336 dns_txt_name);
cd1a5fe0
JH
1337 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1338 }
1339
1340if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1341 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1342 )
1343 {
1344 sig->verify_status = PDKIM_VERIFY_INVALID;
1345 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1346
1347 DEBUG(D_acl)
1348 {
1349 if (p)
1350 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1351 else
1352 debug_printf(" Error while parsing public key record\n");
1353 debug_printf(
1354 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1355 }
1356 return NULL;
1357 }
1358
1359DEBUG(D_acl) debug_printf(
1360 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1361
1362/* Import public key */
286b9d5f
JH
1363
1364if ((*errstr = exim_dkim_verify_init(&p->key,
1365 sig->keytype == KEYTYPE_ED25519 ? KEYFMT_ED25519_BARE : KEYFMT_DER,
1366 vctx)))
cd1a5fe0 1367 {
b9df1829 1368 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
cd1a5fe0
JH
1369 sig->verify_status = PDKIM_VERIFY_INVALID;
1370 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1371 return NULL;
1372 }
1373
286b9d5f 1374vctx->keytype = sig->keytype;
cd1a5fe0
JH
1375return p;
1376}
1377
1378
80a47a2c 1379/* -------------------------------------------------------------------------- */
3045f050
JH
1380
1381DLLEXPORT int
b9df1829
JH
1382pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1383 const uschar ** err)
3045f050 1384{
cf1cce5e 1385pdkim_bodyhash * b;
9e70917d 1386pdkim_signature * sig;
286b9d5f
JH
1387BOOL verify_pass = FALSE;
1388es_ctx sctx;
3045f050
JH
1389
1390/* Check if we must still flush a (partial) header. If that is the
1391 case, the message has no body, and we must compute a body hash
1392 out of '<CR><LF>' */
acec9514 1393if (ctx->cur_header && ctx->cur_header->ptr > 0)
3045f050 1394 {
9e70917d
JH
1395 blob * rnl = NULL;
1396 int rc;
1397
1398 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1399 return rc;
1400
cf1cce5e
JH
1401 for (b = ctx->bodyhash; b; b = b->next)
1402 rnl = pdkim_update_ctx_bodyhash(b, &lineending, rnl);
9e70917d 1403 if (rnl) store_free(rnl);
80a47a2c 1404 }
3045f050 1405else
0d04a285 1406 DEBUG(D_acl) debug_printf(
3045f050 1407 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1408
286b9d5f
JH
1409if (!ctx->sig)
1410 {
1411 DEBUG(D_acl) debug_printf("PDKIM: no signatures\n");
1412 return PDKIM_OK;
1413 }
1414
3045f050 1415/* Build (and/or evaluate) body hash */
ca9cb170 1416pdkim_finish_bodyhash(ctx);
80a47a2c 1417
9e70917d 1418for (sig = ctx->sig; sig; sig = sig->next)
3045f050 1419 {
2592e6c0 1420 hctx hhash_ctx;
ad6f5499 1421 uschar * sig_hdr = US"";
2592e6c0 1422 blob hhash;
acec9514 1423 gstring * hdata = NULL;
286b9d5f
JH
1424 es_ctx sctx;
1425
1426 /*XXX The hash of the headers is needed for GCrypt (for which we can do RSA
1427 suging only, as it happens) and for either GnuTLS and OpenSSL when we are
1428 signing with EC (specifically, Ed25519). The former is because the GCrypt
1429 signing operation is pure (does not do its own hash) so we must hash. The
1430 latter is because we (stupidly, but this is what the IETF draft is saying)
1431 must hash with the declared hash method, then pass the result to the library
1432 hash-and-sign routine (because that's all the libraries are providing. And
1433 we're stuck with whatever that hidden hash method is, too). We may as well
1434 do this hash incrementally.
1435 We don't need the hash we're calculating here for the GnuTLS and OpenSSL
1436 cases of RSA signing, since those library routines can do hash-and-sign.
1437
1438 Some time in the future we could easily avoid doing the hash here for those
1439 cases (which will be common for a long while. We could also change from
1440 the current copy-all-the-headers-into-one-block, then call the hash-and-sign
1441 implementation - to a proper incremental one. Unfortunately, GnuTLS just
1442 cannot do incremental - either signing or verification. Unsure about GCrypt.
1443 */
1444
1445 /*XXX The header hash is also used (so far) by the verify operation */
2592e6c0 1446
d73e45df 1447 if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
7b83389d 1448 {
286b9d5f
JH
1449 log_write(0, LOG_MAIN|LOG_PANIC,
1450 "PDKIM: hash setup error, possibly nonhandled hashtype");
7b83389d
JH
1451 break;
1452 }
80a47a2c 1453
9e70917d
JH
1454 if (ctx->flags & PDKIM_MODE_SIGN)
1455 DEBUG(D_acl) debug_printf(
1456 "PDKIM >> Headers to be signed: >>>>>>>>>>>>\n"
1457 " %s\n",
1458 sig->sign_headers);
1459
0d04a285 1460 DEBUG(D_acl) debug_printf(
328c5688 1461 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
3045f050 1462
9e70917d 1463
3045f050
JH
1464 /* SIGNING ---------------------------------------------------------------- */
1465 /* When signing, walk through our header list and add them to the hash. As we
8ef02a06
JH
1466 go, construct a list of the header's names to use for the h= parameter.
1467 Then append to that list any remaining header names for which there was no
1468 header to sign. */
3045f050 1469
e983e85a 1470 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1471 {
acec9514 1472 gstring * g = NULL;
3045f050 1473 pdkim_stringlist *p;
8ef02a06
JH
1474 const uschar * l;
1475 uschar * s;
1476 int sep = 0;
3045f050 1477
286b9d5f
JH
1478 /* Import private key, including the keytype which we need for building
1479 the signature header */
1480
1481/*XXX extend for non-RSA algos */
1482 if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx)))
1483 {
1484 log_write(0, LOG_MAIN|LOG_PANIC, "signing_init: %s", *err);
1485 return PDKIM_ERR_RSA_PRIVKEY;
1486 }
1487 sig->keytype = sctx.keytype;
9e70917d 1488
286b9d5f
JH
1489 for (sig->headernames = NULL, /* Collected signed header names */
1490 p = sig->headers; p; p = p->next)
9e70917d
JH
1491 {
1492 uschar * rh = p->value;
1493
1494 if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
ab9152ff 1495 {
ab9152ff 1496 /* Collect header names (Note: colon presence is guaranteed here) */
acec9514 1497 g = string_append_listele_n(g, ':', rh, Ustrchr(rh, ':') - rh);
3045f050 1498
9e70917d
JH
1499 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1500 rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */
3045f050 1501
ab9152ff 1502 /* Feed header to the hash algorithm */
e2e3255a 1503 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
f444c2c7 1504
ab9152ff 1505 /* Remember headers block for signing (when the library cannot do incremental) */
286b9d5f 1506 /*XXX we could avoid doing this for all but the GnuTLS/RSA case */
acec9514 1507 hdata = exim_dkim_data_append(hdata, rh);
3045f050 1508
ab9152ff
JH
1509 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1510 }
9e70917d 1511 }
8ef02a06 1512
484cc1a9
JH
1513 /* Any headers we wanted to sign but were not present must also be listed.
1514 Ignore elements that have been ticked-off or are marked as never-oversign. */
1515
ca9cb170 1516 l = sig->sign_headers;
8ef02a06 1517 while((s = string_nextinlist(&l, &sep, NULL, 0)))
484cc1a9
JH
1518 {
1519 if (*s == '+') /* skip oversigning marker */
1520 s++;
1521 if (*s != '_' && *s != '=')
acec9514 1522 g = string_append_listele(g, ':', s);
484cc1a9 1523 }
acec9514 1524 sig->headernames = string_from_gstring(g);
ca9cb170
JH
1525
1526 /* Create signature header with b= omitted */
1527 sig_hdr = pdkim_create_header(sig, FALSE);
80a47a2c 1528 }
37f8b554 1529
3045f050
JH
1530 /* VERIFICATION ----------------------------------------------------------- */
1531 /* When verifying, walk through the header name list in the h= parameter and
1532 add the headers to the hash in that order. */
1533 else
1534 {
10c50704 1535 uschar * p = sig->headernames;
2592e6c0
JH
1536 uschar * q;
1537 pdkim_stringlist * hdrs;
3045f050 1538
10c50704 1539 if (p)
3045f050 1540 {
10c50704 1541 /* clear tags */
3045f050 1542 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
10c50704 1543 hdrs->tag = 0;
3045f050 1544
10c50704
JH
1545 p = string_copy(p);
1546 while(1)
1547 {
1548 if ((q = Ustrchr(p, ':')))
1549 *q = '\0';
1550
1551 /*XXX walk the list of headers in same order as received. */
1552 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1553 if ( hdrs->tag == 0
4dc2379a 1554 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
10c50704
JH
1555 && (hdrs->value)[Ustrlen(p)] == ':'
1556 )
1557 {
1558 /* cook header for relaxed canon, or just copy it for simple */
1559
1560 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
ea18931d 1561 ? pdkim_relax_header(hdrs->value, TRUE)
10c50704
JH
1562 : string_copy(CUS hdrs->value);
1563
1564 /* Feed header to the hash algorithm */
1565 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1566
1567 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1568 hdrs->tag = 1;
1569 break;
1570 }
3045f050 1571
10c50704
JH
1572 if (!q) break;
1573 p = q+1;
1574 }
3045f050 1575
10c50704 1576 sig_hdr = string_copy(sig->rawsig_no_b_val);
80a47a2c 1577 }
80a47a2c
TK
1578 }
1579
0d04a285 1580 DEBUG(D_acl) debug_printf(
3045f050 1581 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1582
9e70917d
JH
1583 DEBUG(D_acl)
1584 {
1585 debug_printf(
1586 "PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
1587 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1588 debug_printf(
1589 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1590 }
1591
3045f050
JH
1592 /* Relax header if necessary */
1593 if (sig->canon_headers == PDKIM_CANON_RELAXED)
ea18931d 1594 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
80a47a2c 1595
0d04a285 1596 DEBUG(D_acl)
3045f050 1597 {
0d04a285 1598 debug_printf(
3045f050 1599 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
e2e3255a 1600 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
0d04a285 1601 debug_printf(
3045f050 1602 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1603 }
3045f050
JH
1604
1605 /* Finalize header hash */
e2e3255a 1606 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
2592e6c0 1607 exim_sha_finish(&hhash_ctx, &hhash);
3045f050 1608
f444c2c7
JH
1609 DEBUG(D_acl)
1610 {
9e70917d
JH
1611 debug_printf("PDKIM [%s] Header %s computed: ",
1612 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
2592e6c0 1613 pdkim_hexprint(hhash.data, hhash.len);
80a47a2c
TK
1614 }
1615
9e70917d
JH
1616 /* Remember headers block for signing (when the signing library cannot do
1617 incremental) */
e983e85a 1618 if (ctx->flags & PDKIM_MODE_SIGN)
acec9514 1619 hdata = exim_dkim_data_append(hdata, US sig_hdr);
f444c2c7 1620
3045f050 1621 /* SIGNING ---------------------------------------------------------------- */
e983e85a 1622 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1623 {
286b9d5f
JH
1624 hashmethod hm = sig->keytype == KEYTYPE_ED25519
1625 ? HASH_SHA2_512 : pdkim_hashes[sig->hashtype].exim_hashmethod;
f444c2c7 1626
286b9d5f
JH
1627#ifdef SIGN_HAVE_ED25519
1628 /* For GCrypt, and for EC, we pass the hash-of-headers to the signing
1629 routine. For anything else we just pass the headers. */
f444c2c7 1630
286b9d5f 1631 if (sig->keytype != KEYTYPE_ED25519)
f444c2c7 1632#endif
286b9d5f
JH
1633 {
1634 hhash.data = hdata->s;
1635 hhash.len = hdata->ptr;
1636 }
f444c2c7 1637
9b2583c4 1638/*XXX extend for non-RSA algos */
286b9d5f
JH
1639/*- done for GnuTLS */
1640 if ((*err = exim_dkim_sign(&sctx, hm, &hhash, &sig->sighash)))
f444c2c7 1641 {
286b9d5f 1642 log_write(0, LOG_MAIN|LOG_PANIC, "signing: %s", *err);
f444c2c7
JH
1643 return PDKIM_ERR_RSA_SIGNING;
1644 }
80a47a2c 1645
0d04a285 1646 DEBUG(D_acl)
3045f050 1647 {
0d04a285 1648 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
dcd03763 1649 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
80a47a2c 1650 }
80a47a2c 1651
ca9cb170 1652 sig->signature_header = pdkim_create_header(sig, TRUE);
80a47a2c 1653 }
80a47a2c 1654
3045f050
JH
1655 /* VERIFICATION ----------------------------------------------------------- */
1656 else
1657 {
2592e6c0 1658 ev_ctx vctx;
3045f050 1659
07eeb4df 1660 /* Make sure we have all required signature tags */
1661 if (!( sig->domain && *sig->domain
1662 && sig->selector && *sig->selector
1663 && sig->headernames && *sig->headernames
1664 && sig->bodyhash.data
dcd03763 1665 && sig->sighash.data
d73e45df
JH
1666 && sig->keytype >= 0
1667 && sig->hashtype >= 0
07eeb4df 1668 && sig->version
1669 ) )
1670 {
1671 sig->verify_status = PDKIM_VERIFY_INVALID;
1672 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1673
1674 DEBUG(D_acl) debug_printf(
1675 " Error in DKIM-Signature header: tags missing or invalid\n"
1676 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1677 goto NEXT_VERIFY;
1678 }
1679
1680 /* Make sure sig uses supported DKIM version (only v1) */
1681 if (sig->version != 1)
1682 {
1683 sig->verify_status = PDKIM_VERIFY_INVALID;
1684 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1685
1686 DEBUG(D_acl) debug_printf(
1687 " Error in DKIM-Signature header: unsupported DKIM version\n"
1688 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1689 goto NEXT_VERIFY;
1690 }
1691
9e70917d
JH
1692 DEBUG(D_acl)
1693 {
1694 debug_printf( "PDKIM [%s] b from mail: ", sig->domain);
1695 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1696 }
1697
b9df1829 1698 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
286b9d5f
JH
1699 {
1700 log_write(0, LOG_MAIN, "PDKIM: %s%s %s%s [failed key import]",
1701 sig->domain ? "d=" : "", sig->domain ? sig->domain : US"",
1702 sig->selector ? "s=" : "", sig->selector ? sig->selector : US"");
3045f050 1703 goto NEXT_VERIFY;
286b9d5f 1704 }
80a47a2c 1705
135e9496
JH
1706 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1707 do not have the hash part of the sig algorithm matching */
1708
1709 if (sig->pubkey->hashes)
1710 {
1711 const uschar * list = sig->pubkey->hashes, * ele;
1712 int sep = ':';
1713 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
d73e45df 1714 if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
135e9496
JH
1715 if (!ele)
1716 {
d73e45df
JH
1717 DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
1718 sig->pubkey->hashes,
1719 pdkim_keytypes[sig->keytype],
1720 pdkim_hashes[sig->hashtype].dkim_hashname);
135e9496
JH
1721 sig->verify_status = PDKIM_VERIFY_FAIL;
1722 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1723 goto NEXT_VERIFY;
1724 }
1725 }
1726
3045f050 1727 /* Check the signature */
286b9d5f
JH
1728/*XXX extend for non-RSA algos */
1729/*- done for GnuTLS */
d73e45df 1730 if ((*err = exim_dkim_verify(&vctx,
286b9d5f
JH
1731 pdkim_hashes[sig->hashtype].exim_hashmethod,
1732 &hhash, &sig->sighash)))
3045f050 1733 {
b9df1829 1734 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
3045f050
JH
1735 sig->verify_status = PDKIM_VERIFY_FAIL;
1736 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1737 goto NEXT_VERIFY;
ff7ddfd7
TK
1738 }
1739
2592e6c0 1740
4c04137d 1741 /* We have a winner! (if bodyhash was correct earlier) */
3045f050 1742 if (sig->verify_status == PDKIM_VERIFY_NONE)
286b9d5f 1743 {
3045f050 1744 sig->verify_status = PDKIM_VERIFY_PASS;
286b9d5f
JH
1745 verify_pass = TRUE;
1746 }
3045f050
JH
1747
1748NEXT_VERIFY:
1749
0d04a285 1750 DEBUG(D_acl)
3045f050 1751 {
286b9d5f
JH
1752 debug_printf("PDKIM [%s] %s signature status: %s",
1753 sig->domain, dkim_sig_to_a_tag(sig),
1754 pdkim_verify_status_str(sig->verify_status));
3045f050 1755 if (sig->verify_ext_status > 0)
0d04a285 1756 debug_printf(" (%s)\n",
3045f050
JH
1757 pdkim_verify_ext_status_str(sig->verify_ext_status));
1758 else
0d04a285 1759 debug_printf("\n");
80a47a2c 1760 }
80a47a2c 1761 }
80a47a2c
TK
1762 }
1763
3045f050
JH
1764/* If requested, set return pointer to signature(s) */
1765if (return_signatures)
1766 *return_signatures = ctx->sig;
80a47a2c 1767
286b9d5f
JH
1768return ctx->flags & PDKIM_MODE_SIGN || verify_pass
1769 ? PDKIM_OK : PDKIM_FAIL;
80a47a2c
TK
1770}
1771
1772
1773/* -------------------------------------------------------------------------- */
3045f050
JH
1774
1775DLLEXPORT pdkim_ctx *
1eedc10f 1776pdkim_init_verify(uschar * (*dns_txt_callback)(char *), BOOL dot_stuffing)
3045f050 1777{
ca9cb170 1778pdkim_ctx * ctx;
3045f050 1779
ca9cb170 1780ctx = store_get(sizeof(pdkim_ctx));
abe1010c 1781memset(ctx, 0, sizeof(pdkim_ctx));
3045f050 1782
e983e85a 1783if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
ca9cb170 1784ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
3045f050 1785ctx->dns_txt_callback = dns_txt_callback;
80a47a2c 1786
3045f050 1787return ctx;
80a47a2c
TK
1788}
1789
1790
1791/* -------------------------------------------------------------------------- */
80a47a2c 1792
9e70917d
JH
1793DLLEXPORT pdkim_signature *
1794pdkim_init_sign(pdkim_ctx * ctx,
1795 uschar * domain, uschar * selector, uschar * privkey,
1796 uschar * hashname, const uschar ** errstr)
3045f050 1797{
d73e45df 1798int hashtype;
cd1a5fe0 1799pdkim_signature * sig;
80a47a2c 1800
d73e45df 1801if (!domain || !selector || !privkey)
3045f050 1802 return NULL;
80a47a2c 1803
9e70917d 1804/* Allocate & init one signature struct */
80a47a2c 1805
9e70917d 1806sig = store_get(sizeof(pdkim_signature));
abe1010c 1807memset(sig, 0, sizeof(pdkim_signature));
80a47a2c 1808
3045f050 1809sig->bodylength = -1;
80a47a2c 1810
e2e3255a
JH
1811sig->domain = string_copy(US domain);
1812sig->selector = string_copy(US selector);
d73e45df 1813sig->privkey = string_copy(US privkey);
286b9d5f 1814sig->keytype = -1;
cb224393 1815
d73e45df
JH
1816for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
1817 if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
1818 { sig->hashtype = hashtype; break; }
1819if (hashtype >= nelem(pdkim_hashes))
7b83389d 1820 {
286b9d5f
JH
1821 log_write(0, LOG_MAIN|LOG_PANIC,
1822 "PDKIM: unrecognised hashname '%s'", hashname);
d73e45df
JH
1823 return NULL;
1824 }
1825
cd1a5fe0
JH
1826DEBUG(D_acl)
1827 {
1828 pdkim_signature s = *sig;
1829 ev_ctx vctx;
1830
328c5688 1831 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
b9df1829 1832 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
cd1a5fe0 1833 debug_printf("WARNING: bad dkim key in dns\n");
328c5688 1834 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
cd1a5fe0 1835 }
9e70917d 1836return sig;
6ab02e3f 1837}
80a47a2c 1838
f444c2c7 1839
80a47a2c 1840/* -------------------------------------------------------------------------- */
3045f050 1841
9e70917d
JH
1842DLLEXPORT void
1843pdkim_set_optional(pdkim_signature * sig,
1844 char * sign_headers,
1845 char * identity,
80a47a2c
TK
1846 int canon_headers,
1847 int canon_body,
1848 long bodylength,
80a47a2c 1849 unsigned long created,
3045f050
JH
1850 unsigned long expires)
1851{
3045f050 1852if (identity)
e2e3255a 1853 sig->identity = string_copy(US identity);
80a47a2c 1854
ca9cb170
JH
1855sig->sign_headers = string_copy(sign_headers
1856 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
80a47a2c 1857
8ef02a06
JH
1858sig->canon_headers = canon_headers;
1859sig->canon_body = canon_body;
1860sig->bodylength = bodylength;
1861sig->created = created;
1862sig->expires = expires;
80a47a2c 1863
9e70917d
JH
1864return;
1865}
1866
1867
1868
cf1cce5e
JH
1869/* Set up a blob for calculating the bodyhash according to the
1870needs of this signature. Use an existing one if possible, or
1871create a new one.
1872
1873Return: hashblob pointer, or NULL on error (only used as a boolean).
1874*/
1875pdkim_bodyhash *
1876pdkim_set_bodyhash(pdkim_ctx * ctx, pdkim_signature * sig)
1877{
1878pdkim_bodyhash * b;
1879
1880for (b = ctx->bodyhash; b; b = b->next)
1881 if ( sig->hashtype == b->hashtype
1882 && sig->canon_body == b->canon_method
1883 && sig->bodylength == b->bodylength)
1884 goto old;
1885
1886b = store_get(sizeof(pdkim_bodyhash));
1887b->next = ctx->bodyhash;
1888b->hashtype = sig->hashtype;
1889b->canon_method = sig->canon_body;
1890b->bodylength = sig->bodylength;
1891if (!exim_sha_init(&b->body_hash_ctx, /*XXX hash method: extend for sha512 */
1892 pdkim_hashes[sig->hashtype].exim_hashmethod))
1893 {
1894 DEBUG(D_acl)
1895 debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n");
1896 return NULL;
1897 }
1898b->signed_body_bytes = 0;
1899b->num_buffered_blanklines = 0;
1900ctx->bodyhash = b;
1901
1902old:
1903sig->calc_body_hash = b;
1904return b;
1905}
1906
1907
1908/* -------------------------------------------------------------------------- */
1909
1910
9e70917d
JH
1911void
1912pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
1eedc10f 1913 uschar * (*dns_txt_callback)(char *))
9e70917d
JH
1914{
1915memset(ctx, 0, sizeof(pdkim_ctx));
1916ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1917ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1918DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
6ab02e3f 1919}
3045f050 1920
3045f050 1921
2592e6c0
JH
1922void
1923pdkim_init(void)
1924{
9b2583c4 1925exim_dkim_init();
2592e6c0
JH
1926}
1927
1928
1929
f444c2c7 1930#endif /*DISABLE_DKIM*/