diff options
author | Jeremy Harris <jgh146exb@wizmail.org> | 2017-09-12 17:37:48 +0100 |
---|---|---|
committer | Jeremy Harris <jgh146exb@wizmail.org> | 2017-09-12 20:01:05 +0100 |
commit | d73e45df63ef6602fa32bd3e196d20735a0b69b5 (patch) | |
tree | fe58c7e3c44669c32118c33d2eb05db2d80eb065 | |
parent | 9b2583c440ab9104070054dfa02e8611799f777b (diff) |
DKIM: support multiple hash methods
-rw-r--r-- | doc/doc-docbook/spec.xfpt | 7 | ||||
-rw-r--r-- | doc/doc-txt/NewStuff | 2 | ||||
-rw-r--r-- | src/src/dkim.c | 39 | ||||
-rw-r--r-- | src/src/expand.c | 2 | ||||
-rw-r--r-- | src/src/hash.c | 53 | ||||
-rw-r--r-- | src/src/hash.h | 10 | ||||
-rw-r--r-- | src/src/pdkim/crypt_ver.h | 8 | ||||
-rw-r--r-- | src/src/pdkim/pdkim.c | 134 | ||||
-rw-r--r-- | src/src/pdkim/pdkim.h | 18 | ||||
-rw-r--r-- | src/src/pdkim/pdkim_hash.h | 4 | ||||
-rw-r--r-- | src/src/pdkim/signing.c | 208 | ||||
-rw-r--r-- | src/src/pdkim/signing.h | 22 | ||||
-rw-r--r-- | src/src/structs.h | 1 | ||||
-rw-r--r-- | src/src/transports/smtp.c | 3 | ||||
l--------- | test/confs/4503 | 1 | ||||
-rw-r--r-- | test/confs/4520 | 3 | ||||
l--------- | test/confs/4523 | 1 | ||||
-rw-r--r-- | test/log/4503 | 6 | ||||
-rw-r--r-- | test/log/4523 | 11 | ||||
-rwxr-xr-x | test/runtest | 2 | ||||
-rw-r--r-- | test/scripts/4500-DKIM/4503 | 45 | ||||
-rw-r--r-- | test/scripts/4500-DKIM/4523 | 15 |
22 files changed, 368 insertions, 227 deletions
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 862c8f91d..61a6f0e83 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -23799,6 +23799,7 @@ of the message. Its value must not be zero. See also &%final_timeout%&. .option dkim_canon smtp string&!! unset .option dkim_strict smtp string&!! unset .option dkim_sign_headers smtp string&!! unset +.option dkim_hash smtp string&!! sha256 DKIM signing options. For details see section &<<SECDKIMSIGN>>&. @@ -38569,6 +38570,12 @@ list of header names. Headers with these names will be included in the message signature. When unspecified, the header names recommended in RFC4871 will be used. +.new +.option dkim_hash smtp string&!! sha256 +Can be set alternatively to &"sha1"& to use an alternate hash +method. Note that sha1 is now condidered insecure, and deprecated. +.wen + .section "Verifying DKIM signatures in incoming mail" "SECID514" .cindex "DKIM" "verification" diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 8ea1708bd..c10649edd 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -52,6 +52,8 @@ Version 4.90 is opened with a TFO cookie. Support varies between platforms (Linux does both. FreeBSD server only, others unknown). +13. DKIM support for multiple hashes. + Version 4.89 ------------ diff --git a/src/src/dkim.c b/src/src/dkim.c index f7b9ee0d1..2b7f55ae8 100644 --- a/src/src/dkim.c +++ b/src/src/dkim.c @@ -20,6 +20,12 @@ pdkim_signature *dkim_signatures = NULL; pdkim_signature *dkim_cur_sig = NULL; static const uschar * dkim_collect_error = NULL; + + +/*XXX the caller only uses the first record if we return multiple. +Could we hand back an allocated string? +*/ + static int dkim_exim_query_dns_txt(char *name, char *answer) { @@ -164,9 +170,7 @@ for (sig = dkim_signatures; sig; sig = sig->next) logmsg = string_append(logmsg, &size, &ptr, 7, " c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed", "/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed", - " a=", sig->algo == PDKIM_ALGO_RSA_SHA256 - ? "rsa-sha256" - : sig->algo == PDKIM_ALGO_RSA_SHA1 ? "rsa-sha1" : "err", + " a=", dkim_sig_to_a_tag(sig), string_sprintf(" b=%d", (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0)); if ((s= sig->identity)) logmsg = string_append(logmsg, &size, &ptr, 2, " i=", s); @@ -338,12 +342,7 @@ if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig) switch (what) { case DKIM_ALGO: - switch (dkim_cur_sig->algo) - { - case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1"; - case PDKIM_ALGO_RSA_SHA256: - default: return US"rsa-sha256"; - } + return dkim_sig_to_a_tag(dkim_cur_sig); case DKIM_BODYLENGTH: return dkim_cur_sig->bodylength >= 0 @@ -466,6 +465,7 @@ int seen_items_offset = 0; uschar *dkim_canon_expanded; uschar *dkim_sign_headers_expanded; uschar *dkim_private_key_expanded; +uschar *dkim_hash_expanded; pdkim_ctx *ctx = NULL; uschar *rc = NULL; uschar *sigbuf = NULL; @@ -608,15 +608,20 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0))) dkim_private_key_expanded = big_buffer; } -/*XXX so we currently nail signing to RSA + SHA256. Need to extract algo -from privkey, and provide means for selecting hash-method. -Check for disallowed combos. -Will need new dkim_ transport option for hash. */ + if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash))) + { + log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand " + "dkim_hash: %s", expand_string_message); + goto bad; + } + +/*XXX so we currently nail signing to RSA + given hash. +Need to extract algo from privkey and check for disallowed combos. */ - if (!(ctx = pdkim_init_sign(CS dkim_signing_domain, - CS dkim_signing_selector, - CS dkim_private_key_expanded, - PDKIM_ALGO_RSA_SHA256, + if (!(ctx = pdkim_init_sign(dkim_signing_domain, + dkim_signing_selector, + dkim_private_key_expanded, + dkim_hash_expanded, dkim->dot_stuffed, &dkim_exim_query_dns_txt, errstr diff --git a/src/src/expand.c b/src/src/expand.c index 83e519a7d..c51c1ff1b 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -6461,7 +6461,7 @@ while (*s != 0) blob b; char st[3]; - if (!exim_sha_init(&h, HASH_SHA256)) + if (!exim_sha_init(&h, HASH_SHA2_256)) { expand_string_message = US"unrecognised sha256 variant"; goto EXPAND_FAILED; diff --git a/src/src/hash.c b/src/src/hash.c index e239516e1..19ab1efd0 100644 --- a/src/src/hash.c +++ b/src/src/hash.c @@ -36,9 +36,11 @@ exim_sha_init(hctx * h, hashmethod m) /*XXX extend for sha512 */ switch (h->method = m) { - case HASH_SHA1: h->hashlen = 20; SHA1_Init (&h->u.sha1); break; - case HASH_SHA256: h->hashlen = 32; SHA256_Init(&h->u.sha2); break; - default: h->hashlen = 0; return FALSE; + case HASH_SHA1: h->hashlen = 20; SHA1_Init (&h->u.sha1); break; + case HASH_SHA2_256: h->hashlen = 32; SHA256_Init(&h->u.sha2_256); break; + case HASH_SHA2_384: h->hashlen = 48; SHA384_Init(&h->u.sha2_512); break; + case HASH_SHA2_512: h->hashlen = 64; SHA512_Init(&h->u.sha2_512); break; + default: h->hashlen = 0; return FALSE; } return TRUE; } @@ -49,8 +51,10 @@ exim_sha_update(hctx * h, const uschar * data, int len) { switch (h->method) { - case HASH_SHA1: SHA1_Update (&h->u.sha1, data, len); break; - case HASH_SHA256: SHA256_Update(&h->u.sha2, data, len); break; + case HASH_SHA1: SHA1_Update (&h->u.sha1, data, len); break; + case HASH_SHA2_256: SHA256_Update(&h->u.sha2_256, data, len); break; + case HASH_SHA2_384: SHA384_Update(&h->u.sha2_512, data, len); break; + case HASH_SHA2_512: SHA512_Update(&h->u.sha2_512, data, len); break; /* should be blocked by init not handling these, but be explicit to guard against accidents later (and hush up clang -Wswitch) */ default: assert(0); @@ -64,8 +68,10 @@ exim_sha_finish(hctx * h, blob * b) b->data = store_get(b->len = h->hashlen); switch (h->method) { - case HASH_SHA1: SHA1_Final (b->data, &h->u.sha1); break; - case HASH_SHA256: SHA256_Final(b->data, &h->u.sha2); break; + case HASH_SHA1: SHA1_Final (b->data, &h->u.sha1); break; + case HASH_SHA2_256: SHA256_Final(b->data, &h->u.sha2_256); break; + case HASH_SHA2_384: SHA384_Final(b->data, &h->u.sha2_512); break; + case HASH_SHA2_512: SHA512_Final(b->data, &h->u.sha2_512); break; default: assert(0); } } @@ -81,10 +87,14 @@ exim_sha_init(hctx * h, hashmethod m) /*XXX extend for sha512 */ switch (h->method = m) { - case HASH_SHA1: h->hashlen = 20; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA1); break; - case HASH_SHA256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA256); break; + case HASH_SHA1: h->hashlen = 20; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA1); break; + case HASH_SHA2_256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA256); break; + case HASH_SHA2_384: h->hashlen = 48; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA384); break; + case HASH_SHA2_512: h->hashlen = 64; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA512); break; #ifdef EXIM_HAVE_SHA3 case HASH_SHA3_256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_256); break; + case HASH_SHA3_384: h->hashlen = 48; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_384); break; + case HASH_SHA3_512: h->hashlen = 64; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_512); break; #endif default: h->hashlen = 0; return FALSE; } @@ -117,8 +127,13 @@ exim_sha_init(hctx * h, hashmethod m) /*XXX extend for sha512 */ switch (h->method = m) { - case HASH_SHA1: h->hashlen = 20; gcry_md_open(&h->sha, GCRY_MD_SHA1, 0); break; - case HASH_SHA256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA256, 0); break; + case HASH_SHA1: h->hashlen = 20; gcry_md_open(&h->sha, GCRY_MD_SHA1, 0); break; + case HASH_SHA2_256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA256, 0); break; + case HASH_SHA2_384: h->hashlen = 48; gcry_md_open(&h->sha, GCRY_MD_SHA384, 0); break; + case HASH_SHA2_512: h->hashlen = 64; gcry_md_open(&h->sha, GCRY_MD_SHA512, 0); break; + case HASH_SHA3_256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA3_256, 0); break; + case HASH_SHA3_384: h->hashlen = 48; gcry_md_open(&h->sha, GCRY_MD_SHA3_384, 0); break; + case HASH_SHA3_512: h->hashlen = 64; gcry_md_open(&h->sha, GCRY_MD_SHA3_512, 0); break; default: h->hashlen = 0; return FALSE; } return TRUE; @@ -152,7 +167,7 @@ exim_sha_init(hctx * h, hashmethod m) switch (h->method = m) { case HASH_SHA1: h->hashlen = 20; sha1_starts(&h->u.sha1); break; - case HASH_SHA256: h->hashlen = 32; sha2_starts(&h->u.sha2, 0); break; + case HASH_SHA2_256: h->hashlen = 32; sha2_starts(&h->u.sha2, 0); break; default: h->hashlen = 0; return FALSE; } return TRUE; @@ -165,7 +180,7 @@ exim_sha_update(hctx * h, const uschar * data, int len) switch (h->method) { case HASH_SHA1: sha1_update(h->u.sha1, US data, len); break; - case HASH_SHA256: sha2_update(h->u.sha2, US data, len); break; + case HASH_SHA2_256: sha2_update(h->u.sha2, US data, len); break; } } @@ -177,7 +192,7 @@ b->data = store_get(b->len = h->hashlen); switch (h->method) { case HASH_SHA1: sha1_finish(h->u.sha1, b->data); break; - case HASH_SHA256: sha2_finish(h->u.sha2, b->data); break; + case HASH_SHA2_256: sha2_finish(h->u.sha2, b->data); break; } } @@ -421,16 +436,6 @@ native_sha1_end(&h->sha1, NULL, 0, b->data); #endif -/******************************************************************************/ - -/* Common to all library versions */ -int -exim_sha_hashlen(hctx * h) -{ -return h->method == HASH_SHA1 ? 20 - : h->method == HASH_SHA256 ? 32 - : 0; -} /******************************************************************************/ diff --git a/src/src/hash.h b/src/src/hash.h index 09b65944d..b745e6218 100644 --- a/src/src/hash.h +++ b/src/src/hash.h @@ -32,7 +32,11 @@ typedef enum hashmethod { HASH_BADTYPE, HASH_SHA1, - HASH_SHA256, + + HASH_SHA2_256, + HASH_SHA2_384, + HASH_SHA2_512, + HASH_SHA3_224, HASH_SHA3_256, HASH_SHA3_384, @@ -46,7 +50,8 @@ typedef struct { #ifdef SHA_OPENSSL union { SHA_CTX sha1; /* SHA1 block */ - SHA256_CTX sha2; /* SHA256 block */ + SHA256_CTX sha2_256; /* SHA256 or 224 block */ + SHA512_CTX sha2_512; /* SHA512 or 384 block */ } u; #elif defined(SHA_GNUTLS) @@ -70,7 +75,6 @@ typedef struct { extern BOOL exim_sha_init(hctx *, hashmethod); extern void exim_sha_update(hctx *, const uschar *a, int); extern void exim_sha_finish(hctx *, blob *); -extern int exim_sha_hashlen(hctx *); #endif /* End of File */ diff --git a/src/src/pdkim/crypt_ver.h b/src/src/pdkim/crypt_ver.h index cd2171c82..439d99b3a 100644 --- a/src/src/pdkim/crypt_ver.h +++ b/src/src/pdkim/crypt_ver.h @@ -5,7 +5,7 @@ /* Copyright (c) Jeremy Harris 2016 */ /* See the file NOTICE for conditions of use and distribution. */ -/* RSA and SHA routine selection for PDKIM */ +/* Signing and hashing routine selection for PDKIM */ #include "../exim.h" #include "../sha_ver.h" @@ -15,12 +15,12 @@ # include <gnutls/gnutls.h> # if GNUTLS_VERSION_NUMBER >= 0x30000 -# define RSA_GNUTLS +# define SIGN_GNUTLS # else -# define RSA_GCRYPT +# define SIGN_GCRYPT # endif #else -# define RSA_OPENSSL +# define SIGN_OPENSSL #endif diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index 441f96cb5..bef6b6a69 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -32,11 +32,11 @@ #include "crypt_ver.h" -#ifdef RSA_OPENSSL +#ifdef SIGN_OPENSSL # include <openssl/rsa.h> # include <openssl/ssl.h> # include <openssl/err.h> -#elif defined(RSA_GNUTLS) +#elif defined(SIGN_GNUTLS) # include <gnutls/gnutls.h> # include <gnutls/x509.h> #endif @@ -73,26 +73,24 @@ const uschar * pdkim_querymethods[] = { US"dns/txt", NULL }; -const uschar * pdkim_algos[] = { - US"rsa-sha256", - US"rsa-sha1", - NULL -}; const uschar * pdkim_canons[] = { US"simple", US"relaxed", NULL }; -/*XXX currently unused */ -const uschar * pdkim_hashes[] = { - US"sha256", - US"sha1", - NULL + +typedef struct { + const uschar * dkim_hashname; + hashmethod exim_hashmethod; +} pdkim_hashtype; +static const pdkim_hashtype pdkim_hashes[] = { + { US"sha1", HASH_SHA1 }, + { US"sha256", HASH_SHA2_256 }, + { US"sha512", HASH_SHA2_512 } }; -/*XXX currently unused */ + const uschar * pdkim_keytypes[] = { - US"rsa", - NULL + US"rsa" }; typedef struct pdkim_combined_canon_entry { @@ -113,6 +111,17 @@ pdkim_combined_canon_entry pdkim_combined_canons[] = { /* -------------------------------------------------------------------------- */ +uschar * +dkim_sig_to_a_tag(pdkim_signature * sig) +{ +if ( sig->keytype < 0 || sig->keytype > nelem(pdkim_keytypes) + || sig->hashtype < 0 || sig->hashtype > nelem(pdkim_hashes)) + return US"err"; +return string_sprintf("%s-%s", + pdkim_keytypes[sig->keytype], pdkim_hashes[sig->hashtype].dkim_hashname); +} + + const char * pdkim_verify_status_str(int status) @@ -433,8 +442,9 @@ memset(sig, 0, sizeof(pdkim_signature)); sig->bodylength = -1; /* Set so invalid/missing data error display is accurate */ -sig->algo = -1; sig->version = 0; +sig->keytype = -1; +sig->hashtype = -1; q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1); @@ -507,14 +517,18 @@ for (p = raw_hdr; ; p++) Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1; break; case 'a': -/*XXX this searches a list of combined (algo + hash-method)s */ - for (i = 0; pdkim_algos[i]; i++) - if (Ustrcmp(cur_val, pdkim_algos[i]) == 0) - { - sig->algo = i; - break; - } + { + uschar * s = Ustrchr(cur_val, '-'); + + for(i = 0; i < nelem(pdkim_keytypes); i++) + if (Ustrncmp(cur_val, pdkim_keytypes[i], s - cur_val) == 0) + { sig->keytype = i; break; } + for (++s, i = 0; i < nelem(pdkim_hashes); i++) + if (Ustrcmp(s, pdkim_hashes[i].dkim_hashname) == 0) + { sig->hashtype = i; break; } break; + } + case 'c': for (i = 0; pdkim_combined_canons[i].str; i++) if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0) @@ -588,9 +602,10 @@ DEBUG(D_acl) /*XXX hash method: extend for sha512 */ if (!exim_sha_init(&sig->body_hash_ctx, - sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256)) + pdkim_hashes[sig->hashtype].exim_hashmethod)) { - DEBUG(D_acl) debug_printf("PDKIM: hash init internal error\n"); + DEBUG(D_acl) + debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n"); return NULL; } return sig; @@ -1189,8 +1204,7 @@ col = hdr_len; /* Required and static bits */ hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=", -/*XXX this is a combo of algo and hash-method */ - pdkim_algos[sig->algo]); + dkim_sig_to_a_tag(sig)); hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=", pdkim_querymethods[sig->querymethod]); hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=", @@ -1375,8 +1389,6 @@ pdkim_finish_bodyhash(ctx); while (sig) { -/*XXX bool probably not enough */ - BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1; hctx hhash_ctx; uschar * sig_hdr = US""; blob hhash; @@ -1386,9 +1398,10 @@ while (sig) hdata.data = NULL; hdata.len = 0; - if (!exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256)) + if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod)) { - DEBUG(D_acl) debug_printf("PDKIM: hask setup internal error\n"); + DEBUG(D_acl) + debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n"); break; } @@ -1537,9 +1550,9 @@ while (sig) { es_ctx sctx; - /* Import private key */ + /* Import private key, including the keytype */ /*XXX extend for non-RSA algos */ - if ((*err = exim_dkim_signing_init(US sig->rsa_privkey, &sctx))) + if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx))) { DEBUG(D_acl) debug_printf("signing_init: %s\n", *err); return PDKIM_ERR_RSA_PRIVKEY; @@ -1549,15 +1562,14 @@ while (sig) calculated, with GnuTLS we have to sign an entire block of headers (due to available interfaces) and it recalculates the hash internally. */ -#if defined(RSA_OPENSSL) || defined(RSA_GCRYPT) +#if defined(SIGN_OPENSSL) || defined(SIGN_GCRYPT) hdata = hhash; #endif /*XXX extend for non-RSA algos */ -/*XXX oddly the dkim rfc does _not_ say what variant (sha1 or sha256) of -RSA signing should be done. We use the same variant as the hash-method. */ - - if ((*err = exim_dkim_sign(&sctx, is_sha1, &hdata, &sig->sighash))) + if ((*err = exim_dkim_sign(&sctx, + pdkim_hashes[sig->hashtype].exim_hashmethod, + &hdata, &sig->sighash))) { DEBUG(D_acl) debug_printf("signing: %s\n", *err); return PDKIM_ERR_RSA_SIGNING; @@ -1583,7 +1595,8 @@ RSA signing should be done. We use the same variant as the hash-method. */ && sig->headernames && *sig->headernames && sig->bodyhash.data && sig->sighash.data - && sig->algo > -1 + && sig->keytype >= 0 + && sig->hashtype >= 0 && sig->version ) ) { @@ -1619,11 +1632,13 @@ RSA signing should be done. We use the same variant as the hash-method. */ const uschar * list = sig->pubkey->hashes, * ele; int sep = ':'; while ((ele = string_nextinlist(&list, &sep, NULL, 0))) - if (Ustrcmp(ele, pdkim_algos[sig->algo] + 4) == 0) break; + if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break; if (!ele) { - DEBUG(D_acl) debug_printf("pubkey h=%s vs sig a=%s\n", - sig->pubkey->hashes, pdkim_algos[sig->algo]); + DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n", + sig->pubkey->hashes, + pdkim_keytypes[sig->keytype], + pdkim_hashes[sig->hashtype].dkim_hashname); sig->verify_status = PDKIM_VERIFY_FAIL; sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH; goto NEXT_VERIFY; @@ -1632,7 +1647,9 @@ RSA signing should be done. We use the same variant as the hash-method. */ /* Check the signature */ /*XXX needs extension for non-RSA */ - if ((*err = exim_dkim_verify(&vctx, is_sha1, &hhash, &sig->sighash))) + if ((*err = exim_dkim_verify(&vctx, + pdkim_hashes[sig->hashtype].exim_hashmethod, + &hhash, &sig->sighash))) { DEBUG(D_acl) debug_printf("headers verify: %s\n", *err); sig->verify_status = PDKIM_VERIFY_FAIL; @@ -1690,18 +1707,18 @@ return ctx; /* -------------------------------------------------------------------------- */ -/*XXX ? needs extension to cover non-RSA algo? Currently the "algo" is actually -the combo of algo and hash-method */ +/*XXX ? needs extension to cover non-RSA algo? */ DLLEXPORT pdkim_ctx * -pdkim_init_sign(char * domain, char * selector, char * rsa_privkey, int algo, - BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *), +pdkim_init_sign(uschar * domain, uschar * selector, uschar * privkey, + uschar * hashname, BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *), const uschar ** errstr) { +int hashtype; pdkim_ctx * ctx; pdkim_signature * sig; -if (!domain || !selector || !rsa_privkey) +if (!domain || !selector || !privkey) return NULL; ctx = store_get(sizeof(pdkim_ctx) + PDKIM_MAX_BODY_LINE_LEN + sizeof(pdkim_signature)); @@ -1720,14 +1737,23 @@ ctx->sig = sig; sig->domain = string_copy(US domain); sig->selector = string_copy(US selector); -sig->rsa_privkey = string_copy(US rsa_privkey); -sig->algo = algo; +sig->privkey = string_copy(US privkey); +/*XXX no keytype yet; comes from privkey */ -/*XXX extend for sha512 */ -if (!exim_sha_init(&sig->body_hash_ctx, - algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256)) +for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++) + if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0) + { sig->hashtype = hashtype; break; } +if (hashtype >= nelem(pdkim_hashes)) { - DEBUG(D_acl) debug_printf("PDKIM: hash setup internal error\n"); + DEBUG(D_acl) + debug_printf("PDKIM: unrecognised hashname '%s'\n", hashname); + return NULL; + } + +if (!exim_sha_init(&sig->body_hash_ctx, pdkim_hashes[hashtype].exim_hashmethod)) + { + DEBUG(D_acl) + debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n"); return NULL; } diff --git a/src/src/pdkim/pdkim.h b/src/src/pdkim/pdkim.h index 176bc36e0..3c420ae63 100644 --- a/src/src/pdkim/pdkim.h +++ b/src/src/pdkim/pdkim.h @@ -63,14 +63,11 @@ /* Some parameter values */ #define PDKIM_QUERYMETHOD_DNS_TXT 0 -#define PDKIM_ALGO_RSA_SHA256 0 -#define PDKIM_ALGO_RSA_SHA1 1 - #define PDKIM_CANON_SIMPLE 0 #define PDKIM_CANON_RELAXED 1 -#define PDKIM_HASH_SHA256 0 -#define PDKIM_HASH_SHA1 1 +/*XXX change to enums */ +#define PDKIM_HASH_SHA256 1 #define PDKIM_KEYTYPE_RSA 0 @@ -122,9 +119,8 @@ typedef struct pdkim_signature { /* (v=) The version, as an integer. Currently, always "1" */ int version; - /* (a=) The signature algorithm. Either PDKIM_ALGO_RSA_SHA256 - or PDKIM_ALGO_RSA_SHA1 */ - int algo; + int keytype; /* PDKIM_KEYTYPE_RSA */ + int hashtype; /* pdkim_hashes index */ /* (c=x/) Header canonicalization method. Either PDKIM_CANON_SIMPLE or PDKIM_CANON_RELAXED */ @@ -239,7 +235,7 @@ typedef struct pdkim_signature { unsigned long signed_body_bytes; /* How many body bytes we hashed */ pdkim_stringlist *headers; /* Raw headers included in the sig */ /* Signing specific ------------------------------------------------- */ - uschar * rsa_privkey; /* Private RSA key */ + uschar * privkey; /* Private key */ uschar * sign_headers; /* To-be-signed header names */ uschar * rawsig_no_b_val; /* Original signature header w/o b= tag value. */ } pdkim_signature; @@ -287,7 +283,7 @@ extern "C" { void pdkim_init (void); DLLEXPORT -pdkim_ctx *pdkim_init_sign (char *, char *, char *, int, +pdkim_ctx *pdkim_init_sign (uschar *, uschar *, uschar *, uschar *, BOOL, int(*)(char *, char *), const uschar **); DLLEXPORT @@ -310,6 +306,8 @@ void pdkim_free_ctx (pdkim_ctx *); const uschar * pdkim_errstr(int); +uschar * dkim_sig_to_a_tag(pdkim_signature * sig); + #ifdef __cplusplus } #endif diff --git a/src/src/pdkim/pdkim_hash.h b/src/src/pdkim/pdkim_hash.h index 143cd19df..008f277b3 100644 --- a/src/src/pdkim/pdkim_hash.h +++ b/src/src/pdkim/pdkim_hash.h @@ -19,11 +19,11 @@ #include "../blob.h" #include "../hash.h" -#ifdef RSA_OPENSSL +#ifdef SIGN_OPENSSL # include <openssl/rsa.h> # include <openssl/ssl.h> # include <openssl/err.h> -#elif defined(RSA_GNUTLS) +#elif defined(SIGN_GNUTLS) # include <gnutls/gnutls.h> # include <gnutls/x509.h> #endif diff --git a/src/src/pdkim/signing.c b/src/src/pdkim/signing.c index bcd64fdc4..ec68414c8 100644 --- a/src/src/pdkim/signing.c +++ b/src/src/pdkim/signing.c @@ -3,11 +3,7 @@ * * Copyright (C) 2016 Exim maintainers * - * RSA signing/verification interface -XXX rename interfaces to cover all signature methods. -the method (algo) needs to be extracted from the supplied private-key -and not only stashed as needed in the sign- or verify- context, but -indicated to caller for protocol tag construction. + * signing/verification interface */ #include "../exim.h" @@ -23,7 +19,7 @@ indicated to caller for protocol tag construction. /******************************************************************************/ -#ifdef RSA_GNUTLS +#ifdef SIGN_GNUTLS void exim_dkim_init(void) @@ -55,8 +51,8 @@ int rc; k.data = privkey_pem; k.size = strlen(privkey_pem); -if ( (rc = gnutls_x509_privkey_init(&sign_ctx->rsa)) != GNUTLS_E_SUCCESS - || (rc = gnutls_x509_privkey_import(sign_ctx->rsa, &k, +if ( (rc = gnutls_x509_privkey_init(&sign_ctx->key)) != GNUTLS_E_SUCCESS + || (rc = gnutls_x509_privkey_import(sign_ctx->key, &k, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS ) return gnutls_strerror(rc); @@ -74,33 +70,38 @@ sign hash. Return: NULL for success, or an error string */ const uschar * -exim_dkim_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig) +exim_dkim_sign(es_ctx * sign_ctx, hashmethod hash, blob * data, blob * sig) { +gnutls_digest_algorithm_t dig; gnutls_datum_t k; size_t sigsize = 0; int rc; const uschar * ret = NULL; +switch (hash) + { + case HASH_SHA1: dig = GNUTLS_DIG_SHA1; break; + case HASH_SHA2_256: dig = GNUTLS_DIG_SHA256; break; + case HASH_SHA2_512: dig = GNUTLS_DIG_SHA512; break; + default: return US"nonhandled hash type"; + } + /* Allocate mem for signature */ k.data = data->data; k.size = data->len; -(void) gnutls_x509_privkey_sign_data(sign_ctx->rsa, - is_sha1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, +(void) gnutls_x509_privkey_sign_data(sign_ctx->key, dig, 0, &k, NULL, &sigsize); sig->data = store_get(sigsize); sig->len = sigsize; /* Do signing */ -/*XXX will need extension for hash type; looks ok for non-RSA algos -so long as the privkey_import stage got them. */ -if ((rc = gnutls_x509_privkey_sign_data(sign_ctx->rsa, - is_sha1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, +if ((rc = gnutls_x509_privkey_sign_data(sign_ctx->key, dig, 0, &k, sig->data, &sigsize)) != GNUTLS_E_SUCCESS ) ret = gnutls_strerror(rc); -gnutls_x509_privkey_deinit(sign_ctx->rsa); +gnutls_x509_privkey_deinit(sign_ctx->key); return ret; } @@ -116,12 +117,12 @@ gnutls_datum_t k; int rc; const uschar * ret = NULL; -gnutls_pubkey_init(&verify_ctx->rsa); +gnutls_pubkey_init(&verify_ctx->key); k.data = pubkey_der->data; k.size = pubkey_der->len; -if ((rc = gnutls_pubkey_import(verify_ctx->rsa, &k, GNUTLS_X509_FMT_DER)) +if ((rc = gnutls_pubkey_import(verify_ctx->key, &k, GNUTLS_X509_FMT_DER)) != GNUTLS_E_SUCCESS) ret = gnutls_strerror(rc); return ret; @@ -132,31 +133,39 @@ return ret; Return: NULL for success, or an error string */ const uschar * -exim_dkim_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig) +exim_dkim_verify(ev_ctx * verify_ctx, hashmethod hash, blob * data_hash, blob * sig) { +gnutls_sign_algorithm_t algo; gnutls_datum_t k, s; int rc; const uschar * ret = NULL; +/*XXX needs extension for non-rsa */ +switch (hash) + { + case HASH_SHA1: algo = GNUTLS_SIGN_RSA_SHA1; break; + case HASH_SHA2_256: algo = GNUTLS_SIGN_RSA_SHA256; break; + case HASH_SHA2_512: algo = GNUTLS_SIGN_RSA_SHA512; break; + default: return US"nonhandled hash type"; + } + k.data = data_hash->data; k.size = data_hash->len; s.data = sig->data; s.size = sig->len; -if ((rc = gnutls_pubkey_verify_hash2(verify_ctx->rsa, -/*XXX needs extension for SHA512 */ - is_sha1 ? GNUTLS_SIGN_RSA_SHA1 : GNUTLS_SIGN_RSA_SHA256, - 0, &k, &s)) < 0) +if ((rc = gnutls_pubkey_verify_hash2(verify_ctx->key, algo, 0, &k, &s)) < 0) ret = gnutls_strerror(rc); -gnutls_pubkey_deinit(verify_ctx->rsa); +gnutls_pubkey_deinit(verify_ctx->key); return ret; } -#elif defined(RSA_GCRYPT) +#elif defined(SIGN_GCRYPT) /******************************************************************************/ +/* This variant is used under pre-3.0.0 GnuTLS. Only rsa-sha1 and rsa-sha256 */ /* Internal service routine: @@ -364,8 +373,9 @@ sign hash. Return: NULL for success, or an error string */ const uschar * -exim_dkim_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig) +exim_dkim_sign(es_ctx * sign_ctx, hashmethod hash, blob * data, blob * sig) { +BOOL is_sha1; gcry_sexp_t s_hash = NULL, s_key = NULL, s_sig = NULL; gcry_mpi_t m_sig; uschar * errstr; @@ -373,11 +383,18 @@ gcry_error_t gerr; /*XXX will need extension for hash types (though, possibly, should be re-specced to not rehash but take an already-hashed value? Actually -current impl looks WRONG - it _is_ given a has so should not be +current impl looks WRONG - it _is_ given a hash so should not be re-hashing. Has this been tested? Will need extension for non-RSA sugning algos. */ +switch (hash) + { + case HASH_SHA1: is_sha1 = TRUE; break; + case HASH_SHA2_256: is_sha1 = FALSE; break; + default: return US"nonhandled hash type"; + } + #define SIGSPACE 128 sig->data = store_get(SIGSPACE); @@ -512,7 +529,7 @@ DEBUG(D_acl) return string_sprintf("%s: %s", stage, asn1_strerror(rc)); Return: NULL for success, or an error string */ const uschar * -exim_dkim_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig) +exim_dkim_verify(ev_ctx * verify_ctx, hashmethod hash, blob * data_hash, blob * sig) { /* cf. libgnutls 2.8.5 _wrap_gcry_pk_verify() @@ -522,6 +539,13 @@ gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL; gcry_error_t gerr; uschar * stage; +switch (hash) + { + case HASH_SHA1: is_sha1 = TRUE; break; + case HASH_SHA2_256: is_sha1 = FALSE; break; + default: return US"nonhandled hash type"; + } + if ( (stage = US"pkey sexp build", gerr = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", verify_ctx->n, verify_ctx->e)) @@ -557,7 +581,7 @@ return NULL; -#elif defined(RSA_OPENSSL) +#elif defined(SIGN_OPENSSL) /******************************************************************************/ void @@ -580,30 +604,10 @@ Return: NULL for success, or an error string */ const uschar * exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx) { -uschar * p, * q; -int len; - -/*XXX maybe use PEM_read_bio_PrivateKey() ??? -The sign_ctx would need to have an EVP_PKEY* */ - -/* Convert PEM to DER */ -if ( !(p = Ustrstr(privkey_pem, "-----BEGIN RSA PRIVATE KEY-----")) - || !(q = Ustrstr(p+=31, "-----END RSA PRIVATE KEY-----")) - ) - return US"Bad PEM wrapping"; - -*q = '\0'; -if ((len = b64decode(p, &p)) < 0) - return US"b64decode failed"; - -if (!(sign_ctx->rsa = d2i_RSAPrivateKey(NULL, CUSS &p, len))) - { - char ssl_errstring[256]; - ERR_load_crypto_strings(); /*XXX move to a startup routine */ - ERR_error_string(ERR_get_error(), ssl_errstring); - return string_copy(US ssl_errstring); - } +BIO * bp = BIO_new_mem_buf(privkey_pem, -1); +if (!(sign_ctx->key = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL))) + return ERR_error_string(ERR_get_error(), NULL); return NULL; } @@ -617,32 +621,37 @@ sign hash. Return: NULL for success, or an error string */ const uschar * -exim_dkim_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig) +exim_dkim_sign(es_ctx * sign_ctx, hashmethod hash, blob * data, blob * sig) { -uint len; -const uschar * ret = NULL; - -/*XXX will need extension for non-RSA signing algo. Maybe use -https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_sign.html ??? */ +const EVP_MD * md; +EVP_PKEY_CTX * ctx; +size_t siglen; -/* Allocate mem for signature */ -len = RSA_size(sign_ctx->rsa); -sig->data = store_get(len); -sig->len = len; +switch (hash) + { + case HASH_SHA1: md = EVP_sha1(); break; + case HASH_SHA2_256: md = EVP_sha256(); break; + case HASH_SHA2_512: md = EVP_sha512(); break; + default: return US"nonhandled hash type"; + } -/* Do signing */ -if (RSA_sign(is_sha1 ? NID_sha1 : NID_sha256, - CUS data->data, data->len, - US sig->data, &len, sign_ctx->rsa) != 1) +if ( (ctx = EVP_PKEY_CTX_new(sign_ctx->key, NULL)) + && EVP_PKEY_sign_init(ctx) > 0 + && EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0 + && EVP_PKEY_CTX_set_signature_md(ctx, md) > 0 + && EVP_PKEY_sign(ctx, NULL, &siglen, data->data, data->len) > 0 + ) { - char ssl_errstring[256]; - ERR_load_crypto_strings(); /*XXX move to a startup routine */ - ERR_error_string(ERR_get_error(), ssl_errstring); - ret = string_copy(US ssl_errstring); + /* Allocate mem for signature */ + sig->data = store_get(siglen); + sig->len = siglen; + + if (EVP_PKEY_sign(ctx, sig->data, &siglen, data->data, data->len) > 0) + { EVP_PKEY_CTX_free(ctx); return NULL; } } -RSA_free(sign_ctx->rsa); -return ret;; +if (ctx) EVP_PKEY_CTX_free(ctx); +return ERR_error_string(ERR_get_error(), NULL); } @@ -653,19 +662,13 @@ Return: NULL for success, or an error string */ const uschar * exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx) { -const uschar * p = CUS pubkey_der->data; -const uschar * ret = NULL; +const uschar * s = pubkey_der->data; -/*XXX d2i_X509_PUBKEY, X509_get_pubkey(), and an EVP_PKEY* in verify_ctx. */ +/*XXX hmm, we never free this */ -if (!(verify_ctx->rsa = d2i_RSA_PUBKEY(NULL, &p, (long) pubkey_der->len))) - { - char ssl_errstring[256]; - ERR_load_crypto_strings(); /*XXX move to a startup routine */ - ERR_error_string(ERR_get_error(), ssl_errstring); - ret = string_copy(CUS ssl_errstring); - } -return ret; +if ((verify_ctx->key = d2i_PUBKEY(NULL, &s, pubkey_der->len))) + return NULL; +return ERR_error_string(ERR_get_error(), NULL); } @@ -675,31 +678,34 @@ return ret; Return: NULL for success, or an error string */ const uschar * -exim_dkim_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig) +exim_dkim_verify(ev_ctx * verify_ctx, hashmethod hash, blob * data_hash, blob * sig) { -const uschar * ret = NULL; +const EVP_MD * md; +EVP_PKEY_CTX * ctx; -/*XXX needs extension for SHA512, Possibly EVP_PKEY_verify() is all we need??? */ -/* with EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) -- see example code at https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_verify.html -and maybe also EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) though unclear -if that only sets a pad/type field byte value, or sets up for an actual hash operation... -Same on the signing side. -https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_padding.html says it does what we want. */ - -if (RSA_verify(is_sha1 ? NID_sha1 : NID_sha256, - CUS data_hash->data, data_hash->len, - US sig->data, (uint) sig->len, verify_ctx->rsa) != 1) +switch (hash) { - char ssl_errstring[256]; - ERR_load_crypto_strings(); /*XXX move to a startup routine */ - ERR_error_string(ERR_get_error(), ssl_errstring); - ret = string_copy(US ssl_errstring); + case HASH_SHA1: md = EVP_sha1(); break; + case HASH_SHA2_256: md = EVP_sha256(); break; + case HASH_SHA2_512: md = EVP_sha512(); break; + default: return US"nonhandled hash type"; } -return ret; + +if ( (ctx = EVP_PKEY_CTX_new(verify_ctx->key, NULL)) + && EVP_PKEY_verify_init(ctx) > 0 + && EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0 + && EVP_PKEY_CTX_set_signature_md(ctx, md) > 0 + && EVP_PKEY_verify(ctx, sig->data, sig->len, + data_hash->data, data_hash->len) == 1 + ) + { EVP_PKEY_CTX_free(ctx); return NULL; } + +if (ctx) EVP_PKEY_CTX_free(ctx); +return ERR_error_string(ERR_get_error(), NULL); } + #endif /******************************************************************************/ diff --git a/src/src/pdkim/signing.h b/src/src/pdkim/signing.h index 4e8580859..04288103e 100644 --- a/src/src/pdkim/signing.h +++ b/src/src/pdkim/signing.h @@ -12,15 +12,15 @@ #include "crypt_ver.h" -#ifdef RSA_OPENSSL +#ifdef SIGN_OPENSSL # include <openssl/rsa.h> # include <openssl/ssl.h> # include <openssl/err.h> -#elif defined(RSA_GNUTLS) +#elif defined(SIGN_GNUTLS) # include <gnutls/gnutls.h> # include <gnutls/x509.h> # include <gnutls/abstract.h> -#elif defined(RSA_GCRYPT) +#elif defined(SIGN_GCRYPT) # include <gcrypt.h> # include <libtasn1.h> #endif @@ -28,29 +28,30 @@ #include "../blob.h" -#ifdef RSA_OPENSSL +#ifdef SIGN_OPENSSL typedef struct { - RSA * rsa; + EVP_PKEY * key; } es_ctx; typedef struct { - RSA * rsa; + EVP_PKEY * key; } ev_ctx; -#elif defined(RSA_GNUTLS) +#elif defined(SIGN_GNUTLS) typedef struct { - gnutls_x509_privkey_t rsa; + gnutls_x509_privkey_t key; } es_ctx; typedef struct { - gnutls_pubkey_t rsa; + gnutls_pubkey_t key; } ev_ctx; -#elif defined(RSA_GCRYPT) +#elif defined(SIGN_GCRYPT) typedef struct { + int keytype; gcry_mpi_t n; gcry_mpi_t e; gcry_mpi_t d; @@ -62,6 +63,7 @@ typedef struct { } es_ctx; typedef struct { + int keytype; gcry_mpi_t n; gcry_mpi_t e; } ev_ctx; diff --git a/src/src/structs.h b/src/src/structs.h index beea57f34..06fcd4188 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -872,6 +872,7 @@ struct ob_dkim { uschar *dkim_canon; uschar *dkim_sign_headers; uschar *dkim_strict; + uschar *dkim_hash; BOOL dot_stuffed; }; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index d8bc596fc..147dfdeaf 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -43,6 +43,8 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, dkim.dkim_canon) }, { "dkim_domain", opt_stringptr, (void *)offsetof(smtp_transport_options_block, dkim.dkim_domain) }, + { "dkim_hash", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, dkim.dkim_hash) }, { "dkim_private_key", opt_stringptr, (void *)offsetof(smtp_transport_options_block, dkim.dkim_private_key) }, { "dkim_selector", opt_stringptr, @@ -281,6 +283,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { .dkim_canon = NULL, .dkim_sign_headers = NULL, .dkim_strict = NULL, + .dkim_hash = US"sha256", .dot_stuffed = FALSE}, #endif }; diff --git a/test/confs/4503 b/test/confs/4503 new file mode 120000 index 000000000..c4f73bacd --- /dev/null +++ b/test/confs/4503 @@ -0,0 +1 @@ +4500
\ No newline at end of file diff --git a/test/confs/4520 b/test/confs/4520 index 70454c33c..449702855 100644 --- a/test/confs/4520 +++ b/test/confs/4520 @@ -46,5 +46,8 @@ send_to_server: .ifndef HEADERS_MAXSIZE dkim_sign_headers = OPT .endif +.ifdef VALUE + dkim_hash = VALUE +.endif # End diff --git a/test/confs/4523 b/test/confs/4523 new file mode 120000 index 000000000..072f5faf2 --- /dev/null +++ b/test/confs/4523 @@ -0,0 +1 @@ +4520
\ No newline at end of file diff --git a/test/log/4503 b/test/log/4503 new file mode 100644 index 000000000..7ec93a1f5 --- /dev/null +++ b/test/log/4503 @@ -0,0 +1,6 @@ + +******** SERVER ******** +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 +1999-03-02 09:44:33 10HmaX-0005vi-00 DKIM: d=test.ex s=sel c=simple/simple a=rsa-sha512 b=1024 [verification failed - signature did not verify (headers probably modified in transit)] +1999-03-02 09:44:33 10HmaX-0005vi-00 signer: test.ex bits: 1024 +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net diff --git a/test/log/4523 b/test/log/4523 new file mode 100644 index 000000000..45eb89c9c --- /dev/null +++ b/test/log/4523 @@ -0,0 +1,11 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmaX-0005vi-00 => a@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmaY-0005vi-00" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed + +******** SERVER ******** +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 +1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha512 b=1024 [verification succeeded] +1999-03-02 09:44:33 10HmaY-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <a@test.ex> R=server_dump +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed diff --git a/test/runtest b/test/runtest index 712ab79bc..35da4931b 100755 --- a/test/runtest +++ b/test/runtest @@ -1527,7 +1527,7 @@ $munges = 'optional_config' => { 'stdout' => '/^( - dkim_(canon|domain|private_key|selector|sign_headers|strict) + dkim_(canon|domain|private_key|selector|sign_headers|strict|hash) |gnutls_require_(kx|mac|protocols) |hosts_(requ(est|ire)|try)_(dane|ocsp) |hosts_(avoid|nopass|require|verify_avoid)_tls diff --git a/test/scripts/4500-DKIM/4503 b/test/scripts/4500-DKIM/4503 new file mode 100644 index 000000000..aca19583b --- /dev/null +++ b/test/scripts/4500-DKIM/4503 @@ -0,0 +1,45 @@ +# DKIM verify, sha512 +# +exim -DSERVER=server -bd -oX PORT_D +**** +# +# This should pass, only Mail::DKIM::Signer does not handle rsa-sha512. +# - sha512, 1024b +# Mail original in aux-fixed/4500.msg1.txt +# Sig generated by: perl aux-fixed/dkim/sign.pl --algorithm=rsa-sha512 \ +# --method=simple/simple < aux-fixed/4500.msg1.txt +# +# TODO - until we have that we can only test internal consistency, +# signing vs. verification. +# +client 127.0.0.1 PORT_D +??? 220 +HELO xxx +??? 250 +MAIL FROM:<CALLER@bloggs.com> +??? 250 +RCPT TO:<a@test.ex> +??? 250 +DATA +??? 354 +DKIM-Signature: v=1; a=rsa-sha512; c=simple/simple; d=test.ex; h=from:to + :date:message-id:subject; s=sel; bh=3UbbJTudPxmejzh7U1Zg33U3QT+1 + 6kfV2eOTvMeiEis=; b=xQSD/JMqz0C+xKf0A1NTkPTbkDuDdJbpBuyjjT9iYvyP + Zez+xl0TkoPobFGVa6EN8+ZeYV18zjifhtWYLSsNmPinUtcpKQLG1zxAKmmS0JEh + +qihlWbeGJ5+tK588ugUzXHPj+4JBW0H6kxHvdH0l2SlQE5xs/cdggnx5QX5USY= +From: mrgus@text.ex +To: bakawolf@yahoo.com +Date: Thu, 19 Nov 2015 17:00:07 -0700 +Message-ID: <qwerty1234@disco-zombie.net> +Subject: simple test + +This is a simple test. +. +??? 250 +QUIT +??? 221 +**** +# +killdaemon +no_stdout_check +no_msglog_check diff --git a/test/scripts/4500-DKIM/4523 b/test/scripts/4500-DKIM/4523 new file mode 100644 index 000000000..b897fc2a5 --- /dev/null +++ b/test/scripts/4500-DKIM/4523 @@ -0,0 +1,15 @@ +# DKIM signing, sha512 +# +exim -bd -DSERVER=server -oX PORT_D +**** +# +# default header set +exim -DHEADERS_MAXSIZE=y -DVALUE=sha512 -odf a@test.ex +From: nobody@example.com + +content +**** +# +millisleep 500 +killdaemon +no_msglog_check |