From: Dmitry Belyavskiy Date: Thu, 9 Jan 2025 18:18:31 +0000 (+0100) Subject: EVP_SKEY implementation for EVP_CIPHER X-Git-Tag: openssl-3.5.0-alpha1~488 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d46e010cd266288a5fb8a663f634c62a3990d6a0;p=thirdparty%2Fopenssl.git EVP_SKEY implementation for EVP_CIPHER Signed-off-by: Dmitry Belyavskiy Signed-off-by: Simo Sorce Reviewed-by: Tomas Mraz Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/26753) --- diff --git a/crypto/evp/build.info b/crypto/evp/build.info index f2d9621e855..80570bdcce4 100644 --- a/crypto/evp/build.info +++ b/crypto/evp/build.info @@ -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\ diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index 833ebdee287..2b7f5ffde9f 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -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 diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h index ef1faa4516f..e1d5f3213b6 100644 --- a/crypto/evp/evp_local.h +++ b/crypto/evp/evp_local.h @@ -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 index 00000000000..d805fc7e4a6 --- /dev/null +++ b/crypto/evp/s_lib.c @@ -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 +#include +#include +#include +#include + +#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 index 00000000000..435d96d4058 --- /dev/null +++ b/crypto/evp/skeymgmt_meth.c @@ -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 +#include +#include +#include +#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; +} diff --git a/include/crypto/evp.h b/include/crypto/evp.h index c65556a511d..db83aab40b2 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -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 diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h index c3de07ff09c..c44766dcb75 100644 --- a/include/openssl/core_dispatch.h +++ b/include/openssl/core_dispatch.h @@ -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 diff --git a/include/openssl/core_names.h.in b/include/openssl/core_names.h.in index d26893a8869..078d5bcf078 100644 --- a/include/openssl/core_names.h.in +++ b/include/openssl/core_names.h.in @@ -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" diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 00570edc17e..7ecc917b31b 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -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 diff --git a/include/openssl/types.h b/include/openssl/types.h index e05a350f1df..d8b0164f1a7 100644 --- a/include/openssl/types.h +++ b/include/openssl/types.h @@ -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; diff --git a/util/libcrypto.num b/util/libcrypto.num index eb6f12bbcf5..f9293b0ffd0 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -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: diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm index 58fc828ab3e..c18a3f866ca 100644 --- a/util/perl/OpenSSL/paramnames.pm +++ b/util/perl/OpenSSL/paramnames.pm @@ -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