2 * PDKIM - a RFC4871 (DKIM) implementation
4 * Copyright (C) 2009 - 2016 Tom Kistner <tom@duncanthrax.net>
5 * Copyright (C) 2016 Jeremy Harris <jgh@exim.org>
7 * http://duncanthrax.net/pdkim/
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.
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.
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.
27 #ifndef DISABLE_DKIM /* entire file */
30 # error Need SUPPORT_TLS for DKIM
33 #include "crypt_ver.h"
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>
47 #define PDKIM_SIGNATURE_VERSION "1"
48 #define PDKIM_PUB_RECORD_VERSION US "DKIM1"
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"
63 /* -------------------------------------------------------------------------- */
64 struct pdkim_stringlist {
70 /* -------------------------------------------------------------------------- */
71 /* A bunch of list constants */
72 const uschar * pdkim_querymethods[] = {
76 const uschar * pdkim_algos[] = {
81 const uschar * pdkim_canons[] = {
86 const uschar * pdkim_hashes[] = {
91 const uschar * pdkim_keytypes[] = {
96 typedef struct pdkim_combined_canon_entry {
100 } pdkim_combined_canon_entry;
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 },
113 /* -------------------------------------------------------------------------- */
116 pdkim_verify_status_str(int status)
119 case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE";
120 case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID";
121 case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL";
122 case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS";
123 default: return "PDKIM_VERIFY_UNKNOWN";
128 pdkim_verify_ext_status_str(int ext_status)
131 case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
132 case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
133 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
134 case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
135 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
136 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
137 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
138 case PDKIM_VERIFY_INVALID_DKIM_VERSION: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
139 default: return "PDKIM_VERIFY_UNKNOWN";
144 /* -------------------------------------------------------------------------- */
145 /* Print debugging functions */
147 pdkim_quoteprint(const uschar *data, int len)
150 for (i = 0; i < len; i++)
152 const int c = data[i];
155 case ' ' : debug_printf("{SP}"); break;
156 case '\t': debug_printf("{TB}"); break;
157 case '\r': debug_printf("{CR}"); break;
158 case '\n': debug_printf("{LF}"); break;
159 case '{' : debug_printf("{BO}"); break;
160 case '}' : debug_printf("{BC}"); break;
162 if ( (c < 32) || (c > 127) )
163 debug_printf("{%02x}", c);
165 debug_printf("%c", c);
173 pdkim_hexprint(const uschar *data, int len)
176 for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
182 static pdkim_stringlist *
183 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
185 pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
187 memset(new_entry, 0, sizeof(pdkim_stringlist));
188 new_entry->value = string_copy(str);
189 if (base) new_entry->next = base;
195 /* Trim whitespace fore & aft */
198 pdkim_strtrim(uschar * str)
202 while (*p == '\t' || *p == ' ') p++; /* skip whitespace */
203 while (*p) {*q = *p; q++; p++;} /* dump the leading whitespace */
205 while (q != str && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
206 { /* dump trailing whitespace */
214 /* -------------------------------------------------------------------------- */
217 pdkim_free_ctx(pdkim_ctx *ctx)
222 /* -------------------------------------------------------------------------- */
223 /* Matches the name of the passed raw "header" against
224 the passed colon-separated "tick", and invalidates
225 the entry in tick. Returns OK or fail-code */
226 /*XXX might be safer done using a pdkim_stringlist for "tick" */
229 header_name_match(const uschar * header, uschar * tick)
235 uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
238 return PDKIM_FAIL; /* This isn't a header */
240 /* if we had strncmpic() we wouldn't need this copy */
241 hname = string_copyn(header, hcolon-header);
243 /* Copy tick-off list locally, so we can punch zeroes into it */
244 p = lcopy = string_copy(tick);
246 for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':'))
249 if (strcmpic(p, hname) == 0)
255 if (strcmpic(p, hname) == 0)
261 /* Invalidate header name instance in tick-off list */
267 /* -------------------------------------------------------------------------- */
268 /* Performs "relaxed" canonicalization of a header. */
271 pdkim_relax_header(const uschar * header, int crlf)
273 BOOL past_field_name = FALSE;
274 BOOL seen_wsp = FALSE;
276 uschar * relaxed = store_get(Ustrlen(header)+3);
277 uschar * q = relaxed;
279 for (p = header; *p; p++)
283 if (c == '\r' || c == '\n')
285 if (c == '\t' || c == ' ')
289 c = ' '; /* Turns WSP into SP */
293 if (!past_field_name && c == ':')
295 if (seen_wsp) q--; /* This removes WSP before the colon */
296 seen_wsp = TRUE; /* This removes WSP after the colon */
297 past_field_name = TRUE;
302 /* Lowercase header name */
303 if (!past_field_name) c = tolower(c);
307 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
309 if (crlf) { *q++ = '\r'; *q++ = '\n'; }
315 /* -------------------------------------------------------------------------- */
316 #define PDKIM_QP_ERROR_DECODE -1
319 pdkim_decode_qp_char(uschar *qp_p, int *c)
321 uschar *initial_pos = qp_p;
323 /* Advance one char */
326 /* Check for two hex digits and decode them */
327 if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
329 /* Do hex conversion */
330 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
331 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
335 /* Illegal char here */
336 *c = PDKIM_QP_ERROR_DECODE;
341 /* -------------------------------------------------------------------------- */
344 pdkim_decode_qp(uschar * str)
349 uschar * n = store_get(Ustrlen(str)+1);
357 p = pdkim_decode_qp_char(p, &nchar);
373 /* -------------------------------------------------------------------------- */
376 pdkim_decode_base64(uschar *str, blob * b)
379 dlen = b64decode(str, &b->data);
380 if (dlen < 0) b->data = NULL;
385 pdkim_encode_base64(blob * b)
387 return b64encode(b->data, b->len);
391 /* -------------------------------------------------------------------------- */
392 #define PDKIM_HDR_LIMBO 0
393 #define PDKIM_HDR_TAG 1
394 #define PDKIM_HDR_VALUE 2
396 static pdkim_signature *
397 pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
399 pdkim_signature *sig ;
401 uschar * cur_tag = NULL; int ts = 0, tl = 0;
402 uschar * cur_val = NULL; int vs = 0, vl = 0;
403 BOOL past_hname = FALSE;
404 BOOL in_b_val = FALSE;
405 int where = PDKIM_HDR_LIMBO;
408 sig = store_get(sizeof(pdkim_signature));
409 memset(sig, 0, sizeof(pdkim_signature));
410 sig->bodylength = -1;
412 /* Set so invalid/missing data error display is accurate */
416 q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
418 for (p = raw_hdr; ; p++)
423 if (c == '\r' || c == '\n')
426 /* Fast-forward through header name */
429 if (c == ':') past_hname = TRUE;
433 if (where == PDKIM_HDR_LIMBO)
435 /* In limbo, just wait for a tag-char to appear */
436 if (!(c >= 'a' && c <= 'z'))
439 where = PDKIM_HDR_TAG;
442 if (where == PDKIM_HDR_TAG)
444 if (c >= 'a' && c <= 'z')
445 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
450 if (Ustrcmp(cur_tag, "b") == 0)
455 where = PDKIM_HDR_VALUE;
460 if (where == PDKIM_HDR_VALUE)
462 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
465 if (c == ';' || c == '\0')
470 pdkim_strtrim(cur_val);
472 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
477 if (cur_tag[1] == 'h')
478 pdkim_decode_base64(cur_val, &sig->bodyhash);
480 pdkim_decode_base64(cur_val, &sig->sigdata);
483 /* We only support version 1, and that is currently the
484 only version there is. */
486 Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
489 for (i = 0; pdkim_algos[i]; i++)
490 if (Ustrcmp(cur_val, pdkim_algos[i]) == 0)
497 for (i = 0; pdkim_combined_canons[i].str; i++)
498 if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0)
500 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
501 sig->canon_body = pdkim_combined_canons[i].canon_body;
506 for (i = 0; pdkim_querymethods[i]; i++)
507 if (Ustrcmp(cur_val, pdkim_querymethods[i]) == 0)
509 sig->querymethod = i;
514 sig->selector = string_copy(cur_val); break;
516 sig->domain = string_copy(cur_val); break;
518 sig->identity = pdkim_decode_qp(cur_val); break;
520 sig->created = strtoul(CS cur_val, NULL, 10); break;
522 sig->expires = strtoul(CS cur_val, NULL, 10); break;
524 sig->bodylength = strtol(CS cur_val, NULL, 10); break;
526 sig->headernames = string_copy(cur_val); break;
528 sig->copiedheaders = pdkim_decode_qp(cur_val); break;
530 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
537 where = PDKIM_HDR_LIMBO;
540 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
552 /* Chomp raw header. The final newline must not be added to the signature. */
553 while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
559 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
560 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
562 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sigdata.len*8);
564 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
567 exim_sha_init(&sig->body_hash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
572 /* -------------------------------------------------------------------------- */
574 static pdkim_pubkey *
575 pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
579 uschar * cur_tag = NULL; int ts = 0, tl = 0;
580 uschar * cur_val = NULL; int vs = 0, vl = 0;
581 int where = PDKIM_HDR_LIMBO;
583 pub = store_get(sizeof(pdkim_pubkey));
584 memset(pub, 0, sizeof(pdkim_pubkey));
586 for (p = raw_record; ; p++)
591 if (c == '\r' || c == '\n')
594 if (where == PDKIM_HDR_LIMBO)
596 /* In limbo, just wait for a tag-char to appear */
597 if (!(c >= 'a' && c <= 'z'))
600 where = PDKIM_HDR_TAG;
603 if (where == PDKIM_HDR_TAG)
605 if (c >= 'a' && c <= 'z')
606 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
611 where = PDKIM_HDR_VALUE;
616 if (where == PDKIM_HDR_VALUE)
618 if (c == ';' || c == '\0')
623 pdkim_strtrim(cur_val);
624 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
629 /* This tag isn't evaluated because:
630 - We only support version DKIM1.
631 - Which is the default for this value (set below)
632 - Other versions are currently not specified. */
636 pub->hashes = string_copy(cur_val); break;
638 pub->granularity = string_copy(cur_val); break;
640 pub->notes = pdkim_decode_qp(cur_val); break;
642 pdkim_decode_base64(US cur_val, &pub->key);
645 pub->srvtype = string_copy(cur_val); break;
647 if (Ustrchr(cur_val, 'y') != NULL) pub->testing = 1;
648 if (Ustrchr(cur_val, 's') != NULL) pub->no_subdomaining = 1;
651 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
657 where = PDKIM_HDR_LIMBO;
660 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
664 if (c == '\0') break;
667 /* Set fallback defaults */
668 if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
669 if (!pub->granularity) pub->granularity = string_copy(US"*");
670 if (!pub->keytype ) pub->keytype = string_copy(US"rsa");
671 if (!pub->srvtype ) pub->srvtype = string_copy(US"*");
681 /* -------------------------------------------------------------------------- */
684 pdkim_update_bodyhash(pdkim_ctx *ctx, const char *data, int len)
686 pdkim_signature *sig = ctx->sig;
687 /* Cache relaxed version of data */
688 uschar *relaxed_data = NULL;
691 /* Traverse all signatures, updating their hashes. */
694 /* Defaults to simple canon (no further treatment necessary) */
695 const uschar *canon_data = CUS data;
698 if (sig->canon_body == PDKIM_CANON_RELAXED)
700 /* Relax the line if not done already */
703 BOOL seen_wsp = FALSE;
707 relaxed_data = store_get(len+1);
709 for (p = data; *p; p++)
714 if (q > 0 && relaxed_data[q-1] == ' ')
717 else if (c == '\t' || c == ' ')
719 c = ' '; /* Turns WSP into SP */
726 relaxed_data[q++] = c;
728 relaxed_data[q] = '\0';
731 canon_data = relaxed_data;
732 canon_len = relaxed_len;
735 /* Make sure we don't exceed the to-be-signed body length */
736 if ( sig->bodylength >= 0
737 && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
739 canon_len = sig->bodylength - sig->signed_body_bytes;
743 exim_sha_update(&sig->body_hash, CUS canon_data, canon_len);
744 sig->signed_body_bytes += canon_len;
745 DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
755 /* -------------------------------------------------------------------------- */
758 pdkim_finish_bodyhash(pdkim_ctx *ctx)
760 pdkim_signature *sig;
762 /* Traverse all signatures */
763 for (sig = ctx->sig; sig; sig = sig->next)
764 { /* Finish hashes */
767 exim_sha_finish(&sig->body_hash, &bh);
771 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
772 "PDKIM [%s] bh computed: ",
773 sig->domain, sig->signed_body_bytes, sig->domain);
774 pdkim_hexprint(CUS bh.data, bh.len);
777 /* SIGNING -------------------------------------------------------------- */
778 if (ctx->mode == PDKIM_MODE_SIGN)
782 /* If bodylength limit is set, and we have received less bytes
783 than the requested amount, effectively remove the limit tag. */
784 if (sig->signed_body_bytes < sig->bodylength)
785 sig->bodylength = -1;
788 /* VERIFICATION --------------------------------------------------------- */
791 /* Compare bodyhash */
792 if (memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
794 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
800 debug_printf("PDKIM [%s] bh signature: ", sig->domain);
801 pdkim_hexprint(sig->bodyhash.data,
802 exim_sha_hashlen(&sig->body_hash));
803 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
805 sig->verify_status = PDKIM_VERIFY_FAIL;
806 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
814 /* -------------------------------------------------------------------------- */
815 /* Callback from pdkim_feed below for processing complete body lines */
818 pdkim_bodyline_complete(pdkim_ctx *ctx)
820 char *p = ctx->linebuf;
821 int n = ctx->linebuf_offset;
822 pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
824 /* Ignore extra data if we've seen the end-of-data marker */
825 if (ctx->seen_eod) goto BAIL;
827 /* We've always got one extra byte to stuff a zero ... */
828 ctx->linebuf[ctx->linebuf_offset] = '\0';
830 /* Terminate on EOD marker */
831 if (memcmp(p, ".\r\n", 3) == 0)
833 /* In simple body mode, if any empty lines were buffered,
834 replace with one. rfc 4871 3.4.3 */
835 /*XXX checking the signed-body-bytes is a gross hack; I think
836 it indicates that all linebreaks should be buffered, including
837 the one terminating a text line */
838 if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
839 && sig->signed_body_bytes == 0
840 && ctx->num_buffered_crlf > 0
842 pdkim_update_bodyhash(ctx, "\r\n", 2);
844 ctx->seen_eod = TRUE;
848 if (memcmp(p, "..", 2) == 0)
854 /* Empty lines need to be buffered until we find a non-empty line */
855 if (memcmp(p, "\r\n", 2) == 0)
857 ctx->num_buffered_crlf++;
861 if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
863 /* Lines with just spaces need to be buffered too */
865 while (memcmp(check, "\r\n", 2) != 0)
869 if (c != '\t' && c != ' ')
874 ctx->num_buffered_crlf++;
879 /* At this point, we have a non-empty line, so release the buffered ones. */
880 while (ctx->num_buffered_crlf)
882 pdkim_update_bodyhash(ctx, "\r\n", 2);
883 ctx->num_buffered_crlf--;
886 pdkim_update_bodyhash(ctx, p, n);
889 ctx->linebuf_offset = 0;
894 /* -------------------------------------------------------------------------- */
895 /* Callback from pdkim_feed below for processing complete headers */
896 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
899 pdkim_header_complete(pdkim_ctx *ctx)
901 /* Special case: The last header can have an extra \r appended */
902 if ( (ctx->cur_header_len > 1) &&
903 (ctx->cur_header[(ctx->cur_header_len)-1] == '\r') )
904 --ctx->cur_header_len;
905 ctx->cur_header[ctx->cur_header_len] = '\0';
908 if (ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
910 /* SIGNING -------------------------------------------------------------- */
911 if (ctx->mode == PDKIM_MODE_SIGN)
913 pdkim_signature *sig;
915 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
917 /* Add header to the signed headers list (in reverse order) */
918 sig->headers = pdkim_prepend_stringlist(sig->headers,
922 /* VERIFICATION ----------------------------------------------------------- */
923 /* DKIM-Signature: headers are added to the verification list */
924 if (ctx->mode == PDKIM_MODE_VERIFY)
926 if (strncasecmp(CCS ctx->cur_header,
927 DKIM_SIGNATURE_HEADERNAME,
928 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
930 pdkim_signature *new_sig;
932 /* Create and chain new signature block */
933 DEBUG(D_acl) debug_printf(
934 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
936 if ((new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header)))
938 pdkim_signature *last_sig = ctx->sig;
943 while (last_sig->next) last_sig = last_sig->next;
944 last_sig->next = new_sig;
948 DEBUG(D_acl) debug_printf(
949 "Error while parsing signature header\n"
950 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
953 /* every other header is stored for signature verification */
955 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header);
959 *ctx->cur_header = '\0';
960 ctx->cur_header_len = 0; /* leave buffer for reuse */
966 /* -------------------------------------------------------------------------- */
967 #define HEADER_BUFFER_FRAG_SIZE 256
970 pdkim_feed(pdkim_ctx *ctx, char *data, int len)
974 for (p = 0; p<len; p++)
978 if (ctx->past_headers)
980 /* Processing body byte */
981 ctx->linebuf[ctx->linebuf_offset++] = c;
984 int rc = pdkim_bodyline_complete(ctx); /* End of line */
985 if (rc != PDKIM_OK) return rc;
987 if (ctx->linebuf_offset == (PDKIM_MAX_BODY_LINE_LEN-1))
988 return PDKIM_ERR_LONG_LINE;
992 /* Processing header byte */
999 int rc = pdkim_header_complete(ctx); /* Seen last header line */
1000 if (rc != PDKIM_OK) return rc;
1002 ctx->past_headers = TRUE;
1004 DEBUG(D_acl) debug_printf(
1005 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n");
1009 ctx->seen_lf = TRUE;
1011 else if (ctx->seen_lf)
1013 if (!(c == '\t' || c == ' '))
1015 int rc = pdkim_header_complete(ctx); /* End of header */
1016 if (rc != PDKIM_OK) return rc;
1018 ctx->seen_lf = FALSE;
1022 if (ctx->cur_header_len < PDKIM_MAX_HEADER_LEN)
1023 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1024 &ctx->cur_header_len, CUS &data[p], 1);
1032 /* Extend a grwong header with a continuation-linebreak */
1034 pdkim_hdr_cont(uschar * str, int * size, int * ptr, int * col)
1037 return string_catn(str, size, ptr, US"\r\n\t", 3);
1043 * RFC 5322 specifies that header line length SHOULD be no more than 78
1047 * returns uschar * (not nul-terminated)
1049 * col: this int holds and receives column number (octets since last '\n')
1050 * str: partial string to append to
1051 * size: current buffer size for str
1052 * ptr: current tail-pointer for str
1053 * pad: padding, split line or space after before or after eg: ";"
1054 * intro: - must join to payload eg "h=", usually the tag name
1055 * payload: eg base64 data - long data can be split arbitrarily.
1057 * this code doesn't fold the header in some of the places that RFC4871
1058 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1059 * pairs and inside long values. it also always spaces or breaks after the
1062 * no guarantees are made for output given out-of range input. like tag
1063 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1067 pdkim_headcat(int * col, uschar * str, int * size, int * ptr,
1068 const uschar * pad, const uschar * intro, const uschar * payload)
1076 str = pdkim_hdr_cont(str, size, ptr, col);
1077 str = string_catn(str, size, ptr, pad, l);
1081 l = (pad?1:0) + (intro?Ustrlen(intro):0);
1084 { /*can't fit intro - start a new line to make room.*/
1085 str = pdkim_hdr_cont(str, size, ptr, col);
1086 l = intro?Ustrlen(intro):0;
1089 l += payload ? Ustrlen(payload):0 ;
1092 { /* this fragment will not fit on a single line */
1095 str = string_catn(str, size, ptr, US" ", 1);
1097 pad = NULL; /* only want this once */
1103 size_t sl = Ustrlen(intro);
1105 str = string_catn(str, size, ptr, intro, sl);
1108 intro = NULL; /* only want this once */
1113 size_t sl = Ustrlen(payload);
1114 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1116 str = string_catn(str, size, ptr, payload, chomp);
1122 /* the while precondition tells us it didn't fit. */
1123 str = pdkim_hdr_cont(str, size, ptr, col);
1128 str = pdkim_hdr_cont(str, size, ptr, col);
1134 str = string_catn(str, size, ptr, US" ", 1);
1141 size_t sl = Ustrlen(intro);
1143 str = string_catn(str, size, ptr, intro, sl);
1151 size_t sl = Ustrlen(payload);
1153 str = string_catn(str, size, ptr, payload, sl);
1161 /* -------------------------------------------------------------------------- */
1164 pdkim_create_header(pdkim_signature *sig, BOOL final)
1169 uschar * hdr; int hdr_size = 0, hdr_len = 0;
1170 uschar * canon_all; int can_size = 0, can_len = 0;
1172 canon_all = string_cat (NULL, &can_size, &can_len,
1173 pdkim_canons[sig->canon_headers]);
1174 canon_all = string_catn(canon_all, &can_size, &can_len, US"/", 1);
1175 canon_all = string_cat (canon_all, &can_size, &can_len,
1176 pdkim_canons[sig->canon_body]);
1177 canon_all[can_len] = '\0';
1179 hdr = string_cat(NULL, &hdr_size, &hdr_len,
1180 US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1183 /* Required and static bits */
1184 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
1185 pdkim_algos[sig->algo]);
1186 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
1187 pdkim_querymethods[sig->querymethod]);
1188 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=",
1190 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"d=",
1192 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=",
1195 /* list of header names can be split between items. */
1197 uschar * n = string_copy(sig->headernames);
1198 uschar * i = US"h=";
1203 uschar * c = Ustrchr(n, ':');
1208 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, NULL, US":");
1210 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, s, i, n);
1221 base64_bh = pdkim_encode_base64(&sig->bodyhash);
1222 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"bh=", base64_bh);
1226 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"i=", sig->identity);
1228 if (sig->created > 0)
1232 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1233 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"t=", minibuf);
1236 if (sig->expires > 0)
1240 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1241 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"x=", minibuf);
1244 if (sig->bodylength >= 0)
1248 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1249 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"l=", minibuf);
1252 /* Preliminary or final version? */
1253 base64_b = final ? pdkim_encode_base64(&sig->sigdata) : US"";
1254 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
1256 /* add trailing semicolon: I'm not sure if this is actually needed */
1257 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
1259 hdr[hdr_len] = '\0';
1264 /* -------------------------------------------------------------------------- */
1267 pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatures)
1269 pdkim_signature *sig = ctx->sig;
1270 uschar * headernames = NULL; /* Collected signed header names */
1273 /* Check if we must still flush a (partial) header. If that is the
1274 case, the message has no body, and we must compute a body hash
1275 out of '<CR><LF>' */
1276 if (ctx->cur_header && ctx->cur_header_len)
1278 int rc = pdkim_header_complete(ctx);
1279 if (rc != PDKIM_OK) return rc;
1280 pdkim_update_bodyhash(ctx, "\r\n", 2);
1283 DEBUG(D_acl) debug_printf(
1284 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1286 /* Build (and/or evaluate) body hash */
1287 pdkim_finish_bodyhash(ctx);
1291 BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
1296 int hdata_alloc = 0;
1301 exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256);
1303 DEBUG(D_acl) debug_printf(
1304 "PDKIM >> Hashed header data, canonicalized, in sequence >>>>>>>>>>>>>>\n");
1306 /* SIGNING ---------------------------------------------------------------- */
1307 /* When signing, walk through our header list and add them to the hash. As we
1308 go, construct a list of the header's names to use for the h= parameter.
1309 Then append to that list any remaining header names for which there was no
1312 if (ctx->mode == PDKIM_MODE_SIGN)
1314 pdkim_stringlist *p;
1319 for (p = sig->headers; p; p = p->next)
1320 if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
1323 /* Collect header names (Note: colon presence is guaranteed here) */
1324 uschar * q = Ustrchr(p->value, ':');
1326 headernames = string_catn(headernames, &hs, &hl,
1327 p->value, (q - US p->value) + (p->next ? 1 : 0));
1329 rh = sig->canon_headers == PDKIM_CANON_RELAXED
1330 ? pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
1331 : string_copy(CUS p->value); /* just copy it for simple canon */
1333 /* Feed header to the hash algorithm */
1334 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1336 /* Remember headers block for signing (when the library cannot do incremental) */
1337 (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
1339 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1342 l = sig->sign_headers;
1343 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1345 { /*SSS string_append_listele() */
1346 if (hl > 0 && headernames[hl-1] != ':')
1347 headernames = string_catn(headernames, &hs, &hl, US":", 1);
1349 headernames = string_cat(headernames, &hs, &hl, s);
1351 headernames[hl] = '\0';
1353 /* Copy headernames to signature struct */
1354 sig->headernames = headernames;
1355 headernames = NULL, hs = hl = 0;
1357 /* Create signature header with b= omitted */
1358 sig_hdr = pdkim_create_header(sig, FALSE);
1361 /* VERIFICATION ----------------------------------------------------------- */
1362 /* When verifying, walk through the header name list in the h= parameter and
1363 add the headers to the hash in that order. */
1366 uschar * b = string_copy(sig->headernames);
1369 pdkim_stringlist * hdrs;
1372 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1377 if ((q = Ustrchr(p, ':')))
1380 /*XXX walk the list of headers in same order as received. */
1381 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1383 && strncasecmp(hdrs->value, CS p, Ustrlen(p)) == 0
1384 && (hdrs->value)[Ustrlen(p)] == ':'
1387 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1388 ? pdkim_relax_header(hdrs->value, 1) /* cook header for relaxed canon */
1389 : string_copy(CUS hdrs->value); /* just copy it for simple canon */
1391 /* Feed header to the hash algorithm */
1392 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1394 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1403 sig_hdr = string_copy(sig->rawsig_no_b_val);
1406 DEBUG(D_acl) debug_printf(
1407 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1409 /* Relax header if necessary */
1410 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1411 sig_hdr = pdkim_relax_header(sig_hdr, 0);
1416 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1417 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1419 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1422 /* Finalize header hash */
1423 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1424 exim_sha_finish(&hhash_ctx, &hhash);
1428 debug_printf("PDKIM [%s] hh computed: ", sig->domain);
1429 pdkim_hexprint(hhash.data, hhash.len);
1432 /* Remember headers block for signing (when the library cannot do incremental) */
1433 if (ctx->mode == PDKIM_MODE_SIGN)
1434 (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
1436 /* SIGNING ---------------------------------------------------------------- */
1437 if (ctx->mode == PDKIM_MODE_SIGN)
1440 const uschar * errstr;
1442 /* Import private key */
1443 if ((errstr = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
1445 DEBUG(D_acl) debug_printf("signing_init: %s\n", errstr);
1446 return PDKIM_ERR_RSA_PRIVKEY;
1449 /* Do signing. With OpenSSL we are signing the hash of headers just
1450 calculated, with GnuTLS we have to sign an entire block of headers
1451 (due to available interfaces) and it recalculates the hash internally. */
1453 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1457 if ((errstr = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sigdata)))
1459 DEBUG(D_acl) debug_printf("signing: %s\n", errstr);
1460 return PDKIM_ERR_RSA_SIGNING;
1465 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1466 pdkim_hexprint(sig->sigdata.data, sig->sigdata.len);
1469 sig->signature_header = pdkim_create_header(sig, TRUE);
1472 /* VERIFICATION ----------------------------------------------------------- */
1476 const uschar * errstr;
1478 uschar *dns_txt_name, *dns_txt_reply;
1480 /* Make sure we have all required signature tags */
1481 if (!( sig->domain && *sig->domain
1482 && sig->selector && *sig->selector
1483 && sig->headernames && *sig->headernames
1484 && sig->bodyhash.data
1485 && sig->sigdata.data
1490 sig->verify_status = PDKIM_VERIFY_INVALID;
1491 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1493 DEBUG(D_acl) debug_printf(
1494 " Error in DKIM-Signature header: tags missing or invalid\n"
1495 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1499 /* Make sure sig uses supported DKIM version (only v1) */
1500 if (sig->version != 1)
1502 sig->verify_status = PDKIM_VERIFY_INVALID;
1503 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1505 DEBUG(D_acl) debug_printf(
1506 " Error in DKIM-Signature header: unsupported DKIM version\n"
1507 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1511 /* Fetch public key for signing domain, from DNS */
1513 dns_txt_name = string_sprintf("%s._domainkey.%s.",
1514 sig->selector, sig->domain);
1516 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1517 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1519 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1520 || dns_txt_reply[0] == '\0')
1522 sig->verify_status = PDKIM_VERIFY_INVALID;
1523 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1530 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1532 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1535 if (!(sig->pubkey = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply)))
1537 sig->verify_status = PDKIM_VERIFY_INVALID;
1538 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1540 DEBUG(D_acl) debug_printf(
1541 " Error while parsing public key record\n"
1542 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1546 DEBUG(D_acl) debug_printf(
1547 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1549 /* Import public key */
1550 if ((errstr = exim_rsa_verify_init(&sig->pubkey->key, &vctx)))
1552 DEBUG(D_acl) debug_printf("verify_init: %s\n", errstr);
1553 sig->verify_status = PDKIM_VERIFY_INVALID;
1554 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1558 /* Check the signature */
1559 if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sigdata)))
1561 DEBUG(D_acl) debug_printf("headers verify: %s\n", errstr);
1562 sig->verify_status = PDKIM_VERIFY_FAIL;
1563 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1568 /* We have a winner! (if bodydhash was correct earlier) */
1569 if (sig->verify_status == PDKIM_VERIFY_NONE)
1570 sig->verify_status = PDKIM_VERIFY_PASS;
1576 debug_printf("PDKIM [%s] signature status: %s",
1577 sig->domain, pdkim_verify_status_str(sig->verify_status));
1578 if (sig->verify_ext_status > 0)
1579 debug_printf(" (%s)\n",
1580 pdkim_verify_ext_status_str(sig->verify_ext_status));
1589 /* If requested, set return pointer to signature(s) */
1590 if (return_signatures)
1591 *return_signatures = ctx->sig;
1597 /* -------------------------------------------------------------------------- */
1599 DLLEXPORT pdkim_ctx *
1600 pdkim_init_verify(int(*dns_txt_callback)(char *, char *))
1604 ctx = store_get(sizeof(pdkim_ctx));
1605 memset(ctx, 0, sizeof(pdkim_ctx));
1607 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1608 ctx->mode = PDKIM_MODE_VERIFY;
1609 ctx->dns_txt_callback = dns_txt_callback;
1615 /* -------------------------------------------------------------------------- */
1617 DLLEXPORT pdkim_ctx *
1618 pdkim_init_sign(char *domain, char *selector, char *rsa_privkey, int algo)
1621 pdkim_signature *sig;
1623 if (!domain || !selector || !rsa_privkey)
1626 ctx = store_get(sizeof(pdkim_ctx));
1627 memset(ctx, 0, sizeof(pdkim_ctx));
1629 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1631 sig = store_get(sizeof(pdkim_signature));
1632 memset(sig, 0, sizeof(pdkim_signature));
1634 sig->bodylength = -1;
1636 ctx->mode = PDKIM_MODE_SIGN;
1639 sig->domain = string_copy(US domain);
1640 sig->selector = string_copy(US selector);
1641 sig->rsa_privkey = string_copy(US rsa_privkey);
1644 exim_sha_init(&sig->body_hash, algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
1649 /* -------------------------------------------------------------------------- */
1652 pdkim_set_optional(pdkim_ctx *ctx,
1658 unsigned long created,
1659 unsigned long expires)
1661 pdkim_signature * sig = ctx->sig;
1664 sig->identity = string_copy(US identity);
1666 sig->sign_headers = string_copy(sign_headers
1667 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1669 sig->canon_headers = canon_headers;
1670 sig->canon_body = canon_body;
1671 sig->bodylength = bodylength;
1672 sig->created = created;
1673 sig->expires = expires;
1687 #endif /*DISABLE_DKIM*/