Routing: dnslookup and manualroute routers: ipv4_only, ipv4_prefer options. Bug...
[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
TK
241
242/* -------------------------------------------------------------------------- */
3045f050 243
3045f050
JH
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
1296/* -------------------------------------------------------------------------- */
3045f050 1297
cd1a5fe0 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
1eedc10f 1309if ( !(dns_txt_reply = ctx->dns_txt_callback(CS dns_txt_name))
cd1a5fe0
JH
1310 || dns_txt_reply[0] == '\0'
1311 )
1312 {
1313 sig->verify_status = PDKIM_VERIFY_INVALID;
1314 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1315 return NULL;
1316 }
1317
1318DEBUG(D_acl)
1319 {
1320 debug_printf(
1321 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
9e70917d
JH
1322 " %s\n"
1323 " Raw record: ",
1324 dns_txt_name);
cd1a5fe0
JH
1325 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1326 }
1327
1328if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1329 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1330 )
1331 {
1332 sig->verify_status = PDKIM_VERIFY_INVALID;
1333 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1334
1335 DEBUG(D_acl)
1336 {
1337 if (p)
1338 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1339 else
1340 debug_printf(" Error while parsing public key record\n");
1341 debug_printf(
1342 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1343 }
1344 return NULL;
1345 }
1346
1347DEBUG(D_acl) debug_printf(
1348 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1349
1350/* Import public key */
9b2583c4 1351if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
cd1a5fe0 1352 {
b9df1829 1353 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
cd1a5fe0
JH
1354 sig->verify_status = PDKIM_VERIFY_INVALID;
1355 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1356 return NULL;
1357 }
1358
1359return p;
1360}
1361
1362
1363/* -------------------------------------------------------------------------- */
1364
3045f050 1365DLLEXPORT int
b9df1829
JH
1366pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1367 const uschar ** err)
3045f050 1368{
9e70917d 1369pdkim_signature * sig;
3045f050
JH
1370
1371/* Check if we must still flush a (partial) header. If that is the
1372 case, the message has no body, and we must compute a body hash
1373 out of '<CR><LF>' */
acec9514 1374if (ctx->cur_header && ctx->cur_header->ptr > 0)
3045f050 1375 {
9e70917d
JH
1376 blob * rnl = NULL;
1377 int rc;
1378
1379 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1380 return rc;
1381
1382 for (sig = ctx->sig; sig; sig = sig->next)
1383 rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
1384 if (rnl) store_free(rnl);
80a47a2c 1385 }
3045f050 1386else
0d04a285 1387 DEBUG(D_acl) debug_printf(
3045f050 1388 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1389
3045f050 1390/* Build (and/or evaluate) body hash */
ca9cb170 1391pdkim_finish_bodyhash(ctx);
80a47a2c 1392
9e70917d 1393for (sig = ctx->sig; sig; sig = sig->next)
3045f050 1394 {
2592e6c0 1395 hctx hhash_ctx;
ad6f5499 1396 uschar * sig_hdr = US"";
2592e6c0 1397 blob hhash;
acec9514 1398 gstring * hdata = NULL;
2592e6c0 1399
d73e45df 1400 if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
7b83389d 1401 {
d73e45df
JH
1402 DEBUG(D_acl)
1403 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
7b83389d
JH
1404 break;
1405 }
80a47a2c 1406
9e70917d
JH
1407 if (ctx->flags & PDKIM_MODE_SIGN)
1408 DEBUG(D_acl) debug_printf(
1409 "PDKIM >> Headers to be signed: >>>>>>>>>>>>\n"
1410 " %s\n",
1411 sig->sign_headers);
1412
0d04a285 1413 DEBUG(D_acl) debug_printf(
328c5688 1414 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
3045f050 1415
9e70917d 1416
3045f050
JH
1417 /* SIGNING ---------------------------------------------------------------- */
1418 /* When signing, walk through our header list and add them to the hash. As we
8ef02a06
JH
1419 go, construct a list of the header's names to use for the h= parameter.
1420 Then append to that list any remaining header names for which there was no
1421 header to sign. */
3045f050 1422
e983e85a 1423 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1424 {
acec9514 1425 gstring * g = NULL;
3045f050 1426 pdkim_stringlist *p;
8ef02a06
JH
1427 const uschar * l;
1428 uschar * s;
1429 int sep = 0;
3045f050 1430
9e70917d
JH
1431 sig->headernames = NULL; /* Collected signed header names */
1432
3045f050 1433 for (p = sig->headers; p; p = p->next)
9e70917d
JH
1434 {
1435 uschar * rh = p->value;
1436
1437 if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
ab9152ff 1438 {
ab9152ff 1439 /* Collect header names (Note: colon presence is guaranteed here) */
acec9514 1440 g = string_append_listele_n(g, ':', rh, Ustrchr(rh, ':') - rh);
3045f050 1441
9e70917d
JH
1442 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1443 rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */
3045f050 1444
ab9152ff 1445 /* Feed header to the hash algorithm */
e2e3255a 1446 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
f444c2c7 1447
ab9152ff 1448 /* Remember headers block for signing (when the library cannot do incremental) */
acec9514 1449 hdata = exim_dkim_data_append(hdata, rh);
3045f050 1450
ab9152ff
JH
1451 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1452 }
9e70917d 1453 }
8ef02a06 1454
484cc1a9
JH
1455 /* Any headers we wanted to sign but were not present must also be listed.
1456 Ignore elements that have been ticked-off or are marked as never-oversign. */
1457
ca9cb170 1458 l = sig->sign_headers;
8ef02a06 1459 while((s = string_nextinlist(&l, &sep, NULL, 0)))
484cc1a9
JH
1460 {
1461 if (*s == '+') /* skip oversigning marker */
1462 s++;
1463 if (*s != '_' && *s != '=')
acec9514 1464 g = string_append_listele(g, ':', s);
484cc1a9 1465 }
acec9514 1466 sig->headernames = string_from_gstring(g);
ca9cb170
JH
1467
1468 /* Create signature header with b= omitted */
1469 sig_hdr = pdkim_create_header(sig, FALSE);
80a47a2c 1470 }
37f8b554 1471
3045f050
JH
1472 /* VERIFICATION ----------------------------------------------------------- */
1473 /* When verifying, walk through the header name list in the h= parameter and
1474 add the headers to the hash in that order. */
1475 else
1476 {
10c50704 1477 uschar * p = sig->headernames;
2592e6c0
JH
1478 uschar * q;
1479 pdkim_stringlist * hdrs;
3045f050 1480
10c50704 1481 if (p)
3045f050 1482 {
10c50704 1483 /* clear tags */
3045f050 1484 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
10c50704 1485 hdrs->tag = 0;
3045f050 1486
10c50704
JH
1487 p = string_copy(p);
1488 while(1)
1489 {
1490 if ((q = Ustrchr(p, ':')))
1491 *q = '\0';
1492
1493 /*XXX walk the list of headers in same order as received. */
1494 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1495 if ( hdrs->tag == 0
4dc2379a 1496 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
10c50704
JH
1497 && (hdrs->value)[Ustrlen(p)] == ':'
1498 )
1499 {
1500 /* cook header for relaxed canon, or just copy it for simple */
1501
1502 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
ea18931d 1503 ? pdkim_relax_header(hdrs->value, TRUE)
10c50704
JH
1504 : string_copy(CUS hdrs->value);
1505
1506 /* Feed header to the hash algorithm */
1507 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1508
1509 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1510 hdrs->tag = 1;
1511 break;
1512 }
3045f050 1513
10c50704
JH
1514 if (!q) break;
1515 p = q+1;
1516 }
3045f050 1517
10c50704 1518 sig_hdr = string_copy(sig->rawsig_no_b_val);
80a47a2c 1519 }
80a47a2c
TK
1520 }
1521
0d04a285 1522 DEBUG(D_acl) debug_printf(
3045f050 1523 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1524
9e70917d
JH
1525 DEBUG(D_acl)
1526 {
1527 debug_printf(
1528 "PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
1529 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1530 debug_printf(
1531 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1532 }
1533
3045f050
JH
1534 /* Relax header if necessary */
1535 if (sig->canon_headers == PDKIM_CANON_RELAXED)
ea18931d 1536 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
80a47a2c 1537
0d04a285 1538 DEBUG(D_acl)
3045f050 1539 {
0d04a285 1540 debug_printf(
3045f050 1541 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
e2e3255a 1542 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
0d04a285 1543 debug_printf(
3045f050 1544 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1545 }
3045f050
JH
1546
1547 /* Finalize header hash */
e2e3255a 1548 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
2592e6c0 1549 exim_sha_finish(&hhash_ctx, &hhash);
3045f050 1550
f444c2c7
JH
1551 DEBUG(D_acl)
1552 {
9e70917d
JH
1553 debug_printf("PDKIM [%s] Header %s computed: ",
1554 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
2592e6c0 1555 pdkim_hexprint(hhash.data, hhash.len);
80a47a2c
TK
1556 }
1557
9e70917d
JH
1558 /* Remember headers block for signing (when the signing library cannot do
1559 incremental) */
e983e85a 1560 if (ctx->flags & PDKIM_MODE_SIGN)
acec9514 1561 hdata = exim_dkim_data_append(hdata, US sig_hdr);
f444c2c7 1562
3045f050 1563 /* SIGNING ---------------------------------------------------------------- */
e983e85a 1564 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1565 {
2592e6c0 1566 es_ctx sctx;
f444c2c7 1567
d73e45df 1568 /* Import private key, including the keytype */
9b2583c4 1569/*XXX extend for non-RSA algos */
d73e45df 1570 if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx)))
f444c2c7 1571 {
b9df1829 1572 DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
f444c2c7
JH
1573 return PDKIM_ERR_RSA_PRIVKEY;
1574 }
80a47a2c 1575
2592e6c0
JH
1576 /* Do signing. With OpenSSL we are signing the hash of headers just
1577 calculated, with GnuTLS we have to sign an entire block of headers
1578 (due to available interfaces) and it recalculates the hash internally. */
f444c2c7 1579
acec9514
JH
1580#if defined(SIGN_GNUTLS)
1581 hhash.data = hdata->s;
1582 hhash.len = hdata->ptr;
f444c2c7
JH
1583#endif
1584
9b2583c4 1585/*XXX extend for non-RSA algos */
d73e45df
JH
1586 if ((*err = exim_dkim_sign(&sctx,
1587 pdkim_hashes[sig->hashtype].exim_hashmethod,
acec9514 1588 &hhash, &sig->sighash)))
f444c2c7 1589 {
b9df1829 1590 DEBUG(D_acl) debug_printf("signing: %s\n", *err);
f444c2c7
JH
1591 return PDKIM_ERR_RSA_SIGNING;
1592 }
80a47a2c 1593
0d04a285 1594 DEBUG(D_acl)
3045f050 1595 {
0d04a285 1596 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
dcd03763 1597 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
80a47a2c 1598 }
80a47a2c 1599
ca9cb170 1600 sig->signature_header = pdkim_create_header(sig, TRUE);
80a47a2c 1601 }
80a47a2c 1602
3045f050
JH
1603 /* VERIFICATION ----------------------------------------------------------- */
1604 else
1605 {
2592e6c0 1606 ev_ctx vctx;
3045f050 1607
07eeb4df 1608 /* Make sure we have all required signature tags */
1609 if (!( sig->domain && *sig->domain
1610 && sig->selector && *sig->selector
1611 && sig->headernames && *sig->headernames
1612 && sig->bodyhash.data
dcd03763 1613 && sig->sighash.data
d73e45df
JH
1614 && sig->keytype >= 0
1615 && sig->hashtype >= 0
07eeb4df 1616 && sig->version
1617 ) )
1618 {
1619 sig->verify_status = PDKIM_VERIFY_INVALID;
1620 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1621
1622 DEBUG(D_acl) debug_printf(
1623 " Error in DKIM-Signature header: tags missing or invalid\n"
1624 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1625 goto NEXT_VERIFY;
1626 }
1627
1628 /* Make sure sig uses supported DKIM version (only v1) */
1629 if (sig->version != 1)
1630 {
1631 sig->verify_status = PDKIM_VERIFY_INVALID;
1632 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1633
1634 DEBUG(D_acl) debug_printf(
1635 " Error in DKIM-Signature header: unsupported DKIM version\n"
1636 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1637 goto NEXT_VERIFY;
1638 }
1639
9e70917d
JH
1640 DEBUG(D_acl)
1641 {
1642 debug_printf( "PDKIM [%s] b from mail: ", sig->domain);
1643 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1644 }
1645
b9df1829 1646 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
3045f050 1647 goto NEXT_VERIFY;
80a47a2c 1648
135e9496
JH
1649 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1650 do not have the hash part of the sig algorithm matching */
1651
1652 if (sig->pubkey->hashes)
1653 {
1654 const uschar * list = sig->pubkey->hashes, * ele;
1655 int sep = ':';
1656 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
d73e45df 1657 if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
135e9496
JH
1658 if (!ele)
1659 {
d73e45df
JH
1660 DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
1661 sig->pubkey->hashes,
1662 pdkim_keytypes[sig->keytype],
1663 pdkim_hashes[sig->hashtype].dkim_hashname);
135e9496
JH
1664 sig->verify_status = PDKIM_VERIFY_FAIL;
1665 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1666 goto NEXT_VERIFY;
1667 }
1668 }
1669
3045f050 1670 /* Check the signature */
9b2583c4 1671/*XXX needs extension for non-RSA */
d73e45df
JH
1672 if ((*err = exim_dkim_verify(&vctx,
1673 pdkim_hashes[sig->hashtype].exim_hashmethod,
1674 &hhash, &sig->sighash)))
3045f050 1675 {
b9df1829 1676 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
3045f050
JH
1677 sig->verify_status = PDKIM_VERIFY_FAIL;
1678 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1679 goto NEXT_VERIFY;
ff7ddfd7
TK
1680 }
1681
2592e6c0 1682
4c04137d 1683 /* We have a winner! (if bodyhash was correct earlier) */
3045f050
JH
1684 if (sig->verify_status == PDKIM_VERIFY_NONE)
1685 sig->verify_status = PDKIM_VERIFY_PASS;
1686
1687NEXT_VERIFY:
1688
0d04a285 1689 DEBUG(D_acl)
3045f050 1690 {
0d04a285 1691 debug_printf("PDKIM [%s] signature status: %s",
3045f050
JH
1692 sig->domain, pdkim_verify_status_str(sig->verify_status));
1693 if (sig->verify_ext_status > 0)
0d04a285 1694 debug_printf(" (%s)\n",
3045f050
JH
1695 pdkim_verify_ext_status_str(sig->verify_ext_status));
1696 else
0d04a285 1697 debug_printf("\n");
80a47a2c 1698 }
80a47a2c 1699 }
80a47a2c
TK
1700 }
1701
3045f050
JH
1702/* If requested, set return pointer to signature(s) */
1703if (return_signatures)
1704 *return_signatures = ctx->sig;
80a47a2c 1705
3045f050 1706return PDKIM_OK;
80a47a2c
TK
1707}
1708
1709
1710/* -------------------------------------------------------------------------- */
3045f050
JH
1711
1712DLLEXPORT pdkim_ctx *
1eedc10f 1713pdkim_init_verify(uschar * (*dns_txt_callback)(char *), BOOL dot_stuffing)
3045f050 1714{
ca9cb170 1715pdkim_ctx * ctx;
3045f050 1716
ca9cb170 1717ctx = store_get(sizeof(pdkim_ctx));
abe1010c 1718memset(ctx, 0, sizeof(pdkim_ctx));
3045f050 1719
e983e85a 1720if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
ca9cb170 1721ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
3045f050 1722ctx->dns_txt_callback = dns_txt_callback;
80a47a2c 1723
3045f050 1724return ctx;
80a47a2c
TK
1725}
1726
1727
1728/* -------------------------------------------------------------------------- */
80a47a2c 1729
d73e45df 1730/*XXX ? needs extension to cover non-RSA algo? */
9b2583c4 1731
9e70917d
JH
1732DLLEXPORT pdkim_signature *
1733pdkim_init_sign(pdkim_ctx * ctx,
1734 uschar * domain, uschar * selector, uschar * privkey,
1735 uschar * hashname, const uschar ** errstr)
3045f050 1736{
d73e45df 1737int hashtype;
cd1a5fe0 1738pdkim_signature * sig;
80a47a2c 1739
d73e45df 1740if (!domain || !selector || !privkey)
3045f050 1741 return NULL;
80a47a2c 1742
9e70917d 1743/* Allocate & init one signature struct */
80a47a2c 1744
9e70917d 1745sig = store_get(sizeof(pdkim_signature));
abe1010c 1746memset(sig, 0, sizeof(pdkim_signature));
80a47a2c 1747
3045f050 1748sig->bodylength = -1;
80a47a2c 1749
e2e3255a
JH
1750sig->domain = string_copy(US domain);
1751sig->selector = string_copy(US selector);
d73e45df
JH
1752sig->privkey = string_copy(US privkey);
1753/*XXX no keytype yet; comes from privkey */
cb224393 1754
d73e45df
JH
1755for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
1756 if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
1757 { sig->hashtype = hashtype; break; }
1758if (hashtype >= nelem(pdkim_hashes))
7b83389d 1759 {
d73e45df
JH
1760 DEBUG(D_acl)
1761 debug_printf("PDKIM: unrecognised hashname '%s'\n", hashname);
1762 return NULL;
1763 }
1764
1765if (!exim_sha_init(&sig->body_hash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
1766 {
1767 DEBUG(D_acl)
1768 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
7b83389d
JH
1769 return NULL;
1770 }
1771
cd1a5fe0
JH
1772DEBUG(D_acl)
1773 {
1774 pdkim_signature s = *sig;
1775 ev_ctx vctx;
1776
328c5688 1777 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
b9df1829 1778 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
cd1a5fe0 1779 debug_printf("WARNING: bad dkim key in dns\n");
328c5688 1780 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
cd1a5fe0 1781 }
9e70917d 1782return sig;
6ab02e3f 1783}
80a47a2c 1784
f444c2c7 1785
80a47a2c 1786/* -------------------------------------------------------------------------- */
3045f050 1787
9e70917d
JH
1788DLLEXPORT void
1789pdkim_set_optional(pdkim_signature * sig,
1790 char * sign_headers,
1791 char * identity,
80a47a2c
TK
1792 int canon_headers,
1793 int canon_body,
1794 long bodylength,
80a47a2c 1795 unsigned long created,
3045f050
JH
1796 unsigned long expires)
1797{
3045f050 1798if (identity)
e2e3255a 1799 sig->identity = string_copy(US identity);
80a47a2c 1800
ca9cb170
JH
1801sig->sign_headers = string_copy(sign_headers
1802 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
80a47a2c 1803
8ef02a06
JH
1804sig->canon_headers = canon_headers;
1805sig->canon_body = canon_body;
1806sig->bodylength = bodylength;
1807sig->created = created;
1808sig->expires = expires;
80a47a2c 1809
9e70917d
JH
1810return;
1811}
1812
1813
1814
1815void
1816pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
1eedc10f 1817 uschar * (*dns_txt_callback)(char *))
9e70917d
JH
1818{
1819memset(ctx, 0, sizeof(pdkim_ctx));
1820ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1821ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1822DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
6ab02e3f 1823}
3045f050 1824
3045f050 1825
2592e6c0
JH
1826void
1827pdkim_init(void)
1828{
9b2583c4 1829exim_dkim_init();
2592e6c0
JH
1830}
1831
1832
1833
f444c2c7 1834#endif /*DISABLE_DKIM*/