]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
EVP_SKEY implementation for EVP_CIPHER
authorDmitry Belyavskiy <beldmit@gmail.com>
Thu, 9 Jan 2025 18:18:31 +0000 (19:18 +0100)
committerDmitry Belyavskiy <beldmit@gmail.com>
Sat, 15 Feb 2025 17:51:30 +0000 (18:51 +0100)
Signed-off-by: Dmitry Belyavskiy <beldmit@gmail.com>
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26753)

12 files changed:
crypto/evp/build.info
crypto/evp/evp_enc.c
crypto/evp/evp_local.h
crypto/evp/s_lib.c [new file with mode: 0644]
crypto/evp/skeymgmt_meth.c [new file with mode: 0644]
include/crypto/evp.h
include/openssl/core_dispatch.h
include/openssl/core_names.h.in
include/openssl/evp.h
include/openssl/types.h
util/libcrypto.num
util/perl/OpenSSL/paramnames.pm

index f2d9621e85596c97121c47e82018f20c920d027b..80570bdcce46a4b007d2a284af133d16414b8a84 100644 (file)
@@ -1,7 +1,8 @@
 LIBS=../../libcrypto
 $COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c evp_utils.c \
         mac_lib.c mac_meth.c keymgmt_meth.c keymgmt_lib.c kdf_lib.c kdf_meth.c \
-        pmeth_lib.c signature.c p_lib.c pmeth_gn.c exchange.c \
+        skeymgmt_meth.c \
+        pmeth_lib.c signature.c p_lib.c s_lib.c pmeth_gn.c exchange.c \
         evp_rand.c asymcipher.c kem.c dh_support.c ec_support.c pmeth_check.c
 
 SOURCE[../../libcrypto]=$COMMON\
index 833ebdee28701790843c103d7ba5eefa407a4a64..2b7f5ffde9f9d3165ca8837629301570747d7b6b 100644 (file)
@@ -283,6 +283,17 @@ nonlegacy:
 
     if (enc) {
         if (ctx->cipher->einit == NULL) {
+            /*
+             * We still should be able to set the IV using the new API
+             * if the key is not specified and old API is not available
+             */
+            if (key == NULL && ctx->cipher->einit_skey != NULL) {
+                return ctx->cipher->einit_skey(ctx->algctx, NULL,
+                                               iv,
+                                               iv == NULL ? 0
+                                                          : EVP_CIPHER_CTX_get_iv_length(ctx),
+                                               params);
+            }
             ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
             return 0;
         }
@@ -298,6 +309,17 @@ nonlegacy:
     }
 
     if (ctx->cipher->dinit == NULL) {
+        /*
+         * We still should be able to set the IV using the new API
+         * if the key is not specified and old API is not available
+         */
+        if (key == NULL && ctx->cipher->dinit_skey != NULL) {
+            return ctx->cipher->dinit_skey(ctx->algctx, NULL,
+                                           iv,
+                                           iv == NULL ? 0
+                                                      : EVP_CIPHER_CTX_get_iv_length(ctx),
+                                           params);
+        }
         ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
         return 0;
     }
@@ -452,6 +474,156 @@ nonlegacy:
     return 1;
 }
 
+/*
+ * This function is basically evp_cipher_init_internal without ENGINE support.
+ * They should be combined when engines are not supported any longer.
+ */
+static int evp_cipher_init_skey_internal(EVP_CIPHER_CTX *ctx,
+                                         const EVP_CIPHER *cipher,
+                                         const EVP_SKEY *skey,
+                                         const unsigned char *iv, size_t iv_len,
+                                         int enc, const OSSL_PARAM params[])
+{
+    int ret;
+
+    /*
+     * enc == 1 means we are encrypting.
+     * enc == 0 means we are decrypting.
+     * enc == -1 means, use the previously initialised value for encrypt/decrypt
+     */
+    if (enc == -1)
+        enc = ctx->encrypt;
+    else
+        ctx->encrypt = enc != 0;
+
+    if (cipher == NULL && ctx->cipher == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET);
+        return 0;
+    }
+
+    /*
+     * If there are engines involved then we throw an error
+     */
+    if (ctx->engine != NULL
+            || (cipher != NULL && cipher->origin == EVP_ORIG_METH)
+            || (cipher == NULL && ctx->cipher != NULL
+                && ctx->cipher->origin == EVP_ORIG_METH)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+        return 0;
+    }
+    /*
+     * Ensure a context left lying around from last time is cleared
+     * (legacy code)
+     */
+    if (cipher != NULL && ctx->cipher != NULL) {
+        if (ctx->cipher->cleanup != NULL && !ctx->cipher->cleanup(ctx))
+            return 0;
+        OPENSSL_clear_free(ctx->cipher_data, ctx->cipher->ctx_size);
+        ctx->cipher_data = NULL;
+    }
+
+    /* Ensure a context left lying around from last time is cleared */
+    if (cipher != NULL && ctx->cipher != NULL) {
+        unsigned long flags = ctx->flags;
+
+        EVP_CIPHER_CTX_reset(ctx);
+        /* Restore encrypt and flags */
+        ctx->encrypt = enc;
+        ctx->flags = flags;
+    }
+
+    if (cipher == NULL)
+        cipher = ctx->cipher;
+
+    if (cipher->prov == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+        return 0;
+    }
+
+    if (cipher != ctx->fetched_cipher) {
+        if (!EVP_CIPHER_up_ref((EVP_CIPHER *)cipher)) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+            return 0;
+        }
+        EVP_CIPHER_free(ctx->fetched_cipher);
+        /* Coverity false positive, the reference counting is confusing it */
+        /* coverity[use_after_free] */
+        ctx->fetched_cipher = (EVP_CIPHER *)cipher;
+    }
+    ctx->cipher = cipher;
+    if (ctx->algctx == NULL) {
+        ctx->algctx = ctx->cipher->newctx(ossl_provider_ctx(cipher->prov));
+        if (ctx->algctx == NULL) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+            return 0;
+        }
+    }
+
+    if (skey != NULL && skey->skeymgmt != NULL
+        && ctx->cipher->prov != skey->skeymgmt->prov) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+        return 0;
+    }
+
+    if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) {
+        /*
+         * If this ctx was already set up for no padding then we need to tell
+         * the new cipher about it.
+         */
+        if (!EVP_CIPHER_CTX_set_padding(ctx, 0))
+            return 0;
+    }
+
+    if (iv == NULL)
+        iv_len = 0;
+
+    /* We have a data managed via key management, using the new callbacks */
+    if (enc) {
+        if (ctx->cipher->einit_skey == NULL) {
+            /* Attempt fallback for providers that do not support SKEYs */
+            const unsigned char *keydata;
+            size_t keylen;
+
+            if (!EVP_SKEY_get_raw_key(skey, &keydata, &keylen)) {
+                ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+                return 0;
+            }
+
+            ret = ctx->cipher->einit(ctx->algctx, keydata, keylen,
+                                     iv, iv_len, params);
+        } else {
+            ret = ctx->cipher->einit_skey(ctx->algctx, skey->keydata,
+                                          iv, iv_len, params);
+        }
+    } else {
+        if (ctx->cipher->dinit_skey == NULL) {
+            /* Attempt fallback for providers that do not support SKEYs */
+            const unsigned char *keydata;
+            size_t keylen;
+
+            if (!EVP_SKEY_get_raw_key(skey, &keydata, &keylen)) {
+                ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+                return 0;
+            }
+
+            ret = ctx->cipher->dinit(ctx->algctx, keydata, keylen,
+                                     iv, iv_len, params);
+        } else {
+            ret = ctx->cipher->dinit_skey(ctx->algctx, skey->keydata,
+                                          iv, iv_len, params);
+        }
+    }
+
+    return ret;
+}
+
+int EVP_CipherInit_SKEY(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+                        EVP_SKEY *skey, const unsigned char *iv, size_t iv_len,
+                        int enc, const OSSL_PARAM params[])
+{
+    return evp_cipher_init_skey_internal(ctx, cipher, skey, iv, iv_len, enc, params);
+}
+
 int EVP_CipherInit_ex2(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
                        const unsigned char *key, const unsigned char *iv,
                        int enc, const OSSL_PARAM params[])
@@ -1707,7 +1879,7 @@ static void *evp_cipher_from_algorithm(const int name_id,
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_CIPHER *cipher = NULL;
-    int fnciphcnt = 0, fnpipecnt = 0, fnctxcnt = 0;
+    int fnciphcnt = 0, encinit = 0, decinit = 0, fnpipecnt = 0, fnctxcnt = 0;
 
     if ((cipher = evp_cipher_new()) == NULL) {
         ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
@@ -1743,13 +1915,25 @@ static void *evp_cipher_from_algorithm(const int name_id,
             if (cipher->einit != NULL)
                 break;
             cipher->einit = OSSL_FUNC_cipher_encrypt_init(fns);
-            fnciphcnt++;
+            encinit = 1;
             break;
         case OSSL_FUNC_CIPHER_DECRYPT_INIT:
             if (cipher->dinit != NULL)
                 break;
             cipher->dinit = OSSL_FUNC_cipher_decrypt_init(fns);
-            fnciphcnt++;
+            decinit = 1;
+            break;
+        case OSSL_FUNC_CIPHER_ENCRYPT_SKEY_INIT:
+            if (cipher->einit_skey != NULL)
+                break;
+            cipher->einit_skey = OSSL_FUNC_cipher_encrypt_skey_init(fns);
+            encinit = 1;
+            break;
+        case OSSL_FUNC_CIPHER_DECRYPT_SKEY_INIT:
+            if (cipher->dinit_skey != NULL)
+                break;
+            cipher->dinit_skey = OSSL_FUNC_cipher_decrypt_skey_init(fns);
+            decinit = 1;
             break;
         case OSSL_FUNC_CIPHER_UPDATE:
             if (cipher->cupdate != NULL)
@@ -1837,6 +2021,7 @@ static void *evp_cipher_from_algorithm(const int name_id,
             break;
         }
     }
+    fnciphcnt += encinit + decinit;
     if ((fnciphcnt != 0 && fnciphcnt != 3 && fnciphcnt != 4)
             || (fnciphcnt == 0 && cipher->ccipher == NULL && fnpipecnt == 0)
             || (fnpipecnt != 0 && (fnpipecnt < 3 || cipher->p_cupdate == NULL
index ef1faa4516f3a4a933c30147f79ba085698c5395..e1d5f3213b657e515161ec867710117bae97fb51 100644 (file)
@@ -201,6 +201,29 @@ struct evp_signature_st {
     OSSL_FUNC_signature_query_key_types_fn *query_key_types;
 } /* EVP_SIGNATURE */;
 
+struct evp_skeymgmt_st {
+    int name_id;
+    char *type_name;
+    const char *description;
+    OSSL_PROVIDER *prov;
+    CRYPTO_REF_COUNT refcnt;
+
+    /* Import and export routines */
+    OSSL_FUNC_skeymgmt_imp_settable_params_fn *imp_params;
+    OSSL_FUNC_skeymgmt_import_fn *import;
+    OSSL_FUNC_skeymgmt_export_fn *export;
+
+    /* Key generation */
+    OSSL_FUNC_skeymgmt_gen_settable_params_fn *gen_params;
+    OSSL_FUNC_skeymgmt_generate_fn *generate;
+
+    /* Key identifier */
+    OSSL_FUNC_skeymgmt_get_key_id_fn *get_key_id;
+
+    /* destructor */
+    OSSL_FUNC_skeymgmt_free_fn *free;
+} /* EVP_SKEYMGMT */;
+
 struct evp_asym_cipher_st {
     int name_id;
     char *type_name;
@@ -391,3 +414,5 @@ int evp_names_do_all(OSSL_PROVIDER *prov, int number,
                      void (*fn)(const char *name, void *data),
                      void *data);
 int evp_cipher_cache_constants(EVP_CIPHER *cipher);
+
+EVP_SKEY *evp_skey_alloc(void);
diff --git a/crypto/evp/s_lib.c b/crypto/evp/s_lib.c
new file mode 100644 (file)
index 0000000..d805fc7
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/params.h>
+#include <openssl/param_build.h>
+#include <openssl/evp.h>
+#include <openssl/core_names.h>
+
+#include "internal/provider.h"
+#include "crypto/evp.h"
+#include "evp_local.h"
+
+int EVP_SKEY_export(const EVP_SKEY *skey, int selection,
+                    OSSL_CALLBACK *export_cb, void *export_cbarg)
+{
+    if (skey == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    if (skey->skeymgmt == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+
+    return evp_skeymgmt_export(skey->skeymgmt, skey->keydata, selection, export_cb, export_cbarg);
+}
+
+EVP_SKEY *evp_skey_alloc(void)
+{
+    EVP_SKEY *skey = OPENSSL_zalloc(sizeof(EVP_SKEY));
+
+    if (!CRYPTO_NEW_REF(&skey->references, 1))
+        goto err;
+
+    skey->lock = CRYPTO_THREAD_lock_new();
+    if (skey->lock == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_CRYPTO_LIB);
+        goto err;
+    }
+    return skey;
+
+ err:
+    CRYPTO_FREE_REF(&skey->references);
+    CRYPTO_THREAD_lock_free(skey->lock);
+    OPENSSL_free(skey);
+    return NULL;
+}
+
+EVP_SKEY *EVP_SKEY_import(OSSL_LIB_CTX *libctx, const char *skeymgmtname, const char *propquery,
+                          int selection, const OSSL_PARAM *params)
+{
+    EVP_SKEYMGMT *skeymgmt = NULL;
+    EVP_SKEY *skey = evp_skey_alloc();
+
+    if (skey == NULL)
+        return NULL;
+
+    skeymgmt = EVP_SKEYMGMT_fetch(libctx, skeymgmtname, propquery);
+    if (skeymgmt == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
+        goto err;
+    }
+    skey->skeymgmt = skeymgmt;
+
+    skey->keydata = evp_skeymgmt_import(skey->skeymgmt, selection, params);
+    if (skey->keydata == NULL)
+        goto err;
+
+    return skey;
+
+ err:
+    EVP_SKEYMGMT_free(skeymgmt);
+    EVP_SKEY_free(skey);
+    return NULL;
+}
+
+EVP_SKEY *EVP_SKEY_generate(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
+                            const char *propquery, const OSSL_PARAM *params)
+{
+    EVP_SKEYMGMT *skeymgmt = NULL;
+    EVP_SKEY *skey = evp_skey_alloc();
+
+    if (skey == NULL)
+        return NULL;
+
+    skeymgmt = EVP_SKEYMGMT_fetch(libctx, skeymgmtname, propquery);
+    if (skeymgmt == NULL) {
+        /*
+         * if the specific key_type is unkown, attempt to use the generic
+         * key management
+         */
+        skeymgmt = EVP_SKEYMGMT_fetch(libctx, OSSL_SKEY_TYPE_GENERIC, propquery);
+        if (skeymgmt == NULL) {
+            ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
+            goto err;
+        }
+    }
+    skey->skeymgmt = skeymgmt;
+
+    skey->keydata = evp_skeymgmt_generate(skey->skeymgmt, params);
+    if (skey->keydata == NULL)
+        goto err;
+
+    return skey;
+
+ err:
+    EVP_SKEYMGMT_free(skeymgmt);
+    EVP_SKEY_free(skey);
+    return NULL;
+}
+
+struct raw_key_details_st {
+    const void **key;
+    size_t *len;
+};
+
+static int get_secret_key(const OSSL_PARAM params[], void *arg)
+{
+    const OSSL_PARAM *p = NULL;
+    struct raw_key_details_st *raw_key = arg;
+
+    if ((p = OSSL_PARAM_locate_const(params, OSSL_SKEY_PARAM_RAW_BYTES)) != NULL)
+        return OSSL_PARAM_get_octet_string_ptr(p, raw_key->key, raw_key->len);
+
+    return 0;
+}
+
+int EVP_SKEY_get_raw_key(const EVP_SKEY *skey, const unsigned char **key,
+                         size_t *len)
+{
+    struct raw_key_details_st raw_key;
+
+    if (skey == NULL || key == NULL || len == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    raw_key.key = (const void **)key;
+    raw_key.len = len;
+
+    return evp_skeymgmt_export(skey->skeymgmt, skey->keydata,
+                               OSSL_SKEYMGMT_SELECT_SECRET_KEY,
+                               get_secret_key, &raw_key);
+}
+
+EVP_SKEY *EVP_SKEY_import_raw_key(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
+                                  unsigned char *key, size_t keylen,
+                                  const char *propquery)
+{
+    OSSL_PARAM params[2];
+
+    params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
+                                                  (void *)key, keylen);
+    params[1] = OSSL_PARAM_construct_end();
+
+    return EVP_SKEY_import(libctx, skeymgmtname, propquery,
+                           OSSL_SKEYMGMT_SELECT_SECRET_KEY, params);
+}
+
+int EVP_SKEY_up_ref(EVP_SKEY *skey)
+{
+    int i;
+
+    if (CRYPTO_UP_REF(&skey->references, &i) <= 0)
+        return 0;
+
+    REF_PRINT_COUNT("EVP_SKEY", i, skey);
+    REF_ASSERT_ISNT(i < 2);
+    return i > 1 ? 1 : 0;
+}
+
+void EVP_SKEY_free(EVP_SKEY *skey)
+{
+    int i;
+
+    if (skey == NULL)
+        return;
+
+    CRYPTO_DOWN_REF(&skey->references, &i);
+    REF_PRINT_COUNT("EVP_SKEY", i, skey);
+    if (i > 0)
+        return;
+    REF_ASSERT_ISNT(i < 0);
+    if (skey->keydata && skey->skeymgmt)
+        evp_skeymgmt_freedata(skey->skeymgmt, skey->keydata);
+
+    EVP_SKEYMGMT_free(skey->skeymgmt);
+
+    CRYPTO_THREAD_lock_free(skey->lock);
+    CRYPTO_FREE_REF(&skey->references);
+    OPENSSL_free(skey);
+}
+
+const char *EVP_SKEY_get0_key_id(const EVP_SKEY *skey)
+{
+    if (skey == NULL)
+        return NULL;
+
+    if (skey->skeymgmt->get_key_id)
+        return skey->skeymgmt->get_key_id(skey->keydata);
+
+    return NULL;
+}
+
+const char *EVP_SKEY_get0_skeymgmt_name(const EVP_SKEY *skey)
+{
+    if (skey == NULL)
+        return NULL;
+
+    return skey->skeymgmt->type_name;
+
+}
+
+const char *EVP_SKEY_get0_provider_name(const EVP_SKEY *skey)
+{
+    if (skey == NULL)
+        return NULL;
+
+    return ossl_provider_name(skey->skeymgmt->prov);
+}
diff --git a/crypto/evp/skeymgmt_meth.c b/crypto/evp/skeymgmt_meth.c
new file mode 100644 (file)
index 0000000..435d96d
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include "internal/core.h"
+#include "internal/provider.h"
+#include "internal/refcount.h"
+#include "crypto/evp.h"
+#include "evp_local.h"
+
+void *evp_skeymgmt_generate(const EVP_SKEYMGMT *skeymgmt, const OSSL_PARAM params[])
+{
+    void *provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt));
+
+    return (skeymgmt->generate != NULL) ? skeymgmt->generate(provctx, params) : NULL;
+}
+
+void *evp_skeymgmt_import(const EVP_SKEYMGMT *skeymgmt, int selection, const OSSL_PARAM params[])
+{
+    void *provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt));
+
+    /* This is mandatory, no need to check for its presence */
+    return skeymgmt->import(provctx, selection, params);
+}
+
+int evp_skeymgmt_export(const EVP_SKEYMGMT *skeymgmt, void *keydata,
+                        int selection, OSSL_CALLBACK *param_cb, void *cbarg)
+{
+    /* This is mandatory, no need to check for its presence */
+    return skeymgmt->export(keydata, selection, param_cb, cbarg);
+}
+
+void evp_skeymgmt_freedata(const EVP_SKEYMGMT *skeymgmt, void *keydata)
+{
+    /* This is mandatory, no need to check for its presence */
+    skeymgmt->free(keydata);
+}
+
+static void *skeymgmt_new(void)
+{
+    EVP_SKEYMGMT *skeymgmt = NULL;
+
+    if ((skeymgmt = OPENSSL_zalloc(sizeof(*skeymgmt))) == NULL)
+        return NULL;
+    if (!CRYPTO_NEW_REF(&skeymgmt->refcnt, 1)) {
+        EVP_SKEYMGMT_free(skeymgmt);
+        return NULL;
+    }
+    return skeymgmt;
+}
+
+static void *skeymgmt_from_algorithm(int name_id,
+                                     const OSSL_ALGORITHM *algodef,
+                                     OSSL_PROVIDER *prov)
+{
+    const OSSL_DISPATCH *fns = algodef->implementation;
+    EVP_SKEYMGMT *skeymgmt = NULL;
+
+    if ((skeymgmt = skeymgmt_new()) == NULL)
+        return NULL;
+
+    skeymgmt->name_id = name_id;
+    if ((skeymgmt->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
+        EVP_SKEYMGMT_free(skeymgmt);
+        return NULL;
+    }
+    skeymgmt->description = algodef->algorithm_description;
+
+    for (; fns->function_id != 0; fns++) {
+        switch (fns->function_id) {
+        case OSSL_FUNC_SKEYMGMT_FREE:
+            if (skeymgmt->free == NULL)
+                skeymgmt->free = OSSL_FUNC_skeymgmt_free(fns);
+            break;
+        case OSSL_FUNC_SKEYMGMT_IMPORT:
+            if (skeymgmt->import == NULL)
+                skeymgmt->import = OSSL_FUNC_skeymgmt_import(fns);
+            break;
+        case OSSL_FUNC_SKEYMGMT_EXPORT:
+            if (skeymgmt->export == NULL)
+                skeymgmt->export = OSSL_FUNC_skeymgmt_export(fns);
+            break;
+        case OSSL_FUNC_SKEYMGMT_GENERATE:
+            if (skeymgmt->generate == NULL)
+                skeymgmt->generate = OSSL_FUNC_skeymgmt_generate(fns);
+            break;
+        case OSSL_FUNC_SKEYMGMT_GET_KEY_ID:
+            if (skeymgmt->get_key_id == NULL)
+                skeymgmt->get_key_id = OSSL_FUNC_skeymgmt_get_key_id(fns);
+            break;
+        case OSSL_FUNC_SKEYMGMT_IMP_SETTABLE_PARAMS:
+            if (skeymgmt->imp_params == NULL)
+                skeymgmt->imp_params = OSSL_FUNC_skeymgmt_imp_settable_params(fns);
+            break;
+        case OSSL_FUNC_SKEYMGMT_GEN_SETTABLE_PARAMS:
+            if (skeymgmt->gen_params == NULL)
+                skeymgmt->gen_params = OSSL_FUNC_skeymgmt_gen_settable_params(fns);
+            break;
+        }
+    }
+
+    /* Check that the provider is sensible */
+    if (skeymgmt->free == NULL
+        || skeymgmt->import == NULL
+        || skeymgmt->export == NULL) {
+        EVP_SKEYMGMT_free(skeymgmt);
+        ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
+        return NULL;
+    }
+    skeymgmt->prov = prov;
+    ossl_provider_up_ref(prov);
+
+    return skeymgmt;
+}
+
+EVP_SKEYMGMT *EVP_SKEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
+                                 const char *properties)
+{
+    return evp_generic_fetch(ctx, OSSL_OP_SKEYMGMT, algorithm, properties,
+                             skeymgmt_from_algorithm,
+                             (int (*)(void *))EVP_SKEYMGMT_up_ref,
+                             (void (*)(void *))EVP_SKEYMGMT_free);
+}
+
+int EVP_SKEYMGMT_up_ref(EVP_SKEYMGMT *skeymgmt)
+{
+    int ref = 0;
+
+    CRYPTO_UP_REF(&skeymgmt->refcnt, &ref);
+    return 1;
+}
+
+void EVP_SKEYMGMT_free(EVP_SKEYMGMT *skeymgmt)
+{
+    int ref = 0;
+
+    if (skeymgmt == NULL)
+        return;
+
+    CRYPTO_DOWN_REF(&skeymgmt->refcnt, &ref);
+    if (ref > 0)
+        return;
+    OPENSSL_free(skeymgmt->type_name);
+    ossl_provider_free(skeymgmt->prov);
+    CRYPTO_FREE_REF(&skeymgmt->refcnt);
+    OPENSSL_free(skeymgmt);
+}
+
+const OSSL_PROVIDER *EVP_SKEYMGMT_get0_provider(const EVP_SKEYMGMT *skeymgmt)
+{
+    return (skeymgmt != NULL) ? skeymgmt->prov : NULL;
+}
+
+const char *EVP_SKEYMGMT_get0_description(const EVP_SKEYMGMT *skeymgmt)
+{
+    return (skeymgmt != NULL) ? skeymgmt->description : NULL;
+}
+
+const char *EVP_SKEYMGMT_get0_name(const EVP_SKEYMGMT *skeymgmt)
+{
+    return (skeymgmt != NULL) ? skeymgmt->type_name : NULL;
+}
+
+int EVP_SKEYMGMT_is_a(const EVP_SKEYMGMT *skeymgmt, const char *name)
+{
+    return skeymgmt != NULL
+        && evp_is_a(skeymgmt->prov, skeymgmt->name_id, NULL, name);
+}
+
+void EVP_SKEYMGMT_do_all_provided(OSSL_LIB_CTX *libctx,
+                                  void (*fn)(EVP_SKEYMGMT *skeymgmt, void *arg),
+                                  void *arg)
+{
+    evp_generic_do_all(libctx, OSSL_OP_KEYMGMT,
+                       (void (*)(void *, void *))fn, arg,
+                       skeymgmt_from_algorithm,
+                       (int (*)(void *))EVP_SKEYMGMT_up_ref,
+                       (void (*)(void *))EVP_SKEYMGMT_free);
+}
+
+int EVP_SKEYMGMT_names_do_all(const EVP_SKEYMGMT *skeymgmt,
+                              void (*fn)(const char *name, void *data),
+                              void *data)
+{
+    if (skeymgmt == NULL)
+        return 0;
+
+    if (skeymgmt->prov != NULL)
+        return evp_names_do_all(skeymgmt->prov, skeymgmt->name_id, fn, data);
+
+    return 1;
+}
+
+const OSSL_PARAM *EVP_SKEYMGMT_get0_gen_settable_params(const EVP_SKEYMGMT *skeymgmt)
+{
+    void *provctx = NULL;
+
+    if (skeymgmt == NULL)
+        return 0;
+
+    provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt));
+
+    return (skeymgmt->gen_params != NULL) ? skeymgmt->gen_params(provctx) : NULL;
+}
+
+const OSSL_PARAM *EVP_SKEYMGMT_get0_imp_settable_params(const EVP_SKEYMGMT *skeymgmt)
+{
+    void *provctx = NULL;
+
+    if (skeymgmt == NULL)
+        return 0;
+
+    provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt));
+
+    return (skeymgmt->imp_params != NULL) ? skeymgmt->imp_params(provctx) : NULL;
+}
index c65556a511d9b93129a0d21be3ce80539db35574..db83aab40b2719209cb9f658ec7a655c48b58d77 100644 (file)
@@ -353,7 +353,9 @@ struct evp_cipher_st {
     OSSL_FUNC_cipher_gettable_params_fn *gettable_params;
     OSSL_FUNC_cipher_gettable_ctx_params_fn *gettable_ctx_params;
     OSSL_FUNC_cipher_settable_ctx_params_fn *settable_ctx_params;
-} /* EVP_CIPHER */ ;
+    OSSL_FUNC_cipher_encrypt_skey_init_fn *einit_skey;
+    OSSL_FUNC_cipher_decrypt_skey_init_fn *dinit_skey;
+} /* EVP_CIPHER */;
 
 /* Macros to code block cipher wrappers */
 
@@ -751,6 +753,15 @@ struct evp_pkey_st {
 # define EVP_PKEY_CTX_IS_KEM_OP(ctx) \
     (((ctx)->operation & EVP_PKEY_OP_TYPE_KEM) != 0)
 
+struct evp_skey_st {
+    /* == Common attributes == */
+    CRYPTO_REF_COUNT references;
+    CRYPTO_RWLOCK *lock;
+
+    void *keydata; /* Alg-specific key data */
+    EVP_SKEYMGMT *skeymgmt; /* Import, export, manage */
+}; /* EVP_SKEY */
+
 void openssl_add_all_ciphers_int(void);
 void openssl_add_all_digests_int(void);
 void evp_cleanup_int(void);
@@ -854,6 +865,14 @@ EVP_KEYMGMT *evp_keymgmt_fetch_from_prov(OSSL_PROVIDER *prov,
                                          const char *name,
                                          const char *properties);
 
+/*
+ * SKEYMGMT provider interface functions
+ */
+void evp_skeymgmt_freedata(const EVP_SKEYMGMT *keymgmt, void *keyddata);
+void *evp_skeymgmt_import(const EVP_SKEYMGMT *skeymgmt, int selection, const OSSL_PARAM params[]);
+int evp_skeymgmt_export(const EVP_SKEYMGMT *skeymgmt, void *keydata,
+                        int selection, OSSL_CALLBACK *param_cb, void *cbarg);
+void *evp_skeymgmt_generate(const EVP_SKEYMGMT *skeymgmt, const OSSL_PARAM params[]);
 /* Pulling defines out of C source files */
 
 # define EVP_RC4_KEY_SIZE 16
index c3de07ff09cb7e132944b435814d831095092b8a..c44766dcb75c7e65626664c3e27bda477d17520c 100644 (file)
@@ -317,6 +317,7 @@ OSSL_CORE_MAKE_FUNC(int, SSL_QUIC_TLS_alert,
 # define OSSL_OP_SIGNATURE                          12
 # define OSSL_OP_ASYM_CIPHER                        13
 # define OSSL_OP_KEM                                14
+# define OSSL_OP_SKEYMGMT                           15
 /* New section for non-EVP operations */
 # define OSSL_OP_ENCODER                            20
 # define OSSL_OP_DECODER                            21
@@ -392,6 +393,8 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, digest_gettable_ctx_params,
 # define OSSL_FUNC_CIPHER_PIPELINE_DECRYPT_INIT     16
 # define OSSL_FUNC_CIPHER_PIPELINE_UPDATE           17
 # define OSSL_FUNC_CIPHER_PIPELINE_FINAL            18
+# define OSSL_FUNC_CIPHER_ENCRYPT_SKEY_INIT         19
+# define OSSL_FUNC_CIPHER_DECRYPT_SKEY_INIT         20
 
 OSSL_CORE_MAKE_FUNC(void *, cipher_newctx, (void *provctx))
 OSSL_CORE_MAKE_FUNC(int, cipher_encrypt_init, (void *cctx,
@@ -447,6 +450,16 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, cipher_settable_ctx_params,
                     (void *cctx, void *provctx))
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, cipher_gettable_ctx_params,
                     (void *cctx, void *provctx))
+OSSL_CORE_MAKE_FUNC(int, cipher_encrypt_skey_init, (void *cctx,
+                                                    void *skeydata,
+                                                    const unsigned char *iv,
+                                                    size_t ivlen,
+                                                    const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(int, cipher_decrypt_skey_init, (void *cctx,
+                                                    void *skeydata,
+                                                    const unsigned char *iv,
+                                                    size_t ivlen,
+                                                    const OSSL_PARAM params[]))
 
 /* MACs */
 
@@ -884,6 +897,52 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, signature_settable_ctx_md_params,
                     (void *ctx))
 OSSL_CORE_MAKE_FUNC(const char **, signature_query_key_types, (void))
 
+/*-
+ * Symmetric key management
+ *
+ * The Key Management takes care of provider side of symmetric key objects, and
+ * includes essentially everything that manipulates the keys  themselves and
+ * their parameters.
+ *
+ * The key objects are commonly referred to as |keydata|, and it MUST be able
+ * to contain parameters if the key has any, and the secret key.
+ *
+ * Key objects are created with OSSL_FUNC_skeymgmt_import() (there is no
+ * dedicated memory allocation function), exported with
+ * OSSL_FUNC_skeymgmt_export() and destroyed with OSSL_FUNC_keymgmt_free().
+ *
+ */
+
+/* Key data subset selection - individual bits */
+# define OSSL_SKEYMGMT_SELECT_PARAMETERS      0x01
+# define OSSL_SKEYMGMT_SELECT_SECRET_KEY      0x02
+
+/* Key data subset selection - combinations */
+# define OSSL_SKEYMGMT_SELECT_ALL                \
+    (OSSL_SKEYMGMT_SELECT_PARAMETERS | OSSL_SKEYMGMT_SELECT_SECRET_KEY)
+
+# define OSSL_FUNC_SKEYMGMT_FREE                1
+# define OSSL_FUNC_SKEYMGMT_IMPORT              2
+# define OSSL_FUNC_SKEYMGMT_EXPORT              3
+# define OSSL_FUNC_SKEYMGMT_GENERATE            4
+# define OSSL_FUNC_SKEYMGMT_GET_KEY_ID          5
+# define OSSL_FUNC_SKEYMGMT_IMP_SETTABLE_PARAMS 6
+# define OSSL_FUNC_SKEYMGMT_GEN_SETTABLE_PARAMS 7
+
+OSSL_CORE_MAKE_FUNC(void, skeymgmt_free, (void *keydata))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *,
+                    skeymgmt_imp_settable_params, (void *provctx))
+OSSL_CORE_MAKE_FUNC(void *, skeymgmt_import, (void *provctx, int selection,
+                                              const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(int, skeymgmt_export,
+                    (void *keydata, int selection,
+                     OSSL_CALLBACK *param_cb, void *cbarg))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *,
+                    skeymgmt_gen_settable_params, (void *provctx))
+OSSL_CORE_MAKE_FUNC(void *, skeymgmt_generate, (void *provctx,
+                                                const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const char *, skeymgmt_get_key_id, (void *keydata))
+
 /* Asymmetric Ciphers */
 
 # define OSSL_FUNC_ASYM_CIPHER_NEWCTX                  1
index d26893a88696b764aa763b4c209c9dc7d0498651..078d5bcf078d89fe9028f0ab86ceffb30be48d4d 100644 (file)
@@ -105,6 +105,10 @@ extern "C" {
 # define OSSL_PKEY_EC_GROUP_CHECK_NAMED       "named"
 # define OSSL_PKEY_EC_GROUP_CHECK_NAMED_NIST  "named-nist"
 
+/* PROV_SKEY well known key types */
+# define OSSL_SKEY_TYPE_GENERIC             "GENERIC-SECRET"
+# define OSSL_SKEY_TYPE_AES                 "AES"
+
 /* OSSL_KEM_PARAM_OPERATION values */
 #define OSSL_KEM_PARAM_OPERATION_RSASVE     "RSASVE"
 #define OSSL_KEM_PARAM_OPERATION_DHKEM      "DHKEM"
index 00570edc17e81e82381da74fcc155c0de599224c..7ecc917b31b6b8f95d8c7fe3216f1d289305944d 100644 (file)
@@ -808,6 +808,9 @@ __owur int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx,
                                  const EVP_CIPHER *cipher, ENGINE *impl,
                                  const unsigned char *key,
                                  const unsigned char *iv, int enc);
+__owur int EVP_CipherInit_SKEY(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+                               EVP_SKEY *skey, const unsigned char *iv, size_t iv_len,
+                               int enc, const OSSL_PARAM params[]);
 __owur int EVP_CipherInit_ex2(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
                               const unsigned char *key, const unsigned char *iv,
                               int enc, const OSSL_PARAM params[]);
@@ -1829,6 +1832,23 @@ const OSSL_PARAM *EVP_KEYMGMT_settable_params(const EVP_KEYMGMT *keymgmt);
 const OSSL_PARAM *EVP_KEYMGMT_gen_settable_params(const EVP_KEYMGMT *keymgmt);
 const OSSL_PARAM *EVP_KEYMGMT_gen_gettable_params(const EVP_KEYMGMT *keymgmt);
 
+EVP_SKEYMGMT *EVP_SKEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
+                                 const char *properties);
+int EVP_SKEYMGMT_up_ref(EVP_SKEYMGMT *keymgmt);
+void EVP_SKEYMGMT_free(EVP_SKEYMGMT *keymgmt);
+const OSSL_PROVIDER *EVP_SKEYMGMT_get0_provider(const EVP_SKEYMGMT *keymgmt);
+const char *EVP_SKEYMGMT_get0_name(const EVP_SKEYMGMT *keymgmt);
+const char *EVP_SKEYMGMT_get0_description(const EVP_SKEYMGMT *keymgmt);
+int EVP_SKEYMGMT_is_a(const EVP_SKEYMGMT *keymgmt, const char *name);
+void EVP_SKEYMGMT_do_all_provided(OSSL_LIB_CTX *libctx,
+                                  void (*fn)(EVP_SKEYMGMT *keymgmt, void *arg),
+                                  void *arg);
+int EVP_SKEYMGMT_names_do_all(const EVP_SKEYMGMT *keymgmt,
+                              void (*fn)(const char *name, void *data),
+                              void *data);
+const OSSL_PARAM *EVP_SKEYMGMT_get0_gen_settable_params(const EVP_SKEYMGMT *skeymgmt);
+const OSSL_PARAM *EVP_SKEYMGMT_get0_imp_settable_params(const EVP_SKEYMGMT *skeymgmt);
+
 EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
 EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
 EVP_PKEY_CTX *EVP_PKEY_CTX_new_from_name(OSSL_LIB_CTX *libctx,
@@ -2251,6 +2271,23 @@ OSSL_LIB_CTX *EVP_PKEY_CTX_get0_libctx(EVP_PKEY_CTX *ctx);
 const char *EVP_PKEY_CTX_get0_propq(const EVP_PKEY_CTX *ctx);
 const OSSL_PROVIDER *EVP_PKEY_CTX_get0_provider(const EVP_PKEY_CTX *ctx);
 
+EVP_SKEY *EVP_SKEY_import(OSSL_LIB_CTX *libctx, const char *skeymgmtname, const char *propquery,
+                          int selection, const OSSL_PARAM *params);
+EVP_SKEY *EVP_SKEY_generate(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
+                            const char *propquery, const OSSL_PARAM *params);
+EVP_SKEY *EVP_SKEY_import_raw_key(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
+                                  unsigned char *key, size_t keylen,
+                                  const char *propquery);
+int EVP_SKEY_get_raw_key(const EVP_SKEY *skey, const unsigned char **key,
+                         size_t *len);
+const char *EVP_SKEY_get0_key_id(const EVP_SKEY *skey);
+int EVP_SKEY_export(const EVP_SKEY *skey, int selection,
+                    OSSL_CALLBACK *export_cb, void *export_cbarg);
+int EVP_SKEY_up_ref(EVP_SKEY *skey);
+void EVP_SKEY_free(EVP_SKEY *skey);
+const char *EVP_SKEY_get0_skeymgmt_name(const EVP_SKEY *skey);
+const char *EVP_SKEY_get0_provider_name(const EVP_SKEY *skey);
+
 # ifdef  __cplusplus
 }
 # endif
index e05a350f1dfc8c5e755109965b5a4d60abf0c780..d8b0164f1a7f2d9bc77db8c7642c4eb5297f9f1b 100644 (file)
@@ -114,6 +114,7 @@ typedef struct evp_md_ctx_st EVP_MD_CTX;
 typedef struct evp_mac_st EVP_MAC;
 typedef struct evp_mac_ctx_st EVP_MAC_CTX;
 typedef struct evp_pkey_st EVP_PKEY;
+typedef struct evp_skey_st EVP_SKEY;
 
 typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD;
 
@@ -132,6 +133,8 @@ typedef struct evp_keyexch_st EVP_KEYEXCH;
 
 typedef struct evp_signature_st EVP_SIGNATURE;
 
+typedef struct evp_skeymgmt_st EVP_SKEYMGMT;
+
 typedef struct evp_asym_cipher_st EVP_ASYM_CIPHER;
 
 typedef struct evp_kem_st EVP_KEM;
index eb6f12bbcf59dcf88edf61ba15dfc7eac3eb764f..f9293b0ffd03b72fb7ebe0473ca800428a956d15 100644 (file)
@@ -5890,6 +5890,23 @@ i2d_OSSL_ALLOWED_ATTRIBUTES_SYNTAX      ?        3_5_0   EXIST::FUNCTION:
 OSSL_ALLOWED_ATTRIBUTES_SYNTAX_free     ?      3_5_0   EXIST::FUNCTION:
 OSSL_ALLOWED_ATTRIBUTES_SYNTAX_new      ?      3_5_0   EXIST::FUNCTION:
 OSSL_ALLOWED_ATTRIBUTES_SYNTAX_it       ?      3_5_0   EXIST::FUNCTION:
+EVP_CipherInit_SKEY                     ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEY_import                         ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEY_generate                       ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEY_import_raw_key                 ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEY_get_raw_key                    ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEY_export                         ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEY_up_ref                         ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEY_free                           ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEYMGMT_fetch                      ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEYMGMT_up_ref                     ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEYMGMT_free                       ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEYMGMT_get0_provider              ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEYMGMT_get0_name                  ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEYMGMT_get0_description           ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEYMGMT_is_a                       ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEYMGMT_do_all_provided            ?      3_5_0   EXIST::FUNCTION:
+EVP_SKEYMGMT_names_do_all               ?      3_5_0   EXIST::FUNCTION:
 OSSL_PROVIDER_add_conf_parameter        ?      3_5_0   EXIST::FUNCTION:
 OSSL_PROVIDER_get_conf_parameters       ?      3_5_0   EXIST::FUNCTION:
 OSSL_PROVIDER_conf_get_bool             ?      3_5_0   EXIST::FUNCTION:
index 58fc828ab3e8e91daad13a4b50f1ef80ad3b1422..c18a3f866ca6b03a2771fe863a349670d3f0faf6 100644 (file)
@@ -609,6 +609,10 @@ my %params = (
     'LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA' => "max_early_data",
     'LIBSSL_RECORD_LAYER_PARAM_BLOCK_PADDING' =>  "block_padding",
     'LIBSSL_RECORD_LAYER_PARAM_HS_PADDING' =>     "hs_padding",
+
+# Symmetric Key parametes
+    'SKEY_PARAM_RAW_BYTES' => "raw-bytes",
+    'SKEY_PARAM_KEY_LENGTH' => "key-length",
 );
 
 # Generate string based macros for public consumption