From 5342559492f503fe288275aaa97a31ded791a3d6 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 26 May 2016 16:13:53 +0200 Subject: crypto: Workaround buggy GCM via EVP --- lib/crypto/c_src/crypto.c | 58 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) (limited to 'lib/crypto/c_src/crypto.c') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 067e220863..1eccc669bb 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -93,6 +93,9 @@ #if OPENSSL_VERSION_NUMBER >= 0x1000100fL # define HAVE_EVP_AES_CTR # define HAVE_GCM +# if OPENSSL_VERSION_NUMBER < 0x1000104fL +# define HAVE_GCM_EVP_DECRYPT_BUG +# endif #endif #if defined(NID_chacha20) && !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) @@ -244,6 +247,9 @@ static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a static ERL_NIF_TERM aes_gcm_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_gcm_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +#ifdef HAVE_GCM_EVP_DECRYPT_BUG +static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +#endif static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -1710,7 +1716,9 @@ out_err: static ERL_NIF_TERM aes_gcm_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key,Iv,AAD,In,Tag) */ -#if defined(HAVE_GCM) +#if defined(HAVE_GCM_EVP_DECRYPT_BUG) + return aes_gcm_decrypt_NO_EVP(env, argc, argv); +#elif defined(HAVE_GCM) EVP_CIPHER_CTX ctx; const EVP_CIPHER *cipher = NULL; ErlNifBinary key, iv, aad, in, tag; @@ -1763,12 +1771,58 @@ static ERL_NIF_TERM aes_gcm_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM out_err: EVP_CIPHER_CTX_cleanup(&ctx); return atom_error; - #else return enif_raise_exception(env, atom_notsup); #endif } +#ifdef HAVE_GCM_EVP_DECRYPT_BUG +static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + GCM128_CONTEXT *ctx; + ErlNifBinary key, iv, aad, in, tag; + AES_KEY aes_key; + unsigned char *outp; + ERL_NIF_TERM out; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key) + || AES_set_encrypt_key(key.data, key.size*8, &aes_key) != 0 + || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 + || !enif_inspect_iolist_as_binary(env, argv[2], &aad) + || !enif_inspect_iolist_as_binary(env, argv[3], &in) + || !enif_inspect_iolist_as_binary(env, argv[4], &tag) || tag.size != EVP_GCM_TLS_TAG_LEN) { + return enif_make_badarg(env); + } + + if (!(ctx = CRYPTO_gcm128_new(&aes_key, (block128_f)AES_encrypt))) + return atom_error; + + CRYPTO_gcm128_setiv(ctx, iv.data, iv.size); + + if (CRYPTO_gcm128_aad(ctx, aad.data, aad.size)) + goto out_err; + + outp = enif_make_new_binary(env, in.size, &out); + + /* decrypt */ + if (CRYPTO_gcm128_decrypt(ctx, in.data, outp, in.size)) + goto out_err; + + /* calculate and check the tag */ + if (CRYPTO_gcm128_finish(ctx, tag.data, EVP_GCM_TLS_TAG_LEN)) + goto out_err; + + CRYPTO_gcm128_release(ctx); + CONSUME_REDS(env, in); + + return out; + +out_err: + CRYPTO_gcm128_release(ctx); + return atom_error; +} +#endif /* HAVE_GCM_EVP_DECRYPT_BUG */ + #if defined(HAVE_CHACHA20_POLY1305) static void poly1305_update_with_length(poly1305_state *poly1305, -- cgit v1.2.3 From 1af338179c779913470cd701e4f37b79565143cb Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 26 May 2016 16:54:02 +0200 Subject: crypto: Allow any AES-GCM tag length for non-EVP impl Same fix as was done for EVP in f4f588683dce36c447017. --- lib/crypto/c_src/crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/crypto/c_src/crypto.c') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 1eccc669bb..839be9e3f3 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -1790,7 +1790,7 @@ static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_N || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 || !enif_inspect_iolist_as_binary(env, argv[2], &aad) || !enif_inspect_iolist_as_binary(env, argv[3], &in) - || !enif_inspect_iolist_as_binary(env, argv[4], &tag) || tag.size != EVP_GCM_TLS_TAG_LEN) { + || !enif_inspect_iolist_as_binary(env, argv[4], &tag)) { return enif_make_badarg(env); } @@ -1809,7 +1809,7 @@ static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_N goto out_err; /* calculate and check the tag */ - if (CRYPTO_gcm128_finish(ctx, tag.data, EVP_GCM_TLS_TAG_LEN)) + if (CRYPTO_gcm128_finish(ctx, tag.data, tag.size)) goto out_err; CRYPTO_gcm128_release(ctx); -- cgit v1.2.3 From e042ed06b62c9279934f0e25bdb63e28c1f44d20 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 26 May 2016 20:14:42 +0200 Subject: crypto: Add OpenSSL_version macros to make it easier to read and construct version checks. --- lib/crypto/c_src/crypto.c | 57 ++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 21 deletions(-) (limited to 'lib/crypto/c_src/crypto.c') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 839be9e3f3..7183c395ae 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -55,45 +55,60 @@ #include #include -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL + +/* Helper macro to construct a OPENSSL_VERSION_NUMBER. + * See openssl/opensslv.h + */ +#define OpenSSL_version(MAJ, MIN, FIX, P) \ + ((((((((MAJ << 8) | MIN) << 8 ) | FIX) << 8) | (P-'a'+1)) << 4) | 0xf) + +#define OpenSSL_version_plain(MAJ, MIN, FIX) \ + OpenSSL_version(MAJ,MIN,FIX,('a'-1)) + + +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0) #include #endif #include "crypto_callback.h" -#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224)\ - && !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */ +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(0,9,8) \ + && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224) \ + && !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */ # define HAVE_SHA224 #endif -#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA256) && defined(NID_sha256) +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(0,9,8) \ + && !defined(OPENSSL_NO_SHA256) && defined(NID_sha256) # define HAVE_SHA256 #endif -#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA384) && defined(NID_sha384)\ - && !defined(OPENSSL_NO_SHA512) /* disabled like this in my sha.h (?) */ +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(0,9,8) \ + && !defined(OPENSSL_NO_SHA384) && defined(NID_sha384)\ + && !defined(OPENSSL_NO_SHA512) /* disabled like this in my sha.h (?) */ # define HAVE_SHA384 #endif -#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA512) && defined(NID_sha512) +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(0,9,8) \ + && !defined(OPENSSL_NO_SHA512) && defined(NID_sha512) # define HAVE_SHA512 #endif -#if OPENSSL_VERSION_NUMBER >= 0x0090705FL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version(0,9,7,'e') # define HAVE_DES_ede3_cfb_encrypt #endif -#if OPENSSL_VERSION_NUMBER >= 0x009080ffL \ +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version(0,9,8,'o') \ && !defined(OPENSSL_NO_EC) \ && !defined(OPENSSL_NO_ECDH) \ && !defined(OPENSSL_NO_ECDSA) # define HAVE_EC #endif -#if OPENSSL_VERSION_NUMBER >= 0x0090803fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version(0,9,8,'c') # define HAVE_AES_IGE #endif -#if OPENSSL_VERSION_NUMBER >= 0x1000100fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,1) # define HAVE_EVP_AES_CTR # define HAVE_GCM -# if OPENSSL_VERSION_NUMBER < 0x1000104fL +# if OPENSSL_VERSION_NUMBER < OpenSSL_version(1,0,1,'d') # define HAVE_GCM_EVP_DECRYPT_BUG # endif #endif @@ -102,7 +117,7 @@ # define HAVE_CHACHA20_POLY1305 #endif -#if OPENSSL_VERSION_NUMBER <= 0x009080cfL +#if OPENSSL_VERSION_NUMBER <= OpenSSL_version(0,9,8,'l') # define HAVE_ECB_IVEC_BUG #endif @@ -485,7 +500,7 @@ static struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len); #define PRINTF_ERR1(FMT,A1) #define PRINTF_ERR2(FMT,A1,A2) -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0) /* Define resource types for OpenSSL context structures. */ static ErlNifResourceType* evp_md_ctx_rtype; static void evp_md_ctx_dtor(ErlNifEnv* env, EVP_MD_CTX* ctx) { @@ -584,7 +599,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) PRINTF_ERR0("CRYPTO: Could not open resource type 'hmac_context'"); return 0; } -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0) evp_md_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_MD_CTX", (ErlNifResourceDtor*) evp_md_ctx_dtor, ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, @@ -883,7 +898,7 @@ static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] return ret; } -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0) static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Type) */ @@ -1259,7 +1274,7 @@ static ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a obj = enif_alloc_resource(hmac_context_rtype, sizeof(struct hmac_context)); obj->mtx = enif_mutex_create("crypto.hmac"); obj->alive = 1; -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0) // Check the return value of HMAC_Init: it may fail in FIPS mode // for disabled algorithms if (!HMAC_Init(&obj->ctx, key.data, key.size, digp->md.p)) { @@ -2211,7 +2226,7 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ERL_NIF_TERM head, tail, ret; int i; RSA *rsa; -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0) EVP_PKEY *pkey; EVP_PKEY_CTX *ctx; #endif @@ -2243,7 +2258,7 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM goto done; } -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0) pkey = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pkey, rsa); @@ -2370,7 +2385,7 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Type, Digest, Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C]) */ ErlNifBinary digest_bin, ret_bin; -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0) EVP_PKEY *pkey; EVP_PKEY_CTX *ctx; size_t rsa_s_len; @@ -2403,7 +2418,7 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar } -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0) pkey = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pkey, rsa); rsa_s_len=(size_t)EVP_PKEY_size(pkey); -- cgit v1.2.3