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 default: return "PDKIM_VERIFY_UNKNOWN";
142 /* -------------------------------------------------------------------------- */
143 /* Print debugging functions */
145 pdkim_quoteprint(const uschar *data, int len)
148 for (i = 0; i < len; i++)
150 const int c = data[i];
153 case ' ' : debug_printf("{SP}"); break;
154 case '\t': debug_printf("{TB}"); break;
155 case '\r': debug_printf("{CR}"); break;
156 case '\n': debug_printf("{LF}"); break;
157 case '{' : debug_printf("{BO}"); break;
158 case '}' : debug_printf("{BC}"); break;
160 if ( (c < 32) || (c > 127) )
161 debug_printf("{%02x}", c);
163 debug_printf("%c", c);
171 pdkim_hexprint(const uschar *data, int len)
174 for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
180 static pdkim_stringlist *
181 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
183 pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
185 memset(new_entry, 0, sizeof(pdkim_stringlist));
186 new_entry->value = string_copy(str);
187 if (base) new_entry->next = base;
193 /* Trim whitespace fore & aft */
196 pdkim_strtrim(uschar * str)
200 while (*p == '\t' || *p == ' ') p++; /* skip whitespace */
201 while (*p) {*q = *p; q++; p++;} /* dump the leading whitespace */
203 while (q != str && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
204 { /* dump trailing whitespace */
212 /* -------------------------------------------------------------------------- */
215 pdkim_free_ctx(pdkim_ctx *ctx)
220 /* -------------------------------------------------------------------------- */
221 /* Matches the name of the passed raw "header" against
222 the passed colon-separated "tick", and invalidates
223 the entry in tick. Returns OK or fail-code */
224 /*XXX might be safer done using a pdkim_stringlist for "tick" */
227 header_name_match(const uschar * header, uschar * tick)
233 uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
236 return PDKIM_FAIL; /* This isn't a header */
238 /* if we had strncmpic() we wouldn't need this copy */
239 hname = string_copyn(header, hcolon-header);
241 /* Copy tick-off list locally, so we can punch zeroes into it */
242 p = lcopy = string_copy(tick);
244 for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':'))
247 if (strcmpic(p, hname) == 0)
253 if (strcmpic(p, hname) == 0)
259 /* Invalidate header name instance in tick-off list */
265 /* -------------------------------------------------------------------------- */
266 /* Performs "relaxed" canonicalization of a header. */
269 pdkim_relax_header(const uschar * header, int crlf)
271 BOOL past_field_name = FALSE;
272 BOOL seen_wsp = FALSE;
274 uschar * relaxed = store_get(Ustrlen(header)+3);
275 uschar * q = relaxed;
277 for (p = header; *p; p++)
281 if (c == '\r' || c == '\n')
283 if (c == '\t' || c == ' ')
287 c = ' '; /* Turns WSP into SP */
291 if (!past_field_name && c == ':')
293 if (seen_wsp) q--; /* This removes WSP before the colon */
294 seen_wsp = TRUE; /* This removes WSP after the colon */
295 past_field_name = TRUE;
300 /* Lowercase header name */
301 if (!past_field_name) c = tolower(c);
305 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
307 if (crlf) { *q++ = '\r'; *q++ = '\n'; }
313 /* -------------------------------------------------------------------------- */
314 #define PDKIM_QP_ERROR_DECODE -1
317 pdkim_decode_qp_char(uschar *qp_p, int *c)
319 uschar *initial_pos = qp_p;
321 /* Advance one char */
324 /* Check for two hex digits and decode them */
325 if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
327 /* Do hex conversion */
328 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
329 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
333 /* Illegal char here */
334 *c = PDKIM_QP_ERROR_DECODE;
339 /* -------------------------------------------------------------------------- */
342 pdkim_decode_qp(uschar * str)
347 uschar * n = store_get(Ustrlen(str)+1);
355 p = pdkim_decode_qp_char(p, &nchar);
371 /* -------------------------------------------------------------------------- */
374 pdkim_decode_base64(uschar *str, blob * b)
377 dlen = b64decode(str, &b->data);
378 if (dlen < 0) b->data = NULL;
383 pdkim_encode_base64(blob * b)
385 return b64encode(b->data, b->len);
389 /* -------------------------------------------------------------------------- */
390 #define PDKIM_HDR_LIMBO 0
391 #define PDKIM_HDR_TAG 1
392 #define PDKIM_HDR_VALUE 2
394 static pdkim_signature *
395 pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
397 pdkim_signature *sig ;
399 uschar * cur_tag = NULL; int ts = 0, tl = 0;
400 uschar * cur_val = NULL; int vs = 0, vl = 0;
401 BOOL past_hname = FALSE;
402 BOOL in_b_val = FALSE;
403 int where = PDKIM_HDR_LIMBO;
406 sig = store_get(sizeof(pdkim_signature));
407 memset(sig, 0, sizeof(pdkim_signature));
408 sig->bodylength = -1;
410 q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
412 for (p = raw_hdr; ; p++)
417 if (c == '\r' || c == '\n')
420 /* Fast-forward through header name */
423 if (c == ':') past_hname = TRUE;
427 if (where == PDKIM_HDR_LIMBO)
429 /* In limbo, just wait for a tag-char to appear */
430 if (!(c >= 'a' && c <= 'z'))
433 where = PDKIM_HDR_TAG;
436 if (where == PDKIM_HDR_TAG)
438 if (c >= 'a' && c <= 'z')
439 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
444 if (Ustrcmp(cur_tag, "b") == 0)
449 where = PDKIM_HDR_VALUE;
454 if (where == PDKIM_HDR_VALUE)
456 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
459 if (c == ';' || c == '\0')
464 pdkim_strtrim(cur_val);
466 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
471 if (cur_tag[1] == 'h')
472 pdkim_decode_base64(cur_val, &sig->bodyhash);
474 pdkim_decode_base64(cur_val, &sig->sigdata);
477 /* We only support version 1, and that is currently the
478 only version there is. */
479 if (Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0)
483 for (i = 0; pdkim_algos[i]; i++)
484 if (Ustrcmp(cur_val, pdkim_algos[i]) == 0)
491 for (i = 0; pdkim_combined_canons[i].str; i++)
492 if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0)
494 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
495 sig->canon_body = pdkim_combined_canons[i].canon_body;
500 for (i = 0; pdkim_querymethods[i]; i++)
501 if (Ustrcmp(cur_val, pdkim_querymethods[i]) == 0)
503 sig->querymethod = i;
508 sig->selector = string_copy(cur_val); break;
510 sig->domain = string_copy(cur_val); break;
512 sig->identity = pdkim_decode_qp(cur_val); break;
514 sig->created = strtoul(CS cur_val, NULL, 10); break;
516 sig->expires = strtoul(CS cur_val, NULL, 10); break;
518 sig->bodylength = strtol(CS cur_val, NULL, 10); break;
520 sig->headernames = string_copy(cur_val); break;
522 sig->copiedheaders = pdkim_decode_qp(cur_val); break;
524 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
531 where = PDKIM_HDR_LIMBO;
534 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
545 /* Make sure the most important bits are there. */
550 /* Chomp raw header. The final newline must not be added to the signature. */
551 while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
557 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
558 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
560 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sigdata.len*8);
562 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
565 exim_sha_init(&sig->body_hash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
570 /* -------------------------------------------------------------------------- */
572 static pdkim_pubkey *
573 pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
577 uschar * cur_tag = NULL; int ts = 0, tl = 0;
578 uschar * cur_val = NULL; int vs = 0, vl = 0;
579 int where = PDKIM_HDR_LIMBO;
581 pub = store_get(sizeof(pdkim_pubkey));
582 memset(pub, 0, sizeof(pdkim_pubkey));
584 for (p = raw_record; ; p++)
589 if (c == '\r' || c == '\n')
592 if (where == PDKIM_HDR_LIMBO)
594 /* In limbo, just wait for a tag-char to appear */
595 if (!(c >= 'a' && c <= 'z'))
598 where = PDKIM_HDR_TAG;
601 if (where == PDKIM_HDR_TAG)
603 if (c >= 'a' && c <= 'z')
604 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
609 where = PDKIM_HDR_VALUE;
614 if (where == PDKIM_HDR_VALUE)
616 if (c == ';' || c == '\0')
621 pdkim_strtrim(cur_val);
622 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
627 /* This tag isn't evaluated because:
628 - We only support version DKIM1.
629 - Which is the default for this value (set below)
630 - Other versions are currently not specified. */
634 pub->hashes = string_copy(cur_val); break;
636 pub->granularity = string_copy(cur_val); break;
638 pub->notes = pdkim_decode_qp(cur_val); break;
640 pdkim_decode_base64(US cur_val, &pub->key);
643 pub->srvtype = string_copy(cur_val); break;
645 if (Ustrchr(cur_val, 'y') != NULL) pub->testing = 1;
646 if (Ustrchr(cur_val, 's') != NULL) pub->no_subdomaining = 1;
649 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
655 where = PDKIM_HDR_LIMBO;
658 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
662 if (c == '\0') break;
665 /* Set fallback defaults */
666 if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
667 if (!pub->granularity) pub->granularity = string_copy(US"*");
668 if (!pub->keytype ) pub->keytype = string_copy(US"rsa");
669 if (!pub->srvtype ) pub->srvtype = string_copy(US"*");
679 /* -------------------------------------------------------------------------- */
682 pdkim_update_bodyhash(pdkim_ctx *ctx, const char *data, int len)
684 pdkim_signature *sig = ctx->sig;
685 /* Cache relaxed version of data */
686 uschar *relaxed_data = NULL;
689 /* Traverse all signatures, updating their hashes. */
692 /* Defaults to simple canon (no further treatment necessary) */
693 const uschar *canon_data = CUS data;
696 if (sig->canon_body == PDKIM_CANON_RELAXED)
698 /* Relax the line if not done already */
701 BOOL seen_wsp = FALSE;
705 relaxed_data = store_get(len+1);
707 for (p = data; *p; p++)
712 if (q > 0 && relaxed_data[q-1] == ' ')
715 else if (c == '\t' || c == ' ')
717 c = ' '; /* Turns WSP into SP */
724 relaxed_data[q++] = c;
726 relaxed_data[q] = '\0';
729 canon_data = relaxed_data;
730 canon_len = relaxed_len;
733 /* Make sure we don't exceed the to-be-signed body length */
734 if ( sig->bodylength >= 0
735 && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
737 canon_len = sig->bodylength - sig->signed_body_bytes;
741 exim_sha_update(&sig->body_hash, CUS canon_data, canon_len);
742 sig->signed_body_bytes += canon_len;
743 DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
753 /* -------------------------------------------------------------------------- */
756 pdkim_finish_bodyhash(pdkim_ctx *ctx)
758 pdkim_signature *sig;
760 /* Traverse all signatures */
761 for (sig = ctx->sig; sig; sig = sig->next)
762 { /* Finish hashes */
765 exim_sha_finish(&sig->body_hash, &bh);
769 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
770 "PDKIM [%s] bh computed: ",
771 sig->domain, sig->signed_body_bytes, sig->domain);
772 pdkim_hexprint(CUS bh.data, bh.len);
775 /* SIGNING -------------------------------------------------------------- */
776 if (ctx->mode == PDKIM_MODE_SIGN)
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;
786 /* VERIFICATION --------------------------------------------------------- */
789 /* Compare bodyhash */
790 if (memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
792 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
798 debug_printf("PDKIM [%s] bh signature: ", sig->domain);
799 pdkim_hexprint(sig->bodyhash.data,
800 exim_sha_hashlen(&sig->body_hash));
801 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
803 sig->verify_status = PDKIM_VERIFY_FAIL;
804 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
812 /* -------------------------------------------------------------------------- */
813 /* Callback from pdkim_feed below for processing complete body lines */
816 pdkim_bodyline_complete(pdkim_ctx *ctx)
818 char *p = ctx->linebuf;
819 int n = ctx->linebuf_offset;
820 pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
822 /* Ignore extra data if we've seen the end-of-data marker */
823 if (ctx->seen_eod) goto BAIL;
825 /* We've always got one extra byte to stuff a zero ... */
826 ctx->linebuf[ctx->linebuf_offset] = '\0';
828 /* Terminate on EOD marker */
829 if (memcmp(p, ".\r\n", 3) == 0)
831 /* In simple body mode, if any empty lines were buffered,
832 replace with one. rfc 4871 3.4.3 */
833 /*XXX checking the signed-body-bytes is a gross hack; I think
834 it indicates that all linebreaks should be buffered, including
835 the one terminating a text line */
836 if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
837 && sig->signed_body_bytes == 0
838 && ctx->num_buffered_crlf > 0
840 pdkim_update_bodyhash(ctx, "\r\n", 2);
842 ctx->seen_eod = TRUE;
846 if (memcmp(p, "..", 2) == 0)
852 /* Empty lines need to be buffered until we find a non-empty line */
853 if (memcmp(p, "\r\n", 2) == 0)
855 ctx->num_buffered_crlf++;
859 if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
861 /* Lines with just spaces need to be buffered too */
863 while (memcmp(check, "\r\n", 2) != 0)
867 if (c != '\t' && c != ' ')
872 ctx->num_buffered_crlf++;
877 /* At this point, we have a non-empty line, so release the buffered ones. */
878 while (ctx->num_buffered_crlf)
880 pdkim_update_bodyhash(ctx, "\r\n", 2);
881 ctx->num_buffered_crlf--;
884 pdkim_update_bodyhash(ctx, p, n);
887 ctx->linebuf_offset = 0;
892 /* -------------------------------------------------------------------------- */
893 /* Callback from pdkim_feed below for processing complete headers */
894 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
897 pdkim_header_complete(pdkim_ctx *ctx)
899 /* Special case: The last header can have an extra \r appended */
900 if ( (ctx->cur_header_len > 1) &&
901 (ctx->cur_header[(ctx->cur_header_len)-1] == '\r') )
902 --ctx->cur_header_len;
903 ctx->cur_header[ctx->cur_header_len] = '\0';
906 if (ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
908 /* SIGNING -------------------------------------------------------------- */
909 if (ctx->mode == PDKIM_MODE_SIGN)
911 pdkim_signature *sig;
913 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
915 /* Add header to the signed headers list (in reverse order) */
916 sig->headers = pdkim_prepend_stringlist(sig->headers,
920 /* VERIFICATION ----------------------------------------------------------- */
921 /* DKIM-Signature: headers are added to the verification list */
922 if (ctx->mode == PDKIM_MODE_VERIFY)
924 if (strncasecmp(CCS ctx->cur_header,
925 DKIM_SIGNATURE_HEADERNAME,
926 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
928 pdkim_signature *new_sig;
930 /* Create and chain new signature block */
931 DEBUG(D_acl) debug_printf(
932 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
934 if ((new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header)))
936 pdkim_signature *last_sig = ctx->sig;
941 while (last_sig->next) last_sig = last_sig->next;
942 last_sig->next = new_sig;
946 DEBUG(D_acl) debug_printf(
947 "Error while parsing signature header\n"
948 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
951 /* every other header is stored for signature verification */
953 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header);
957 *ctx->cur_header = '\0';
958 ctx->cur_header_len = 0; /* leave buffer for reuse */
964 /* -------------------------------------------------------------------------- */
965 #define HEADER_BUFFER_FRAG_SIZE 256
968 pdkim_feed(pdkim_ctx *ctx, char *data, int len)
972 for (p = 0; p<len; p++)
976 if (ctx->past_headers)
978 /* Processing body byte */
979 ctx->linebuf[ctx->linebuf_offset++] = c;
982 int rc = pdkim_bodyline_complete(ctx); /* End of line */
983 if (rc != PDKIM_OK) return rc;
985 if (ctx->linebuf_offset == (PDKIM_MAX_BODY_LINE_LEN-1))
986 return PDKIM_ERR_LONG_LINE;
990 /* Processing header byte */
997 int rc = pdkim_header_complete(ctx); /* Seen last header line */
998 if (rc != PDKIM_OK) return rc;
1000 ctx->past_headers = TRUE;
1002 DEBUG(D_acl) debug_printf(
1003 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n");
1007 ctx->seen_lf = TRUE;
1009 else if (ctx->seen_lf)
1011 if (!(c == '\t' || c == ' '))
1013 int rc = pdkim_header_complete(ctx); /* End of header */
1014 if (rc != PDKIM_OK) return rc;
1016 ctx->seen_lf = FALSE;
1020 if (ctx->cur_header_len < PDKIM_MAX_HEADER_LEN)
1021 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1022 &ctx->cur_header_len, CUS &data[p], 1);
1030 /* Extend a grwong header with a continuation-linebreak */
1032 pdkim_hdr_cont(uschar * str, int * size, int * ptr, int * col)
1035 return string_catn(str, size, ptr, US"\r\n\t", 3);
1041 * RFC 5322 specifies that header line length SHOULD be no more than 78
1045 * returns uschar * (not nul-terminated)
1047 * col: this int holds and receives column number (octets since last '\n')
1048 * str: partial string to append to
1049 * size: current buffer size for str
1050 * ptr: current tail-pointer for str
1051 * pad: padding, split line or space after before or after eg: ";"
1052 * intro: - must join to payload eg "h=", usually the tag name
1053 * payload: eg base64 data - long data can be split arbitrarily.
1055 * this code doesn't fold the header in some of the places that RFC4871
1056 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1057 * pairs and inside long values. it also always spaces or breaks after the
1060 * no guarantees are made for output given out-of range input. like tag
1061 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1065 pdkim_headcat(int * col, uschar * str, int * size, int * ptr,
1066 const uschar * pad, const uschar * intro, const uschar * payload)
1074 str = pdkim_hdr_cont(str, size, ptr, col);
1075 str = string_catn(str, size, ptr, pad, l);
1079 l = (pad?1:0) + (intro?Ustrlen(intro):0);
1082 { /*can't fit intro - start a new line to make room.*/
1083 str = pdkim_hdr_cont(str, size, ptr, col);
1084 l = intro?Ustrlen(intro):0;
1087 l += payload ? Ustrlen(payload):0 ;
1090 { /* this fragment will not fit on a single line */
1093 str = string_catn(str, size, ptr, US" ", 1);
1095 pad = NULL; /* only want this once */
1101 size_t sl = Ustrlen(intro);
1103 str = string_catn(str, size, ptr, intro, sl);
1106 intro = NULL; /* only want this once */
1111 size_t sl = Ustrlen(payload);
1112 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1114 str = string_catn(str, size, ptr, payload, chomp);
1120 /* the while precondition tells us it didn't fit. */
1121 str = pdkim_hdr_cont(str, size, ptr, col);
1126 str = pdkim_hdr_cont(str, size, ptr, col);
1132 str = string_catn(str, size, ptr, US" ", 1);
1139 size_t sl = Ustrlen(intro);
1141 str = string_catn(str, size, ptr, intro, sl);
1149 size_t sl = Ustrlen(payload);
1151 str = string_catn(str, size, ptr, payload, sl);
1159 /* -------------------------------------------------------------------------- */
1162 pdkim_create_header(pdkim_signature *sig, BOOL final)
1167 uschar * hdr; int hdr_size = 0, hdr_len = 0;
1168 uschar * canon_all; int can_size = 0, can_len = 0;
1170 canon_all = string_cat (NULL, &can_size, &can_len,
1171 pdkim_canons[sig->canon_headers]);
1172 canon_all = string_catn(canon_all, &can_size, &can_len, US"/", 1);
1173 canon_all = string_cat (canon_all, &can_size, &can_len,
1174 pdkim_canons[sig->canon_body]);
1175 canon_all[can_len] = '\0';
1177 hdr = string_cat(NULL, &hdr_size, &hdr_len,
1178 US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1181 /* Required and static bits */
1182 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
1183 pdkim_algos[sig->algo]);
1184 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
1185 pdkim_querymethods[sig->querymethod]);
1186 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=",
1188 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"d=",
1190 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=",
1193 /* list of header names can be split between items. */
1195 uschar * n = string_copy(sig->headernames);
1196 uschar * i = US"h=";
1201 uschar * c = Ustrchr(n, ':');
1206 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, NULL, US":");
1208 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, s, i, n);
1219 base64_bh = pdkim_encode_base64(&sig->bodyhash);
1220 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"bh=", base64_bh);
1224 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"i=", sig->identity);
1226 if (sig->created > 0)
1230 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1231 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"t=", minibuf);
1234 if (sig->expires > 0)
1238 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1239 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"x=", minibuf);
1242 if (sig->bodylength >= 0)
1246 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1247 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"l=", minibuf);
1250 /* Preliminary or final version? */
1251 base64_b = final ? pdkim_encode_base64(&sig->sigdata) : US"";
1252 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
1254 /* add trailing semicolon: I'm not sure if this is actually needed */
1255 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
1257 hdr[hdr_len] = '\0';
1262 /* -------------------------------------------------------------------------- */
1265 pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatures)
1267 pdkim_signature *sig = ctx->sig;
1268 uschar * headernames = NULL; /* Collected signed header names */
1271 /* Check if we must still flush a (partial) header. If that is the
1272 case, the message has no body, and we must compute a body hash
1273 out of '<CR><LF>' */
1274 if (ctx->cur_header && ctx->cur_header_len)
1276 int rc = pdkim_header_complete(ctx);
1277 if (rc != PDKIM_OK) return rc;
1278 pdkim_update_bodyhash(ctx, "\r\n", 2);
1281 DEBUG(D_acl) debug_printf(
1282 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1284 /* Build (and/or evaluate) body hash */
1285 pdkim_finish_bodyhash(ctx);
1289 BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
1294 int hdata_alloc = 0;
1299 exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256);
1301 DEBUG(D_acl) debug_printf(
1302 "PDKIM >> Hashed header data, canonicalized, in sequence >>>>>>>>>>>>>>\n");
1304 /* SIGNING ---------------------------------------------------------------- */
1305 /* When signing, walk through our header list and add them to the hash. As we
1306 go, construct a list of the header's names to use for the h= parameter.
1307 Then append to that list any remaining header names for which there was no
1310 if (ctx->mode == PDKIM_MODE_SIGN)
1312 pdkim_stringlist *p;
1317 for (p = sig->headers; p; p = p->next)
1318 if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
1321 /* Collect header names (Note: colon presence is guaranteed here) */
1322 uschar * q = Ustrchr(p->value, ':');
1324 headernames = string_catn(headernames, &hs, &hl,
1325 p->value, (q - US p->value) + (p->next ? 1 : 0));
1327 rh = sig->canon_headers == PDKIM_CANON_RELAXED
1328 ? pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
1329 : string_copy(CUS p->value); /* just copy it for simple canon */
1331 /* Feed header to the hash algorithm */
1332 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1334 /* Remember headers block for signing (when the library cannot do incremental) */
1335 (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
1337 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1340 l = sig->sign_headers;
1341 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1343 { /*SSS string_append_listele() */
1344 if (hl > 0 && headernames[hl-1] != ':')
1345 headernames = string_catn(headernames, &hs, &hl, US":", 1);
1347 headernames = string_cat(headernames, &hs, &hl, s);
1349 headernames[hl] = '\0';
1351 /* Copy headernames to signature struct */
1352 sig->headernames = headernames;
1353 headernames = NULL, hs = hl = 0;
1355 /* Create signature header with b= omitted */
1356 sig_hdr = pdkim_create_header(sig, FALSE);
1359 /* VERIFICATION ----------------------------------------------------------- */
1360 /* When verifying, walk through the header name list in the h= parameter and
1361 add the headers to the hash in that order. */
1364 uschar * b = string_copy(sig->headernames);
1367 pdkim_stringlist * hdrs;
1370 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1375 if ((q = Ustrchr(p, ':')))
1378 /*XXX walk the list of headers in same order as received. */
1379 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1381 && strncasecmp(hdrs->value, CS p, Ustrlen(p)) == 0
1382 && (hdrs->value)[Ustrlen(p)] == ':'
1385 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1386 ? pdkim_relax_header(hdrs->value, 1) /* cook header for relaxed canon */
1387 : string_copy(CUS hdrs->value); /* just copy it for simple canon */
1389 /* Feed header to the hash algorithm */
1390 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1392 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1401 sig_hdr = string_copy(sig->rawsig_no_b_val);
1404 DEBUG(D_acl) debug_printf(
1405 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1407 /* Relax header if necessary */
1408 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1409 sig_hdr = pdkim_relax_header(sig_hdr, 0);
1414 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1415 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1417 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1420 /* Finalize header hash */
1421 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1422 exim_sha_finish(&hhash_ctx, &hhash);
1426 debug_printf("PDKIM [%s] hh computed: ", sig->domain);
1427 pdkim_hexprint(hhash.data, hhash.len);
1430 /* Remember headers block for signing (when the library cannot do incremental) */
1431 if (ctx->mode == PDKIM_MODE_SIGN)
1432 (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
1434 /* SIGNING ---------------------------------------------------------------- */
1435 if (ctx->mode == PDKIM_MODE_SIGN)
1438 const uschar * errstr;
1440 /* Import private key */
1441 if ((errstr = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
1443 DEBUG(D_acl) debug_printf("signing_init: %s\n", errstr);
1444 return PDKIM_ERR_RSA_PRIVKEY;
1447 /* Do signing. With OpenSSL we are signing the hash of headers just
1448 calculated, with GnuTLS we have to sign an entire block of headers
1449 (due to available interfaces) and it recalculates the hash internally. */
1451 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1455 if ((errstr = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sigdata)))
1457 DEBUG(D_acl) debug_printf("signing: %s\n", errstr);
1458 return PDKIM_ERR_RSA_SIGNING;
1463 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1464 pdkim_hexprint(sig->sigdata.data, sig->sigdata.len);
1467 sig->signature_header = pdkim_create_header(sig, TRUE);
1470 /* VERIFICATION ----------------------------------------------------------- */
1474 const uschar * errstr;
1476 uschar *dns_txt_name, *dns_txt_reply;
1478 /* Fetch public key for signing domain, from DNS */
1480 dns_txt_name = string_sprintf("%s._domainkey.%s.",
1481 sig->selector, sig->domain);
1483 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1484 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1486 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1487 || dns_txt_reply[0] == '\0')
1489 sig->verify_status = PDKIM_VERIFY_INVALID;
1490 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1497 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1499 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1502 if (!(sig->pubkey = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply)))
1504 sig->verify_status = PDKIM_VERIFY_INVALID;
1505 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1507 DEBUG(D_acl) debug_printf(
1508 " Error while parsing public key record\n"
1509 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1513 DEBUG(D_acl) debug_printf(
1514 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1516 /* Import public key */
1517 if ((errstr = exim_rsa_verify_init(&sig->pubkey->key, &vctx)))
1519 DEBUG(D_acl) debug_printf("verify_init: %s\n", errstr);
1520 sig->verify_status = PDKIM_VERIFY_INVALID;
1521 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1525 /* Check the signature */
1526 if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sigdata)))
1528 DEBUG(D_acl) debug_printf("headers verify: %s\n", errstr);
1529 sig->verify_status = PDKIM_VERIFY_FAIL;
1530 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1535 /* We have a winner! (if bodydhash was correct earlier) */
1536 if (sig->verify_status == PDKIM_VERIFY_NONE)
1537 sig->verify_status = PDKIM_VERIFY_PASS;
1543 debug_printf("PDKIM [%s] signature status: %s",
1544 sig->domain, pdkim_verify_status_str(sig->verify_status));
1545 if (sig->verify_ext_status > 0)
1546 debug_printf(" (%s)\n",
1547 pdkim_verify_ext_status_str(sig->verify_ext_status));
1556 /* If requested, set return pointer to signature(s) */
1557 if (return_signatures)
1558 *return_signatures = ctx->sig;
1564 /* -------------------------------------------------------------------------- */
1566 DLLEXPORT pdkim_ctx *
1567 pdkim_init_verify(int(*dns_txt_callback)(char *, char *))
1571 ctx = store_get(sizeof(pdkim_ctx));
1572 memset(ctx, 0, sizeof(pdkim_ctx));
1574 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1575 ctx->mode = PDKIM_MODE_VERIFY;
1576 ctx->dns_txt_callback = dns_txt_callback;
1582 /* -------------------------------------------------------------------------- */
1584 DLLEXPORT pdkim_ctx *
1585 pdkim_init_sign(char *domain, char *selector, char *rsa_privkey, int algo)
1588 pdkim_signature *sig;
1590 if (!domain || !selector || !rsa_privkey)
1593 ctx = store_get(sizeof(pdkim_ctx));
1594 memset(ctx, 0, sizeof(pdkim_ctx));
1596 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1598 sig = store_get(sizeof(pdkim_signature));
1599 memset(sig, 0, sizeof(pdkim_signature));
1601 sig->bodylength = -1;
1603 ctx->mode = PDKIM_MODE_SIGN;
1606 sig->domain = string_copy(US domain);
1607 sig->selector = string_copy(US selector);
1608 sig->rsa_privkey = string_copy(US rsa_privkey);
1611 exim_sha_init(&sig->body_hash, algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
1616 /* -------------------------------------------------------------------------- */
1619 pdkim_set_optional(pdkim_ctx *ctx,
1625 unsigned long created,
1626 unsigned long expires)
1628 pdkim_signature * sig = ctx->sig;
1631 sig->identity = string_copy(US identity);
1633 sig->sign_headers = string_copy(sign_headers
1634 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1636 sig->canon_headers = canon_headers;
1637 sig->canon_body = canon_body;
1638 sig->bodylength = bodylength;
1639 sig->created = created;
1640 sig->expires = expires;
1654 #endif /*DISABLE_DKIM*/