tidying: coverity issues
[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. */
763q--;
764while (q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
765 *q = '\0'; q--; /*XXX questionable code layout; possible bug */
80a47a2c 766
0d04a285 767DEBUG(D_acl)
3045f050 768 {
0d04a285 769 debug_printf(
3045f050 770 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
b78006ac 771 pdkim_quoteprint(US sig->rawsig_no_b_val, strlen(sig->rawsig_no_b_val));
0d04a285 772 debug_printf(
b78006ac 773 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sigdata.len*8);
0d04a285 774 debug_printf(
3045f050 775 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 776 }
80a47a2c 777
2592e6c0 778exim_sha_init(&sig->body_hash, sig->algo == PDKIM_ALGO_RSA_SHA1);
3045f050 779return sig;
80a47a2c
TK
780}
781
782
783/* -------------------------------------------------------------------------- */
80a47a2c 784
f444c2c7 785static pdkim_pubkey *
3045f050
JH
786pdkim_parse_pubkey_record(pdkim_ctx *ctx, char *raw_record)
787{
788pdkim_pubkey *pub;
789char *p;
790pdkim_str *cur_tag = NULL;
791pdkim_str *cur_val = NULL;
792int where = PDKIM_HDR_LIMBO;
80a47a2c 793
3045f050 794if (!(pub = malloc(sizeof(pdkim_pubkey)))) return NULL;
abe1010c 795memset(pub, 0, sizeof(pdkim_pubkey));
80a47a2c 796
3045f050
JH
797for (p = raw_record; ; p++)
798 {
799 char c = *p;
80a47a2c 800
3045f050
JH
801 /* Ignore FWS */
802 if (c == '\r' || c == '\n')
803 goto NEXT_CHAR;
80a47a2c 804
3045f050
JH
805 if (where == PDKIM_HDR_LIMBO)
806 {
807 /* In limbo, just wait for a tag-char to appear */
808 if (!(c >= 'a' && c <= 'z'))
809 goto NEXT_CHAR;
80a47a2c 810
3045f050 811 where = PDKIM_HDR_TAG;
80a47a2c
TK
812 }
813
3045f050
JH
814 if (where == PDKIM_HDR_TAG)
815 {
816 if (!cur_tag)
817 cur_tag = pdkim_strnew(NULL);
80a47a2c 818
3045f050
JH
819 if (c >= 'a' && c <= 'z')
820 pdkim_strncat(cur_tag, p, 1);
80a47a2c 821
3045f050
JH
822 if (c == '=')
823 {
824 where = PDKIM_HDR_VALUE;
825 goto NEXT_CHAR;
80a47a2c
TK
826 }
827 }
828
3045f050
JH
829 if (where == PDKIM_HDR_VALUE)
830 {
831 if (!cur_val)
832 cur_val = pdkim_strnew(NULL);
833
3045f050
JH
834 if (c == ';' || c == '\0')
835 {
836 if (cur_tag->len > 0)
837 {
838 pdkim_strtrim(cur_val);
0d04a285 839 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->str, cur_val->str);
3045f050
JH
840
841 switch (cur_tag->str[0])
842 {
843 case 'v':
844 /* This tag isn't evaluated because:
845 - We only support version DKIM1.
846 - Which is the default for this value (set below)
847 - Other versions are currently not specified. */
848 break;
849 case 'h':
850 pub->hashes = strdup(cur_val->str); break;
851 case 'g':
852 pub->granularity = strdup(cur_val->str); break;
853 case 'n':
854 pub->notes = pdkim_decode_qp(cur_val->str); break;
855 case 'p':
2592e6c0
JH
856 pdkim_decode_base64(US cur_val->str, &pub->key);
857 break;
3045f050
JH
858 case 'k':
859 pub->hashes = strdup(cur_val->str); break;
860 case 's':
861 pub->srvtype = strdup(cur_val->str); break;
862 case 't':
abe1010c
JH
863 if (strchr(cur_val->str, 'y') != NULL) pub->testing = 1;
864 if (strchr(cur_val->str, 's') != NULL) pub->no_subdomaining = 1;
3045f050
JH
865 break;
866 default:
0d04a285 867 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
3045f050
JH
868 break;
869 }
870 }
871 pdkim_strclear(cur_tag);
872 pdkim_strclear(cur_val);
873 where = PDKIM_HDR_LIMBO;
80a47a2c 874 }
3045f050
JH
875 else
876 pdkim_strncat(cur_val, p, 1);
80a47a2c
TK
877 }
878
3045f050
JH
879NEXT_CHAR:
880 if (c == '\0') break;
80a47a2c
TK
881 }
882
3045f050
JH
883/* Set fallback defaults */
884if (!pub->version ) pub->version = strdup(PDKIM_PUB_RECORD_VERSION);
885if (!pub->granularity) pub->granularity = strdup("*");
886if (!pub->keytype ) pub->keytype = strdup("rsa");
887if (!pub->srvtype ) pub->srvtype = strdup("*");
80a47a2c 888
3045f050 889/* p= is required */
2592e6c0 890if (pub->key.data)
80a47a2c 891 return pub;
3045f050
JH
892
893pdkim_free_pubkey(pub);
894return NULL;
80a47a2c
TK
895}
896
897
898/* -------------------------------------------------------------------------- */
3045f050 899
f444c2c7 900static int
3045f050
JH
901pdkim_update_bodyhash(pdkim_ctx *ctx, const char *data, int len)
902{
903pdkim_signature *sig = ctx->sig;
904/* Cache relaxed version of data */
b78006ac
JH
905uschar *relaxed_data = NULL;
906int relaxed_len = 0;
3045f050
JH
907
908/* Traverse all signatures, updating their hashes. */
909while (sig)
910 {
911 /* Defaults to simple canon (no further treatment necessary) */
b78006ac
JH
912 const uschar *canon_data = CUS data;
913 int canon_len = len;
3045f050
JH
914
915 if (sig->canon_body == PDKIM_CANON_RELAXED)
916 {
917 /* Relax the line if not done already */
918 if (!relaxed_data)
919 {
920 BOOL seen_wsp = FALSE;
921 const char *p;
922 int q = 0;
923
924 if (!(relaxed_data = malloc(len+1)))
925 return PDKIM_ERR_OOM;
926
927 for (p = data; *p; p++)
928 {
929 char c = *p;
930 if (c == '\r')
931 {
932 if (q > 0 && relaxed_data[q-1] == ' ')
933 q--;
934 }
935 else if (c == '\t' || c == ' ')
936 {
937 c = ' '; /* Turns WSP into SP */
938 if (seen_wsp)
939 continue;
940 seen_wsp = TRUE;
941 }
942 else
943 seen_wsp = FALSE;
944 relaxed_data[q++] = c;
945 }
946 relaxed_data[q] = '\0';
947 relaxed_len = q;
80a47a2c 948 }
3045f050
JH
949 canon_data = relaxed_data;
950 canon_len = relaxed_len;
80a47a2c
TK
951 }
952
3045f050
JH
953 /* Make sure we don't exceed the to-be-signed body length */
954 if ( sig->bodylength >= 0
955 && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
956 )
957 canon_len = sig->bodylength - sig->signed_body_bytes;
80a47a2c 958
3045f050
JH
959 if (canon_len > 0)
960 {
b78006ac 961 exim_sha_update(&sig->body_hash, CCS canon_data, canon_len);
3045f050 962 sig->signed_body_bytes += canon_len;
2592e6c0 963 DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
80a47a2c
TK
964 }
965
3045f050 966 sig = sig->next;
80a47a2c
TK
967 }
968
3045f050
JH
969if (relaxed_data) free(relaxed_data);
970return PDKIM_OK;
6ab02e3f 971}
80a47a2c
TK
972
973
974/* -------------------------------------------------------------------------- */
80a47a2c 975
f444c2c7 976static int
3045f050
JH
977pdkim_finish_bodyhash(pdkim_ctx *ctx)
978{
f4d091fb 979pdkim_signature *sig;
80a47a2c 980
3045f050 981/* Traverse all signatures */
f4d091fb 982for (sig = ctx->sig; sig; sig = sig->next)
3045f050 983 { /* Finish hashes */
2592e6c0
JH
984 blob bh;
985
986 exim_sha_finish(&sig->body_hash, &bh);
3045f050 987
0d04a285 988 DEBUG(D_acl)
3045f050 989 {
0d04a285
JH
990 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
991 "PDKIM [%s] bh computed: ",
992 sig->domain, sig->signed_body_bytes, sig->domain);
b78006ac 993 pdkim_hexprint(CUS bh.data, bh.len);
80a47a2c 994 }
3045f050
JH
995
996 /* SIGNING -------------------------------------------------------------- */
997 if (ctx->mode == PDKIM_MODE_SIGN)
998 {
2592e6c0 999 sig->bodyhash = bh;
3045f050
JH
1000
1001 /* If bodylength limit is set, and we have received less bytes
1002 than the requested amount, effectively remove the limit tag. */
1003 if (sig->signed_body_bytes < sig->bodylength)
1004 sig->bodylength = -1;
80a47a2c 1005 }
3045f050
JH
1006
1007 /* VERIFICATION --------------------------------------------------------- */
1008 else
1009 {
1010 /* Compare bodyhash */
2592e6c0 1011 if (memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
3045f050 1012 {
0d04a285 1013 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
80a47a2c 1014 }
3045f050
JH
1015 else
1016 {
0d04a285 1017 DEBUG(D_acl)
3045f050 1018 {
0d04a285 1019 debug_printf("PDKIM [%s] bh signature: ", sig->domain);
2592e6c0
JH
1020 pdkim_hexprint(sig->bodyhash.data,
1021 exim_sha_hashlen(&sig->body_hash));
0d04a285 1022 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
3045f050 1023 }
3045f050
JH
1024 sig->verify_status = PDKIM_VERIFY_FAIL;
1025 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
80a47a2c
TK
1026 }
1027 }
80a47a2c
TK
1028 }
1029
3045f050 1030return PDKIM_OK;
6ab02e3f 1031}
80a47a2c
TK
1032
1033
1034
1035/* -------------------------------------------------------------------------- */
1036/* Callback from pdkim_feed below for processing complete body lines */
3045f050 1037
0d04a285 1038static int
3045f050
JH
1039pdkim_bodyline_complete(pdkim_ctx *ctx)
1040{
1041char *p = ctx->linebuf;
1042int n = ctx->linebuf_offset;
c14470c3 1043pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
3045f050
JH
1044
1045/* Ignore extra data if we've seen the end-of-data marker */
1046if (ctx->seen_eod) goto BAIL;
1047
1048/* We've always got one extra byte to stuff a zero ... */
0d04a285 1049ctx->linebuf[ctx->linebuf_offset] = '\0';
3045f050 1050
0d04a285
JH
1051/* Terminate on EOD marker */
1052if (memcmp(p, ".\r\n", 3) == 0)
3045f050 1053 {
0d04a285
JH
1054 /* In simple body mode, if any empty lines were buffered,
1055 replace with one. rfc 4871 3.4.3 */
1056 /*XXX checking the signed-body-bytes is a gross hack; I think
1057 it indicates that all linebreaks should be buffered, including
1058 the one terminating a text line */
1059 if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
1060 && sig->signed_body_bytes == 0
1061 && ctx->num_buffered_crlf > 0
1062 )
1063 pdkim_update_bodyhash(ctx, "\r\n", 2);
1064
1065 ctx->seen_eod = TRUE;
1066 goto BAIL;
1067 }
1068/* Unstuff dots */
1069if (memcmp(p, "..", 2) == 0)
1070 {
1071 p++;
1072 n--;
80a47a2c
TK
1073 }
1074
3045f050
JH
1075/* Empty lines need to be buffered until we find a non-empty line */
1076if (memcmp(p, "\r\n", 2) == 0)
1077 {
1078 ctx->num_buffered_crlf++;
1079 goto BAIL;
80a47a2c
TK
1080 }
1081
c14470c3 1082if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
3045f050
JH
1083 {
1084 /* Lines with just spaces need to be buffered too */
1085 char *check = p;
1086 while (memcmp(check, "\r\n", 2) != 0)
1087 {
1088 char c = *check;
6a11a9e6 1089
3045f050
JH
1090 if (c != '\t' && c != ' ')
1091 goto PROCESS;
1092 check++;
6a11a9e6
JH
1093 }
1094
3045f050
JH
1095 ctx->num_buffered_crlf++;
1096 goto BAIL;
1097}
6a11a9e6 1098
3045f050
JH
1099PROCESS:
1100/* At this point, we have a non-empty line, so release the buffered ones. */
1101while (ctx->num_buffered_crlf)
1102 {
1103 pdkim_update_bodyhash(ctx, "\r\n", 2);
1104 ctx->num_buffered_crlf--;
80a47a2c
TK
1105 }
1106
3045f050 1107pdkim_update_bodyhash(ctx, p, n);
80a47a2c 1108
3045f050
JH
1109BAIL:
1110ctx->linebuf_offset = 0;
1111return PDKIM_OK;
80a47a2c
TK
1112}
1113
1114
1115/* -------------------------------------------------------------------------- */
1116/* Callback from pdkim_feed below for processing complete headers */
1117#define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
3045f050 1118
f444c2c7 1119static int
3045f050
JH
1120pdkim_header_complete(pdkim_ctx *ctx)
1121{
3045f050
JH
1122/* Special case: The last header can have an extra \r appended */
1123if ( (ctx->cur_header->len > 1) &&
1124 (ctx->cur_header->str[(ctx->cur_header->len)-1] == '\r') )
1125 {
1126 ctx->cur_header->str[(ctx->cur_header->len)-1] = '\0';
1127 ctx->cur_header->len--;
80a47a2c
TK
1128 }
1129
3045f050
JH
1130ctx->num_headers++;
1131if (ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
80a47a2c 1132
3045f050
JH
1133/* SIGNING -------------------------------------------------------------- */
1134if (ctx->mode == PDKIM_MODE_SIGN)
0d04a285
JH
1135 {
1136 pdkim_signature *sig;
1137
1138 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
ab9152ff
JH
1139 {
1140 pdkim_stringlist *list;
80a47a2c 1141
ab9152ff
JH
1142 /* Add header to the signed headers list (in reverse order) */
1143 if (!(list = pdkim_prepend_stringlist(sig->headers,
1144 ctx->cur_header->str)))
1145 return PDKIM_ERR_OOM;
1146 sig->headers = list;
1147 }
0d04a285 1148 }
94431adb 1149
0d04a285 1150/* VERIFICATION ----------------------------------------------------------- */
3045f050
JH
1151/* DKIM-Signature: headers are added to the verification list */
1152if (ctx->mode == PDKIM_MODE_VERIFY)
1153 {
1154 if (strncasecmp(ctx->cur_header->str,
1155 DKIM_SIGNATURE_HEADERNAME,
1156 strlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
1157 {
1158 pdkim_signature *new_sig;
80a47a2c 1159
3045f050 1160 /* Create and chain new signature block */
0d04a285 1161 DEBUG(D_acl) debug_printf(
3045f050 1162 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
3045f050
JH
1163
1164 if ((new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header->str)))
1165 {
1166 pdkim_signature *last_sig = ctx->sig;
1167 if (!last_sig)
1168 ctx->sig = new_sig;
1169 else
1170 {
1171 while (last_sig->next) last_sig = last_sig->next;
1172 last_sig->next = new_sig;
1173 }
80a47a2c 1174 }
abe1010c 1175 else
0d04a285
JH
1176 DEBUG(D_acl) debug_printf(
1177 "Error while parsing signature header\n"
3045f050 1178 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1179 }
37f8b554 1180
3045f050
JH
1181 /* every other header is stored for signature verification */
1182 else
1183 {
1184 pdkim_stringlist *list;
1185
abe1010c 1186 if (!(list = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->str)))
3045f050
JH
1187 return PDKIM_ERR_OOM;
1188 ctx->headers = list;
80a47a2c
TK
1189 }
1190 }
1191
3045f050
JH
1192BAIL:
1193pdkim_strclear(ctx->cur_header); /* Re-use existing pdkim_str */
1194return PDKIM_OK;
6ab02e3f 1195}
80a47a2c
TK
1196
1197
1198
1199/* -------------------------------------------------------------------------- */
1200#define HEADER_BUFFER_FRAG_SIZE 256
3045f050
JH
1201
1202DLLEXPORT int
1203pdkim_feed (pdkim_ctx *ctx, char *data, int len)
1204{
1205int p;
1206
1207for (p = 0; p<len; p++)
1208 {
1209 char c = data[p];
1210
1211 if (ctx->past_headers)
1212 {
1213 /* Processing body byte */
0d04a285 1214 ctx->linebuf[ctx->linebuf_offset++] = c;
3045f050
JH
1215 if (c == '\n')
1216 {
1217 int rc = pdkim_bodyline_complete(ctx); /* End of line */
1218 if (rc != PDKIM_OK) return rc;
80a47a2c 1219 }
3045f050
JH
1220 if (ctx->linebuf_offset == (PDKIM_MAX_BODY_LINE_LEN-1))
1221 return PDKIM_ERR_LONG_LINE;
80a47a2c 1222 }
3045f050
JH
1223 else
1224 {
1225 /* Processing header byte */
1226 if (c != '\r')
1227 {
1228 if (c == '\n')
1229 {
1230 if (ctx->seen_lf)
1231 {
1232 int rc = pdkim_header_complete(ctx); /* Seen last header line */
1233 if (rc != PDKIM_OK) return rc;
1234
0d04a285 1235 ctx->past_headers = TRUE;
3045f050 1236 ctx->seen_lf = 0;
0d04a285 1237 DEBUG(D_acl) debug_printf(
8ef02a06 1238 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n");
3045f050
JH
1239 continue;
1240 }
1241 else
0d04a285 1242 ctx->seen_lf = TRUE;
3045f050
JH
1243 }
1244 else if (ctx->seen_lf)
1245 {
1246 if (!(c == '\t' || c == ' '))
1247 {
1248 int rc = pdkim_header_complete(ctx); /* End of header */
1249 if (rc != PDKIM_OK) return rc;
1250 }
0d04a285 1251 ctx->seen_lf = FALSE;
3045f050 1252 }
80a47a2c 1253 }
3045f050
JH
1254
1255 if (!ctx->cur_header)
1256 if (!(ctx->cur_header = pdkim_strnew(NULL)))
1257 return PDKIM_ERR_OOM;
1258
1259 if (ctx->cur_header->len < PDKIM_MAX_HEADER_LEN)
1260 if (!pdkim_strncat(ctx->cur_header, &data[p], 1))
1261 return PDKIM_ERR_OOM;
80a47a2c
TK
1262 }
1263 }
3045f050 1264return PDKIM_OK;
6ab02e3f 1265}
80a47a2c 1266
05b7d6de
JB
1267/*
1268 * RFC 5322 specifies that header line length SHOULD be no more than 78
1269 * lets make it so!
1270 * pdkim_headcat
1271 * returns char*
1272 *
1273 * col: this int holds and receives column number (octets since last '\n')
1274 * str: partial string to append to
94431adb 1275 * pad: padding, split line or space after before or after eg: ";"
05b7d6de
JB
1276 * intro: - must join to payload eg "h=", usually the tag name
1277 * payload: eg base64 data - long data can be split arbitrarily.
1278 *
1279 * this code doesn't fold the header in some of the places that RFC4871
1280 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1281 * pairs and inside long values. it also always spaces or breaks after the
94431adb 1282 * "pad"
05b7d6de
JB
1283 *
1284 * no guarantees are made for output given out-of range input. like tag
f444c2c7 1285 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
05b7d6de
JB
1286 */
1287
3045f050
JH
1288static char *
1289pdkim_headcat(int *col, pdkim_str *str, const char * pad,
1290 const char *intro, const char *payload)
1291{
1292size_t l;
1293
1294if (pad)
05b7d6de 1295 {
3045f050
JH
1296 l = strlen(pad);
1297 if (*col + l > 78)
05b7d6de 1298 {
3045f050
JH
1299 pdkim_strcat(str, "\r\n\t");
1300 *col = 1;
05b7d6de 1301 }
3045f050
JH
1302 pdkim_strncat(str, pad, l);
1303 *col += l;
05b7d6de
JB
1304 }
1305
3045f050 1306l = (pad?1:0) + (intro?strlen(intro):0);
05b7d6de 1307
3045f050 1308if (*col + l > 78)
05b7d6de 1309 { /*can't fit intro - start a new line to make room.*/
3045f050
JH
1310 pdkim_strcat(str, "\r\n\t");
1311 *col = 1;
1312 l = intro?strlen(intro):0;
05b7d6de
JB
1313 }
1314
3045f050 1315l += payload ? strlen(payload):0 ;
05b7d6de 1316
3045f050 1317while (l>77)
05b7d6de 1318 { /* this fragment will not fit on a single line */
3045f050 1319 if (pad)
05b7d6de 1320 {
3045f050
JH
1321 pdkim_strcat(str, " ");
1322 *col += 1;
1323 pad = NULL; /* only want this once */
1324 l--;
05b7d6de 1325 }
3045f050
JH
1326
1327 if (intro)
05b7d6de 1328 {
3045f050
JH
1329 size_t sl = strlen(intro);
1330
abe1010c 1331 pdkim_strncat(str, intro, sl);
3045f050
JH
1332 *col += sl;
1333 l -= sl;
1334 intro = NULL; /* only want this once */
05b7d6de 1335 }
3045f050
JH
1336
1337 if (payload)
05b7d6de 1338 {
3045f050
JH
1339 size_t sl = strlen(payload);
1340 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1341
abe1010c 1342 pdkim_strncat(str, payload, chomp);
3045f050
JH
1343 *col += chomp;
1344 payload += chomp;
1345 l -= chomp-1;
05b7d6de 1346 }
3045f050
JH
1347
1348 /* the while precondition tells us it didn't fit. */
1349 pdkim_strcat(str, "\r\n\t");
1350 *col = 1;
05b7d6de 1351 }
3045f050
JH
1352
1353if (*col + l > 78)
05b7d6de 1354 {
3045f050
JH
1355 pdkim_strcat(str, "\r\n\t");
1356 *col = 1;
1357 pad = NULL;
05b7d6de
JB
1358 }
1359
3045f050 1360if (pad)
05b7d6de 1361 {
3045f050
JH
1362 pdkim_strcat(str, " ");
1363 *col += 1;
1364 pad = NULL;
05b7d6de
JB
1365 }
1366
3045f050 1367if (intro)
05b7d6de 1368 {
3045f050
JH
1369 size_t sl = strlen(intro);
1370
1371 pdkim_strncat(str, intro, sl);
1372 *col += sl;
1373 l -= sl;
1374 intro = NULL;
05b7d6de 1375 }
3045f050
JH
1376
1377if (payload)
05b7d6de 1378 {
3045f050
JH
1379 size_t sl = strlen(payload);
1380
1381 pdkim_strncat(str, payload, sl);
1382 *col += sl;
05b7d6de
JB
1383 }
1384
3045f050 1385return str->str;
05b7d6de 1386}
80a47a2c 1387
3045f050 1388
80a47a2c 1389/* -------------------------------------------------------------------------- */
3045f050 1390
f444c2c7 1391static char *
2592e6c0 1392pdkim_create_header(pdkim_signature *sig, BOOL final)
3045f050
JH
1393{
1394char *rc = NULL;
1395char *base64_bh = NULL;
1396char *base64_b = NULL;
1397int col = 0;
1398pdkim_str *hdr;
1399pdkim_str *canon_all;
1400
1401if (!(hdr = pdkim_strnew("DKIM-Signature: v="PDKIM_SIGNATURE_VERSION)))
1402 return NULL;
1403
1404if (!(canon_all = pdkim_strnew(pdkim_canons[sig->canon_headers])))
1405 goto BAIL;
1406
2592e6c0 1407if (!(base64_bh = pdkim_encode_base64(&sig->bodyhash)))
3045f050
JH
1408 goto BAIL;
1409
1410col = strlen(hdr->str);
1411
1412/* Required and static bits */
abe1010c
JH
1413if ( pdkim_headcat(&col, hdr, ";", "a=", pdkim_algos[sig->algo])
1414 && pdkim_headcat(&col, hdr, ";", "q=", pdkim_querymethods[sig->querymethod])
1415 && pdkim_strcat(canon_all, "/")
1416 && pdkim_strcat(canon_all, pdkim_canons[sig->canon_body])
1417 && pdkim_headcat(&col, hdr, ";", "c=", canon_all->str)
1418 && pdkim_headcat(&col, hdr, ";", "d=", sig->domain)
1419 && pdkim_headcat(&col, hdr, ";", "s=", sig->selector)
3045f050
JH
1420 )
1421 {
2592e6c0 1422 /* list of header names can be split between items. */
05b7d6de 1423 {
2592e6c0 1424 char *n = CS string_copy(sig->headernames);
3045f050
JH
1425 char *i = "h=";
1426 char *s = ";";
1427
1428 if (!n) goto BAIL;
1429 while (*n)
05b7d6de 1430 {
abe1010c 1431 char *c = strchr(n, ':');
05b7d6de 1432
3045f050 1433 if (c) *c ='\0';
05b7d6de 1434
3045f050 1435 if (!i)
abe1010c 1436 if (!pdkim_headcat(&col, hdr, NULL, NULL, ":"))
3045f050 1437 {
3045f050
JH
1438 goto BAIL;
1439 }
1440
abe1010c 1441 if (!pdkim_headcat(&col, hdr, s, i, n))
3045f050 1442 {
3045f050
JH
1443 goto BAIL;
1444 }
1445
1446 if (!c)
1447 break;
1448
1449 n = c+1;
1450 s = NULL;
1451 i = NULL;
80a47a2c
TK
1452 }
1453 }
05b7d6de 1454
3045f050
JH
1455 if(!pdkim_headcat(&col, hdr, ";", "bh=", base64_bh))
1456 goto BAIL;
1457
1458 /* Optional bits */
1459 if (sig->identity)
1460 if(!pdkim_headcat(&col, hdr, ";", "i=", sig->identity))
1461 goto BAIL;
1462
1463 if (sig->created > 0)
1464 {
1465 char minibuf[20];
1466
abe1010c 1467 snprintf(minibuf, 20, "%lu", sig->created);
3045f050
JH
1468 if(!pdkim_headcat(&col, hdr, ";", "t=", minibuf))
1469 goto BAIL;
1470 }
1471
1472 if (sig->expires > 0)
1473 {
1474 char minibuf[20];
1475
abe1010c 1476 snprintf(minibuf, 20, "%lu", sig->expires);
3045f050
JH
1477 if(!pdkim_headcat(&col, hdr, ";", "x=", minibuf))
1478 goto BAIL;
80a47a2c 1479 }
3045f050
JH
1480
1481 if (sig->bodylength >= 0)
1482 {
1483 char minibuf[20];
1484
abe1010c 1485 snprintf(minibuf, 20, "%lu", sig->bodylength);
3045f050
JH
1486 if(!pdkim_headcat(&col, hdr, ";", "l=", minibuf))
1487 goto BAIL;
80a47a2c
TK
1488 }
1489
3045f050
JH
1490 /* Preliminary or final version? */
1491 if (final)
1492 {
2592e6c0 1493 if (!(base64_b = pdkim_encode_base64(&sig->sigdata)))
3045f050
JH
1494 goto BAIL;
1495 if (!pdkim_headcat(&col, hdr, ";", "b=", base64_b))
1496 goto BAIL;
1497 }
1498 else
1499 if(!pdkim_headcat(&col, hdr, ";", "b=", ""))
1500 goto BAIL;
05b7d6de 1501
3045f050 1502 /* add trailing semicolon: I'm not sure if this is actually needed */
abe1010c 1503 if (!pdkim_headcat(&col, hdr, NULL, ";", ""))
3045f050 1504 goto BAIL;
80a47a2c
TK
1505 }
1506
3045f050 1507rc = strdup(hdr->str);
80a47a2c 1508
3045f050
JH
1509BAIL:
1510pdkim_strfree(hdr);
1511if (canon_all) pdkim_strfree(canon_all);
3045f050 1512return rc;
80a47a2c
TK
1513}
1514
1515
1516/* -------------------------------------------------------------------------- */
3045f050
JH
1517
1518DLLEXPORT int
1519pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatures)
1520{
1521pdkim_signature *sig = ctx->sig;
1522pdkim_str *headernames = NULL; /* Collected signed header names */
1523
1524/* Check if we must still flush a (partial) header. If that is the
1525 case, the message has no body, and we must compute a body hash
1526 out of '<CR><LF>' */
1527if (ctx->cur_header && ctx->cur_header->len)
1528 {
1529 int rc = pdkim_header_complete(ctx);
1530 if (rc != PDKIM_OK) return rc;
1531 pdkim_update_bodyhash(ctx, "\r\n", 2);
80a47a2c 1532 }
3045f050 1533else
0d04a285 1534 DEBUG(D_acl) debug_printf(
3045f050 1535 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1536
3045f050
JH
1537/* Build (and/or evaluate) body hash */
1538if (pdkim_finish_bodyhash(ctx) != PDKIM_OK)
1539 return PDKIM_ERR_OOM;
80a47a2c 1540
3045f050
JH
1541/* SIGNING -------------------------------------------------------------- */
1542if (ctx->mode == PDKIM_MODE_SIGN)
1543 if (!(headernames = pdkim_strnew(NULL)))
1544 return PDKIM_ERR_OOM;
1545/* ---------------------------------------------------------------------- */
80a47a2c 1546
3045f050
JH
1547while (sig)
1548 {
2592e6c0
JH
1549 BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
1550 hctx hhash_ctx;
1551 char * sig_hdr;
1552 blob hhash;
1553 blob hdata;
cb224393 1554 int hdata_alloc = 0;
cb224393 1555
2592e6c0
JH
1556 hdata.data = NULL;
1557 hdata.len = 0;
1558
1559 exim_sha_init(&hhash_ctx, is_sha1);
80a47a2c 1560
0d04a285
JH
1561 DEBUG(D_acl) debug_printf(
1562 "PDKIM >> Hashed header data, canonicalized, in sequence >>>>>>>>>>>>>>\n");
3045f050
JH
1563
1564 /* SIGNING ---------------------------------------------------------------- */
1565 /* When signing, walk through our header list and add them to the hash. As we
8ef02a06
JH
1566 go, construct a list of the header's names to use for the h= parameter.
1567 Then append to that list any remaining header names for which there was no
1568 header to sign. */
3045f050
JH
1569
1570 if (ctx->mode == PDKIM_MODE_SIGN)
1571 {
1572 pdkim_stringlist *p;
8ef02a06
JH
1573 const uschar * l;
1574 uschar * s;
1575 int sep = 0;
3045f050
JH
1576
1577 for (p = sig->headers; p; p = p->next)
ab9152ff
JH
1578 if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
1579 {
1580 uschar * rh;
1581 /* Collect header names (Note: colon presence is guaranteed here) */
1582 uschar * q = Ustrchr(p->value, ':');
3045f050 1583
ab9152ff
JH
1584 if (!(pdkim_strncat(headernames, p->value,
1585 (q - US p->value) + (p->next ? 1 : 0))))
1586 return PDKIM_ERR_OOM;
3045f050 1587
ab9152ff
JH
1588 rh = sig->canon_headers == PDKIM_CANON_RELAXED
1589 ? US pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
b78006ac 1590 : string_copy(CUS p->value); /* just copy it for simple canon */
ab9152ff
JH
1591 if (!rh)
1592 return PDKIM_ERR_OOM;
3045f050 1593
ab9152ff 1594 /* Feed header to the hash algorithm */
b78006ac 1595 exim_sha_update(&hhash_ctx, CCS rh, Ustrlen(rh));
f444c2c7 1596
ab9152ff
JH
1597 /* Remember headers block for signing (when the library cannot do incremental) */
1598 (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
3045f050 1599
ab9152ff
JH
1600 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1601 }
8ef02a06
JH
1602
1603 l = US sig->sign_headers;
1604 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1605 if (*s != '_')
ab9152ff
JH
1606 { /*SSS string_append_listele() */
1607 if (headernames->len > 0 && headernames->str[headernames->len-1] != ':')
8ef02a06
JH
1608 if (!(pdkim_strncat(headernames, ":", 1)))
1609 return PDKIM_ERR_OOM;
1610 if (!(pdkim_strncat(headernames, CS s, Ustrlen(s))))
1611 return PDKIM_ERR_OOM;
1612 }
80a47a2c 1613 }
37f8b554 1614
3045f050
JH
1615 /* VERIFICATION ----------------------------------------------------------- */
1616 /* When verifying, walk through the header name list in the h= parameter and
1617 add the headers to the hash in that order. */
1618 else
1619 {
2592e6c0
JH
1620 uschar * b = string_copy(sig->headernames);
1621 uschar * p = b;
1622 uschar * q;
1623 pdkim_stringlist * hdrs;
3045f050
JH
1624
1625 if (!b) return PDKIM_ERR_OOM;
1626
1627 /* clear tags */
1628 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1629 hdrs->tag = 0;
1630
1631 while(1)
1632 {
2592e6c0 1633 if ((q = Ustrchr(p, ':')))
3045f050
JH
1634 *q = '\0';
1635
ab9152ff 1636/*XXX walk the list of headers in same order as received. */
3045f050
JH
1637 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1638 if ( hdrs->tag == 0
2592e6c0
JH
1639 && strncasecmp(hdrs->value, CS p, Ustrlen(p)) == 0
1640 && (hdrs->value)[Ustrlen(p)] == ':'
3045f050
JH
1641 )
1642 {
2592e6c0
JH
1643 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1644 ? US pdkim_relax_header(hdrs->value, 1) /* cook header for relaxed canon */
b78006ac 1645 : string_copy(CUS hdrs->value); /* just copy it for simple canon */
3045f050
JH
1646 if (!rh)
1647 return PDKIM_ERR_OOM;
1648
1649 /* Feed header to the hash algorithm */
b78006ac 1650 exim_sha_update(&hhash_ctx, CCS rh, Ustrlen(rh));
3045f050 1651
2592e6c0 1652 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
3045f050
JH
1653 hdrs->tag = 1;
1654 break;
1655 }
1656
1657 if (!q) break;
1658 p = q+1;
80a47a2c 1659 }
80a47a2c
TK
1660 }
1661
0d04a285 1662 DEBUG(D_acl) debug_printf(
3045f050 1663 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1664
3045f050
JH
1665 /* SIGNING ---------------------------------------------------------------- */
1666 if (ctx->mode == PDKIM_MODE_SIGN)
1667 {
1668 /* Copy headernames to signature struct */
2592e6c0 1669 sig->headernames = string_copy(US headernames->str);
3045f050 1670 pdkim_strfree(headernames);
80a47a2c 1671
3045f050 1672 /* Create signature header with b= omitted */
8ef02a06 1673 sig_hdr = pdkim_create_header(sig, FALSE);
80a47a2c 1674 }
80a47a2c 1675
3045f050
JH
1676 /* VERIFICATION ----------------------------------------------------------- */
1677 else
1678 sig_hdr = strdup(sig->rawsig_no_b_val);
1679 /* ------------------------------------------------------------------------ */
1680
1681 if (!sig_hdr)
1682 return PDKIM_ERR_OOM;
80a47a2c 1683
3045f050
JH
1684 /* Relax header if necessary */
1685 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1686 {
1687 char *relaxed_hdr = pdkim_relax_header(sig_hdr, 0);
1688
1689 free(sig_hdr);
1690 if (!relaxed_hdr)
1691 return PDKIM_ERR_OOM;
1692 sig_hdr = relaxed_hdr;
80a47a2c
TK
1693 }
1694
0d04a285 1695 DEBUG(D_acl)
3045f050 1696 {
0d04a285 1697 debug_printf(
3045f050 1698 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
b78006ac 1699 pdkim_quoteprint(CUS sig_hdr, strlen(sig_hdr));
0d04a285 1700 debug_printf(
3045f050 1701 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
80a47a2c 1702 }
3045f050
JH
1703
1704 /* Finalize header hash */
2592e6c0
JH
1705 exim_sha_update(&hhash_ctx, sig_hdr, strlen(sig_hdr));
1706 exim_sha_finish(&hhash_ctx, &hhash);
3045f050 1707
f444c2c7
JH
1708 DEBUG(D_acl)
1709 {
1710 debug_printf("PDKIM [%s] hh computed: ", sig->domain);
2592e6c0 1711 pdkim_hexprint(hhash.data, hhash.len);
80a47a2c
TK
1712 }
1713
2592e6c0 1714 /* Remember headers block for signing (when the library cannot do incremental) */
f444c2c7 1715 if (ctx->mode == PDKIM_MODE_SIGN)
b78006ac 1716 (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
f444c2c7 1717
3045f050 1718 free(sig_hdr);
80a47a2c 1719
3045f050
JH
1720 /* SIGNING ---------------------------------------------------------------- */
1721 if (ctx->mode == PDKIM_MODE_SIGN)
1722 {
2592e6c0
JH
1723 es_ctx sctx;
1724 const uschar * errstr;
f444c2c7
JH
1725
1726 /* Import private key */
b78006ac 1727 if ((errstr = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
f444c2c7 1728 {
2592e6c0 1729 DEBUG(D_acl) debug_printf("signing_init: %s\n", errstr);
f444c2c7
JH
1730 return PDKIM_ERR_RSA_PRIVKEY;
1731 }
80a47a2c 1732
2592e6c0
JH
1733 /* Do signing. With OpenSSL we are signing the hash of headers just
1734 calculated, with GnuTLS we have to sign an entire block of headers
1735 (due to available interfaces) and it recalculates the hash internally. */
f444c2c7 1736
2592e6c0
JH
1737#if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1738 hdata = hhash;
f444c2c7
JH
1739#endif
1740
2592e6c0 1741 if ((errstr = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sigdata)))
f444c2c7 1742 {
2592e6c0 1743 DEBUG(D_acl) debug_printf("signing: %s\n", errstr);
f444c2c7
JH
1744 return PDKIM_ERR_RSA_SIGNING;
1745 }
80a47a2c 1746
0d04a285 1747 DEBUG(D_acl)
3045f050 1748 {
0d04a285 1749 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
2592e6c0 1750 pdkim_hexprint(sig->sigdata.data, sig->sigdata.len);
80a47a2c 1751 }
80a47a2c 1752
8ef02a06 1753 if (!(sig->signature_header = pdkim_create_header(sig, TRUE)))
3045f050 1754 return PDKIM_ERR_OOM;
cb570b5e
JH
1755
1756 /* We only ever sign with one sig, and we free'd "headernames"
1757 above. So to keep static-analysers happy, exit the loop explicitly.
1758 Perhaps the code would be more clear if signing and verification
1759 loops were separated? */
1760
1761 break;
80a47a2c 1762 }
80a47a2c 1763
3045f050
JH
1764 /* VERIFICATION ----------------------------------------------------------- */
1765 else
1766 {
2592e6c0
JH
1767 ev_ctx vctx;
1768 const uschar * errstr;
3045f050 1769
2592e6c0 1770 char *dns_txt_name, *dns_txt_reply;
f444c2c7
JH
1771
1772 /* Fetch public key for signing domain, from DNS */
3045f050
JH
1773
1774 if (!(dns_txt_name = malloc(PDKIM_DNS_TXT_MAX_NAMELEN)))
1775 return PDKIM_ERR_OOM;
1776
1777 if (!(dns_txt_reply = malloc(PDKIM_DNS_TXT_MAX_RECLEN)))
1778 {
1779 free(dns_txt_name);
1780 return PDKIM_ERR_OOM;
80a47a2c
TK
1781 }
1782
3045f050
JH
1783 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1784 memset(dns_txt_name , 0, PDKIM_DNS_TXT_MAX_NAMELEN);
1785
abe1010c 1786 if (snprintf(dns_txt_name, PDKIM_DNS_TXT_MAX_NAMELEN,
3045f050 1787 "%s._domainkey.%s.",
abe1010c 1788 sig->selector, sig->domain) >= PDKIM_DNS_TXT_MAX_NAMELEN)
3045f050
JH
1789 {
1790 sig->verify_status = PDKIM_VERIFY_INVALID;
1791 sig->verify_ext_status = PDKIM_VERIFY_INVALID_BUFFER_SIZE;
1792 goto NEXT_VERIFY;
80a47a2c 1793 }
3045f050
JH
1794
1795 if ( ctx->dns_txt_callback(dns_txt_name, dns_txt_reply) != PDKIM_OK
1796 || dns_txt_reply[0] == '\0')
1797 {
1798 sig->verify_status = PDKIM_VERIFY_INVALID;
1799 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1800 goto NEXT_VERIFY;
80a47a2c
TK
1801 }
1802
0d04a285 1803 DEBUG(D_acl)
3045f050 1804 {
0d04a285 1805 debug_printf(
2592e6c0
JH
1806 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1807 " Raw record: ");
b78006ac 1808 pdkim_quoteprint(CUS dns_txt_reply, strlen(dns_txt_reply));
80a47a2c 1809 }
3045f050 1810
abe1010c 1811 if (!(sig->pubkey = pdkim_parse_pubkey_record(ctx, dns_txt_reply)))
3045f050
JH
1812 {
1813 sig->verify_status = PDKIM_VERIFY_INVALID;
df3def24 1814 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
3045f050 1815
0d04a285
JH
1816 DEBUG(D_acl) debug_printf(
1817 " Error while parsing public key record\n"
3045f050 1818 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
3045f050 1819 goto NEXT_VERIFY;
80a47a2c
TK
1820 }
1821
0d04a285 1822 DEBUG(D_acl) debug_printf(
2592e6c0 1823 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
3045f050 1824
f444c2c7 1825 /* Import public key */
2592e6c0 1826 if ((errstr = exim_rsa_verify_init(&sig->pubkey->key, &vctx)))
3045f050 1827 {
2592e6c0 1828 DEBUG(D_acl) debug_printf("verify_init: %s\n", errstr);
3045f050 1829 sig->verify_status = PDKIM_VERIFY_INVALID;
df3def24 1830 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
3045f050 1831 goto NEXT_VERIFY;
80a47a2c
TK
1832 }
1833
3045f050 1834 /* Check the signature */
2592e6c0 1835 if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sigdata)))
3045f050 1836 {
2592e6c0 1837 DEBUG(D_acl) debug_printf("headers verify: %s\n", errstr);
3045f050
JH
1838 sig->verify_status = PDKIM_VERIFY_FAIL;
1839 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1840 goto NEXT_VERIFY;
ff7ddfd7
TK
1841 }
1842
2592e6c0 1843
3045f050
JH
1844 /* We have a winner! (if bodydhash was correct earlier) */
1845 if (sig->verify_status == PDKIM_VERIFY_NONE)
1846 sig->verify_status = PDKIM_VERIFY_PASS;
1847
1848NEXT_VERIFY:
1849
0d04a285 1850 DEBUG(D_acl)
3045f050 1851 {
0d04a285 1852 debug_printf("PDKIM [%s] signature status: %s",
3045f050
JH
1853 sig->domain, pdkim_verify_status_str(sig->verify_status));
1854 if (sig->verify_ext_status > 0)
0d04a285 1855 debug_printf(" (%s)\n",
3045f050
JH
1856 pdkim_verify_ext_status_str(sig->verify_ext_status));
1857 else
0d04a285 1858 debug_printf("\n");
80a47a2c 1859 }
80a47a2c 1860
3045f050
JH
1861 free(dns_txt_name);
1862 free(dns_txt_reply);
80a47a2c
TK
1863 }
1864
3045f050 1865 sig = sig->next;
80a47a2c
TK
1866 }
1867
3045f050
JH
1868/* If requested, set return pointer to signature(s) */
1869if (return_signatures)
1870 *return_signatures = ctx->sig;
80a47a2c 1871
3045f050 1872return PDKIM_OK;
80a47a2c
TK
1873}
1874
1875
1876/* -------------------------------------------------------------------------- */
3045f050
JH
1877
1878DLLEXPORT pdkim_ctx *
0d04a285 1879pdkim_init_verify(int(*dns_txt_callback)(char *, char *))
3045f050
JH
1880{
1881pdkim_ctx *ctx = malloc(sizeof(pdkim_ctx));
1882
1883if (!ctx)
1884 return NULL;
abe1010c 1885memset(ctx, 0, sizeof(pdkim_ctx));
3045f050
JH
1886
1887if (!(ctx->linebuf = malloc(PDKIM_MAX_BODY_LINE_LEN)))
1888 {
1889 free(ctx);
1890 return NULL;
80a47a2c
TK
1891 }
1892
3045f050 1893ctx->mode = PDKIM_MODE_VERIFY;
3045f050 1894ctx->dns_txt_callback = dns_txt_callback;
80a47a2c 1895
3045f050 1896return ctx;
80a47a2c
TK
1897}
1898
1899
1900/* -------------------------------------------------------------------------- */
80a47a2c 1901
3045f050 1902DLLEXPORT pdkim_ctx *
f444c2c7 1903pdkim_init_sign(char *domain, char *selector, char *rsa_privkey, int algo)
3045f050
JH
1904{
1905pdkim_ctx *ctx;
1906pdkim_signature *sig;
80a47a2c 1907
3045f050
JH
1908if (!domain || !selector || !rsa_privkey)
1909 return NULL;
80a47a2c 1910
3045f050
JH
1911if (!(ctx = malloc(sizeof(pdkim_ctx))))
1912 return NULL;
abe1010c 1913memset(ctx, 0, sizeof(pdkim_ctx));
80a47a2c 1914
3045f050
JH
1915if (!(ctx->linebuf = malloc(PDKIM_MAX_BODY_LINE_LEN)))
1916 {
1917 free(ctx);
1918 return NULL;
80a47a2c
TK
1919 }
1920
3045f050
JH
1921if (!(sig = malloc(sizeof(pdkim_signature))))
1922 {
1923 free(ctx->linebuf);
1924 free(ctx);
1925 return NULL;
80a47a2c 1926 }
abe1010c 1927memset(sig, 0, sizeof(pdkim_signature));
80a47a2c 1928
3045f050 1929sig->bodylength = -1;
80a47a2c 1930
3045f050 1931ctx->mode = PDKIM_MODE_SIGN;
3045f050 1932ctx->sig = sig;
80a47a2c 1933
2592e6c0
JH
1934sig->domain = strdup(domain);
1935sig->selector = strdup(selector);
1936sig->rsa_privkey = strdup(rsa_privkey);
1937sig->algo = algo;
cb224393 1938
2592e6c0 1939if (!sig->domain || !sig->selector || !sig->rsa_privkey)
cb224393 1940 goto BAIL;
3045f050 1941
2592e6c0 1942exim_sha_init(&sig->body_hash, algo == PDKIM_ALGO_RSA_SHA1);
3045f050
JH
1943return ctx;
1944
1945BAIL:
1946 pdkim_free_ctx(ctx);
1947 return NULL;
6ab02e3f 1948}
80a47a2c 1949
f444c2c7 1950
80a47a2c 1951/* -------------------------------------------------------------------------- */
3045f050
JH
1952
1953DLLEXPORT int
1954pdkim_set_optional(pdkim_ctx *ctx,
80a47a2c
TK
1955 char *sign_headers,
1956 char *identity,
1957 int canon_headers,
1958 int canon_body,
1959 long bodylength,
80a47a2c 1960 unsigned long created,
3045f050
JH
1961 unsigned long expires)
1962{
8ef02a06
JH
1963pdkim_signature * sig = ctx->sig;
1964
3045f050 1965if (identity)
8ef02a06 1966 if (!(sig->identity = strdup(identity)))
3045f050 1967 return PDKIM_ERR_OOM;
80a47a2c 1968
8ef02a06
JH
1969if (!(sig->sign_headers = strdup(sign_headers
1970 ? sign_headers : PDKIM_DEFAULT_SIGN_HEADERS)))
1971 return PDKIM_ERR_OOM;
80a47a2c 1972
8ef02a06
JH
1973sig->canon_headers = canon_headers;
1974sig->canon_body = canon_body;
1975sig->bodylength = bodylength;
1976sig->created = created;
1977sig->expires = expires;
80a47a2c 1978
3045f050 1979return PDKIM_OK;
6ab02e3f 1980}
3045f050 1981
3045f050 1982
2592e6c0
JH
1983void
1984pdkim_init(void)
1985{
1986exim_rsa_init();
1987}
1988
1989
1990
f444c2c7 1991#endif /*DISABLE_DKIM*/