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