]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - crypto/evp/evp_lib.c
evp enc: cache cipher key length
[thirdparty/openssl.git] / crypto / evp / evp_lib.c
index 8a03c4490b145d36185c8f17bb08892e32c6f948..7e03d03bf652a5d360c3717a133e4c0b40b5eccb 100644 (file)
@@ -15,7 +15,7 @@
 
 #include <stdio.h>
 #include <string.h>
-#include "e_os.h" /* strcasecmp */
+#include "internal/e_os.h" /* strcasecmp */
 #include "internal/cryptlib.h"
 #include <openssl/evp.h>
 #include <openssl/objects.h>
 #include <openssl/dh.h>
 #include <openssl/ec.h>
 #include "crypto/evp.h"
-#include "crypto/asn1.h"
 #include "internal/provider.h"
 #include "evp_local.h"
 
 #if !defined(FIPS_MODULE)
+# include "crypto/asn1.h"
 
 int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
 {
@@ -340,12 +340,12 @@ int EVP_CIPHER_get_type(const EVP_CIPHER *cipher)
 
 int evp_cipher_cache_constants(EVP_CIPHER *cipher)
 {
-    int ok, aead = 0, custom_iv = 0, cts = 0, multiblock = 0;
+    int ok, aead = 0, custom_iv = 0, cts = 0, multiblock = 0, randkey = 0;
     size_t ivlen = 0;
     size_t blksz = 0;
     size_t keylen = 0;
     unsigned int mode = 0;
-    OSSL_PARAM params[9];
+    OSSL_PARAM params[10];
 
     params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, &blksz);
     params[1] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_IVLEN, &ivlen);
@@ -357,7 +357,9 @@ int evp_cipher_cache_constants(EVP_CIPHER *cipher)
     params[6] = OSSL_PARAM_construct_int(OSSL_CIPHER_PARAM_CTS, &cts);
     params[7] = OSSL_PARAM_construct_int(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK,
                                          &multiblock);
-    params[8] = OSSL_PARAM_construct_end();
+    params[8] = OSSL_PARAM_construct_int(OSSL_CIPHER_PARAM_HAS_RAND_KEY,
+                                         &randkey);
+    params[9] = OSSL_PARAM_construct_end();
     ok = evp_do_ciph_getparams(cipher, params) > 0;
     if (ok) {
         cipher->block_size = blksz;
@@ -374,6 +376,8 @@ int evp_cipher_cache_constants(EVP_CIPHER *cipher)
             cipher->flags |= EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK;
         if (cipher->ccipher != NULL)
             cipher->flags |= EVP_CIPH_FLAG_CUSTOM_CIPHER;
+        if (randkey)
+            cipher->flags |= EVP_CIPH_RAND_KEY;
         if (OSSL_PARAM_locate_const(EVP_CIPHER_gettable_ctx_params(cipher),
                                     OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS))
             cipher->flags |= EVP_CIPH_FLAG_CUSTOM_ASN1;
@@ -500,23 +504,33 @@ int EVP_CIPHER_get_iv_length(const EVP_CIPHER *cipher)
 
 int EVP_CIPHER_CTX_get_iv_length(const EVP_CIPHER_CTX *ctx)
 {
-    int rv, len = EVP_CIPHER_get_iv_length(ctx->cipher);
-    size_t v = len;
-    OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
-
-    params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_IVLEN, &v);
-    rv = evp_do_ciph_ctx_getparams(ctx->cipher, ctx->algctx, params);
-    if (rv == EVP_CTRL_RET_UNSUPPORTED)
-        goto legacy;
-    return rv != 0 ? (int)v : -1;
-    /* Code below to be removed when legacy support is dropped. */
-legacy:
-    if ((EVP_CIPHER_get_flags(ctx->cipher) & EVP_CIPH_CUSTOM_IV_LENGTH) != 0) {
-        rv = EVP_CIPHER_CTX_ctrl((EVP_CIPHER_CTX *)ctx, EVP_CTRL_GET_IVLEN,
-                                 0, &len);
-        return (rv == 1) ? len : -1;
+    if (ctx->iv_len < 0) {
+        int rv, len = EVP_CIPHER_get_iv_length(ctx->cipher);
+        size_t v = len;
+        OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+
+        params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_IVLEN, &v);
+        rv = evp_do_ciph_ctx_getparams(ctx->cipher, ctx->algctx, params);
+        if (rv != EVP_CTRL_RET_UNSUPPORTED) {
+            if (rv <= 0)
+                return -1;
+            len = (int)v;
+        }
+        /* Code below to be removed when legacy support is dropped. */
+        else if ((EVP_CIPHER_get_flags(ctx->cipher)
+                  & EVP_CIPH_CUSTOM_IV_LENGTH) != 0) {
+            rv = EVP_CIPHER_CTX_ctrl((EVP_CIPHER_CTX *)ctx, EVP_CTRL_GET_IVLEN,
+                                     0, &len);
+            if (rv <= 0)
+                return -1;
+        }
+        /*-
+         * Casting away the const is annoying but required here.  We need to
+         * cache the result for performance reasons.
+         */
+        ((EVP_CIPHER_CTX *)ctx)->iv_len = len;
     }
-    return len;
+    return ctx->iv_len;
 }
 
 int EVP_CIPHER_CTX_get_tag_length(const EVP_CIPHER_CTX *ctx)
@@ -633,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)
@@ -660,7 +688,7 @@ int EVP_CIPHER_is_a(const EVP_CIPHER *cipher, const char *name)
     return evp_is_a(NULL, 0, EVP_CIPHER_get0_name(cipher), name);
 }
 
-int EVP_CIPHER_get_number(const EVP_CIPHER *cipher)
+int evp_cipher_get_number(const EVP_CIPHER *cipher)
 {
     return cipher->name_id;
 }
@@ -714,7 +742,7 @@ int EVP_MD_is_a(const EVP_MD *md, const char *name)
     return evp_is_a(NULL, 0, EVP_MD_get0_name(md), name);
 }
 
-int EVP_MD_get_number(const EVP_MD *md)
+int evp_md_get_number(const EVP_MD *md)
 {
     return md->name_id;
 }
@@ -819,6 +847,7 @@ EVP_MD *EVP_MD_meth_dup(const EVP_MD *md)
 
         memcpy(to, md, sizeof(*to));
         to->lock = lock;
+        to->origin = EVP_ORIG_METH;
     }
     return to;
 }
@@ -994,7 +1023,7 @@ EVP_MD *EVP_MD_CTX_get1_md(EVP_MD_CTX *ctx)
     if (ctx == NULL)
         return NULL;
     md = (EVP_MD *)ctx->reqdigest;
-    if (!EVP_MD_up_ref(md))
+    if (md == NULL || !EVP_MD_up_ref(md))
         return NULL;
     return md;
 }