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