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