From 70f39a487d3f7d976a01e0ee7ae98a82ceeea7a0 Mon Sep 17 00:00:00 2001 From: Pauli Date: Thu, 27 Jan 2022 13:33:36 +1100 Subject: [PATCH] evp enc: cache cipher key length Instead of doing a heavy params based query every time a context is asked for its key length, this value is cached in the context and only queried if it could have been modified. Fixes #17064 Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/17543) --- crypto/evp/evp_enc.c | 31 ++++++++++++++++++++++++------- crypto/evp/evp_lib.c | 26 ++++++++++++++++++++------ 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index ff315bd922..7ae92df98b 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -62,7 +62,7 @@ int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) ENGINE_finish(ctx->engine); #endif memset(ctx, 0, sizeof(*ctx)); - ctx->iv_len = -1; + ctx->iv_len = 0; return 1; } @@ -984,7 +984,7 @@ int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen) if (c->cipher->prov != NULL) { int ok; OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; - size_t len = keylen; + size_t len; if (EVP_CIPHER_CTX_get_key_length(c) == keylen) return 1; @@ -997,9 +997,13 @@ int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen) } params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &len); + if (!OSSL_PARAM_set_int(params, keylen)) + return 0; ok = evp_do_ciph_ctx_setparams(c->cipher, c->algctx, params); - - return ok > 0 ? 1 : 0; + if (ok <= 0) + return 0; + c->key_len = keylen; + return 1; } /* Code below to be removed when legacy support is dropped. */ @@ -1060,6 +1064,7 @@ int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) switch (type) { case EVP_CTRL_SET_KEY_LENGTH: params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &sz); + ctx->key_len = -1; break; case EVP_CTRL_RAND_KEY: /* Used by DES */ set_params = 0; @@ -1255,11 +1260,23 @@ int EVP_CIPHER_get_params(EVP_CIPHER *cipher, OSSL_PARAM params[]) int EVP_CIPHER_CTX_set_params(EVP_CIPHER_CTX *ctx, const OSSL_PARAM params[]) { + int r = 0; + const OSSL_PARAM *p; + if (ctx->cipher != NULL && ctx->cipher->set_ctx_params != NULL) { - ctx->iv_len = -1; - return ctx->cipher->set_ctx_params(ctx->algctx, params); + r = ctx->cipher->set_ctx_params(ctx->algctx, params); + if (r > 0) { + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->key_len)) + r = 0; + } + if (r > 0) { + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->iv_len)) + r = 0; + } } - return 0; + return r; } int EVP_CIPHER_CTX_get_params(EVP_CIPHER_CTX *ctx, OSSL_PARAM params[]) diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c index 8bac09bba0..7e03d03bf6 100644 --- a/crypto/evp/evp_lib.c +++ b/crypto/evp/evp_lib.c @@ -647,14 +647,28 @@ int EVP_CIPHER_get_key_length(const EVP_CIPHER *cipher) int EVP_CIPHER_CTX_get_key_length(const EVP_CIPHER_CTX *ctx) { - int ok; - size_t v = ctx->key_len; - OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + if (ctx->key_len <= 0 && ctx->cipher->prov != NULL) { + int ok; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + size_t len; - params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &v); - ok = evp_do_ciph_ctx_getparams(ctx->cipher, ctx->algctx, params); + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &len); + ok = evp_do_ciph_ctx_getparams(ctx->cipher, ctx->algctx, params); + if (ok <= 0) + return EVP_CTRL_RET_UNSUPPORTED; - return ok != 0 ? (int)v : EVP_CTRL_RET_UNSUPPORTED; + /*- + * The if branch should never be taken since EVP_MAX_KEY_LENGTH is + * less than INT_MAX but best to be safe. + * + * Casting away the const is annoying but required here. We need to + * cache the result for performance reasons. + */ + if (!OSSL_PARAM_get_int(params, &((EVP_CIPHER_CTX *)ctx)->key_len)) + return -1; + ((EVP_CIPHER_CTX *)ctx)->key_len = (int)len; + } + return ctx->key_len; } int EVP_CIPHER_get_nid(const EVP_CIPHER *cipher) -- 2.39.5