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