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