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