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