2 * PDKIM - a RFC4871 (DKIM) implementation
4 * Copyright (C) 2009 - 2016 Tom Kistner <tom@duncanthrax.net>
5 * Copyright (C) 2016 - 2017 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)
120 case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE";
121 case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID";
122 case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL";
123 case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS";
124 default: return "PDKIM_VERIFY_UNKNOWN";
129 pdkim_verify_ext_status_str(int ext_status)
133 case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
134 case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
135 case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
136 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
137 case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
138 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
139 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
140 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
141 case PDKIM_VERIFY_INVALID_DKIM_VERSION: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
142 default: return "PDKIM_VERIFY_UNKNOWN";
147 pdkim_errstr(int status)
151 case PDKIM_OK: return US"OK";
152 case PDKIM_FAIL: return US"FAIL";
153 case PDKIM_ERR_RSA_PRIVKEY: return US"RSA_PRIVKEY";
154 case PDKIM_ERR_RSA_SIGNING: return US"RSA SIGNING";
155 case PDKIM_ERR_LONG_LINE: return US"RSA_LONG_LINE";
156 case PDKIM_ERR_BUFFER_TOO_SMALL: return US"BUFFER_TOO_SMALL";
157 case PDKIM_SIGN_PRIVKEY_WRAP: return US"PRIVKEY_WRAP";
158 case PDKIM_SIGN_PRIVKEY_B64D: return US"PRIVKEY_B64D";
159 default: return US"(unknown)";
164 /* -------------------------------------------------------------------------- */
165 /* Print debugging functions */
167 pdkim_quoteprint(const uschar *data, int len)
170 for (i = 0; i < len; i++)
172 const int c = data[i];
175 case ' ' : debug_printf("{SP}"); break;
176 case '\t': debug_printf("{TB}"); break;
177 case '\r': debug_printf("{CR}"); break;
178 case '\n': debug_printf("{LF}"); break;
179 case '{' : debug_printf("{BO}"); break;
180 case '}' : debug_printf("{BC}"); break;
182 if ( (c < 32) || (c > 127) )
183 debug_printf("{%02x}", c);
185 debug_printf("%c", c);
193 pdkim_hexprint(const uschar *data, int len)
196 if (data) for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
197 else debug_printf("<NULL>");
203 static pdkim_stringlist *
204 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
206 pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
208 memset(new_entry, 0, sizeof(pdkim_stringlist));
209 new_entry->value = string_copy(str);
210 if (base) new_entry->next = base;
216 /* Trim whitespace fore & aft */
219 pdkim_strtrim(uschar * str)
223 while (*p == '\t' || *p == ' ') p++; /* skip whitespace */
224 while (*p) {*q = *p; q++; p++;} /* dump the leading whitespace */
226 while (q != str && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
227 { /* dump trailing whitespace */
235 /* -------------------------------------------------------------------------- */
238 pdkim_free_ctx(pdkim_ctx *ctx)
243 /* -------------------------------------------------------------------------- */
244 /* Matches the name of the passed raw "header" against
245 the passed colon-separated "tick", and invalidates
246 the entry in tick. Returns OK or fail-code */
247 /*XXX might be safer done using a pdkim_stringlist for "tick" */
250 header_name_match(const uschar * header, uschar * tick)
256 uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
259 return PDKIM_FAIL; /* This isn't a header */
261 /* if we had strncmpic() we wouldn't need this copy */
262 hname = string_copyn(header, hcolon-header);
264 /* Copy tick-off list locally, so we can punch zeroes into it */
265 p = lcopy = string_copy(tick);
267 for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':'))
270 if (strcmpic(p, hname) == 0)
276 if (strcmpic(p, hname) == 0)
282 /* Invalidate header name instance in tick-off list */
288 /* -------------------------------------------------------------------------- */
289 /* Performs "relaxed" canonicalization of a header. */
292 pdkim_relax_header(const uschar * header, int crlf)
294 BOOL past_field_name = FALSE;
295 BOOL seen_wsp = FALSE;
297 uschar * relaxed = store_get(Ustrlen(header)+3);
298 uschar * q = relaxed;
300 for (p = header; *p; p++)
304 if (c == '\r' || c == '\n')
306 if (c == '\t' || c == ' ')
310 c = ' '; /* Turns WSP into SP */
314 if (!past_field_name && c == ':')
316 if (seen_wsp) q--; /* This removes WSP before the colon */
317 seen_wsp = TRUE; /* This removes WSP after the colon */
318 past_field_name = TRUE;
323 /* Lowercase header name */
324 if (!past_field_name) c = tolower(c);
328 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
330 if (crlf) { *q++ = '\r'; *q++ = '\n'; }
336 /* -------------------------------------------------------------------------- */
337 #define PDKIM_QP_ERROR_DECODE -1
340 pdkim_decode_qp_char(uschar *qp_p, int *c)
342 uschar *initial_pos = qp_p;
344 /* Advance one char */
347 /* Check for two hex digits and decode them */
348 if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
350 /* Do hex conversion */
351 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
352 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
356 /* Illegal char here */
357 *c = PDKIM_QP_ERROR_DECODE;
362 /* -------------------------------------------------------------------------- */
365 pdkim_decode_qp(uschar * str)
370 uschar * n = store_get(Ustrlen(str)+1);
378 p = pdkim_decode_qp_char(p, &nchar);
394 /* -------------------------------------------------------------------------- */
397 pdkim_decode_base64(uschar *str, blob * b)
400 dlen = b64decode(str, &b->data);
401 if (dlen < 0) b->data = NULL;
406 pdkim_encode_base64(blob * b)
408 return b64encode(b->data, b->len);
412 /* -------------------------------------------------------------------------- */
413 #define PDKIM_HDR_LIMBO 0
414 #define PDKIM_HDR_TAG 1
415 #define PDKIM_HDR_VALUE 2
417 static pdkim_signature *
418 pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
420 pdkim_signature * sig;
422 uschar * cur_tag = NULL; int ts = 0, tl = 0;
423 uschar * cur_val = NULL; int vs = 0, vl = 0;
424 BOOL past_hname = FALSE;
425 BOOL in_b_val = FALSE;
426 int where = PDKIM_HDR_LIMBO;
429 sig = store_get(sizeof(pdkim_signature));
430 memset(sig, 0, sizeof(pdkim_signature));
431 sig->bodylength = -1;
433 /* Set so invalid/missing data error display is accurate */
437 q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
439 for (p = raw_hdr; ; p++)
444 if (c == '\r' || c == '\n')
447 /* Fast-forward through header name */
450 if (c == ':') past_hname = TRUE;
454 if (where == PDKIM_HDR_LIMBO)
456 /* In limbo, just wait for a tag-char to appear */
457 if (!(c >= 'a' && c <= 'z'))
460 where = PDKIM_HDR_TAG;
463 if (where == PDKIM_HDR_TAG)
465 if (c >= 'a' && c <= 'z')
466 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
471 if (Ustrcmp(cur_tag, "b") == 0)
476 where = PDKIM_HDR_VALUE;
481 if (where == PDKIM_HDR_VALUE)
483 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
486 if (c == ';' || c == '\0')
491 pdkim_strtrim(cur_val);
493 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
498 pdkim_decode_base64(cur_val,
499 cur_tag[1] == 'h' ? &sig->bodyhash : &sig->sighash);
502 /* We only support version 1, and that is currently the
503 only version there is. */
505 Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
508 for (i = 0; pdkim_algos[i]; i++)
509 if (Ustrcmp(cur_val, pdkim_algos[i]) == 0)
516 for (i = 0; pdkim_combined_canons[i].str; i++)
517 if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0)
519 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
520 sig->canon_body = pdkim_combined_canons[i].canon_body;
525 for (i = 0; pdkim_querymethods[i]; i++)
526 if (Ustrcmp(cur_val, pdkim_querymethods[i]) == 0)
528 sig->querymethod = i;
533 sig->selector = string_copy(cur_val); break;
535 sig->domain = string_copy(cur_val); break;
537 sig->identity = pdkim_decode_qp(cur_val); break;
539 sig->created = strtoul(CS cur_val, NULL, 10); break;
541 sig->expires = strtoul(CS cur_val, NULL, 10); break;
543 sig->bodylength = strtol(CS cur_val, NULL, 10); break;
545 sig->headernames = string_copy(cur_val); break;
547 sig->copiedheaders = pdkim_decode_qp(cur_val); break;
549 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
556 where = PDKIM_HDR_LIMBO;
559 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
571 /* Chomp raw header. The final newline must not be added to the signature. */
572 while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
578 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
579 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
581 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sighash.len*8);
583 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
586 if (!exim_sha_init(&sig->body_hash_ctx,
587 sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
589 DEBUG(D_acl) debug_printf("PDKIM: hash init internal error\n");
596 /* -------------------------------------------------------------------------- */
598 static pdkim_pubkey *
599 pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
603 uschar * cur_tag = NULL; int ts = 0, tl = 0;
604 uschar * cur_val = NULL; int vs = 0, vl = 0;
605 int where = PDKIM_HDR_LIMBO;
607 pub = store_get(sizeof(pdkim_pubkey));
608 memset(pub, 0, sizeof(pdkim_pubkey));
610 for (p = raw_record; ; p++)
615 if (c != '\r' && c != '\n') switch (where)
617 case PDKIM_HDR_LIMBO: /* In limbo, just wait for a tag-char to appear */
618 if (!(c >= 'a' && c <= 'z'))
620 where = PDKIM_HDR_TAG;
624 if (c >= 'a' && c <= 'z')
625 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
630 where = PDKIM_HDR_VALUE;
634 case PDKIM_HDR_VALUE:
635 if (c == ';' || c == '\0')
640 pdkim_strtrim(cur_val);
641 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
646 pub->version = string_copy(cur_val); break;
648 pub->hashes = string_copy(cur_val); break;
652 pub->granularity = string_copy(cur_val); break;
654 pub->notes = pdkim_decode_qp(cur_val); break;
656 pdkim_decode_base64(US cur_val, &pub->key); break;
658 pub->srvtype = string_copy(cur_val); break;
660 if (Ustrchr(cur_val, 'y') != NULL) pub->testing = 1;
661 if (Ustrchr(cur_val, 's') != NULL) pub->no_subdomaining = 1;
664 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
670 where = PDKIM_HDR_LIMBO;
673 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
677 if (c == '\0') break;
680 /* Set fallback defaults */
681 if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
682 else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
684 DEBUG(D_acl) debug_printf(" Bad v= field\n");
688 if (!pub->granularity) pub->granularity = string_copy(US"*");
690 if (!pub->keytype ) pub->keytype = string_copy(US"rsa");
692 if (!pub->srvtype ) pub->srvtype = string_copy(US"*");
698 DEBUG(D_acl) debug_printf(" Missing p= field\n");
703 /* -------------------------------------------------------------------------- */
706 pdkim_update_bodyhash(pdkim_ctx * ctx, const char * data, int len)
708 pdkim_signature * sig;
709 uschar * relaxed_data = NULL; /* Cache relaxed version of data */
712 /* Traverse all signatures, updating their hashes. */
713 for (sig = ctx->sig; sig; sig = sig->next)
715 /* Defaults to simple canon (no further treatment necessary) */
716 const uschar *canon_data = CUS data;
719 if (sig->canon_body == PDKIM_CANON_RELAXED)
721 /* Relax the line if not done already */
724 BOOL seen_wsp = FALSE;
728 /* We want to be able to free this else we allocate
729 for the entire message which could be many MB. Since
730 we don't know what allocations the SHA routines might
731 do, not safe to use store_get()/store_reset(). */
733 relaxed_data = store_malloc(len+1);
735 for (p = data; *p; p++)
740 if (q > 0 && relaxed_data[q-1] == ' ')
743 else if (c == '\t' || c == ' ')
745 c = ' '; /* Turns WSP into SP */
752 relaxed_data[q++] = c;
754 relaxed_data[q] = '\0';
757 canon_data = relaxed_data;
758 canon_len = relaxed_len;
761 /* Make sure we don't exceed the to-be-signed body length */
762 if ( sig->bodylength >= 0
763 && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
765 canon_len = sig->bodylength - sig->signed_body_bytes;
769 exim_sha_update(&sig->body_hash_ctx, CUS canon_data, canon_len);
770 sig->signed_body_bytes += canon_len;
771 DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
775 if (relaxed_data) store_free(relaxed_data);
780 /* -------------------------------------------------------------------------- */
783 pdkim_finish_bodyhash(pdkim_ctx *ctx)
785 pdkim_signature *sig;
787 /* Traverse all signatures */
788 for (sig = ctx->sig; sig; sig = sig->next)
789 { /* Finish hashes */
792 exim_sha_finish(&sig->body_hash_ctx, &bh);
796 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
797 "PDKIM [%s] Body hash computed: ",
798 sig->domain, sig->signed_body_bytes, sig->domain);
799 pdkim_hexprint(CUS bh.data, bh.len);
802 /* SIGNING -------------------------------------------------------------- */
803 if (ctx->flags & PDKIM_MODE_SIGN)
807 /* If bodylength limit is set, and we have received less bytes
808 than the requested amount, effectively remove the limit tag. */
809 if (sig->signed_body_bytes < sig->bodylength)
810 sig->bodylength = -1;
814 /* VERIFICATION --------------------------------------------------------- */
815 /* Be careful that the header sig included a bodyash */
817 if (sig->bodyhash.data && memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
819 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
825 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain);
826 pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
827 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
829 sig->verify_status = PDKIM_VERIFY_FAIL;
830 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
838 pdkim_body_complete(pdkim_ctx * ctx)
840 pdkim_signature * sig = ctx->sig; /*XXX assumes only one sig */
842 /* In simple body mode, if any empty lines were buffered,
843 replace with one. rfc 4871 3.4.3 */
844 /*XXX checking the signed-body-bytes is a gross hack; I think
845 it indicates that all linebreaks should be buffered, including
846 the one terminating a text line */
848 if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
849 && sig->signed_body_bytes == 0
850 && ctx->num_buffered_crlf > 0
852 pdkim_update_bodyhash(ctx, "\r\n", 2);
854 ctx->flags |= PDKIM_SEEN_EOD;
855 ctx->linebuf_offset = 0;
861 /* -------------------------------------------------------------------------- */
862 /* Call from pdkim_feed below for processing complete body lines */
865 pdkim_bodyline_complete(pdkim_ctx *ctx)
867 char *p = ctx->linebuf;
868 int n = ctx->linebuf_offset;
869 pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
871 /* Ignore extra data if we've seen the end-of-data marker */
872 if (ctx->flags & PDKIM_SEEN_EOD) goto BAIL;
874 /* We've always got one extra byte to stuff a zero ... */
875 ctx->linebuf[ctx->linebuf_offset] = '\0';
877 /* Terminate on EOD marker */
878 if (ctx->flags & PDKIM_DOT_TERM)
880 if (memcmp(p, ".\r\n", 3) == 0)
881 return pdkim_body_complete(ctx);
884 if (memcmp(p, "..", 2) == 0)
891 /* Empty lines need to be buffered until we find a non-empty line */
892 if (memcmp(p, "\r\n", 2) == 0)
894 ctx->num_buffered_crlf++;
898 if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
900 /* Lines with just spaces need to be buffered too */
902 while (memcmp(check, "\r\n", 2) != 0)
906 if (c != '\t' && c != ' ')
911 ctx->num_buffered_crlf++;
916 /* At this point, we have a non-empty line, so release the buffered ones. */
917 while (ctx->num_buffered_crlf)
919 pdkim_update_bodyhash(ctx, "\r\n", 2);
920 ctx->num_buffered_crlf--;
923 pdkim_update_bodyhash(ctx, p, n);
926 ctx->linebuf_offset = 0;
931 /* -------------------------------------------------------------------------- */
932 /* Callback from pdkim_feed below for processing complete headers */
933 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
936 pdkim_header_complete(pdkim_ctx * ctx)
938 pdkim_signature * sig, * last_sig;
940 /* Special case: The last header can have an extra \r appended */
941 if ( (ctx->cur_header_len > 1) &&
942 (ctx->cur_header[(ctx->cur_header_len)-1] == '\r') )
943 --ctx->cur_header_len;
944 ctx->cur_header[ctx->cur_header_len] = '\0';
946 if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
948 /* SIGNING -------------------------------------------------------------- */
949 if (ctx->flags & PDKIM_MODE_SIGN)
950 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
952 /* Add header to the signed headers list (in reverse order) */
953 sig->headers = pdkim_prepend_stringlist(sig->headers,
956 /* VERIFICATION ----------------------------------------------------------- */
957 /* DKIM-Signature: headers are added to the verification list */
963 debug_printf("PDKIM >> raw hdr: ");
964 pdkim_quoteprint(CUS ctx->cur_header, ctx->cur_header_len);
967 if (strncasecmp(CCS ctx->cur_header,
968 DKIM_SIGNATURE_HEADERNAME,
969 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
971 /* Create and chain new signature block. We could error-check for all
972 required tags here, but prefer to create the internal sig and expicitly
973 fail verification of it later. */
975 DEBUG(D_acl) debug_printf(
976 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
978 sig = pdkim_parse_sig_header(ctx, ctx->cur_header);
980 if (!(last_sig = ctx->sig))
984 while (last_sig->next) last_sig = last_sig->next;
985 last_sig->next = sig;
989 /* all headers are stored for signature verification */
990 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header);
994 ctx->cur_header[ctx->cur_header_len = 0] = '\0'; /* leave buffer for reuse */
1000 /* -------------------------------------------------------------------------- */
1001 #define HEADER_BUFFER_FRAG_SIZE 256
1004 pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
1008 /* Alternate EOD signal, used in non-dotstuffing mode */
1010 pdkim_body_complete(ctx);
1012 else for (p = 0; p<len; p++)
1016 if (ctx->flags & PDKIM_PAST_HDRS)
1018 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1020 ctx->linebuf[ctx->linebuf_offset++] = '\r';
1021 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1022 return PDKIM_ERR_LONG_LINE;
1025 /* Processing body byte */
1026 ctx->linebuf[ctx->linebuf_offset++] = c;
1028 ctx->flags |= PDKIM_SEEN_CR;
1031 ctx->flags &= ~PDKIM_SEEN_CR;
1032 if ((rc = pdkim_bodyline_complete(ctx)) != PDKIM_OK)
1036 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1037 return PDKIM_ERR_LONG_LINE;
1041 /* Processing header byte */
1043 ctx->flags |= PDKIM_SEEN_CR;
1046 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1047 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1048 &ctx->cur_header_len, CUS "\r", 1);
1050 if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */
1052 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1055 ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS;
1056 DEBUG(D_acl) debug_printf(
1057 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1061 ctx->flags = (ctx->flags & ~PDKIM_SEEN_CR) | PDKIM_SEEN_LF;
1063 else if (ctx->flags & PDKIM_SEEN_LF)
1065 if (!(c == '\t' || c == ' ')) /* End of header */
1066 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1068 ctx->flags &= ~PDKIM_SEEN_LF;
1071 if (ctx->cur_header_len < PDKIM_MAX_HEADER_LEN)
1072 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1073 &ctx->cur_header_len, CUS &data[p], 1);
1081 /* Extend a grwong header with a continuation-linebreak */
1083 pdkim_hdr_cont(uschar * str, int * size, int * ptr, int * col)
1086 return string_catn(str, size, ptr, US"\r\n\t", 3);
1092 * RFC 5322 specifies that header line length SHOULD be no more than 78
1096 * returns uschar * (not nul-terminated)
1098 * col: this int holds and receives column number (octets since last '\n')
1099 * str: partial string to append to
1100 * size: current buffer size for str
1101 * ptr: current tail-pointer for str
1102 * pad: padding, split line or space after before or after eg: ";"
1103 * intro: - must join to payload eg "h=", usually the tag name
1104 * payload: eg base64 data - long data can be split arbitrarily.
1106 * this code doesn't fold the header in some of the places that RFC4871
1107 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1108 * pairs and inside long values. it also always spaces or breaks after the
1111 * no guarantees are made for output given out-of range input. like tag
1112 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1116 pdkim_headcat(int * col, uschar * str, int * size, int * ptr,
1117 const uschar * pad, const uschar * intro, const uschar * payload)
1125 str = pdkim_hdr_cont(str, size, ptr, col);
1126 str = string_catn(str, size, ptr, pad, l);
1130 l = (pad?1:0) + (intro?Ustrlen(intro):0);
1133 { /*can't fit intro - start a new line to make room.*/
1134 str = pdkim_hdr_cont(str, size, ptr, col);
1135 l = intro?Ustrlen(intro):0;
1138 l += payload ? Ustrlen(payload):0 ;
1141 { /* this fragment will not fit on a single line */
1144 str = string_catn(str, size, ptr, US" ", 1);
1146 pad = NULL; /* only want this once */
1152 size_t sl = Ustrlen(intro);
1154 str = string_catn(str, size, ptr, intro, sl);
1157 intro = NULL; /* only want this once */
1162 size_t sl = Ustrlen(payload);
1163 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1165 str = string_catn(str, size, ptr, payload, chomp);
1171 /* the while precondition tells us it didn't fit. */
1172 str = pdkim_hdr_cont(str, size, ptr, col);
1177 str = pdkim_hdr_cont(str, size, ptr, col);
1183 str = string_catn(str, size, ptr, US" ", 1);
1190 size_t sl = Ustrlen(intro);
1192 str = string_catn(str, size, ptr, intro, sl);
1200 size_t sl = Ustrlen(payload);
1202 str = string_catn(str, size, ptr, payload, sl);
1210 /* -------------------------------------------------------------------------- */
1213 pdkim_create_header(pdkim_signature *sig, BOOL final)
1218 uschar * hdr; int hdr_size = 0, hdr_len = 0;
1219 uschar * canon_all; int can_size = 0, can_len = 0;
1221 canon_all = string_cat (NULL, &can_size, &can_len,
1222 pdkim_canons[sig->canon_headers]);
1223 canon_all = string_catn(canon_all, &can_size, &can_len, US"/", 1);
1224 canon_all = string_cat (canon_all, &can_size, &can_len,
1225 pdkim_canons[sig->canon_body]);
1226 canon_all[can_len] = '\0';
1228 hdr = string_cat(NULL, &hdr_size, &hdr_len,
1229 US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1232 /* Required and static bits */
1233 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
1234 pdkim_algos[sig->algo]);
1235 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
1236 pdkim_querymethods[sig->querymethod]);
1237 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=",
1239 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"d=",
1241 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=",
1244 /* list of header names can be split between items. */
1246 uschar * n = string_copy(sig->headernames);
1247 uschar * i = US"h=";
1252 uschar * c = Ustrchr(n, ':');
1257 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, NULL, US":");
1259 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, s, i, n);
1270 base64_bh = pdkim_encode_base64(&sig->bodyhash);
1271 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"bh=", base64_bh);
1275 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"i=", sig->identity);
1277 if (sig->created > 0)
1281 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1282 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"t=", minibuf);
1285 if (sig->expires > 0)
1289 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1290 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"x=", minibuf);
1293 if (sig->bodylength >= 0)
1297 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1298 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"l=", minibuf);
1301 /* Preliminary or final version? */
1302 base64_b = final ? pdkim_encode_base64(&sig->sighash) : US"";
1303 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
1305 /* add trailing semicolon: I'm not sure if this is actually needed */
1306 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
1308 hdr[hdr_len] = '\0';
1313 /* -------------------------------------------------------------------------- */
1315 static pdkim_pubkey *
1316 pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1317 const uschar ** errstr)
1319 uschar * dns_txt_name, * dns_txt_reply;
1322 /* Fetch public key for signing domain, from DNS */
1324 dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1326 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1327 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1329 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1330 || dns_txt_reply[0] == '\0'
1333 sig->verify_status = PDKIM_VERIFY_INVALID;
1334 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1341 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1343 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1346 if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1347 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1350 sig->verify_status = PDKIM_VERIFY_INVALID;
1351 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1356 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1358 debug_printf(" Error while parsing public key record\n");
1360 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1365 DEBUG(D_acl) debug_printf(
1366 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1368 /* Import public key */
1369 if ((*errstr = exim_rsa_verify_init(&p->key, vctx)))
1371 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
1372 sig->verify_status = PDKIM_VERIFY_INVALID;
1373 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1381 /* -------------------------------------------------------------------------- */
1384 pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1385 const uschar ** err)
1387 pdkim_signature *sig = ctx->sig;
1389 /* Check if we must still flush a (partial) header. If that is the
1390 case, the message has no body, and we must compute a body hash
1391 out of '<CR><LF>' */
1392 if (ctx->cur_header && ctx->cur_header_len)
1394 int rc = pdkim_header_complete(ctx);
1395 if (rc != PDKIM_OK) return rc;
1396 pdkim_update_bodyhash(ctx, "\r\n", 2);
1399 DEBUG(D_acl) debug_printf(
1400 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1402 /* Build (and/or evaluate) body hash */
1403 pdkim_finish_bodyhash(ctx);
1407 BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
1409 uschar * sig_hdr = US"";
1412 int hdata_alloc = 0;
1417 if (!exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256))
1419 DEBUG(D_acl) debug_printf("PDKIM: hask setup internal error\n");
1423 DEBUG(D_acl) debug_printf(
1424 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
1426 /* SIGNING ---------------------------------------------------------------- */
1427 /* When signing, walk through our header list and add them to the hash. As we
1428 go, construct a list of the header's names to use for the h= parameter.
1429 Then append to that list any remaining header names for which there was no
1432 if (ctx->flags & PDKIM_MODE_SIGN)
1434 uschar * headernames = NULL; /* Collected signed header names */
1436 pdkim_stringlist *p;
1441 for (p = sig->headers; p; p = p->next)
1442 if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
1445 /* Collect header names (Note: colon presence is guaranteed here) */
1446 uschar * q = Ustrchr(p->value, ':');
1448 headernames = string_catn(headernames, &hs, &hl,
1449 p->value, (q - US p->value) + (p->next ? 1 : 0));
1451 rh = sig->canon_headers == PDKIM_CANON_RELAXED
1452 ? pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
1453 : string_copy(CUS p->value); /* just copy it for simple canon */
1455 /* Feed header to the hash algorithm */
1456 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1458 /* Remember headers block for signing (when the library cannot do incremental) */
1459 (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
1461 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1464 l = sig->sign_headers;
1465 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1467 { /*SSS string_append_listele() */
1468 if (hl > 0 && headernames[hl-1] != ':')
1469 headernames = string_catn(headernames, &hs, &hl, US":", 1);
1471 headernames = string_cat(headernames, &hs, &hl, s);
1473 headernames[hl] = '\0';
1475 /* Copy headernames to signature struct */
1476 sig->headernames = headernames;
1478 /* Create signature header with b= omitted */
1479 sig_hdr = pdkim_create_header(sig, FALSE);
1482 /* VERIFICATION ----------------------------------------------------------- */
1483 /* When verifying, walk through the header name list in the h= parameter and
1484 add the headers to the hash in that order. */
1487 uschar * p = sig->headernames;
1489 pdkim_stringlist * hdrs;
1494 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1500 if ((q = Ustrchr(p, ':')))
1503 /*XXX walk the list of headers in same order as received. */
1504 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1506 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
1507 && (hdrs->value)[Ustrlen(p)] == ':'
1510 /* cook header for relaxed canon, or just copy it for simple */
1512 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1513 ? pdkim_relax_header(hdrs->value, 1)
1514 : string_copy(CUS hdrs->value);
1516 /* Feed header to the hash algorithm */
1517 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1519 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1528 sig_hdr = string_copy(sig->rawsig_no_b_val);
1532 DEBUG(D_acl) debug_printf(
1533 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1535 /* Relax header if necessary */
1536 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1537 sig_hdr = pdkim_relax_header(sig_hdr, 0);
1542 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1543 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1545 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1548 /* Finalize header hash */
1549 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1550 exim_sha_finish(&hhash_ctx, &hhash);
1554 debug_printf("PDKIM [%s] Header hash computed: ", sig->domain);
1555 pdkim_hexprint(hhash.data, hhash.len);
1558 /* Remember headers block for signing (when the library cannot do incremental) */
1559 if (ctx->flags & PDKIM_MODE_SIGN)
1560 (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
1562 /* SIGNING ---------------------------------------------------------------- */
1563 if (ctx->flags & PDKIM_MODE_SIGN)
1567 /* Import private key */
1568 if ((*err = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
1570 DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
1571 return PDKIM_ERR_RSA_PRIVKEY;
1574 /* Do signing. With OpenSSL we are signing the hash of headers just
1575 calculated, with GnuTLS we have to sign an entire block of headers
1576 (due to available interfaces) and it recalculates the hash internally. */
1578 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1582 if ((*err = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sighash)))
1584 DEBUG(D_acl) debug_printf("signing: %s\n", *err);
1585 return PDKIM_ERR_RSA_SIGNING;
1590 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1591 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1594 sig->signature_header = pdkim_create_header(sig, TRUE);
1597 /* VERIFICATION ----------------------------------------------------------- */
1602 /* Make sure we have all required signature tags */
1603 if (!( sig->domain && *sig->domain
1604 && sig->selector && *sig->selector
1605 && sig->headernames && *sig->headernames
1606 && sig->bodyhash.data
1607 && sig->sighash.data
1612 sig->verify_status = PDKIM_VERIFY_INVALID;
1613 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1615 DEBUG(D_acl) debug_printf(
1616 " Error in DKIM-Signature header: tags missing or invalid\n"
1617 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1621 /* Make sure sig uses supported DKIM version (only v1) */
1622 if (sig->version != 1)
1624 sig->verify_status = PDKIM_VERIFY_INVALID;
1625 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1627 DEBUG(D_acl) debug_printf(
1628 " Error in DKIM-Signature header: unsupported DKIM version\n"
1629 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1633 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
1636 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1637 do not have the hash part of the sig algorithm matching */
1639 if (sig->pubkey->hashes)
1641 const uschar * list = sig->pubkey->hashes, * ele;
1643 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
1644 if (Ustrcmp(ele, pdkim_algos[sig->algo] + 4) == 0) break;
1647 DEBUG(D_acl) debug_printf("pubkey h=%s vs sig a=%s\n",
1648 sig->pubkey->hashes, pdkim_algos[sig->algo]);
1649 sig->verify_status = PDKIM_VERIFY_FAIL;
1650 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1655 /* Check the signature */
1656 if ((*err = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sighash)))
1658 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
1659 sig->verify_status = PDKIM_VERIFY_FAIL;
1660 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1665 /* We have a winner! (if bodyhash was correct earlier) */
1666 if (sig->verify_status == PDKIM_VERIFY_NONE)
1667 sig->verify_status = PDKIM_VERIFY_PASS;
1673 debug_printf("PDKIM [%s] signature status: %s",
1674 sig->domain, pdkim_verify_status_str(sig->verify_status));
1675 if (sig->verify_ext_status > 0)
1676 debug_printf(" (%s)\n",
1677 pdkim_verify_ext_status_str(sig->verify_ext_status));
1686 /* If requested, set return pointer to signature(s) */
1687 if (return_signatures)
1688 *return_signatures = ctx->sig;
1694 /* -------------------------------------------------------------------------- */
1696 DLLEXPORT pdkim_ctx *
1697 pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
1701 ctx = store_get(sizeof(pdkim_ctx));
1702 memset(ctx, 0, sizeof(pdkim_ctx));
1704 if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1705 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1706 ctx->dns_txt_callback = dns_txt_callback;
1712 /* -------------------------------------------------------------------------- */
1714 DLLEXPORT pdkim_ctx *
1715 pdkim_init_sign(char * domain, char * selector, char * rsa_privkey, int algo,
1716 BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *),
1717 const uschar ** errstr)
1720 pdkim_signature * sig;
1722 if (!domain || !selector || !rsa_privkey)
1725 ctx = store_get(sizeof(pdkim_ctx) + PDKIM_MAX_BODY_LINE_LEN + sizeof(pdkim_signature));
1726 memset(ctx, 0, sizeof(pdkim_ctx));
1728 ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1729 ctx->linebuf = CS (ctx+1);
1731 DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
1733 sig = (pdkim_signature *)(ctx->linebuf + PDKIM_MAX_BODY_LINE_LEN);
1734 memset(sig, 0, sizeof(pdkim_signature));
1736 sig->bodylength = -1;
1739 sig->domain = string_copy(US domain);
1740 sig->selector = string_copy(US selector);
1741 sig->rsa_privkey = string_copy(US rsa_privkey);
1744 if (!exim_sha_init(&sig->body_hash_ctx,
1745 algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
1747 DEBUG(D_acl) debug_printf("PDKIM: hash setup internal error\n");
1753 pdkim_signature s = *sig;
1756 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1757 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
1758 debug_printf("WARNING: bad dkim key in dns\n");
1759 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1765 /* -------------------------------------------------------------------------- */
1768 pdkim_set_optional(pdkim_ctx *ctx,
1774 unsigned long created,
1775 unsigned long expires)
1777 pdkim_signature * sig = ctx->sig;
1780 sig->identity = string_copy(US identity);
1782 sig->sign_headers = string_copy(sign_headers
1783 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1785 sig->canon_headers = canon_headers;
1786 sig->canon_body = canon_body;
1787 sig->bodylength = bodylength;
1788 sig->created = created;
1789 sig->expires = expires;
1803 #endif /*DISABLE_DKIM*/