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