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 /*XXX currently unused */
87 const uschar * pdkim_hashes[] = {
92 /*XXX currently unused */
93 const uschar * pdkim_keytypes[] = {
98 typedef struct pdkim_combined_canon_entry {
102 } pdkim_combined_canon_entry;
104 pdkim_combined_canon_entry pdkim_combined_canons[] = {
105 { US"simple/simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
106 { US"simple/relaxed", PDKIM_CANON_SIMPLE, PDKIM_CANON_RELAXED },
107 { US"relaxed/simple", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
108 { US"relaxed/relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_RELAXED },
109 { US"simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
110 { US"relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
115 /* -------------------------------------------------------------------------- */
118 pdkim_verify_status_str(int status)
122 case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE";
123 case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID";
124 case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL";
125 case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS";
126 default: return "PDKIM_VERIFY_UNKNOWN";
131 pdkim_verify_ext_status_str(int ext_status)
135 case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
136 case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
137 case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
138 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
139 case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
140 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
141 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
142 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
143 case PDKIM_VERIFY_INVALID_DKIM_VERSION: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
144 default: return "PDKIM_VERIFY_UNKNOWN";
149 pdkim_errstr(int status)
153 case PDKIM_OK: return US"OK";
154 case PDKIM_FAIL: return US"FAIL";
155 case PDKIM_ERR_RSA_PRIVKEY: return US"RSA_PRIVKEY";
156 case PDKIM_ERR_RSA_SIGNING: return US"RSA SIGNING";
157 case PDKIM_ERR_LONG_LINE: return US"RSA_LONG_LINE";
158 case PDKIM_ERR_BUFFER_TOO_SMALL: return US"BUFFER_TOO_SMALL";
159 case PDKIM_SIGN_PRIVKEY_WRAP: return US"PRIVKEY_WRAP";
160 case PDKIM_SIGN_PRIVKEY_B64D: return US"PRIVKEY_B64D";
161 default: return US"(unknown)";
166 /* -------------------------------------------------------------------------- */
167 /* Print debugging functions */
169 pdkim_quoteprint(const uschar *data, int len)
172 for (i = 0; i < len; i++)
174 const int c = data[i];
177 case ' ' : debug_printf("{SP}"); break;
178 case '\t': debug_printf("{TB}"); break;
179 case '\r': debug_printf("{CR}"); break;
180 case '\n': debug_printf("{LF}"); break;
181 case '{' : debug_printf("{BO}"); break;
182 case '}' : debug_printf("{BC}"); break;
184 if ( (c < 32) || (c > 127) )
185 debug_printf("{%02x}", c);
187 debug_printf("%c", c);
195 pdkim_hexprint(const uschar *data, int len)
198 if (data) for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
199 else debug_printf("<NULL>");
205 static pdkim_stringlist *
206 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
208 pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
210 memset(new_entry, 0, sizeof(pdkim_stringlist));
211 new_entry->value = string_copy(str);
212 if (base) new_entry->next = base;
218 /* Trim whitespace fore & aft */
221 pdkim_strtrim(uschar * str)
225 while (*p == '\t' || *p == ' ') p++; /* skip whitespace */
226 while (*p) {*q = *p; q++; p++;} /* dump the leading whitespace */
228 while (q != str && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
229 { /* dump trailing whitespace */
237 /* -------------------------------------------------------------------------- */
240 pdkim_free_ctx(pdkim_ctx *ctx)
245 /* -------------------------------------------------------------------------- */
246 /* Matches the name of the passed raw "header" against
247 the passed colon-separated "tick", and invalidates
248 the entry in tick. Returns OK or fail-code */
249 /*XXX might be safer done using a pdkim_stringlist for "tick" */
252 header_name_match(const uschar * header, uschar * tick)
258 uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
261 return PDKIM_FAIL; /* This isn't a header */
263 /* if we had strncmpic() we wouldn't need this copy */
264 hname = string_copyn(header, hcolon-header);
266 /* Copy tick-off list locally, so we can punch zeroes into it */
267 p = lcopy = string_copy(tick);
269 for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':'))
272 if (strcmpic(p, hname) == 0)
278 if (strcmpic(p, hname) == 0)
284 /* Invalidate header name instance in tick-off list */
290 /* -------------------------------------------------------------------------- */
291 /* Performs "relaxed" canonicalization of a header. */
294 pdkim_relax_header(const uschar * header, BOOL append_crlf)
296 BOOL past_field_name = FALSE;
297 BOOL seen_wsp = FALSE;
299 uschar * relaxed = store_get(Ustrlen(header)+3);
300 uschar * q = relaxed;
302 for (p = header; *p; p++)
306 if (c == '\r' || c == '\n') /* Ignore CR & LF */
308 if (c == '\t' || c == ' ')
312 c = ' '; /* Turns WSP into SP */
316 if (!past_field_name && c == ':')
318 if (seen_wsp) q--; /* This removes WSP immediately before the colon */
319 seen_wsp = TRUE; /* This removes WSP immediately after the colon */
320 past_field_name = TRUE;
325 /* Lowercase header name */
326 if (!past_field_name) c = tolower(c);
330 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
332 if (append_crlf) { *q++ = '\r'; *q++ = '\n'; }
338 /* -------------------------------------------------------------------------- */
339 #define PDKIM_QP_ERROR_DECODE -1
341 static const uschar *
342 pdkim_decode_qp_char(const uschar *qp_p, int *c)
344 const uschar *initial_pos = qp_p;
346 /* Advance one char */
349 /* Check for two hex digits and decode them */
350 if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
352 /* Do hex conversion */
353 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
354 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
358 /* Illegal char here */
359 *c = PDKIM_QP_ERROR_DECODE;
364 /* -------------------------------------------------------------------------- */
367 pdkim_decode_qp(const uschar * str)
371 const uschar * p = str;
372 uschar * n = store_get(Ustrlen(str)+1);
380 p = pdkim_decode_qp_char(p, &nchar);
396 /* -------------------------------------------------------------------------- */
399 pdkim_decode_base64(const uschar * str, blob * b)
402 dlen = b64decode(str, &b->data);
403 if (dlen < 0) b->data = NULL;
408 pdkim_encode_base64(blob * b)
410 return b64encode(b->data, b->len);
414 /* -------------------------------------------------------------------------- */
415 #define PDKIM_HDR_LIMBO 0
416 #define PDKIM_HDR_TAG 1
417 #define PDKIM_HDR_VALUE 2
419 static pdkim_signature *
420 pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
422 pdkim_signature * sig;
424 uschar * cur_tag = NULL; int ts = 0, tl = 0;
425 uschar * cur_val = NULL; int vs = 0, vl = 0;
426 BOOL past_hname = FALSE;
427 BOOL in_b_val = FALSE;
428 int where = PDKIM_HDR_LIMBO;
431 sig = store_get(sizeof(pdkim_signature));
432 memset(sig, 0, sizeof(pdkim_signature));
433 sig->bodylength = -1;
435 /* Set so invalid/missing data error display is accurate */
439 q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
441 for (p = raw_hdr; ; p++)
446 if (c == '\r' || c == '\n')
449 /* Fast-forward through header name */
452 if (c == ':') past_hname = TRUE;
456 if (where == PDKIM_HDR_LIMBO)
458 /* In limbo, just wait for a tag-char to appear */
459 if (!(c >= 'a' && c <= 'z'))
462 where = PDKIM_HDR_TAG;
465 if (where == PDKIM_HDR_TAG)
467 if (c >= 'a' && c <= 'z')
468 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
473 if (Ustrcmp(cur_tag, "b") == 0)
478 where = PDKIM_HDR_VALUE;
483 if (where == PDKIM_HDR_VALUE)
485 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
488 if (c == ';' || c == '\0')
493 pdkim_strtrim(cur_val);
495 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
500 pdkim_decode_base64(cur_val,
501 cur_tag[1] == 'h' ? &sig->bodyhash : &sig->sighash);
504 /* We only support version 1, and that is currently the
505 only version there is. */
507 Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
510 /*XXX this searches a list of combined (algo + hash-method)s */
511 for (i = 0; pdkim_algos[i]; i++)
512 if (Ustrcmp(cur_val, pdkim_algos[i]) == 0)
519 for (i = 0; pdkim_combined_canons[i].str; i++)
520 if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0)
522 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
523 sig->canon_body = pdkim_combined_canons[i].canon_body;
528 for (i = 0; pdkim_querymethods[i]; i++)
529 if (Ustrcmp(cur_val, pdkim_querymethods[i]) == 0)
531 sig->querymethod = i;
536 sig->selector = string_copy(cur_val); break;
538 sig->domain = string_copy(cur_val); break;
540 sig->identity = pdkim_decode_qp(cur_val); break;
542 sig->created = strtoul(CS cur_val, NULL, 10); break;
544 sig->expires = strtoul(CS cur_val, NULL, 10); break;
546 sig->bodylength = strtol(CS cur_val, NULL, 10); break;
548 sig->headernames = string_copy(cur_val); break;
550 sig->copiedheaders = pdkim_decode_qp(cur_val); break;
552 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
559 where = PDKIM_HDR_LIMBO;
562 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
574 /* Chomp raw header. The final newline must not be added to the signature. */
575 while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
581 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
582 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
584 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sighash.len*8);
586 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
589 /*XXX hash method: extend for sha512 */
590 if (!exim_sha_init(&sig->body_hash_ctx,
591 sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
593 DEBUG(D_acl) debug_printf("PDKIM: hash init internal error\n");
600 /* -------------------------------------------------------------------------- */
602 static pdkim_pubkey *
603 pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
609 pub = store_get(sizeof(pdkim_pubkey));
610 memset(pub, 0, sizeof(pdkim_pubkey));
612 while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
616 if ((val = Ustrchr(ele, '=')))
618 int taglen = val++ - ele;
620 DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
623 case 'v': pub->version = val; break;
624 case 'h': pub->hashes = val; break;
626 case 'g': pub->granularity = val; break;
627 case 'n': pub->notes = pdkim_decode_qp(val); break;
628 case 'p': pdkim_decode_base64(val, &pub->key); break;
629 case 's': pub->srvtype = val; break;
630 case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
631 if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
633 default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
638 /* Set fallback defaults */
639 if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
640 else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
642 DEBUG(D_acl) debug_printf(" Bad v= field\n");
646 if (!pub->granularity) pub->granularity = US"*";
648 if (!pub->keytype ) pub->keytype = US"rsa";
650 if (!pub->srvtype ) pub->srvtype = US"*";
656 DEBUG(D_acl) debug_printf(" Missing p= field\n");
661 /* -------------------------------------------------------------------------- */
664 pdkim_update_bodyhash(pdkim_ctx * ctx, const char * data, int len)
666 pdkim_signature * sig;
667 uschar * relaxed_data = NULL; /* Cache relaxed version of data */
670 /* Traverse all signatures, updating their hashes. */
671 for (sig = ctx->sig; sig; sig = sig->next)
673 /* Defaults to simple canon (no further treatment necessary) */
674 const uschar *canon_data = CUS data;
677 if (sig->canon_body == PDKIM_CANON_RELAXED)
679 /* Relax the line if not done already */
682 BOOL seen_wsp = FALSE;
686 /* We want to be able to free this else we allocate
687 for the entire message which could be many MB. Since
688 we don't know what allocations the SHA routines might
689 do, not safe to use store_get()/store_reset(). */
691 relaxed_data = store_malloc(len+1);
693 for (p = data; *p; p++)
698 if (q > 0 && relaxed_data[q-1] == ' ')
701 else if (c == '\t' || c == ' ')
703 c = ' '; /* Turns WSP into SP */
710 relaxed_data[q++] = c;
712 relaxed_data[q] = '\0';
715 canon_data = relaxed_data;
716 canon_len = relaxed_len;
719 /* Make sure we don't exceed the to-be-signed body length */
720 if ( sig->bodylength >= 0
721 && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
723 canon_len = sig->bodylength - sig->signed_body_bytes;
727 exim_sha_update(&sig->body_hash_ctx, CUS canon_data, canon_len);
728 sig->signed_body_bytes += canon_len;
729 DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
733 if (relaxed_data) store_free(relaxed_data);
738 /* -------------------------------------------------------------------------- */
741 pdkim_finish_bodyhash(pdkim_ctx *ctx)
743 pdkim_signature *sig;
745 /* Traverse all signatures */
746 for (sig = ctx->sig; sig; sig = sig->next)
747 { /* Finish hashes */
750 exim_sha_finish(&sig->body_hash_ctx, &bh);
754 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
755 "PDKIM [%s] Body hash computed: ",
756 sig->domain, sig->signed_body_bytes, sig->domain);
757 pdkim_hexprint(CUS bh.data, bh.len);
760 /* SIGNING -------------------------------------------------------------- */
761 if (ctx->flags & PDKIM_MODE_SIGN)
765 /* If bodylength limit is set, and we have received less bytes
766 than the requested amount, effectively remove the limit tag. */
767 if (sig->signed_body_bytes < sig->bodylength)
768 sig->bodylength = -1;
772 /* VERIFICATION --------------------------------------------------------- */
773 /* Be careful that the header sig included a bodyash */
775 if (sig->bodyhash.data && memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
777 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
783 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain);
784 pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
785 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
787 sig->verify_status = PDKIM_VERIFY_FAIL;
788 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
796 pdkim_body_complete(pdkim_ctx * ctx)
798 pdkim_signature * sig = ctx->sig; /*XXX assumes only one sig */
800 /* In simple body mode, if any empty lines were buffered,
801 replace with one. rfc 4871 3.4.3 */
802 /*XXX checking the signed-body-bytes is a gross hack; I think
803 it indicates that all linebreaks should be buffered, including
804 the one terminating a text line */
806 if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
807 && sig->signed_body_bytes == 0
808 && ctx->num_buffered_crlf > 0
810 pdkim_update_bodyhash(ctx, "\r\n", 2);
812 ctx->flags |= PDKIM_SEEN_EOD;
813 ctx->linebuf_offset = 0;
819 /* -------------------------------------------------------------------------- */
820 /* Call from pdkim_feed below for processing complete body lines */
823 pdkim_bodyline_complete(pdkim_ctx *ctx)
825 char *p = ctx->linebuf;
826 int n = ctx->linebuf_offset;
827 pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
829 /* Ignore extra data if we've seen the end-of-data marker */
830 if (ctx->flags & PDKIM_SEEN_EOD) goto BAIL;
832 /* We've always got one extra byte to stuff a zero ... */
833 ctx->linebuf[ctx->linebuf_offset] = '\0';
835 /* Terminate on EOD marker */
836 if (ctx->flags & PDKIM_DOT_TERM)
838 if (memcmp(p, ".\r\n", 3) == 0)
839 return pdkim_body_complete(ctx);
842 if (memcmp(p, "..", 2) == 0)
849 /* Empty lines need to be buffered until we find a non-empty line */
850 if (memcmp(p, "\r\n", 2) == 0)
852 ctx->num_buffered_crlf++;
856 if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
858 /* Lines with just spaces need to be buffered too */
860 while (memcmp(check, "\r\n", 2) != 0)
864 if (c != '\t' && c != ' ')
869 ctx->num_buffered_crlf++;
874 /* At this point, we have a non-empty line, so release the buffered ones. */
875 while (ctx->num_buffered_crlf)
877 pdkim_update_bodyhash(ctx, "\r\n", 2);
878 ctx->num_buffered_crlf--;
881 pdkim_update_bodyhash(ctx, p, n);
884 ctx->linebuf_offset = 0;
889 /* -------------------------------------------------------------------------- */
890 /* Callback from pdkim_feed below for processing complete headers */
891 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
894 pdkim_header_complete(pdkim_ctx * ctx)
896 pdkim_signature * sig, * last_sig;
898 /* Special case: The last header can have an extra \r appended */
899 if ( (ctx->cur_header_len > 1) &&
900 (ctx->cur_header[(ctx->cur_header_len)-1] == '\r') )
901 --ctx->cur_header_len;
902 ctx->cur_header[ctx->cur_header_len] = '\0';
904 if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
906 /* SIGNING -------------------------------------------------------------- */
907 if (ctx->flags & PDKIM_MODE_SIGN)
908 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
910 /* Add header to the signed headers list (in reverse order) */
911 sig->headers = pdkim_prepend_stringlist(sig->headers,
914 /* VERIFICATION ----------------------------------------------------------- */
915 /* DKIM-Signature: headers are added to the verification list */
921 debug_printf("PDKIM >> raw hdr: ");
922 pdkim_quoteprint(CUS ctx->cur_header, ctx->cur_header_len);
925 if (strncasecmp(CCS ctx->cur_header,
926 DKIM_SIGNATURE_HEADERNAME,
927 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
929 /* Create and chain new signature block. We could error-check for all
930 required tags here, but prefer to create the internal sig and expicitly
931 fail verification of it later. */
933 DEBUG(D_acl) debug_printf(
934 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
936 sig = pdkim_parse_sig_header(ctx, ctx->cur_header);
938 if (!(last_sig = ctx->sig))
942 while (last_sig->next) last_sig = last_sig->next;
943 last_sig->next = sig;
947 /* all headers are stored for signature verification */
948 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header);
952 ctx->cur_header[ctx->cur_header_len = 0] = '\0'; /* leave buffer for reuse */
958 /* -------------------------------------------------------------------------- */
959 #define HEADER_BUFFER_FRAG_SIZE 256
962 pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
966 /* Alternate EOD signal, used in non-dotstuffing mode */
968 pdkim_body_complete(ctx);
970 else for (p = 0; p<len; p++)
974 if (ctx->flags & PDKIM_PAST_HDRS)
976 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
978 ctx->linebuf[ctx->linebuf_offset++] = '\r';
979 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
980 return PDKIM_ERR_LONG_LINE;
983 /* Processing body byte */
984 ctx->linebuf[ctx->linebuf_offset++] = c;
986 ctx->flags |= PDKIM_SEEN_CR;
989 ctx->flags &= ~PDKIM_SEEN_CR;
990 if ((rc = pdkim_bodyline_complete(ctx)) != PDKIM_OK)
994 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
995 return PDKIM_ERR_LONG_LINE;
999 /* Processing header byte */
1001 ctx->flags |= PDKIM_SEEN_CR;
1004 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1005 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1006 &ctx->cur_header_len, CUS "\r", 1);
1008 if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */
1010 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1013 ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS;
1014 DEBUG(D_acl) debug_printf(
1015 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1019 ctx->flags = (ctx->flags & ~PDKIM_SEEN_CR) | PDKIM_SEEN_LF;
1021 else if (ctx->flags & PDKIM_SEEN_LF)
1023 if (!(c == '\t' || c == ' ')) /* End of header */
1024 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1026 ctx->flags &= ~PDKIM_SEEN_LF;
1029 if (ctx->cur_header_len < PDKIM_MAX_HEADER_LEN)
1030 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1031 &ctx->cur_header_len, CUS &data[p], 1);
1039 /* Extend a grwong header with a continuation-linebreak */
1041 pdkim_hdr_cont(uschar * str, int * size, int * ptr, int * col)
1044 return string_catn(str, size, ptr, US"\r\n\t", 3);
1050 * RFC 5322 specifies that header line length SHOULD be no more than 78
1054 * returns uschar * (not nul-terminated)
1056 * col: this int holds and receives column number (octets since last '\n')
1057 * str: partial string to append to
1058 * size: current buffer size for str
1059 * ptr: current tail-pointer for str
1060 * pad: padding, split line or space after before or after eg: ";"
1061 * intro: - must join to payload eg "h=", usually the tag name
1062 * payload: eg base64 data - long data can be split arbitrarily.
1064 * this code doesn't fold the header in some of the places that RFC4871
1065 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1066 * pairs and inside long values. it also always spaces or breaks after the
1069 * no guarantees are made for output given out-of range input. like tag
1070 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1074 pdkim_headcat(int * col, uschar * str, int * size, int * ptr,
1075 const uschar * pad, const uschar * intro, const uschar * payload)
1083 str = pdkim_hdr_cont(str, size, ptr, col);
1084 str = string_catn(str, size, ptr, pad, l);
1088 l = (pad?1:0) + (intro?Ustrlen(intro):0);
1091 { /*can't fit intro - start a new line to make room.*/
1092 str = pdkim_hdr_cont(str, size, ptr, col);
1093 l = intro?Ustrlen(intro):0;
1096 l += payload ? Ustrlen(payload):0 ;
1099 { /* this fragment will not fit on a single line */
1102 str = string_catn(str, size, ptr, US" ", 1);
1104 pad = NULL; /* only want this once */
1110 size_t sl = Ustrlen(intro);
1112 str = string_catn(str, size, ptr, intro, sl);
1115 intro = NULL; /* only want this once */
1120 size_t sl = Ustrlen(payload);
1121 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1123 str = string_catn(str, size, ptr, payload, chomp);
1129 /* the while precondition tells us it didn't fit. */
1130 str = pdkim_hdr_cont(str, size, ptr, col);
1135 str = pdkim_hdr_cont(str, size, ptr, col);
1141 str = string_catn(str, size, ptr, US" ", 1);
1148 size_t sl = Ustrlen(intro);
1150 str = string_catn(str, size, ptr, intro, sl);
1158 size_t sl = Ustrlen(payload);
1160 str = string_catn(str, size, ptr, payload, sl);
1168 /* -------------------------------------------------------------------------- */
1171 pdkim_create_header(pdkim_signature *sig, BOOL final)
1176 uschar * hdr; int hdr_size = 0, hdr_len = 0;
1177 uschar * canon_all; int can_size = 0, can_len = 0;
1179 canon_all = string_cat (NULL, &can_size, &can_len,
1180 pdkim_canons[sig->canon_headers]);
1181 canon_all = string_catn(canon_all, &can_size, &can_len, US"/", 1);
1182 canon_all = string_cat (canon_all, &can_size, &can_len,
1183 pdkim_canons[sig->canon_body]);
1184 canon_all[can_len] = '\0';
1186 hdr = string_cat(NULL, &hdr_size, &hdr_len,
1187 US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1190 /* Required and static bits */
1191 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
1192 /*XXX this is a combo of algo and hash-method */
1193 pdkim_algos[sig->algo]);
1194 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
1195 pdkim_querymethods[sig->querymethod]);
1196 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=",
1198 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"d=",
1200 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=",
1203 /* list of header names can be split between items. */
1205 uschar * n = string_copy(sig->headernames);
1206 uschar * i = US"h=";
1211 uschar * c = Ustrchr(n, ':');
1216 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, NULL, US":");
1218 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, s, i, n);
1229 base64_bh = pdkim_encode_base64(&sig->bodyhash);
1230 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"bh=", base64_bh);
1234 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"i=", sig->identity);
1236 if (sig->created > 0)
1240 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1241 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"t=", minibuf);
1244 if (sig->expires > 0)
1248 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1249 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"x=", minibuf);
1252 if (sig->bodylength >= 0)
1256 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1257 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"l=", minibuf);
1260 /* Preliminary or final version? */
1263 base64_b = pdkim_encode_base64(&sig->sighash);
1264 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
1266 /* add trailing semicolon: I'm not sure if this is actually needed */
1267 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
1271 /* To satisfy the rule "all surrounding whitespace [...] deleted"
1272 ( RFC 6376 section 3.7 ) we ensure there is no whitespace here. Otherwise
1273 the headcat routine could insert a linebreak which the relaxer would reduce
1274 to a single space preceding the terminating semicolon, resulting in an
1275 incorrect header-hash. */
1276 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=;", US"");
1279 hdr[hdr_len] = '\0';
1284 /* -------------------------------------------------------------------------- */
1286 static pdkim_pubkey *
1287 pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1288 const uschar ** errstr)
1290 uschar * dns_txt_name, * dns_txt_reply;
1293 /* Fetch public key for signing domain, from DNS */
1295 dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1297 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1298 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1300 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1301 || dns_txt_reply[0] == '\0'
1304 sig->verify_status = PDKIM_VERIFY_INVALID;
1305 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1312 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1314 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1317 if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1318 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1321 sig->verify_status = PDKIM_VERIFY_INVALID;
1322 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1327 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1329 debug_printf(" Error while parsing public key record\n");
1331 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1336 DEBUG(D_acl) debug_printf(
1337 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1339 /* Import public key */
1340 if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
1342 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
1343 sig->verify_status = PDKIM_VERIFY_INVALID;
1344 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1352 /* -------------------------------------------------------------------------- */
1355 pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1356 const uschar ** err)
1358 pdkim_signature *sig = ctx->sig;
1360 /* Check if we must still flush a (partial) header. If that is the
1361 case, the message has no body, and we must compute a body hash
1362 out of '<CR><LF>' */
1363 if (ctx->cur_header && ctx->cur_header_len)
1365 int rc = pdkim_header_complete(ctx);
1366 if (rc != PDKIM_OK) return rc;
1367 pdkim_update_bodyhash(ctx, "\r\n", 2);
1370 DEBUG(D_acl) debug_printf(
1371 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1373 /* Build (and/or evaluate) body hash */
1374 pdkim_finish_bodyhash(ctx);
1378 /*XXX bool probably not enough */
1379 BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
1381 uschar * sig_hdr = US"";
1384 int hdata_alloc = 0;
1389 if (!exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256))
1391 DEBUG(D_acl) debug_printf("PDKIM: hask setup internal error\n");
1395 DEBUG(D_acl) debug_printf(
1396 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
1398 /* SIGNING ---------------------------------------------------------------- */
1399 /* When signing, walk through our header list and add them to the hash. As we
1400 go, construct a list of the header's names to use for the h= parameter.
1401 Then append to that list any remaining header names for which there was no
1404 if (ctx->flags & PDKIM_MODE_SIGN)
1406 uschar * headernames = NULL; /* Collected signed header names */
1408 pdkim_stringlist *p;
1413 for (p = sig->headers; p; p = p->next)
1414 if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
1417 /* Collect header names (Note: colon presence is guaranteed here) */
1418 uschar * q = Ustrchr(p->value, ':');
1420 headernames = string_catn(headernames, &hs, &hl,
1421 p->value, (q - US p->value) + (p->next ? 1 : 0));
1423 rh = sig->canon_headers == PDKIM_CANON_RELAXED
1424 ? pdkim_relax_header(p->value, TRUE) /* cook header for relaxed canon */
1425 : string_copy(CUS p->value); /* just copy it for simple canon */
1427 /* Feed header to the hash algorithm */
1428 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1430 /* Remember headers block for signing (when the library cannot do incremental) */
1431 (void) exim_dkim_data_append(&hdata, &hdata_alloc, rh);
1433 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1436 l = sig->sign_headers;
1437 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1439 { /*SSS string_append_listele() */
1440 if (hl > 0 && headernames[hl-1] != ':')
1441 headernames = string_catn(headernames, &hs, &hl, US":", 1);
1443 headernames = string_cat(headernames, &hs, &hl, s);
1445 headernames[hl] = '\0';
1447 /* Copy headernames to signature struct */
1448 sig->headernames = headernames;
1450 /* Create signature header with b= omitted */
1451 sig_hdr = pdkim_create_header(sig, FALSE);
1454 /* VERIFICATION ----------------------------------------------------------- */
1455 /* When verifying, walk through the header name list in the h= parameter and
1456 add the headers to the hash in that order. */
1459 uschar * p = sig->headernames;
1461 pdkim_stringlist * hdrs;
1466 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1472 if ((q = Ustrchr(p, ':')))
1475 /*XXX walk the list of headers in same order as received. */
1476 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1478 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
1479 && (hdrs->value)[Ustrlen(p)] == ':'
1482 /* cook header for relaxed canon, or just copy it for simple */
1484 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1485 ? pdkim_relax_header(hdrs->value, TRUE)
1486 : string_copy(CUS hdrs->value);
1488 /* Feed header to the hash algorithm */
1489 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1491 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1500 sig_hdr = string_copy(sig->rawsig_no_b_val);
1504 DEBUG(D_acl) debug_printf(
1505 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1507 /* Relax header if necessary */
1508 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1509 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
1514 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1515 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1517 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1520 /* Finalize header hash */
1521 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1522 exim_sha_finish(&hhash_ctx, &hhash);
1526 debug_printf("PDKIM [%s] Header hash computed: ", sig->domain);
1527 pdkim_hexprint(hhash.data, hhash.len);
1530 /* Remember headers block for signing (when the library cannot do incremental) */
1531 /*XXX is this assuing algo == RSA? */
1532 if (ctx->flags & PDKIM_MODE_SIGN)
1533 (void) exim_dkim_data_append(&hdata, &hdata_alloc, US sig_hdr);
1535 /* SIGNING ---------------------------------------------------------------- */
1536 if (ctx->flags & PDKIM_MODE_SIGN)
1540 /* Import private key */
1541 /*XXX extend for non-RSA algos */
1542 if ((*err = exim_dkim_signing_init(US sig->rsa_privkey, &sctx)))
1544 DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
1545 return PDKIM_ERR_RSA_PRIVKEY;
1548 /* Do signing. With OpenSSL we are signing the hash of headers just
1549 calculated, with GnuTLS we have to sign an entire block of headers
1550 (due to available interfaces) and it recalculates the hash internally. */
1552 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1556 /*XXX extend for non-RSA algos */
1557 /*XXX oddly the dkim rfc does _not_ say what variant (sha1 or sha256) of
1558 RSA signing should be done. We use the same variant as the hash-method. */
1560 if ((*err = exim_dkim_sign(&sctx, is_sha1, &hdata, &sig->sighash)))
1562 DEBUG(D_acl) debug_printf("signing: %s\n", *err);
1563 return PDKIM_ERR_RSA_SIGNING;
1568 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1569 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1572 sig->signature_header = pdkim_create_header(sig, TRUE);
1575 /* VERIFICATION ----------------------------------------------------------- */
1580 /* Make sure we have all required signature tags */
1581 if (!( sig->domain && *sig->domain
1582 && sig->selector && *sig->selector
1583 && sig->headernames && *sig->headernames
1584 && sig->bodyhash.data
1585 && sig->sighash.data
1590 sig->verify_status = PDKIM_VERIFY_INVALID;
1591 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1593 DEBUG(D_acl) debug_printf(
1594 " Error in DKIM-Signature header: tags missing or invalid\n"
1595 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1599 /* Make sure sig uses supported DKIM version (only v1) */
1600 if (sig->version != 1)
1602 sig->verify_status = PDKIM_VERIFY_INVALID;
1603 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1605 DEBUG(D_acl) debug_printf(
1606 " Error in DKIM-Signature header: unsupported DKIM version\n"
1607 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1611 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
1614 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1615 do not have the hash part of the sig algorithm matching */
1617 if (sig->pubkey->hashes)
1619 const uschar * list = sig->pubkey->hashes, * ele;
1621 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
1622 if (Ustrcmp(ele, pdkim_algos[sig->algo] + 4) == 0) break;
1625 DEBUG(D_acl) debug_printf("pubkey h=%s vs sig a=%s\n",
1626 sig->pubkey->hashes, pdkim_algos[sig->algo]);
1627 sig->verify_status = PDKIM_VERIFY_FAIL;
1628 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1633 /* Check the signature */
1634 /*XXX needs extension for non-RSA */
1635 if ((*err = exim_dkim_verify(&vctx, is_sha1, &hhash, &sig->sighash)))
1637 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
1638 sig->verify_status = PDKIM_VERIFY_FAIL;
1639 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1644 /* We have a winner! (if bodyhash was correct earlier) */
1645 if (sig->verify_status == PDKIM_VERIFY_NONE)
1646 sig->verify_status = PDKIM_VERIFY_PASS;
1652 debug_printf("PDKIM [%s] signature status: %s",
1653 sig->domain, pdkim_verify_status_str(sig->verify_status));
1654 if (sig->verify_ext_status > 0)
1655 debug_printf(" (%s)\n",
1656 pdkim_verify_ext_status_str(sig->verify_ext_status));
1665 /* If requested, set return pointer to signature(s) */
1666 if (return_signatures)
1667 *return_signatures = ctx->sig;
1673 /* -------------------------------------------------------------------------- */
1675 DLLEXPORT pdkim_ctx *
1676 pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
1680 ctx = store_get(sizeof(pdkim_ctx));
1681 memset(ctx, 0, sizeof(pdkim_ctx));
1683 if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1684 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1685 ctx->dns_txt_callback = dns_txt_callback;
1691 /* -------------------------------------------------------------------------- */
1693 /*XXX ? needs extension to cover non-RSA algo? Currently the "algo" is actually
1694 the combo of algo and hash-method */
1696 DLLEXPORT pdkim_ctx *
1697 pdkim_init_sign(char * domain, char * selector, char * rsa_privkey, int algo,
1698 BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *),
1699 const uschar ** errstr)
1702 pdkim_signature * sig;
1704 if (!domain || !selector || !rsa_privkey)
1707 ctx = store_get(sizeof(pdkim_ctx) + PDKIM_MAX_BODY_LINE_LEN + sizeof(pdkim_signature));
1708 memset(ctx, 0, sizeof(pdkim_ctx));
1710 ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1711 ctx->linebuf = CS (ctx+1);
1713 DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
1715 sig = (pdkim_signature *)(ctx->linebuf + PDKIM_MAX_BODY_LINE_LEN);
1716 memset(sig, 0, sizeof(pdkim_signature));
1718 sig->bodylength = -1;
1721 sig->domain = string_copy(US domain);
1722 sig->selector = string_copy(US selector);
1723 sig->rsa_privkey = string_copy(US rsa_privkey);
1726 /*XXX extend for sha512 */
1727 if (!exim_sha_init(&sig->body_hash_ctx,
1728 algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
1730 DEBUG(D_acl) debug_printf("PDKIM: hash setup internal error\n");
1736 pdkim_signature s = *sig;
1739 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1740 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
1741 debug_printf("WARNING: bad dkim key in dns\n");
1742 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1748 /* -------------------------------------------------------------------------- */
1751 pdkim_set_optional(pdkim_ctx *ctx,
1757 unsigned long created,
1758 unsigned long expires)
1760 pdkim_signature * sig = ctx->sig;
1763 sig->identity = string_copy(US identity);
1765 sig->sign_headers = string_copy(sign_headers
1766 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1768 sig->canon_headers = canon_headers;
1769 sig->canon_body = canon_body;
1770 sig->bodylength = bodylength;
1771 sig->created = created;
1772 sig->expires = expires;
1786 #endif /*DISABLE_DKIM*/