DKIM: DNS records having no v= tag are acceptable. Bug 2207
[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
9b2583c4 606/*XXX hash method: extend for sha512 */
7b83389d 607if (!exim_sha_init(&sig->body_hash_ctx,
d73e45df 608 pdkim_hashes[sig->hashtype].exim_hashmethod))
7b83389d 609 {
d73e45df
JH
610 DEBUG(D_acl)
611 debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n");
7b83389d
JH
612 return NULL;
613 }
3045f050 614return sig;
80a47a2c
TK
615}
616
617
618/* -------------------------------------------------------------------------- */
80a47a2c 619
f444c2c7 620static pdkim_pubkey *
e2e3255a 621pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
3045f050 622{
35cf75e9
JH
623const uschar * ele;
624int sep = ';';
625pdkim_pubkey * pub;
80a47a2c 626
ca9cb170 627pub = store_get(sizeof(pdkim_pubkey));
abe1010c 628memset(pub, 0, sizeof(pdkim_pubkey));
80a47a2c 629
35cf75e9
JH
630while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
631 {
632 const uschar * val;
633
634 if ((val = Ustrchr(ele, '=')))
3045f050 635 {
35cf75e9 636 int taglen = val++ - ele;
80a47a2c 637
35cf75e9
JH
638 DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
639 switch (ele[0])
3045f050 640 {
35cf75e9
JH
641 case 'v': pub->version = val; break;
642 case 'h': pub->hashes = val; break;
643 case 'k': break;
644 case 'g': pub->granularity = val; break;
645 case 'n': pub->notes = pdkim_decode_qp(val); break;
646 case 'p': pdkim_decode_base64(val, &pub->key); break;
647 case 's': pub->srvtype = val; break;
648 case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
649 if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
e21a4d00 650 break;
35cf75e9 651 default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
80a47a2c 652 }
e21a4d00 653 }
35cf75e9 654 }
80a47a2c 655
3045f050 656/* Set fallback defaults */
fc6fb551
JH
657if (!pub->version)
658 pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
135e9496
JH
659else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
660 {
661 DEBUG(D_acl) debug_printf(" Bad v= field\n");
662 return NULL;
663 }
e21a4d00 664
35cf75e9 665if (!pub->granularity) pub->granularity = US"*";
e21a4d00 666/*
35cf75e9 667if (!pub->keytype ) pub->keytype = US"rsa";
e21a4d00 668*/
35cf75e9 669if (!pub->srvtype ) pub->srvtype = US"*";
80a47a2c 670
3045f050 671/* p= is required */
2592e6c0 672if (pub->key.data)
80a47a2c 673 return pub;
3045f050 674
135e9496 675DEBUG(D_acl) debug_printf(" Missing p= field\n");
3045f050 676return NULL;
80a47a2c
TK
677}
678
679
680/* -------------------------------------------------------------------------- */
3045f050 681
9e70917d
JH
682/* Update the bodyhash for one sig, with some additional data.
683If we have to relax the data for this sig, return our copy of it. */
684
685/*XXX Currently we calculate a hash for each sig. But it is possible
686that multi-signing will be wanted using different signing algos
687(rsa, ec) using the same hash and canonicalization. Consider in future
688hanging the hash+cacnon from the ctx and only referencing from the sig,
689so that it can be calculated only once - being over the body this
690caould be meagbytes, hence expensive. */
691
692static blob *
693pdkim_update_sig_bodyhash(pdkim_signature * sig, blob * orig_data, blob * relaxed_data)
3045f050 694{
9e70917d
JH
695blob * canon_data = orig_data;
696/* Defaults to simple canon (no further treatment necessary) */
3045f050 697
9e70917d 698if (sig->canon_body == PDKIM_CANON_RELAXED)
3045f050 699 {
9e70917d
JH
700 /* Relax the line if not done already */
701 if (!relaxed_data)
3045f050 702 {
9e70917d 703 BOOL seen_wsp = FALSE;
7845dbb3 704 const uschar * p;
9e70917d 705 int q = 0;
3045f050 706
9e70917d
JH
707 /* We want to be able to free this else we allocate
708 for the entire message which could be many MB. Since
709 we don't know what allocations the SHA routines might
710 do, not safe to use store_get()/store_reset(). */
d5bccfc8 711
9e70917d
JH
712 relaxed_data = store_malloc(sizeof(blob) + orig_data->len+1);
713 relaxed_data->data = US (relaxed_data+1);
3045f050 714
9e70917d
JH
715 for (p = orig_data->data; *p; p++)
716 {
717 char c = *p;
718 if (c == '\r')
719 {
720 if (q > 0 && relaxed_data->data[q-1] == ' ')
721 q--;
722 }
723 else if (c == '\t' || c == ' ')
724 {
725 c = ' '; /* Turns WSP into SP */
726 if (seen_wsp)
727 continue;
728 seen_wsp = TRUE;
3045f050 729 }
9e70917d
JH
730 else
731 seen_wsp = FALSE;
732 relaxed_data->data[q++] = c;
80a47a2c 733 }
9e70917d
JH
734 relaxed_data->data[q] = '\0';
735 relaxed_data->len = q;
80a47a2c 736 }
9e70917d
JH
737 canon_data = relaxed_data;
738 }
80a47a2c 739
9e70917d
JH
740/* Make sure we don't exceed the to-be-signed body length */
741if ( sig->bodylength >= 0
742 && sig->signed_body_bytes + (unsigned long)canon_data->len > sig->bodylength
743 )
744 canon_data->len = sig->bodylength - sig->signed_body_bytes;
80a47a2c 745
9e70917d
JH
746if (canon_data->len > 0)
747 {
748 exim_sha_update(&sig->body_hash_ctx, CUS canon_data->data, canon_data->len);
749 sig->signed_body_bytes += canon_data->len;
750 DEBUG(D_acl) pdkim_quoteprint(canon_data->data, canon_data->len);
80a47a2c
TK
751 }
752
9e70917d 753return relaxed_data;
6ab02e3f 754}
80a47a2c
TK
755
756
757/* -------------------------------------------------------------------------- */
80a47a2c 758
ca9cb170 759static void
9e70917d 760pdkim_finish_bodyhash(pdkim_ctx * ctx)
3045f050 761{
9e70917d 762pdkim_signature * sig;
80a47a2c 763
3045f050 764/* Traverse all signatures */
f4d091fb 765for (sig = ctx->sig; sig; sig = sig->next)
3045f050 766 { /* Finish hashes */
2592e6c0
JH
767 blob bh;
768
dcd03763 769 exim_sha_finish(&sig->body_hash_ctx, &bh);
3045f050 770
0d04a285 771 DEBUG(D_acl)
3045f050 772 {
0d04a285 773 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
9e70917d
JH
774 "PDKIM [%s] Body %s computed: ",
775 sig->domain, sig->signed_body_bytes,
776 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
b78006ac 777 pdkim_hexprint(CUS bh.data, bh.len);
80a47a2c 778 }
3045f050
JH
779
780 /* SIGNING -------------------------------------------------------------- */
e983e85a 781 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 782 {
2592e6c0 783 sig->bodyhash = bh;
3045f050
JH
784
785 /* If bodylength limit is set, and we have received less bytes
786 than the requested amount, effectively remove the limit tag. */
787 if (sig->signed_body_bytes < sig->bodylength)
788 sig->bodylength = -1;
80a47a2c 789 }
3045f050 790
3045f050 791 else
02c4f8fb
JH
792 /* VERIFICATION --------------------------------------------------------- */
793 /* Be careful that the header sig included a bodyash */
794
795 if (sig->bodyhash.data && memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
3045f050 796 {
0d04a285 797 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
80a47a2c 798 }
3045f050
JH
799 else
800 {
0d04a285 801 DEBUG(D_acl)
3045f050 802 {
e21a4d00 803 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain);
dcd03763 804 pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
0d04a285 805 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
3045f050 806 }
3045f050
JH
807 sig->verify_status = PDKIM_VERIFY_FAIL;
808 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
80a47a2c 809 }
80a47a2c 810 }
6ab02e3f 811}
80a47a2c
TK
812
813
814
9e70917d 815static void
e983e85a
JH
816pdkim_body_complete(pdkim_ctx * ctx)
817{
9e70917d 818pdkim_signature * sig;
e983e85a
JH
819
820/* In simple body mode, if any empty lines were buffered,
821replace with one. rfc 4871 3.4.3 */
822/*XXX checking the signed-body-bytes is a gross hack; I think
823it indicates that all linebreaks should be buffered, including
824the one terminating a text line */
825
9e70917d
JH
826for (sig = ctx->sig; sig; sig = sig->next)
827 if ( sig->canon_body == PDKIM_CANON_SIMPLE
828 && sig->signed_body_bytes == 0
829 && sig->num_buffered_blanklines > 0
830 )
831 (void) pdkim_update_sig_bodyhash(sig, &lineending, NULL);
e983e85a
JH
832
833ctx->flags |= PDKIM_SEEN_EOD;
834ctx->linebuf_offset = 0;
e983e85a
JH
835}
836
837
838
80a47a2c 839/* -------------------------------------------------------------------------- */
e983e85a 840/* Call from pdkim_feed below for processing complete body lines */
3045f050 841
9e70917d
JH
842static void
843pdkim_bodyline_complete(pdkim_ctx * ctx)
3045f050 844{
9e70917d
JH
845blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
846pdkim_signature * sig;
847blob * rnl = NULL;
848blob * rline = NULL;
3045f050
JH
849
850/* Ignore extra data if we've seen the end-of-data marker */
9e70917d 851if (ctx->flags & PDKIM_SEEN_EOD) goto all_skip;
3045f050
JH
852
853/* We've always got one extra byte to stuff a zero ... */
9e70917d 854ctx->linebuf[line.len] = '\0';
3045f050 855
0d04a285 856/* Terminate on EOD marker */
e983e85a 857if (ctx->flags & PDKIM_DOT_TERM)
3045f050 858 {
9e70917d
JH
859 if (memcmp(line.data, ".\r\n", 3) == 0)
860 { pdkim_body_complete(ctx); return; }
0d04a285 861
e983e85a 862 /* Unstuff dots */
9e70917d
JH
863 if (memcmp(line.data, "..", 2) == 0)
864 { line.data++; line.len--; }
80a47a2c
TK
865 }
866
3045f050 867/* Empty lines need to be buffered until we find a non-empty line */
9e70917d 868if (memcmp(line.data, "\r\n", 2) == 0)
3045f050 869 {
9e70917d
JH
870 for (sig = ctx->sig; sig; sig = sig->next) sig->num_buffered_blanklines++;
871 goto all_skip;
80a47a2c
TK
872 }
873
9e70917d
JH
874/* Process line for each sig separately */
875for (sig = ctx->sig; sig; sig = sig->next)
3045f050 876 {
9e70917d 877 if (sig->canon_body == PDKIM_CANON_RELAXED)
3045f050 878 {
9e70917d 879 /* Lines with just spaces need to be buffered too */
7845dbb3 880 uschar * cp = line.data;
9e70917d 881 char c;
6a11a9e6 882
9e70917d
JH
883 while ((c = *cp))
884 {
885 if (c == '\r' && cp[1] == '\n') break;
886 if (c != ' ' && c != '\t') goto sig_process;
887 cp++;
888 }
889
890 sig->num_buffered_blanklines++;
891 goto sig_skip;
6a11a9e6
JH
892 }
893
9e70917d
JH
894sig_process:
895 /* At this point, we have a non-empty line, so release the buffered ones. */
6a11a9e6 896
9e70917d
JH
897 while (sig->num_buffered_blanklines)
898 {
899 rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
900 sig->num_buffered_blanklines--;
901 }
902
903 rline = pdkim_update_sig_bodyhash(sig, &line, rline);
904sig_skip: ;
80a47a2c
TK
905 }
906
9e70917d
JH
907if (rnl) store_free(rnl);
908if (rline) store_free(rline);
909
910all_skip:
80a47a2c 911
3045f050 912ctx->linebuf_offset = 0;
9e70917d 913return;
80a47a2c
TK
914}
915
916
917/* -------------------------------------------------------------------------- */
918/* Callback from pdkim_feed below for processing complete headers */
919#define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
3045f050 920
f444c2c7 921static int
2c0f3ea1 922pdkim_header_complete(pdkim_ctx * ctx)
3045f050 923{
2c0f3ea1
JH
924pdkim_signature * sig, * last_sig;
925
3045f050 926/* Special case: The last header can have an extra \r appended */
acec9514
JH
927if ( (ctx->cur_header->ptr > 1) &&
928 (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
929 --ctx->cur_header->ptr;
930(void) string_from_gstring(ctx->cur_header);
80a47a2c 931
2c0f3ea1 932if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
80a47a2c 933
3045f050 934/* SIGNING -------------------------------------------------------------- */
e983e85a 935if (ctx->flags & PDKIM_MODE_SIGN)
0d04a285 936 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
80a47a2c 937
ab9152ff 938 /* Add header to the signed headers list (in reverse order) */
acec9514 939 sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s);
94431adb 940
0d04a285 941/* VERIFICATION ----------------------------------------------------------- */
3045f050 942/* DKIM-Signature: headers are added to the verification list */
e983e85a 943else
3045f050 944 {
f6ee24a2 945#ifdef notdef
bd8fbe36
JH
946 DEBUG(D_acl)
947 {
948 debug_printf("PDKIM >> raw hdr: ");
acec9514 949 pdkim_quoteprint(CUS ctx->cur_header->s, ctx->cur_header->ptr);
bd8fbe36 950 }
f6ee24a2 951#endif
acec9514 952 if (strncasecmp(CCS ctx->cur_header->s,
3045f050 953 DKIM_SIGNATURE_HEADERNAME,
e2e3255a 954 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
3045f050 955 {
02c4f8fb
JH
956 /* Create and chain new signature block. We could error-check for all
957 required tags here, but prefer to create the internal sig and expicitly
958 fail verification of it later. */
80a47a2c 959
0d04a285 960 DEBUG(D_acl) debug_printf(
3045f050 961 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
3045f050 962
acec9514 963 sig = pdkim_parse_sig_header(ctx, ctx->cur_header->s);
02c4f8fb
JH
964
965 if (!(last_sig = ctx->sig))
2c0f3ea1 966 ctx->sig = sig;
02c4f8fb 967 else
3045f050 968 {
02c4f8fb 969 while (last_sig->next) last_sig = last_sig->next;
2c0f3ea1 970 last_sig->next = sig;
80a47a2c
TK
971 }
972 }
37f8b554 973
eea19017 974 /* all headers are stored for signature verification */
acec9514 975 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->s);
80a47a2c
TK
976 }
977
3045f050 978BAIL:
acec9514 979ctx->cur_header->s[ctx->cur_header->ptr = 0] = '\0'; /* leave buffer for reuse */
3045f050 980return PDKIM_OK;
6ab02e3f 981}
80a47a2c
TK
982
983
984
985/* -------------------------------------------------------------------------- */
986#define HEADER_BUFFER_FRAG_SIZE 256
3045f050
JH
987
988DLLEXPORT int
ef698bf6 989pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
3045f050 990{
02c4f8fb 991int p, rc;
3045f050 992
e983e85a
JH
993/* Alternate EOD signal, used in non-dotstuffing mode */
994if (!data)
995 pdkim_body_complete(ctx);
996
10c50704 997else for (p = 0; p<len; p++)
3045f050 998 {
ca9cb170 999 uschar c = data[p];
3045f050 1000
e983e85a 1001 if (ctx->flags & PDKIM_PAST_HDRS)
3045f050 1002 {
b895f4b2
JH
1003 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1004 {
1005 ctx->linebuf[ctx->linebuf_offset++] = '\r';
1006 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1007 return PDKIM_ERR_LONG_LINE;
1008 }
1009
3045f050 1010 /* Processing body byte */
0d04a285 1011 ctx->linebuf[ctx->linebuf_offset++] = c;
b895f4b2
JH
1012 if (c == '\r')
1013 ctx->flags |= PDKIM_SEEN_CR;
1014 else if (c == '\n')
3045f050 1015 {
b895f4b2 1016 ctx->flags &= ~PDKIM_SEEN_CR;
9e70917d 1017 pdkim_bodyline_complete(ctx);
80a47a2c 1018 }
b895f4b2
JH
1019
1020 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
3045f050 1021 return PDKIM_ERR_LONG_LINE;
80a47a2c 1022 }
3045f050
JH
1023 else
1024 {
1025 /* Processing header byte */
b895f4b2
JH
1026 if (c == '\r')
1027 ctx->flags |= PDKIM_SEEN_CR;
1028 else if (c == '\n')
3045f050 1029 {
b895f4b2 1030 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
acec9514 1031 ctx->cur_header = string_catn(ctx->cur_header, CUS "\r", 1);
b895f4b2 1032
02c4f8fb 1033 if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */
b895f4b2 1034 {
02c4f8fb
JH
1035 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1036 return rc;
b895f4b2 1037
863bd541 1038 ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS;
b895f4b2 1039 DEBUG(D_acl) debug_printf(
02c4f8fb 1040 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
b895f4b2 1041 continue;
3045f050 1042 }
b895f4b2 1043 else
863bd541 1044 ctx->flags = (ctx->flags & ~PDKIM_SEEN_CR) | PDKIM_SEEN_LF;
b895f4b2
JH
1045 }
1046 else if (ctx->flags & PDKIM_SEEN_LF)
1047 {
02c4f8fb
JH
1048 if (!(c == '\t' || c == ' ')) /* End of header */
1049 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1050 return rc;
b895f4b2 1051 ctx->flags &= ~PDKIM_SEEN_LF;
80a47a2c 1052 }
3045f050 1053
acec9514
JH
1054 if (!ctx->cur_header || ctx->cur_header->ptr < PDKIM_MAX_HEADER_LEN)
1055 ctx->cur_header = string_catn(ctx->cur_header, CUS &data[p], 1);
80a47a2c
TK
1056 }
1057 }
3045f050 1058return PDKIM_OK;
6ab02e3f 1059}
80a47a2c 1060
ca9cb170
JH
1061
1062
acec9514
JH
1063/* Extend a growing header with a continuation-linebreak */
1064static gstring *
1065pdkim_hdr_cont(gstring * str, int * col)
ca9cb170
JH
1066{
1067*col = 1;
acec9514 1068return string_catn(str, US"\r\n\t", 3);
ca9cb170
JH
1069}
1070
1071
1072
05b7d6de
JB
1073/*
1074 * RFC 5322 specifies that header line length SHOULD be no more than 78
1075 * lets make it so!
1076 * pdkim_headcat
ca9cb170
JH
1077 *
1078 * returns uschar * (not nul-terminated)
05b7d6de
JB
1079 *
1080 * col: this int holds and receives column number (octets since last '\n')
1081 * str: partial string to append to
94431adb 1082 * pad: padding, split line or space after before or after eg: ";"
05b7d6de
JB
1083 * intro: - must join to payload eg "h=", usually the tag name
1084 * payload: eg base64 data - long data can be split arbitrarily.
1085 *
1086 * this code doesn't fold the header in some of the places that RFC4871
1087 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1088 * pairs and inside long values. it also always spaces or breaks after the
94431adb 1089 * "pad"
05b7d6de
JB
1090 *
1091 * no guarantees are made for output given out-of range input. like tag
f444c2c7 1092 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
05b7d6de
JB
1093 */
1094
acec9514
JH
1095static gstring *
1096pdkim_headcat(int * col, gstring * str,
ca9cb170 1097 const uschar * pad, const uschar * intro, const uschar * payload)
3045f050
JH
1098{
1099size_t l;
1100
1101if (pad)
05b7d6de 1102 {
ca9cb170 1103 l = Ustrlen(pad);
3045f050 1104 if (*col + l > 78)
acec9514
JH
1105 str = pdkim_hdr_cont(str, col);
1106 str = string_catn(str, pad, l);
3045f050 1107 *col += l;
05b7d6de
JB
1108 }
1109
ca9cb170 1110l = (pad?1:0) + (intro?Ustrlen(intro):0);
05b7d6de 1111
3045f050 1112if (*col + l > 78)
05b7d6de 1113 { /*can't fit intro - start a new line to make room.*/
acec9514 1114 str = pdkim_hdr_cont(str, col);
ca9cb170 1115 l = intro?Ustrlen(intro):0;
05b7d6de
JB
1116 }
1117
ca9cb170 1118l += payload ? Ustrlen(payload):0 ;
05b7d6de 1119
3045f050 1120while (l>77)
05b7d6de 1121 { /* this fragment will not fit on a single line */
3045f050 1122 if (pad)
05b7d6de 1123 {
acec9514 1124 str = string_catn(str, US" ", 1);
3045f050
JH
1125 *col += 1;
1126 pad = NULL; /* only want this once */
1127 l--;
05b7d6de 1128 }
3045f050
JH
1129
1130 if (intro)
05b7d6de 1131 {
ca9cb170 1132 size_t sl = Ustrlen(intro);
3045f050 1133
acec9514 1134 str = string_catn(str, intro, sl);
3045f050
JH
1135 *col += sl;
1136 l -= sl;
1137 intro = NULL; /* only want this once */
05b7d6de 1138 }
3045f050
JH
1139
1140 if (payload)
05b7d6de 1141 {
ca9cb170 1142 size_t sl = Ustrlen(payload);
3045f050
JH
1143 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1144
acec9514 1145 str = string_catn(str, payload, chomp);
3045f050
JH
1146 *col += chomp;
1147 payload += chomp;
1148 l -= chomp-1;
05b7d6de 1149 }
3045f050
JH
1150
1151 /* the while precondition tells us it didn't fit. */
acec9514 1152 str = pdkim_hdr_cont(str, col);
05b7d6de 1153 }
3045f050
JH
1154
1155if (*col + l > 78)
05b7d6de 1156 {
acec9514 1157 str = pdkim_hdr_cont(str, col);
3045f050 1158 pad = NULL;
05b7d6de
JB
1159 }
1160
3045f050 1161if (pad)
05b7d6de 1162 {
acec9514 1163 str = string_catn(str, US" ", 1);
3045f050
JH
1164 *col += 1;
1165 pad = NULL;
05b7d6de
JB
1166 }
1167
3045f050 1168if (intro)
05b7d6de 1169 {
ca9cb170 1170 size_t sl = Ustrlen(intro);
3045f050 1171
acec9514 1172 str = string_catn(str, intro, sl);
3045f050
JH
1173 *col += sl;
1174 l -= sl;
1175 intro = NULL;
05b7d6de 1176 }
3045f050
JH
1177
1178if (payload)
05b7d6de 1179 {
ca9cb170 1180 size_t sl = Ustrlen(payload);
3045f050 1181
acec9514 1182 str = string_catn(str, payload, sl);
3045f050 1183 *col += sl;
05b7d6de
JB
1184 }
1185
ca9cb170 1186return str;
05b7d6de 1187}
80a47a2c 1188
3045f050 1189
80a47a2c 1190/* -------------------------------------------------------------------------- */
3045f050 1191
ca9cb170 1192static uschar *
9e70917d 1193pdkim_create_header(pdkim_signature * sig, BOOL final)
3045f050 1194{
ca9cb170
JH
1195uschar * base64_bh;
1196uschar * base64_b;
3045f050 1197int col = 0;
acec9514
JH
1198gstring * hdr;
1199gstring * canon_all;
3045f050 1200
acec9514
JH
1201canon_all = string_cat (NULL, pdkim_canons[sig->canon_headers]);
1202canon_all = string_catn(canon_all, US"/", 1);
1203canon_all = string_cat (canon_all, pdkim_canons[sig->canon_body]);
1204(void) string_from_gstring(canon_all);
3045f050 1205
acec9514
JH
1206hdr = string_cat(NULL, US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1207col = hdr->ptr;
3045f050
JH
1208
1209/* Required and static bits */
acec9514
JH
1210hdr = pdkim_headcat(&col, hdr, US";", US"a=", dkim_sig_to_a_tag(sig));
1211hdr = pdkim_headcat(&col, hdr, US";", US"q=", pdkim_querymethods[sig->querymethod]);
1212hdr = pdkim_headcat(&col, hdr, US";", US"c=", canon_all->s);
1213hdr = pdkim_headcat(&col, hdr, US";", US"d=", sig->domain);
1214hdr = pdkim_headcat(&col, hdr, US";", US"s=", sig->selector);
ca9cb170
JH
1215
1216/* list of header names can be split between items. */
3045f050 1217 {
e2e3255a 1218 uschar * n = string_copy(sig->headernames);
ca9cb170
JH
1219 uschar * i = US"h=";
1220 uschar * s = US";";
1221
1222 while (*n)
05b7d6de 1223 {
ca9cb170 1224 uschar * c = Ustrchr(n, ':');
3045f050 1225
ca9cb170 1226 if (c) *c ='\0';
05b7d6de 1227
ca9cb170 1228 if (!i)
acec9514 1229 hdr = pdkim_headcat(&col, hdr, NULL, NULL, US":");
05b7d6de 1230
acec9514 1231 hdr = pdkim_headcat(&col, hdr, s, i, n);
3045f050 1232
ca9cb170
JH
1233 if (!c)
1234 break;
3045f050 1235
ca9cb170
JH
1236 n = c+1;
1237 s = NULL;
1238 i = NULL;
80a47a2c 1239 }
ca9cb170 1240 }
05b7d6de 1241
ca9cb170 1242base64_bh = pdkim_encode_base64(&sig->bodyhash);
acec9514 1243hdr = pdkim_headcat(&col, hdr, US";", US"bh=", base64_bh);
3045f050 1244
ca9cb170
JH
1245/* Optional bits */
1246if (sig->identity)
acec9514 1247 hdr = pdkim_headcat(&col, hdr, US";", US"i=", sig->identity);
3045f050 1248
ca9cb170
JH
1249if (sig->created > 0)
1250 {
e2e3255a 1251 uschar minibuf[20];
3045f050 1252
e2e3255a 1253 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
acec9514 1254 hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf);
ca9cb170 1255}
3045f050 1256
ca9cb170
JH
1257if (sig->expires > 0)
1258 {
e2e3255a 1259 uschar minibuf[20];
3045f050 1260
e2e3255a 1261 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
acec9514 1262 hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf);
ca9cb170 1263 }
3045f050 1264
ca9cb170
JH
1265if (sig->bodylength >= 0)
1266 {
e2e3255a 1267 uschar minibuf[20];
80a47a2c 1268
e2e3255a 1269 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
acec9514 1270 hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf);
3045f050 1271 }
05b7d6de 1272
ca9cb170 1273/* Preliminary or final version? */
ea18931d
JH
1274if (final)
1275 {
1276 base64_b = pdkim_encode_base64(&sig->sighash);
acec9514 1277 hdr = pdkim_headcat(&col, hdr, US";", US"b=", base64_b);
80a47a2c 1278
ea18931d 1279 /* add trailing semicolon: I'm not sure if this is actually needed */
acec9514 1280 hdr = pdkim_headcat(&col, hdr, NULL, US";", US"");
ea18931d
JH
1281 }
1282else
1283 {
1284 /* To satisfy the rule "all surrounding whitespace [...] deleted"
1285 ( RFC 6376 section 3.7 ) we ensure there is no whitespace here. Otherwise
1286 the headcat routine could insert a linebreak which the relaxer would reduce
1287 to a single space preceding the terminating semicolon, resulting in an
1288 incorrect header-hash. */
acec9514 1289 hdr = pdkim_headcat(&col, hdr, US";", US"b=;", US"");
ea18931d 1290 }
80a47a2c 1291
acec9514 1292return string_from_gstring(hdr);
80a47a2c
TK
1293}
1294
1295
cd1a5fe0
JH
1296/* -------------------------------------------------------------------------- */
1297
1298static pdkim_pubkey *
b9df1829
JH
1299pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1300 const uschar ** errstr)
cd1a5fe0
JH
1301{
1302uschar * dns_txt_name, * dns_txt_reply;
1303pdkim_pubkey * p;
cd1a5fe0
JH
1304
1305/* Fetch public key for signing domain, from DNS */
1306
1307dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1308
1309dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1310memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1311
1312if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1313 || dns_txt_reply[0] == '\0'
1314 )
1315 {
1316 sig->verify_status = PDKIM_VERIFY_INVALID;
1317 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1318 return NULL;
1319 }
1320
1321DEBUG(D_acl)
1322 {
1323 debug_printf(
1324 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
9e70917d
JH
1325 " %s\n"
1326 " Raw record: ",
1327 dns_txt_name);
cd1a5fe0
JH
1328 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1329 }
1330
1331if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1332 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1333 )
1334 {
1335 sig->verify_status = PDKIM_VERIFY_INVALID;
1336 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1337
1338 DEBUG(D_acl)
1339 {
1340 if (p)
1341 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1342 else
1343 debug_printf(" Error while parsing public key record\n");
1344 debug_printf(
1345 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1346 }
1347 return NULL;
1348 }
1349
1350DEBUG(D_acl) debug_printf(
1351 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1352
1353/* Import public key */
9b2583c4 1354if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
cd1a5fe0 1355 {
b9df1829 1356 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
cd1a5fe0
JH
1357 sig->verify_status = PDKIM_VERIFY_INVALID;
1358 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1359 return NULL;
1360 }
1361
1362return p;
1363}
1364
1365
80a47a2c 1366/* -------------------------------------------------------------------------- */
3045f050
JH
1367
1368DLLEXPORT int
b9df1829
JH
1369pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1370 const uschar ** err)
3045f050 1371{
9e70917d 1372pdkim_signature * sig;
3045f050
JH
1373
1374/* Check if we must still flush a (partial) header. If that is the
1375 case, the message has no body, and we must compute a body hash
1376 out of '<CR><LF>' */
acec9514 1377if (ctx->cur_header && ctx->cur_header->ptr > 0)
3045f050 1378 {
9e70917d
JH
1379 blob * rnl = NULL;
1380 int rc;
1381
1382 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1383 return rc;
1384
1385 for (sig = ctx->sig; sig; sig = sig->next)
1386 rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
1387 if (rnl) store_free(rnl);
80a47a2c 1388 }
3045f050 1389else
0d04a285 1390 DEBUG(D_acl) debug_printf(
3045f050 1391 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1392
3045f050 1393/* Build (and/or evaluate) body hash */
ca9cb170 1394pdkim_finish_bodyhash(ctx);
80a47a2c 1395
9e70917d 1396for (sig = ctx->sig; sig; sig = sig->next)
3045f050 1397 {
2592e6c0 1398 hctx hhash_ctx;
ad6f5499 1399 uschar * sig_hdr = US"";
2592e6c0 1400 blob hhash;
acec9514 1401 gstring * hdata = NULL;
2592e6c0 1402
d73e45df 1403 if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
7b83389d 1404 {
d73e45df
JH
1405 DEBUG(D_acl)
1406 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
7b83389d
JH
1407 break;
1408 }
80a47a2c 1409
9e70917d
JH
1410 if (ctx->flags & PDKIM_MODE_SIGN)
1411 DEBUG(D_acl) debug_printf(
1412 "PDKIM >> Headers to be signed: >>>>>>>>>>>>\n"
1413 " %s\n",
1414 sig->sign_headers);
1415
0d04a285 1416 DEBUG(D_acl) debug_printf(
328c5688 1417 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
3045f050 1418
9e70917d 1419
3045f050
JH
1420 /* SIGNING ---------------------------------------------------------------- */
1421 /* When signing, walk through our header list and add them to the hash. As we
8ef02a06
JH
1422 go, construct a list of the header's names to use for the h= parameter.
1423 Then append to that list any remaining header names for which there was no
1424 header to sign. */
3045f050 1425
e983e85a 1426 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1427 {
acec9514 1428 gstring * g = NULL;
3045f050 1429 pdkim_stringlist *p;
8ef02a06
JH
1430 const uschar * l;
1431 uschar * s;
1432 int sep = 0;
3045f050 1433
9e70917d
JH
1434 sig->headernames = NULL; /* Collected signed header names */
1435
3045f050 1436 for (p = sig->headers; p; p = p->next)
9e70917d
JH
1437 {
1438 uschar * rh = p->value;
1439
1440 if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
ab9152ff 1441 {
ab9152ff 1442 /* Collect header names (Note: colon presence is guaranteed here) */
acec9514 1443 g = string_append_listele_n(g, ':', rh, Ustrchr(rh, ':') - rh);
3045f050 1444
9e70917d
JH
1445 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1446 rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */
3045f050 1447
ab9152ff 1448 /* Feed header to the hash algorithm */
e2e3255a 1449 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
f444c2c7 1450
ab9152ff 1451 /* Remember headers block for signing (when the library cannot do incremental) */
acec9514 1452 hdata = exim_dkim_data_append(hdata, rh);
3045f050 1453
ab9152ff
JH
1454 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1455 }
9e70917d 1456 }
8ef02a06 1457
484cc1a9
JH
1458 /* Any headers we wanted to sign but were not present must also be listed.
1459 Ignore elements that have been ticked-off or are marked as never-oversign. */
1460
ca9cb170 1461 l = sig->sign_headers;
8ef02a06 1462 while((s = string_nextinlist(&l, &sep, NULL, 0)))
484cc1a9
JH
1463 {
1464 if (*s == '+') /* skip oversigning marker */
1465 s++;
1466 if (*s != '_' && *s != '=')
acec9514 1467 g = string_append_listele(g, ':', s);
484cc1a9 1468 }
acec9514 1469 sig->headernames = string_from_gstring(g);
ca9cb170
JH
1470
1471 /* Create signature header with b= omitted */
1472 sig_hdr = pdkim_create_header(sig, FALSE);
80a47a2c 1473 }
37f8b554 1474
3045f050
JH
1475 /* VERIFICATION ----------------------------------------------------------- */
1476 /* When verifying, walk through the header name list in the h= parameter and
1477 add the headers to the hash in that order. */
1478 else
1479 {
10c50704 1480 uschar * p = sig->headernames;
2592e6c0
JH
1481 uschar * q;
1482 pdkim_stringlist * hdrs;
3045f050 1483
10c50704 1484 if (p)
3045f050 1485 {
10c50704 1486 /* clear tags */
3045f050 1487 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
10c50704 1488 hdrs->tag = 0;
3045f050 1489
10c50704
JH
1490 p = string_copy(p);
1491 while(1)
1492 {
1493 if ((q = Ustrchr(p, ':')))
1494 *q = '\0';
1495
1496 /*XXX walk the list of headers in same order as received. */
1497 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1498 if ( hdrs->tag == 0
4dc2379a 1499 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
10c50704
JH
1500 && (hdrs->value)[Ustrlen(p)] == ':'
1501 )
1502 {
1503 /* cook header for relaxed canon, or just copy it for simple */
1504
1505 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
ea18931d 1506 ? pdkim_relax_header(hdrs->value, TRUE)
10c50704
JH
1507 : string_copy(CUS hdrs->value);
1508
1509 /* Feed header to the hash algorithm */
1510 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1511
1512 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1513 hdrs->tag = 1;
1514 break;
1515 }
3045f050 1516
10c50704
JH
1517 if (!q) break;
1518 p = q+1;
1519 }
3045f050 1520
10c50704 1521 sig_hdr = string_copy(sig->rawsig_no_b_val);
80a47a2c 1522 }
80a47a2c
TK
1523 }
1524
0d04a285 1525 DEBUG(D_acl) debug_printf(
3045f050 1526 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1527
9e70917d
JH
1528 DEBUG(D_acl)
1529 {
1530 debug_printf(
1531 "PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
1532 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1533 debug_printf(
1534 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1535 }
1536
3045f050
JH
1537 /* Relax header if necessary */
1538 if (sig->canon_headers == PDKIM_CANON_RELAXED)
ea18931d 1539 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
80a47a2c 1540
0d04a285 1541 DEBUG(D_acl)
3045f050 1542 {
0d04a285 1543 debug_printf(
3045f050 1544 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
e2e3255a 1545 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
0d04a285 1546 debug_printf(
3045f050 1547 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1548 }
3045f050
JH
1549
1550 /* Finalize header hash */
e2e3255a 1551 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
2592e6c0 1552 exim_sha_finish(&hhash_ctx, &hhash);
3045f050 1553
f444c2c7
JH
1554 DEBUG(D_acl)
1555 {
9e70917d
JH
1556 debug_printf("PDKIM [%s] Header %s computed: ",
1557 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
2592e6c0 1558 pdkim_hexprint(hhash.data, hhash.len);
80a47a2c
TK
1559 }
1560
9e70917d
JH
1561 /* Remember headers block for signing (when the signing library cannot do
1562 incremental) */
e983e85a 1563 if (ctx->flags & PDKIM_MODE_SIGN)
acec9514 1564 hdata = exim_dkim_data_append(hdata, US sig_hdr);
f444c2c7 1565
3045f050 1566 /* SIGNING ---------------------------------------------------------------- */
e983e85a 1567 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1568 {
2592e6c0 1569 es_ctx sctx;
f444c2c7 1570
d73e45df 1571 /* Import private key, including the keytype */
9b2583c4 1572/*XXX extend for non-RSA algos */
d73e45df 1573 if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx)))
f444c2c7 1574 {
b9df1829 1575 DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
f444c2c7
JH
1576 return PDKIM_ERR_RSA_PRIVKEY;
1577 }
80a47a2c 1578
2592e6c0
JH
1579 /* Do signing. With OpenSSL we are signing the hash of headers just
1580 calculated, with GnuTLS we have to sign an entire block of headers
1581 (due to available interfaces) and it recalculates the hash internally. */
f444c2c7 1582
acec9514
JH
1583#if defined(SIGN_GNUTLS)
1584 hhash.data = hdata->s;
1585 hhash.len = hdata->ptr;
f444c2c7
JH
1586#endif
1587
9b2583c4 1588/*XXX extend for non-RSA algos */
d73e45df
JH
1589 if ((*err = exim_dkim_sign(&sctx,
1590 pdkim_hashes[sig->hashtype].exim_hashmethod,
acec9514 1591 &hhash, &sig->sighash)))
f444c2c7 1592 {
b9df1829 1593 DEBUG(D_acl) debug_printf("signing: %s\n", *err);
f444c2c7
JH
1594 return PDKIM_ERR_RSA_SIGNING;
1595 }
80a47a2c 1596
0d04a285 1597 DEBUG(D_acl)
3045f050 1598 {
0d04a285 1599 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
dcd03763 1600 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
80a47a2c 1601 }
80a47a2c 1602
ca9cb170 1603 sig->signature_header = pdkim_create_header(sig, TRUE);
80a47a2c 1604 }
80a47a2c 1605
3045f050
JH
1606 /* VERIFICATION ----------------------------------------------------------- */
1607 else
1608 {
2592e6c0 1609 ev_ctx vctx;
3045f050 1610
07eeb4df 1611 /* Make sure we have all required signature tags */
1612 if (!( sig->domain && *sig->domain
1613 && sig->selector && *sig->selector
1614 && sig->headernames && *sig->headernames
1615 && sig->bodyhash.data
dcd03763 1616 && sig->sighash.data
d73e45df
JH
1617 && sig->keytype >= 0
1618 && sig->hashtype >= 0
07eeb4df 1619 && sig->version
1620 ) )
1621 {
1622 sig->verify_status = PDKIM_VERIFY_INVALID;
1623 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1624
1625 DEBUG(D_acl) debug_printf(
1626 " Error in DKIM-Signature header: tags missing or invalid\n"
1627 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1628 goto NEXT_VERIFY;
1629 }
1630
1631 /* Make sure sig uses supported DKIM version (only v1) */
1632 if (sig->version != 1)
1633 {
1634 sig->verify_status = PDKIM_VERIFY_INVALID;
1635 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1636
1637 DEBUG(D_acl) debug_printf(
1638 " Error in DKIM-Signature header: unsupported DKIM version\n"
1639 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1640 goto NEXT_VERIFY;
1641 }
1642
9e70917d
JH
1643 DEBUG(D_acl)
1644 {
1645 debug_printf( "PDKIM [%s] b from mail: ", sig->domain);
1646 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1647 }
1648
b9df1829 1649 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
3045f050 1650 goto NEXT_VERIFY;
80a47a2c 1651
135e9496
JH
1652 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1653 do not have the hash part of the sig algorithm matching */
1654
1655 if (sig->pubkey->hashes)
1656 {
1657 const uschar * list = sig->pubkey->hashes, * ele;
1658 int sep = ':';
1659 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
d73e45df 1660 if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
135e9496
JH
1661 if (!ele)
1662 {
d73e45df
JH
1663 DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
1664 sig->pubkey->hashes,
1665 pdkim_keytypes[sig->keytype],
1666 pdkim_hashes[sig->hashtype].dkim_hashname);
135e9496
JH
1667 sig->verify_status = PDKIM_VERIFY_FAIL;
1668 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1669 goto NEXT_VERIFY;
1670 }
1671 }
1672
3045f050 1673 /* Check the signature */
9b2583c4 1674/*XXX needs extension for non-RSA */
d73e45df
JH
1675 if ((*err = exim_dkim_verify(&vctx,
1676 pdkim_hashes[sig->hashtype].exim_hashmethod,
1677 &hhash, &sig->sighash)))
3045f050 1678 {
b9df1829 1679 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
3045f050
JH
1680 sig->verify_status = PDKIM_VERIFY_FAIL;
1681 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1682 goto NEXT_VERIFY;
ff7ddfd7
TK
1683 }
1684
2592e6c0 1685
4c04137d 1686 /* We have a winner! (if bodyhash was correct earlier) */
3045f050
JH
1687 if (sig->verify_status == PDKIM_VERIFY_NONE)
1688 sig->verify_status = PDKIM_VERIFY_PASS;
1689
1690NEXT_VERIFY:
1691
0d04a285 1692 DEBUG(D_acl)
3045f050 1693 {
0d04a285 1694 debug_printf("PDKIM [%s] signature status: %s",
3045f050
JH
1695 sig->domain, pdkim_verify_status_str(sig->verify_status));
1696 if (sig->verify_ext_status > 0)
0d04a285 1697 debug_printf(" (%s)\n",
3045f050
JH
1698 pdkim_verify_ext_status_str(sig->verify_ext_status));
1699 else
0d04a285 1700 debug_printf("\n");
80a47a2c 1701 }
80a47a2c 1702 }
80a47a2c
TK
1703 }
1704
3045f050
JH
1705/* If requested, set return pointer to signature(s) */
1706if (return_signatures)
1707 *return_signatures = ctx->sig;
80a47a2c 1708
3045f050 1709return PDKIM_OK;
80a47a2c
TK
1710}
1711
1712
1713/* -------------------------------------------------------------------------- */
3045f050
JH
1714
1715DLLEXPORT pdkim_ctx *
e983e85a 1716pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
3045f050 1717{
ca9cb170 1718pdkim_ctx * ctx;
3045f050 1719
ca9cb170 1720ctx = store_get(sizeof(pdkim_ctx));
abe1010c 1721memset(ctx, 0, sizeof(pdkim_ctx));
3045f050 1722
e983e85a 1723if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
ca9cb170 1724ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
3045f050 1725ctx->dns_txt_callback = dns_txt_callback;
80a47a2c 1726
3045f050 1727return ctx;
80a47a2c
TK
1728}
1729
1730
1731/* -------------------------------------------------------------------------- */
80a47a2c 1732
d73e45df 1733/*XXX ? needs extension to cover non-RSA algo? */
9b2583c4 1734
9e70917d
JH
1735DLLEXPORT pdkim_signature *
1736pdkim_init_sign(pdkim_ctx * ctx,
1737 uschar * domain, uschar * selector, uschar * privkey,
1738 uschar * hashname, const uschar ** errstr)
3045f050 1739{
d73e45df 1740int hashtype;
cd1a5fe0 1741pdkim_signature * sig;
80a47a2c 1742
d73e45df 1743if (!domain || !selector || !privkey)
3045f050 1744 return NULL;
80a47a2c 1745
9e70917d 1746/* Allocate & init one signature struct */
80a47a2c 1747
9e70917d 1748sig = store_get(sizeof(pdkim_signature));
abe1010c 1749memset(sig, 0, sizeof(pdkim_signature));
80a47a2c 1750
3045f050 1751sig->bodylength = -1;
80a47a2c 1752
e2e3255a
JH
1753sig->domain = string_copy(US domain);
1754sig->selector = string_copy(US selector);
d73e45df
JH
1755sig->privkey = string_copy(US privkey);
1756/*XXX no keytype yet; comes from privkey */
cb224393 1757
d73e45df
JH
1758for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
1759 if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
1760 { sig->hashtype = hashtype; break; }
1761if (hashtype >= nelem(pdkim_hashes))
7b83389d 1762 {
d73e45df
JH
1763 DEBUG(D_acl)
1764 debug_printf("PDKIM: unrecognised hashname '%s'\n", hashname);
1765 return NULL;
1766 }
1767
1768if (!exim_sha_init(&sig->body_hash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
1769 {
1770 DEBUG(D_acl)
1771 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
7b83389d
JH
1772 return NULL;
1773 }
1774
cd1a5fe0
JH
1775DEBUG(D_acl)
1776 {
1777 pdkim_signature s = *sig;
1778 ev_ctx vctx;
1779
328c5688 1780 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
b9df1829 1781 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
cd1a5fe0 1782 debug_printf("WARNING: bad dkim key in dns\n");
328c5688 1783 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
cd1a5fe0 1784 }
9e70917d 1785return sig;
6ab02e3f 1786}
80a47a2c 1787
f444c2c7 1788
80a47a2c 1789/* -------------------------------------------------------------------------- */
3045f050 1790
9e70917d
JH
1791DLLEXPORT void
1792pdkim_set_optional(pdkim_signature * sig,
1793 char * sign_headers,
1794 char * identity,
80a47a2c
TK
1795 int canon_headers,
1796 int canon_body,
1797 long bodylength,
80a47a2c 1798 unsigned long created,
3045f050
JH
1799 unsigned long expires)
1800{
3045f050 1801if (identity)
e2e3255a 1802 sig->identity = string_copy(US identity);
80a47a2c 1803
ca9cb170
JH
1804sig->sign_headers = string_copy(sign_headers
1805 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
80a47a2c 1806
8ef02a06
JH
1807sig->canon_headers = canon_headers;
1808sig->canon_body = canon_body;
1809sig->bodylength = bodylength;
1810sig->created = created;
1811sig->expires = expires;
80a47a2c 1812
9e70917d
JH
1813return;
1814}
1815
1816
1817
1818void
1819pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
1820 int(*dns_txt_callback)(char *, char *))
1821{
1822memset(ctx, 0, sizeof(pdkim_ctx));
1823ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1824ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1825DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
6ab02e3f 1826}
3045f050 1827
3045f050 1828
2592e6c0
JH
1829void
1830pdkim_init(void)
1831{
9b2583c4 1832exim_dkim_init();
2592e6c0
JH
1833}
1834
1835
1836
f444c2c7 1837#endif /*DISABLE_DKIM*/