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(SIGN_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_canons[] = {
83 const uschar * dkim_hashname;
84 hashmethod exim_hashmethod;
86 static const pdkim_hashtype pdkim_hashes[] = {
87 { US"sha1", HASH_SHA1 },
88 { US"sha256", HASH_SHA2_256 },
89 { US"sha512", HASH_SHA2_512 }
92 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 /* -------------------------------------------------------------------------- */
115 dkim_sig_to_a_tag(pdkim_signature * sig)
117 if ( sig->keytype < 0 || sig->keytype > nelem(pdkim_keytypes)
118 || sig->hashtype < 0 || sig->hashtype > nelem(pdkim_hashes))
120 return string_sprintf("%s-%s",
121 pdkim_keytypes[sig->keytype], pdkim_hashes[sig->hashtype].dkim_hashname);
127 pdkim_verify_status_str(int status)
131 case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE";
132 case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID";
133 case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL";
134 case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS";
135 default: return "PDKIM_VERIFY_UNKNOWN";
140 pdkim_verify_ext_status_str(int ext_status)
144 case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
145 case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
146 case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
147 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
148 case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
149 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
150 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
151 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
152 case PDKIM_VERIFY_INVALID_DKIM_VERSION: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
153 default: return "PDKIM_VERIFY_UNKNOWN";
158 pdkim_errstr(int status)
162 case PDKIM_OK: return US"OK";
163 case PDKIM_FAIL: return US"FAIL";
164 case PDKIM_ERR_RSA_PRIVKEY: return US"RSA_PRIVKEY";
165 case PDKIM_ERR_RSA_SIGNING: return US"RSA SIGNING";
166 case PDKIM_ERR_LONG_LINE: return US"RSA_LONG_LINE";
167 case PDKIM_ERR_BUFFER_TOO_SMALL: return US"BUFFER_TOO_SMALL";
168 case PDKIM_SIGN_PRIVKEY_WRAP: return US"PRIVKEY_WRAP";
169 case PDKIM_SIGN_PRIVKEY_B64D: return US"PRIVKEY_B64D";
170 default: return US"(unknown)";
175 /* -------------------------------------------------------------------------- */
176 /* Print debugging functions */
178 pdkim_quoteprint(const uschar *data, int len)
181 for (i = 0; i < len; i++)
183 const int c = data[i];
186 case ' ' : debug_printf("{SP}"); break;
187 case '\t': debug_printf("{TB}"); break;
188 case '\r': debug_printf("{CR}"); break;
189 case '\n': debug_printf("{LF}"); break;
190 case '{' : debug_printf("{BO}"); break;
191 case '}' : debug_printf("{BC}"); break;
193 if ( (c < 32) || (c > 127) )
194 debug_printf("{%02x}", c);
196 debug_printf("%c", c);
204 pdkim_hexprint(const uschar *data, int len)
207 if (data) for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
208 else debug_printf("<NULL>");
214 static pdkim_stringlist *
215 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
217 pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
219 memset(new_entry, 0, sizeof(pdkim_stringlist));
220 new_entry->value = string_copy(str);
221 if (base) new_entry->next = base;
227 /* Trim whitespace fore & aft */
230 pdkim_strtrim(uschar * str)
234 while (*p == '\t' || *p == ' ') p++; /* skip whitespace */
235 while (*p) {*q = *p; q++; p++;} /* dump the leading whitespace */
237 while (q != str && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
238 { /* dump trailing whitespace */
246 /* -------------------------------------------------------------------------- */
249 pdkim_free_ctx(pdkim_ctx *ctx)
254 /* -------------------------------------------------------------------------- */
255 /* Matches the name of the passed raw "header" against
256 the passed colon-separated "tick", and invalidates
257 the entry in tick. Returns OK or fail-code */
258 /*XXX might be safer done using a pdkim_stringlist for "tick" */
261 header_name_match(const uschar * header, uschar * tick)
267 uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
270 return PDKIM_FAIL; /* This isn't a header */
272 /* if we had strncmpic() we wouldn't need this copy */
273 hname = string_copyn(header, hcolon-header);
275 /* Copy tick-off list locally, so we can punch zeroes into it */
276 p = lcopy = string_copy(tick);
278 for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':'))
281 if (strcmpic(p, hname) == 0)
287 if (strcmpic(p, hname) == 0)
293 /* Invalidate header name instance in tick-off list */
299 /* -------------------------------------------------------------------------- */
300 /* Performs "relaxed" canonicalization of a header. */
303 pdkim_relax_header(const uschar * header, BOOL append_crlf)
305 BOOL past_field_name = FALSE;
306 BOOL seen_wsp = FALSE;
308 uschar * relaxed = store_get(Ustrlen(header)+3);
309 uschar * q = relaxed;
311 for (p = header; *p; p++)
315 if (c == '\r' || c == '\n') /* Ignore CR & LF */
317 if (c == '\t' || c == ' ')
321 c = ' '; /* Turns WSP into SP */
325 if (!past_field_name && c == ':')
327 if (seen_wsp) q--; /* This removes WSP immediately before the colon */
328 seen_wsp = TRUE; /* This removes WSP immediately after the colon */
329 past_field_name = TRUE;
334 /* Lowercase header name */
335 if (!past_field_name) c = tolower(c);
339 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
341 if (append_crlf) { *q++ = '\r'; *q++ = '\n'; }
347 /* -------------------------------------------------------------------------- */
348 #define PDKIM_QP_ERROR_DECODE -1
350 static const uschar *
351 pdkim_decode_qp_char(const uschar *qp_p, int *c)
353 const uschar *initial_pos = qp_p;
355 /* Advance one char */
358 /* Check for two hex digits and decode them */
359 if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
361 /* Do hex conversion */
362 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
363 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
367 /* Illegal char here */
368 *c = PDKIM_QP_ERROR_DECODE;
373 /* -------------------------------------------------------------------------- */
376 pdkim_decode_qp(const uschar * str)
380 const uschar * p = str;
381 uschar * n = store_get(Ustrlen(str)+1);
389 p = pdkim_decode_qp_char(p, &nchar);
405 /* -------------------------------------------------------------------------- */
408 pdkim_decode_base64(const uschar * str, blob * b)
411 dlen = b64decode(str, &b->data);
412 if (dlen < 0) b->data = NULL;
417 pdkim_encode_base64(blob * b)
419 return b64encode(b->data, b->len);
423 /* -------------------------------------------------------------------------- */
424 #define PDKIM_HDR_LIMBO 0
425 #define PDKIM_HDR_TAG 1
426 #define PDKIM_HDR_VALUE 2
428 static pdkim_signature *
429 pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
431 pdkim_signature * sig;
433 uschar * cur_tag = NULL; int ts = 0, tl = 0;
434 uschar * cur_val = NULL; int vs = 0, vl = 0;
435 BOOL past_hname = FALSE;
436 BOOL in_b_val = FALSE;
437 int where = PDKIM_HDR_LIMBO;
440 sig = store_get(sizeof(pdkim_signature));
441 memset(sig, 0, sizeof(pdkim_signature));
442 sig->bodylength = -1;
444 /* Set so invalid/missing data error display is accurate */
449 q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
451 for (p = raw_hdr; ; p++)
456 if (c == '\r' || c == '\n')
459 /* Fast-forward through header name */
462 if (c == ':') past_hname = TRUE;
466 if (where == PDKIM_HDR_LIMBO)
468 /* In limbo, just wait for a tag-char to appear */
469 if (!(c >= 'a' && c <= 'z'))
472 where = PDKIM_HDR_TAG;
475 if (where == PDKIM_HDR_TAG)
477 if (c >= 'a' && c <= 'z')
478 cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
483 if (Ustrcmp(cur_tag, "b") == 0)
488 where = PDKIM_HDR_VALUE;
493 if (where == PDKIM_HDR_VALUE)
495 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
498 if (c == ';' || c == '\0')
503 pdkim_strtrim(cur_val);
505 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
510 pdkim_decode_base64(cur_val,
511 cur_tag[1] == 'h' ? &sig->bodyhash : &sig->sighash);
514 /* We only support version 1, and that is currently the
515 only version there is. */
517 Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
521 uschar * s = Ustrchr(cur_val, '-');
523 for(i = 0; i < nelem(pdkim_keytypes); i++)
524 if (Ustrncmp(cur_val, pdkim_keytypes[i], s - cur_val) == 0)
525 { sig->keytype = i; break; }
526 for (++s, i = 0; i < nelem(pdkim_hashes); i++)
527 if (Ustrcmp(s, pdkim_hashes[i].dkim_hashname) == 0)
528 { sig->hashtype = i; break; }
533 for (i = 0; pdkim_combined_canons[i].str; i++)
534 if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0)
536 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
537 sig->canon_body = pdkim_combined_canons[i].canon_body;
542 for (i = 0; pdkim_querymethods[i]; i++)
543 if (Ustrcmp(cur_val, pdkim_querymethods[i]) == 0)
545 sig->querymethod = i;
550 sig->selector = string_copy(cur_val); break;
552 sig->domain = string_copy(cur_val); break;
554 sig->identity = pdkim_decode_qp(cur_val); break;
556 sig->created = strtoul(CS cur_val, NULL, 10); break;
558 sig->expires = strtoul(CS cur_val, NULL, 10); break;
560 sig->bodylength = strtol(CS cur_val, NULL, 10); break;
562 sig->headernames = string_copy(cur_val); break;
564 sig->copiedheaders = pdkim_decode_qp(cur_val); break;
566 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
573 where = PDKIM_HDR_LIMBO;
576 cur_val = string_catn(cur_val, &vs, &vl, p, 1);
588 /* Chomp raw header. The final newline must not be added to the signature. */
589 while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
595 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
596 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
598 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sighash.len*8);
600 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
603 /*XXX hash method: extend for sha512 */
604 if (!exim_sha_init(&sig->body_hash_ctx,
605 pdkim_hashes[sig->hashtype].exim_hashmethod))
608 debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n");
615 /* -------------------------------------------------------------------------- */
617 static pdkim_pubkey *
618 pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
624 pub = store_get(sizeof(pdkim_pubkey));
625 memset(pub, 0, sizeof(pdkim_pubkey));
627 while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
631 if ((val = Ustrchr(ele, '=')))
633 int taglen = val++ - ele;
635 DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
638 case 'v': pub->version = val; break;
639 case 'h': pub->hashes = val; break;
641 case 'g': pub->granularity = val; break;
642 case 'n': pub->notes = pdkim_decode_qp(val); break;
643 case 'p': pdkim_decode_base64(val, &pub->key); break;
644 case 's': pub->srvtype = val; break;
645 case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
646 if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
648 default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
653 /* Set fallback defaults */
654 if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
655 else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
657 DEBUG(D_acl) debug_printf(" Bad v= field\n");
661 if (!pub->granularity) pub->granularity = US"*";
663 if (!pub->keytype ) pub->keytype = US"rsa";
665 if (!pub->srvtype ) pub->srvtype = US"*";
671 DEBUG(D_acl) debug_printf(" Missing p= field\n");
676 /* -------------------------------------------------------------------------- */
679 pdkim_update_bodyhash(pdkim_ctx * ctx, const char * data, int len)
681 pdkim_signature * sig;
682 uschar * relaxed_data = NULL; /* Cache relaxed version of data */
685 /* Traverse all signatures, updating their hashes. */
686 for (sig = ctx->sig; sig; sig = sig->next)
688 /* Defaults to simple canon (no further treatment necessary) */
689 const uschar *canon_data = CUS data;
692 if (sig->canon_body == PDKIM_CANON_RELAXED)
694 /* Relax the line if not done already */
697 BOOL seen_wsp = FALSE;
701 /* We want to be able to free this else we allocate
702 for the entire message which could be many MB. Since
703 we don't know what allocations the SHA routines might
704 do, not safe to use store_get()/store_reset(). */
706 relaxed_data = store_malloc(len+1);
708 for (p = data; *p; p++)
713 if (q > 0 && relaxed_data[q-1] == ' ')
716 else if (c == '\t' || c == ' ')
718 c = ' '; /* Turns WSP into SP */
725 relaxed_data[q++] = c;
727 relaxed_data[q] = '\0';
730 canon_data = relaxed_data;
731 canon_len = relaxed_len;
734 /* Make sure we don't exceed the to-be-signed body length */
735 if ( sig->bodylength >= 0
736 && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
738 canon_len = sig->bodylength - sig->signed_body_bytes;
742 exim_sha_update(&sig->body_hash_ctx, CUS canon_data, canon_len);
743 sig->signed_body_bytes += canon_len;
744 DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
748 if (relaxed_data) store_free(relaxed_data);
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_ctx, &bh);
769 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
770 "PDKIM [%s] Body hash computed: ",
771 sig->domain, sig->signed_body_bytes, sig->domain);
772 pdkim_hexprint(CUS bh.data, bh.len);
775 /* SIGNING -------------------------------------------------------------- */
776 if (ctx->flags & 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;
787 /* VERIFICATION --------------------------------------------------------- */
788 /* Be careful that the header sig included a bodyash */
790 if (sig->bodyhash.data && 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] Body hash signature from headers: ", sig->domain);
799 pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
800 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
802 sig->verify_status = PDKIM_VERIFY_FAIL;
803 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
811 pdkim_body_complete(pdkim_ctx * ctx)
813 pdkim_signature * sig = ctx->sig; /*XXX assumes only one sig */
815 /* In simple body mode, if any empty lines were buffered,
816 replace with one. rfc 4871 3.4.3 */
817 /*XXX checking the signed-body-bytes is a gross hack; I think
818 it indicates that all linebreaks should be buffered, including
819 the one terminating a text line */
821 if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
822 && sig->signed_body_bytes == 0
823 && ctx->num_buffered_crlf > 0
825 pdkim_update_bodyhash(ctx, "\r\n", 2);
827 ctx->flags |= PDKIM_SEEN_EOD;
828 ctx->linebuf_offset = 0;
834 /* -------------------------------------------------------------------------- */
835 /* Call from pdkim_feed below for processing complete body lines */
838 pdkim_bodyline_complete(pdkim_ctx *ctx)
840 char *p = ctx->linebuf;
841 int n = ctx->linebuf_offset;
842 pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
844 /* Ignore extra data if we've seen the end-of-data marker */
845 if (ctx->flags & PDKIM_SEEN_EOD) goto BAIL;
847 /* We've always got one extra byte to stuff a zero ... */
848 ctx->linebuf[ctx->linebuf_offset] = '\0';
850 /* Terminate on EOD marker */
851 if (ctx->flags & PDKIM_DOT_TERM)
853 if (memcmp(p, ".\r\n", 3) == 0)
854 return pdkim_body_complete(ctx);
857 if (memcmp(p, "..", 2) == 0)
864 /* Empty lines need to be buffered until we find a non-empty line */
865 if (memcmp(p, "\r\n", 2) == 0)
867 ctx->num_buffered_crlf++;
871 if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
873 /* Lines with just spaces need to be buffered too */
875 while (memcmp(check, "\r\n", 2) != 0)
879 if (c != '\t' && c != ' ')
884 ctx->num_buffered_crlf++;
889 /* At this point, we have a non-empty line, so release the buffered ones. */
890 while (ctx->num_buffered_crlf)
892 pdkim_update_bodyhash(ctx, "\r\n", 2);
893 ctx->num_buffered_crlf--;
896 pdkim_update_bodyhash(ctx, p, n);
899 ctx->linebuf_offset = 0;
904 /* -------------------------------------------------------------------------- */
905 /* Callback from pdkim_feed below for processing complete headers */
906 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
909 pdkim_header_complete(pdkim_ctx * ctx)
911 pdkim_signature * sig, * last_sig;
913 /* Special case: The last header can have an extra \r appended */
914 if ( (ctx->cur_header_len > 1) &&
915 (ctx->cur_header[(ctx->cur_header_len)-1] == '\r') )
916 --ctx->cur_header_len;
917 ctx->cur_header[ctx->cur_header_len] = '\0';
919 if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
921 /* SIGNING -------------------------------------------------------------- */
922 if (ctx->flags & PDKIM_MODE_SIGN)
923 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
925 /* Add header to the signed headers list (in reverse order) */
926 sig->headers = pdkim_prepend_stringlist(sig->headers,
929 /* VERIFICATION ----------------------------------------------------------- */
930 /* DKIM-Signature: headers are added to the verification list */
936 debug_printf("PDKIM >> raw hdr: ");
937 pdkim_quoteprint(CUS ctx->cur_header, ctx->cur_header_len);
940 if (strncasecmp(CCS ctx->cur_header,
941 DKIM_SIGNATURE_HEADERNAME,
942 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
944 /* Create and chain new signature block. We could error-check for all
945 required tags here, but prefer to create the internal sig and expicitly
946 fail verification of it later. */
948 DEBUG(D_acl) debug_printf(
949 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
951 sig = pdkim_parse_sig_header(ctx, ctx->cur_header);
953 if (!(last_sig = ctx->sig))
957 while (last_sig->next) last_sig = last_sig->next;
958 last_sig->next = sig;
962 /* all headers are stored for signature verification */
963 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header);
967 ctx->cur_header[ctx->cur_header_len = 0] = '\0'; /* leave buffer for reuse */
973 /* -------------------------------------------------------------------------- */
974 #define HEADER_BUFFER_FRAG_SIZE 256
977 pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
981 /* Alternate EOD signal, used in non-dotstuffing mode */
983 pdkim_body_complete(ctx);
985 else for (p = 0; p<len; p++)
989 if (ctx->flags & PDKIM_PAST_HDRS)
991 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
993 ctx->linebuf[ctx->linebuf_offset++] = '\r';
994 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
995 return PDKIM_ERR_LONG_LINE;
998 /* Processing body byte */
999 ctx->linebuf[ctx->linebuf_offset++] = c;
1001 ctx->flags |= PDKIM_SEEN_CR;
1004 ctx->flags &= ~PDKIM_SEEN_CR;
1005 if ((rc = pdkim_bodyline_complete(ctx)) != PDKIM_OK)
1009 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1010 return PDKIM_ERR_LONG_LINE;
1014 /* Processing header byte */
1016 ctx->flags |= PDKIM_SEEN_CR;
1019 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1020 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1021 &ctx->cur_header_len, CUS "\r", 1);
1023 if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */
1025 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1028 ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS;
1029 DEBUG(D_acl) debug_printf(
1030 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1034 ctx->flags = (ctx->flags & ~PDKIM_SEEN_CR) | PDKIM_SEEN_LF;
1036 else if (ctx->flags & PDKIM_SEEN_LF)
1038 if (!(c == '\t' || c == ' ')) /* End of header */
1039 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1041 ctx->flags &= ~PDKIM_SEEN_LF;
1044 if (ctx->cur_header_len < PDKIM_MAX_HEADER_LEN)
1045 ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size,
1046 &ctx->cur_header_len, CUS &data[p], 1);
1054 /* Extend a grwong header with a continuation-linebreak */
1056 pdkim_hdr_cont(uschar * str, int * size, int * ptr, int * col)
1059 return string_catn(str, size, ptr, US"\r\n\t", 3);
1065 * RFC 5322 specifies that header line length SHOULD be no more than 78
1069 * returns uschar * (not nul-terminated)
1071 * col: this int holds and receives column number (octets since last '\n')
1072 * str: partial string to append to
1073 * size: current buffer size for str
1074 * ptr: current tail-pointer for str
1075 * pad: padding, split line or space after before or after eg: ";"
1076 * intro: - must join to payload eg "h=", usually the tag name
1077 * payload: eg base64 data - long data can be split arbitrarily.
1079 * this code doesn't fold the header in some of the places that RFC4871
1080 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1081 * pairs and inside long values. it also always spaces or breaks after the
1084 * no guarantees are made for output given out-of range input. like tag
1085 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1089 pdkim_headcat(int * col, uschar * str, int * size, int * ptr,
1090 const uschar * pad, const uschar * intro, const uschar * payload)
1098 str = pdkim_hdr_cont(str, size, ptr, col);
1099 str = string_catn(str, size, ptr, pad, l);
1103 l = (pad?1:0) + (intro?Ustrlen(intro):0);
1106 { /*can't fit intro - start a new line to make room.*/
1107 str = pdkim_hdr_cont(str, size, ptr, col);
1108 l = intro?Ustrlen(intro):0;
1111 l += payload ? Ustrlen(payload):0 ;
1114 { /* this fragment will not fit on a single line */
1117 str = string_catn(str, size, ptr, US" ", 1);
1119 pad = NULL; /* only want this once */
1125 size_t sl = Ustrlen(intro);
1127 str = string_catn(str, size, ptr, intro, sl);
1130 intro = NULL; /* only want this once */
1135 size_t sl = Ustrlen(payload);
1136 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1138 str = string_catn(str, size, ptr, payload, chomp);
1144 /* the while precondition tells us it didn't fit. */
1145 str = pdkim_hdr_cont(str, size, ptr, col);
1150 str = pdkim_hdr_cont(str, size, ptr, col);
1156 str = string_catn(str, size, ptr, US" ", 1);
1163 size_t sl = Ustrlen(intro);
1165 str = string_catn(str, size, ptr, intro, sl);
1173 size_t sl = Ustrlen(payload);
1175 str = string_catn(str, size, ptr, payload, sl);
1183 /* -------------------------------------------------------------------------- */
1186 pdkim_create_header(pdkim_signature *sig, BOOL final)
1191 uschar * hdr; int hdr_size = 0, hdr_len = 0;
1192 uschar * canon_all; int can_size = 0, can_len = 0;
1194 canon_all = string_cat (NULL, &can_size, &can_len,
1195 pdkim_canons[sig->canon_headers]);
1196 canon_all = string_catn(canon_all, &can_size, &can_len, US"/", 1);
1197 canon_all = string_cat (canon_all, &can_size, &can_len,
1198 pdkim_canons[sig->canon_body]);
1199 canon_all[can_len] = '\0';
1201 hdr = string_cat(NULL, &hdr_size, &hdr_len,
1202 US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1205 /* Required and static bits */
1206 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
1207 dkim_sig_to_a_tag(sig));
1208 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
1209 pdkim_querymethods[sig->querymethod]);
1210 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=",
1212 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"d=",
1214 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"s=",
1217 /* list of header names can be split between items. */
1219 uschar * n = string_copy(sig->headernames);
1220 uschar * i = US"h=";
1225 uschar * c = Ustrchr(n, ':');
1230 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, NULL, US":");
1232 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, s, i, n);
1243 base64_bh = pdkim_encode_base64(&sig->bodyhash);
1244 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"bh=", base64_bh);
1248 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"i=", sig->identity);
1250 if (sig->created > 0)
1254 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1255 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"t=", minibuf);
1258 if (sig->expires > 0)
1262 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1263 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"x=", minibuf);
1266 if (sig->bodylength >= 0)
1270 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1271 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"l=", minibuf);
1274 /* Preliminary or final version? */
1277 base64_b = pdkim_encode_base64(&sig->sighash);
1278 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
1280 /* add trailing semicolon: I'm not sure if this is actually needed */
1281 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
1285 /* To satisfy the rule "all surrounding whitespace [...] deleted"
1286 ( RFC 6376 section 3.7 ) we ensure there is no whitespace here. Otherwise
1287 the headcat routine could insert a linebreak which the relaxer would reduce
1288 to a single space preceding the terminating semicolon, resulting in an
1289 incorrect header-hash. */
1290 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=;", US"");
1293 hdr[hdr_len] = '\0';
1298 /* -------------------------------------------------------------------------- */
1300 static pdkim_pubkey *
1301 pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1302 const uschar ** errstr)
1304 uschar * dns_txt_name, * dns_txt_reply;
1307 /* Fetch public key for signing domain, from DNS */
1309 dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1311 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1312 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1314 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1315 || dns_txt_reply[0] == '\0'
1318 sig->verify_status = PDKIM_VERIFY_INVALID;
1319 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1326 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1328 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1331 if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1332 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1335 sig->verify_status = PDKIM_VERIFY_INVALID;
1336 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1341 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1343 debug_printf(" Error while parsing public key record\n");
1345 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1350 DEBUG(D_acl) debug_printf(
1351 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1353 /* Import public key */
1354 if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
1356 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
1357 sig->verify_status = PDKIM_VERIFY_INVALID;
1358 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1366 /* -------------------------------------------------------------------------- */
1369 pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1370 const uschar ** err)
1372 pdkim_signature *sig = ctx->sig;
1374 /* Check if we must still flush a (partial) header. If that is the
1375 case, the message has no body, and we must compute a body hash
1376 out of '<CR><LF>' */
1377 if (ctx->cur_header && ctx->cur_header_len)
1379 int rc = pdkim_header_complete(ctx);
1380 if (rc != PDKIM_OK) return rc;
1381 pdkim_update_bodyhash(ctx, "\r\n", 2);
1384 DEBUG(D_acl) debug_printf(
1385 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1387 /* Build (and/or evaluate) body hash */
1388 pdkim_finish_bodyhash(ctx);
1393 uschar * sig_hdr = US"";
1396 int hdata_alloc = 0;
1401 if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
1404 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
1408 DEBUG(D_acl) debug_printf(
1409 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
1411 /* SIGNING ---------------------------------------------------------------- */
1412 /* When signing, walk through our header list and add them to the hash. As we
1413 go, construct a list of the header's names to use for the h= parameter.
1414 Then append to that list any remaining header names for which there was no
1417 if (ctx->flags & PDKIM_MODE_SIGN)
1419 uschar * headernames = NULL; /* Collected signed header names */
1421 pdkim_stringlist *p;
1426 for (p = sig->headers; p; p = p->next)
1427 if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
1430 /* Collect header names (Note: colon presence is guaranteed here) */
1431 uschar * q = Ustrchr(p->value, ':');
1433 headernames = string_catn(headernames, &hs, &hl,
1434 p->value, (q - US p->value) + (p->next ? 1 : 0));
1436 rh = sig->canon_headers == PDKIM_CANON_RELAXED
1437 ? pdkim_relax_header(p->value, TRUE) /* cook header for relaxed canon */
1438 : string_copy(CUS p->value); /* just copy it for simple canon */
1440 /* Feed header to the hash algorithm */
1441 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1443 /* Remember headers block for signing (when the library cannot do incremental) */
1444 (void) exim_dkim_data_append(&hdata, &hdata_alloc, rh);
1446 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1449 l = sig->sign_headers;
1450 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1452 { /*SSS string_append_listele() */
1453 if (hl > 0 && headernames[hl-1] != ':')
1454 headernames = string_catn(headernames, &hs, &hl, US":", 1);
1456 headernames = string_cat(headernames, &hs, &hl, s);
1458 headernames[hl] = '\0';
1460 /* Copy headernames to signature struct */
1461 sig->headernames = headernames;
1463 /* Create signature header with b= omitted */
1464 sig_hdr = pdkim_create_header(sig, FALSE);
1467 /* VERIFICATION ----------------------------------------------------------- */
1468 /* When verifying, walk through the header name list in the h= parameter and
1469 add the headers to the hash in that order. */
1472 uschar * p = sig->headernames;
1474 pdkim_stringlist * hdrs;
1479 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1485 if ((q = Ustrchr(p, ':')))
1488 /*XXX walk the list of headers in same order as received. */
1489 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1491 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
1492 && (hdrs->value)[Ustrlen(p)] == ':'
1495 /* cook header for relaxed canon, or just copy it for simple */
1497 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1498 ? pdkim_relax_header(hdrs->value, TRUE)
1499 : string_copy(CUS hdrs->value);
1501 /* Feed header to the hash algorithm */
1502 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1504 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1513 sig_hdr = string_copy(sig->rawsig_no_b_val);
1517 DEBUG(D_acl) debug_printf(
1518 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1520 /* Relax header if necessary */
1521 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1522 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
1527 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1528 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1530 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1533 /* Finalize header hash */
1534 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1535 exim_sha_finish(&hhash_ctx, &hhash);
1539 debug_printf("PDKIM [%s] Header hash computed: ", sig->domain);
1540 pdkim_hexprint(hhash.data, hhash.len);
1543 /* Remember headers block for signing (when the library cannot do incremental) */
1544 /*XXX is this assuing algo == RSA? */
1545 if (ctx->flags & PDKIM_MODE_SIGN)
1546 (void) exim_dkim_data_append(&hdata, &hdata_alloc, US sig_hdr);
1548 /* SIGNING ---------------------------------------------------------------- */
1549 if (ctx->flags & PDKIM_MODE_SIGN)
1553 /* Import private key, including the keytype */
1554 /*XXX extend for non-RSA algos */
1555 if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx)))
1557 DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
1558 return PDKIM_ERR_RSA_PRIVKEY;
1561 /* Do signing. With OpenSSL we are signing the hash of headers just
1562 calculated, with GnuTLS we have to sign an entire block of headers
1563 (due to available interfaces) and it recalculates the hash internally. */
1565 #if defined(SIGN_OPENSSL) || defined(SIGN_GCRYPT)
1569 /*XXX extend for non-RSA algos */
1570 if ((*err = exim_dkim_sign(&sctx,
1571 pdkim_hashes[sig->hashtype].exim_hashmethod,
1572 &hdata, &sig->sighash)))
1574 DEBUG(D_acl) debug_printf("signing: %s\n", *err);
1575 return PDKIM_ERR_RSA_SIGNING;
1580 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1581 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1584 sig->signature_header = pdkim_create_header(sig, TRUE);
1587 /* VERIFICATION ----------------------------------------------------------- */
1592 /* Make sure we have all required signature tags */
1593 if (!( sig->domain && *sig->domain
1594 && sig->selector && *sig->selector
1595 && sig->headernames && *sig->headernames
1596 && sig->bodyhash.data
1597 && sig->sighash.data
1598 && sig->keytype >= 0
1599 && sig->hashtype >= 0
1603 sig->verify_status = PDKIM_VERIFY_INVALID;
1604 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1606 DEBUG(D_acl) debug_printf(
1607 " Error in DKIM-Signature header: tags missing or invalid\n"
1608 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1612 /* Make sure sig uses supported DKIM version (only v1) */
1613 if (sig->version != 1)
1615 sig->verify_status = PDKIM_VERIFY_INVALID;
1616 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1618 DEBUG(D_acl) debug_printf(
1619 " Error in DKIM-Signature header: unsupported DKIM version\n"
1620 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1624 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
1627 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1628 do not have the hash part of the sig algorithm matching */
1630 if (sig->pubkey->hashes)
1632 const uschar * list = sig->pubkey->hashes, * ele;
1634 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
1635 if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
1638 DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
1639 sig->pubkey->hashes,
1640 pdkim_keytypes[sig->keytype],
1641 pdkim_hashes[sig->hashtype].dkim_hashname);
1642 sig->verify_status = PDKIM_VERIFY_FAIL;
1643 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1648 /* Check the signature */
1649 /*XXX needs extension for non-RSA */
1650 if ((*err = exim_dkim_verify(&vctx,
1651 pdkim_hashes[sig->hashtype].exim_hashmethod,
1652 &hhash, &sig->sighash)))
1654 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
1655 sig->verify_status = PDKIM_VERIFY_FAIL;
1656 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1661 /* We have a winner! (if bodyhash was correct earlier) */
1662 if (sig->verify_status == PDKIM_VERIFY_NONE)
1663 sig->verify_status = PDKIM_VERIFY_PASS;
1669 debug_printf("PDKIM [%s] signature status: %s",
1670 sig->domain, pdkim_verify_status_str(sig->verify_status));
1671 if (sig->verify_ext_status > 0)
1672 debug_printf(" (%s)\n",
1673 pdkim_verify_ext_status_str(sig->verify_ext_status));
1682 /* If requested, set return pointer to signature(s) */
1683 if (return_signatures)
1684 *return_signatures = ctx->sig;
1690 /* -------------------------------------------------------------------------- */
1692 DLLEXPORT pdkim_ctx *
1693 pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
1697 ctx = store_get(sizeof(pdkim_ctx));
1698 memset(ctx, 0, sizeof(pdkim_ctx));
1700 if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1701 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1702 ctx->dns_txt_callback = dns_txt_callback;
1708 /* -------------------------------------------------------------------------- */
1710 /*XXX ? needs extension to cover non-RSA algo? */
1712 DLLEXPORT pdkim_ctx *
1713 pdkim_init_sign(uschar * domain, uschar * selector, uschar * privkey,
1714 uschar * hashname, BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *),
1715 const uschar ** errstr)
1719 pdkim_signature * sig;
1721 if (!domain || !selector || !privkey)
1724 ctx = store_get(sizeof(pdkim_ctx) + PDKIM_MAX_BODY_LINE_LEN + sizeof(pdkim_signature));
1725 memset(ctx, 0, sizeof(pdkim_ctx));
1727 ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1728 ctx->linebuf = CS (ctx+1);
1730 DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
1732 sig = (pdkim_signature *)(ctx->linebuf + PDKIM_MAX_BODY_LINE_LEN);
1733 memset(sig, 0, sizeof(pdkim_signature));
1735 sig->bodylength = -1;
1738 sig->domain = string_copy(US domain);
1739 sig->selector = string_copy(US selector);
1740 sig->privkey = string_copy(US privkey);
1741 /*XXX no keytype yet; comes from privkey */
1743 for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
1744 if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
1745 { sig->hashtype = hashtype; break; }
1746 if (hashtype >= nelem(pdkim_hashes))
1749 debug_printf("PDKIM: unrecognised hashname '%s'\n", hashname);
1753 if (!exim_sha_init(&sig->body_hash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
1756 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
1762 pdkim_signature s = *sig;
1765 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1766 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
1767 debug_printf("WARNING: bad dkim key in dns\n");
1768 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1774 /* -------------------------------------------------------------------------- */
1777 pdkim_set_optional(pdkim_ctx *ctx,
1783 unsigned long created,
1784 unsigned long expires)
1786 pdkim_signature * sig = ctx->sig;
1789 sig->identity = string_copy(US identity);
1791 sig->sign_headers = string_copy(sign_headers
1792 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1794 sig->canon_headers = canon_headers;
1795 sig->canon_body = canon_body;
1796 sig->bodylength = bodylength;
1797 sig->created = created;
1798 sig->expires = expires;
1812 #endif /*DISABLE_DKIM*/