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