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