OpenSSL: add detail to certname verify fail log line
[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
TK
232
233/* -------------------------------------------------------------------------- */
3045f050 234
3045f050
JH
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
40c90bca 731 relaxed_data = store_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
40c90bca 775if (relaxed_data) store_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
10c50704 1017else for (p = 0; p<len; p++)
3045f050 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;
3045f050
JH
1312
1313/* Check if we must still flush a (partial) header. If that is the
1314 case, the message has no body, and we must compute a body hash
1315 out of '<CR><LF>' */
ca9cb170 1316if (ctx->cur_header && ctx->cur_header_len)
3045f050
JH
1317 {
1318 int rc = pdkim_header_complete(ctx);
1319 if (rc != PDKIM_OK) return rc;
1320 pdkim_update_bodyhash(ctx, "\r\n", 2);
80a47a2c 1321 }
3045f050 1322else
0d04a285 1323 DEBUG(D_acl) debug_printf(
3045f050 1324 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1325
3045f050 1326/* Build (and/or evaluate) body hash */
ca9cb170 1327pdkim_finish_bodyhash(ctx);
80a47a2c 1328
3045f050
JH
1329while (sig)
1330 {
2592e6c0
JH
1331 BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
1332 hctx hhash_ctx;
ad6f5499 1333 uschar * sig_hdr = US"";
2592e6c0
JH
1334 blob hhash;
1335 blob hdata;
cb224393 1336 int hdata_alloc = 0;
cb224393 1337
2592e6c0
JH
1338 hdata.data = NULL;
1339 hdata.len = 0;
1340
1ed59855 1341 exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256);
80a47a2c 1342
0d04a285
JH
1343 DEBUG(D_acl) debug_printf(
1344 "PDKIM >> Hashed header data, canonicalized, in sequence >>>>>>>>>>>>>>\n");
3045f050
JH
1345
1346 /* SIGNING ---------------------------------------------------------------- */
1347 /* When signing, walk through our header list and add them to the hash. As we
8ef02a06
JH
1348 go, construct a list of the header's names to use for the h= parameter.
1349 Then append to that list any remaining header names for which there was no
1350 header to sign. */
3045f050 1351
e983e85a 1352 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1353 {
10c50704
JH
1354 uschar * headernames = NULL; /* Collected signed header names */
1355 int hs = 0, hl = 0;
3045f050 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;
ca9cb170
JH
1397
1398 /* Create signature header with b= omitted */
1399 sig_hdr = pdkim_create_header(sig, FALSE);
80a47a2c 1400 }
37f8b554 1401
3045f050
JH
1402 /* VERIFICATION ----------------------------------------------------------- */
1403 /* When verifying, walk through the header name list in the h= parameter and
1404 add the headers to the hash in that order. */
1405 else
1406 {
10c50704 1407 uschar * p = sig->headernames;
2592e6c0
JH
1408 uschar * q;
1409 pdkim_stringlist * hdrs;
3045f050 1410
10c50704 1411 if (p)
3045f050 1412 {
10c50704 1413 /* clear tags */
3045f050 1414 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
10c50704 1415 hdrs->tag = 0;
3045f050 1416
10c50704
JH
1417 p = string_copy(p);
1418 while(1)
1419 {
1420 if ((q = Ustrchr(p, ':')))
1421 *q = '\0';
1422
1423 /*XXX walk the list of headers in same order as received. */
1424 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1425 if ( hdrs->tag == 0
4dc2379a 1426 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
10c50704
JH
1427 && (hdrs->value)[Ustrlen(p)] == ':'
1428 )
1429 {
1430 /* cook header for relaxed canon, or just copy it for simple */
1431
1432 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1433 ? pdkim_relax_header(hdrs->value, 1)
1434 : string_copy(CUS hdrs->value);
1435
1436 /* Feed header to the hash algorithm */
1437 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1438
1439 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1440 hdrs->tag = 1;
1441 break;
1442 }
3045f050 1443
10c50704
JH
1444 if (!q) break;
1445 p = q+1;
1446 }
3045f050 1447
10c50704 1448 sig_hdr = string_copy(sig->rawsig_no_b_val);
80a47a2c 1449 }
80a47a2c
TK
1450 }
1451
0d04a285 1452 DEBUG(D_acl) debug_printf(
3045f050 1453 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1454
3045f050
JH
1455 /* Relax header if necessary */
1456 if (sig->canon_headers == PDKIM_CANON_RELAXED)
ca9cb170 1457 sig_hdr = pdkim_relax_header(sig_hdr, 0);
80a47a2c 1458
0d04a285 1459 DEBUG(D_acl)
3045f050 1460 {
0d04a285 1461 debug_printf(
3045f050 1462 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
e2e3255a 1463 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
0d04a285 1464 debug_printf(
3045f050 1465 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1466 }
3045f050
JH
1467
1468 /* Finalize header hash */
e2e3255a 1469 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
2592e6c0 1470 exim_sha_finish(&hhash_ctx, &hhash);
3045f050 1471
f444c2c7
JH
1472 DEBUG(D_acl)
1473 {
1474 debug_printf("PDKIM [%s] hh computed: ", sig->domain);
2592e6c0 1475 pdkim_hexprint(hhash.data, hhash.len);
80a47a2c
TK
1476 }
1477
2592e6c0 1478 /* Remember headers block for signing (when the library cannot do incremental) */
e983e85a 1479 if (ctx->flags & PDKIM_MODE_SIGN)
b78006ac 1480 (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
f444c2c7 1481
3045f050 1482 /* SIGNING ---------------------------------------------------------------- */
e983e85a 1483 if (ctx->flags & PDKIM_MODE_SIGN)
3045f050 1484 {
2592e6c0
JH
1485 es_ctx sctx;
1486 const uschar * errstr;
f444c2c7
JH
1487
1488 /* Import private key */
b78006ac 1489 if ((errstr = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
f444c2c7 1490 {
2592e6c0 1491 DEBUG(D_acl) debug_printf("signing_init: %s\n", errstr);
f444c2c7
JH
1492 return PDKIM_ERR_RSA_PRIVKEY;
1493 }
80a47a2c 1494
2592e6c0
JH
1495 /* Do signing. With OpenSSL we are signing the hash of headers just
1496 calculated, with GnuTLS we have to sign an entire block of headers
1497 (due to available interfaces) and it recalculates the hash internally. */
f444c2c7 1498
2592e6c0
JH
1499#if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1500 hdata = hhash;
f444c2c7
JH
1501#endif
1502
2592e6c0 1503 if ((errstr = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sigdata)))
f444c2c7 1504 {
2592e6c0 1505 DEBUG(D_acl) debug_printf("signing: %s\n", errstr);
f444c2c7
JH
1506 return PDKIM_ERR_RSA_SIGNING;
1507 }
80a47a2c 1508
0d04a285 1509 DEBUG(D_acl)
3045f050 1510 {
0d04a285 1511 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
2592e6c0 1512 pdkim_hexprint(sig->sigdata.data, sig->sigdata.len);
80a47a2c 1513 }
80a47a2c 1514
ca9cb170 1515 sig->signature_header = pdkim_create_header(sig, TRUE);
80a47a2c 1516 }
80a47a2c 1517
3045f050
JH
1518 /* VERIFICATION ----------------------------------------------------------- */
1519 else
1520 {
2592e6c0
JH
1521 ev_ctx vctx;
1522 const uschar * errstr;
3045f050 1523
ca9cb170 1524 uschar *dns_txt_name, *dns_txt_reply;
f444c2c7 1525
07eeb4df 1526 /* Make sure we have all required signature tags */
1527 if (!( sig->domain && *sig->domain
1528 && sig->selector && *sig->selector
1529 && sig->headernames && *sig->headernames
1530 && sig->bodyhash.data
1531 && sig->sigdata.data
1532 && sig->algo > -1
1533 && sig->version
1534 ) )
1535 {
1536 sig->verify_status = PDKIM_VERIFY_INVALID;
1537 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1538
1539 DEBUG(D_acl) debug_printf(
1540 " Error in DKIM-Signature header: tags missing or invalid\n"
1541 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1542 goto NEXT_VERIFY;
1543 }
1544
1545 /* Make sure sig uses supported DKIM version (only v1) */
1546 if (sig->version != 1)
1547 {
1548 sig->verify_status = PDKIM_VERIFY_INVALID;
1549 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1550
1551 DEBUG(D_acl) debug_printf(
1552 " Error in DKIM-Signature header: unsupported DKIM version\n"
1553 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1554 goto NEXT_VERIFY;
1555 }
1556
f444c2c7 1557 /* Fetch public key for signing domain, from DNS */
3045f050 1558
ca9cb170
JH
1559 dns_txt_name = string_sprintf("%s._domainkey.%s.",
1560 sig->selector, sig->domain);
80a47a2c 1561
ca9cb170 1562 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
3045f050 1563 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
3045f050 1564
ca9cb170 1565 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
3045f050
JH
1566 || dns_txt_reply[0] == '\0')
1567 {
1568 sig->verify_status = PDKIM_VERIFY_INVALID;
1569 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1570 goto NEXT_VERIFY;
80a47a2c
TK
1571 }
1572
0d04a285 1573 DEBUG(D_acl)
3045f050 1574 {
0d04a285 1575 debug_printf(
2592e6c0
JH
1576 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1577 " Raw record: ");
ca9cb170 1578 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
80a47a2c 1579 }
3045f050 1580
e2e3255a 1581 if (!(sig->pubkey = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply)))
3045f050
JH
1582 {
1583 sig->verify_status = PDKIM_VERIFY_INVALID;
df3def24 1584 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
3045f050 1585
0d04a285
JH
1586 DEBUG(D_acl) debug_printf(
1587 " Error while parsing public key record\n"
3045f050 1588 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
3045f050 1589 goto NEXT_VERIFY;
80a47a2c
TK
1590 }
1591
0d04a285 1592 DEBUG(D_acl) debug_printf(
2592e6c0 1593 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
3045f050 1594
f444c2c7 1595 /* Import public key */
2592e6c0 1596 if ((errstr = exim_rsa_verify_init(&sig->pubkey->key, &vctx)))
3045f050 1597 {
2592e6c0 1598 DEBUG(D_acl) debug_printf("verify_init: %s\n", errstr);
3045f050 1599 sig->verify_status = PDKIM_VERIFY_INVALID;
df3def24 1600 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
3045f050 1601 goto NEXT_VERIFY;
80a47a2c
TK
1602 }
1603
3045f050 1604 /* Check the signature */
2592e6c0 1605 if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sigdata)))
3045f050 1606 {
2592e6c0 1607 DEBUG(D_acl) debug_printf("headers verify: %s\n", errstr);
3045f050
JH
1608 sig->verify_status = PDKIM_VERIFY_FAIL;
1609 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1610 goto NEXT_VERIFY;
ff7ddfd7
TK
1611 }
1612
2592e6c0 1613
3045f050
JH
1614 /* We have a winner! (if bodydhash was correct earlier) */
1615 if (sig->verify_status == PDKIM_VERIFY_NONE)
1616 sig->verify_status = PDKIM_VERIFY_PASS;
1617
1618NEXT_VERIFY:
1619
0d04a285 1620 DEBUG(D_acl)
3045f050 1621 {
0d04a285 1622 debug_printf("PDKIM [%s] signature status: %s",
3045f050
JH
1623 sig->domain, pdkim_verify_status_str(sig->verify_status));
1624 if (sig->verify_ext_status > 0)
0d04a285 1625 debug_printf(" (%s)\n",
3045f050
JH
1626 pdkim_verify_ext_status_str(sig->verify_ext_status));
1627 else
0d04a285 1628 debug_printf("\n");
80a47a2c 1629 }
80a47a2c
TK
1630 }
1631
3045f050 1632 sig = sig->next;
80a47a2c
TK
1633 }
1634
3045f050
JH
1635/* If requested, set return pointer to signature(s) */
1636if (return_signatures)
1637 *return_signatures = ctx->sig;
80a47a2c 1638
3045f050 1639return PDKIM_OK;
80a47a2c
TK
1640}
1641
1642
1643/* -------------------------------------------------------------------------- */
3045f050
JH
1644
1645DLLEXPORT pdkim_ctx *
e983e85a 1646pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
3045f050 1647{
ca9cb170 1648pdkim_ctx * ctx;
3045f050 1649
ca9cb170 1650ctx = store_get(sizeof(pdkim_ctx));
abe1010c 1651memset(ctx, 0, sizeof(pdkim_ctx));
3045f050 1652
e983e85a 1653if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
ca9cb170 1654ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
3045f050 1655ctx->dns_txt_callback = dns_txt_callback;
80a47a2c 1656
3045f050 1657return ctx;
80a47a2c
TK
1658}
1659
1660
1661/* -------------------------------------------------------------------------- */
80a47a2c 1662
3045f050 1663DLLEXPORT pdkim_ctx *
e983e85a
JH
1664pdkim_init_sign(char *domain, char *selector, char *rsa_privkey, int algo,
1665 BOOL dot_stuffed)
3045f050
JH
1666{
1667pdkim_ctx *ctx;
1668pdkim_signature *sig;
80a47a2c 1669
3045f050
JH
1670if (!domain || !selector || !rsa_privkey)
1671 return NULL;
80a47a2c 1672
ca9cb170 1673ctx = store_get(sizeof(pdkim_ctx));
abe1010c 1674memset(ctx, 0, sizeof(pdkim_ctx));
80a47a2c 1675
e983e85a 1676ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
ca9cb170 1677ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
80a47a2c 1678
ca9cb170 1679sig = store_get(sizeof(pdkim_signature));
abe1010c 1680memset(sig, 0, sizeof(pdkim_signature));
80a47a2c 1681
3045f050 1682sig->bodylength = -1;
3045f050 1683ctx->sig = sig;
80a47a2c 1684
e2e3255a
JH
1685sig->domain = string_copy(US domain);
1686sig->selector = string_copy(US selector);
1687sig->rsa_privkey = string_copy(US rsa_privkey);
2592e6c0 1688sig->algo = algo;
cb224393 1689
1ed59855 1690exim_sha_init(&sig->body_hash, algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
3045f050 1691return ctx;
6ab02e3f 1692}
80a47a2c 1693
f444c2c7 1694
80a47a2c 1695/* -------------------------------------------------------------------------- */
3045f050
JH
1696
1697DLLEXPORT int
1698pdkim_set_optional(pdkim_ctx *ctx,
80a47a2c
TK
1699 char *sign_headers,
1700 char *identity,
1701 int canon_headers,
1702 int canon_body,
1703 long bodylength,
80a47a2c 1704 unsigned long created,
3045f050
JH
1705 unsigned long expires)
1706{
8ef02a06
JH
1707pdkim_signature * sig = ctx->sig;
1708
3045f050 1709if (identity)
e2e3255a 1710 sig->identity = string_copy(US identity);
80a47a2c 1711
ca9cb170
JH
1712sig->sign_headers = string_copy(sign_headers
1713 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
80a47a2c 1714
8ef02a06
JH
1715sig->canon_headers = canon_headers;
1716sig->canon_body = canon_body;
1717sig->bodylength = bodylength;
1718sig->created = created;
1719sig->expires = expires;
80a47a2c 1720
3045f050 1721return PDKIM_OK;
6ab02e3f 1722}
3045f050 1723
3045f050 1724
2592e6c0
JH
1725void
1726pdkim_init(void)
1727{
1728exim_rsa_init();
1729}
1730
1731
1732
f444c2c7 1733#endif /*DISABLE_DKIM*/