typedef struct ecx_key_st ECX_KEY;
# endif
+typedef struct prov_skey_st PROV_SKEY;
+
#endif
--- /dev/null
+/*
+ * 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
+ */
+
+#ifndef OSSL_CRYPTO_SKEY_H
+# define OSSL_CRYPTO_SKEY_H
+
+/* Known symmetric key type definitions */
+# define SKEY_TYPE_GENERIC 1 /* generic bytes container unknown key types */
+# define SKEY_TYPE_AES 2 /* AES keys */
+
+struct prov_skey_st {
+ /*
+ * Internal skey implementation,
+ * A symmetric key is basically just a buffer of bytes of
+ * defined length, and a type, that defines, what
+ * cryptosystem the key is meant for (AES, HMAC, etc...)
+ */
+ OSSL_LIB_CTX *libctx;
+
+ int type;
+
+ unsigned char *data;
+ size_t length;
+};
+
+#endif /* OSSL_CRYPTO_SKEY_H */
{ NULL, NULL, NULL }
};
+static const OSSL_ALGORITHM deflt_skeymgmt[] = {
+ { PROV_NAMES_AES, "provider=default", ossl_aes_skeymgmt_functions,
+ PROV_DESCS_AES },
+ { PROV_NAMES_GENERIC, "provider=default", ossl_generic_skeymgmt_functions,
+ PROV_DESCS_GENERIC },
+ { NULL, NULL, NULL }
+};
+
static const OSSL_ALGORITHM deflt_encoder[] = {
#define ENCODER_PROVIDER "default"
#include "encoders.inc"
return deflt_decoder;
case OSSL_OP_STORE:
return deflt_store;
+ case OSSL_OP_SKEYMGMT:
+ return deflt_skeymgmt;
}
return NULL;
}
SUBDIRS=digests ciphers rands macs kdfs exchange keymgmt signature asymciphers \
- encode_decode storemgmt kem
+ encode_decode storemgmt kem skeymgmt
#include "ciphercommon_local.h"
#include "prov/provider_ctx.h"
#include "prov/providercommon.h"
+#include "internal/skey.h"
+#include "crypto/types.h"
/*-
* Generic cipher functions for OSSL_PARAM gettables and settables
iv, ivlen, params, 0);
}
+int ossl_cipher_generic_skey_einit(void *vctx, void *skeydata,
+ const unsigned char *iv, size_t ivlen,
+ const OSSL_PARAM params[])
+{
+ PROV_SKEY *key = skeydata;
+
+ return cipher_generic_init_internal((PROV_CIPHER_CTX *)vctx,
+ key->data, key->length,
+ iv, ivlen, params, 1);
+}
+
+int ossl_cipher_generic_skey_dinit(void *vctx, void *skeydata,
+ const unsigned char *iv, size_t ivlen,
+ const OSSL_PARAM params[])
+{
+ PROV_SKEY *key = skeydata;
+
+ return cipher_generic_init_internal((PROV_CIPHER_CTX *)vctx,
+ key->data, key->length,
+ iv, ivlen, params, 0);
+}
+
/* Max padding including padding length byte */
#define MAX_PADDING 256
OSSL_FUNC_cipher_settable_ctx_params_fn ossl_cipher_var_keylen_settable_ctx_params;
OSSL_FUNC_cipher_gettable_ctx_params_fn ossl_cipher_aead_gettable_ctx_params;
OSSL_FUNC_cipher_settable_ctx_params_fn ossl_cipher_aead_settable_ctx_params;
+OSSL_FUNC_cipher_encrypt_skey_init_fn ossl_cipher_generic_skey_einit;
+OSSL_FUNC_cipher_decrypt_skey_init_fn ossl_cipher_generic_skey_dinit;
int ossl_cipher_generic_get_params(OSSL_PARAM params[], unsigned int md,
uint64_t flags,
(void (*)(void))ossl_cipher_generic_gettable_ctx_params }, \
{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
(void (*)(void))ossl_cipher_generic_settable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_ENCRYPT_SKEY_INIT, (void (*)(void))ossl_cipher_generic_skey_einit },\
+ { OSSL_FUNC_CIPHER_DECRYPT_SKEY_INIT, (void (*)(void))ossl_cipher_generic_skey_dinit },\
OSSL_DISPATCH_END \
};
(void (*)(void))ossl_cipher_generic_gettable_ctx_params }, \
{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
(void (*)(void))ossl_cipher_var_keylen_settable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_ENCRYPT_SKEY_INIT, (void (*)(void))ossl_cipher_generic_skey_einit },\
+ { OSSL_FUNC_CIPHER_DECRYPT_SKEY_INIT, (void (*)(void))ossl_cipher_generic_skey_dinit },\
OSSL_DISPATCH_END \
};
extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_ml_dsa_87_decoder_functions[];
extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ml_dsa_87_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_generic_skeymgmt_functions[];
+extern const OSSL_DISPATCH ossl_aes_skeymgmt_functions[];
* Symmetric ciphers
* -----------------
*/
+#define PROV_NAMES_AES "AES:2.16.840.1.101.3.4.1"
+#define PROV_DESCS_AES "OpenSSL AES opaque secret key"
+#define PROV_NAMES_GENERIC "GENERIC-SECRET"
+#define PROV_DESCS_GENERIC "OpenSSL generic opaque secret key"
+
#define PROV_NAMES_AES_256_ECB "AES-256-ECB:2.16.840.1.101.3.4.1.41"
#define PROV_NAMES_AES_192_ECB "AES-192-ECB:2.16.840.1.101.3.4.1.21"
#define PROV_NAMES_AES_128_ECB "AES-128-ECB:2.16.840.1.101.3.4.1.1"
--- /dev/null
+/*
+ * 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/core_dispatch.h>
+#include "crypto/types.h"
+#include "skeymgmt_lcl.h"
+#include "internal/skey.h"
+#include "prov/implementations.h"
+
+static OSSL_FUNC_skeymgmt_import_fn aes_import;
+static OSSL_FUNC_skeymgmt_export_fn aes_export;
+
+static void *aes_import(void *provctx, int selection,
+ const OSSL_PARAM params[])
+{
+ PROV_SKEY *aes = generic_import(provctx, selection, params);
+
+ if (aes == NULL)
+ return NULL;
+
+ if (aes->length != 16 && aes->length != 24 && aes->length != 32) {
+ generic_free(aes);
+ return NULL;
+ }
+ aes->type = SKEY_TYPE_AES;
+
+ return aes;
+}
+
+static int aes_export(void *keydata, int selection,
+ OSSL_CALLBACK *param_callback, void *cbarg)
+{
+ PROV_SKEY *aes = keydata;
+
+ if (aes->type != SKEY_TYPE_AES)
+ return 0;
+
+ return generic_export(keydata, selection, param_callback, cbarg);
+}
+
+const OSSL_DISPATCH ossl_aes_skeymgmt_functions[] = {
+ { OSSL_FUNC_SKEYMGMT_FREE, (void (*)(void))generic_free },
+ { OSSL_FUNC_SKEYMGMT_IMPORT, (void (*)(void))aes_import },
+ { OSSL_FUNC_SKEYMGMT_EXPORT, (void (*)(void))aes_export },
+ OSSL_DISPATCH_END
+};
--- /dev/null
+# We make separate GOAL variables for each algorithm, to make it easy to
+# switch each to the Legacy provider when needed.
+
+$AES_GOAL=../../libdefault.a ../../libfips.a
+$GENERIC_GOAL=../../libdefault.a ../../libfips.a
+
+SOURCE[$AES_GOAL]=aes_skmgmt.c
+SOURCE[$GENERIC_GOAL]=generic.c
--- /dev/null
+/*
+ * 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/core_dispatch.h>
+#include <openssl/core_names.h>
+#include "crypto/types.h"
+#include "internal/skey.h"
+#include "prov/provider_ctx.h"
+#include "prov/providercommon.h"
+#include "prov/implementations.h"
+#include "skeymgmt_lcl.h"
+
+void generic_free(void *keydata)
+{
+ PROV_SKEY *generic = keydata;
+
+ if (generic == NULL)
+ return;
+
+ OPENSSL_free(generic->data);
+ OPENSSL_free(generic);
+}
+
+void *generic_import(void *provctx, int selection, const OSSL_PARAM params[])
+{
+ OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
+ const OSSL_PARAM *raw_bytes;
+ PROV_SKEY *generic = NULL;
+ int ok = 0;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ if ((selection & OSSL_SKEYMGMT_SELECT_SECRET_KEY) == 0)
+ return NULL;
+
+ raw_bytes = OSSL_PARAM_locate_const(params, OSSL_SKEY_PARAM_RAW_BYTES);
+ if (raw_bytes == NULL)
+ return NULL;
+
+ generic = OPENSSL_zalloc(sizeof(PROV_SKEY));
+ generic->libctx = libctx;
+
+ generic->type = SKEY_TYPE_GENERIC;
+
+ if ((generic->data = OPENSSL_memdup(raw_bytes->data, raw_bytes->data_size)) == NULL)
+ goto end;
+ generic->length = raw_bytes->data_size;
+ ok = 1;
+
+end:
+ if (ok == 0) {
+ generic_free(generic);
+ generic = NULL;
+ }
+ return generic;
+}
+
+int generic_export(void *keydata, int selection,
+ OSSL_CALLBACK *param_callback, void *cbarg)
+{
+ PROV_SKEY *gen = keydata;
+ OSSL_PARAM params[2];
+
+ if (!ossl_prov_is_running() || gen == NULL)
+ return 0;
+
+ /* If we use generic SKEYMGMT as a "base class", we shouldn't check the type */
+ if ((selection & OSSL_SKEYMGMT_SELECT_SECRET_KEY) == 0)
+ return 0;
+
+ params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
+ gen->data, gen->length);
+ params[1] = OSSL_PARAM_construct_end();
+
+ return param_callback(params, cbarg);
+}
+
+const OSSL_DISPATCH ossl_generic_skeymgmt_functions[] = {
+ { OSSL_FUNC_SKEYMGMT_FREE, (void (*)(void))generic_free },
+ { OSSL_FUNC_SKEYMGMT_IMPORT, (void (*)(void))generic_import },
+ { OSSL_FUNC_SKEYMGMT_EXPORT, (void (*)(void))generic_export },
+ OSSL_DISPATCH_END
+};
--- /dev/null
+/*
+ * 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
+ */
+
+#ifndef OSSL_PROVIDERS_SKEYMGMT_LCL_H
+# define OSSL_PROVIDERS_SKEYMGMT_LCL_H
+# pragma once
+# include <openssl/core_dispatch.h>
+
+OSSL_FUNC_skeymgmt_import_fn generic_import;
+OSSL_FUNC_skeymgmt_export_fn generic_export;
+OSSL_FUNC_skeymgmt_free_fn generic_free;
+
+#endif
#include <openssl/provider.h>
#include <openssl/params.h>
+#include <openssl/param_build.h>
#include <openssl/core_names.h>
#include <openssl/evp.h>
#include "testutil.h"
goto end;
/* Export params */
- if (!TEST_int_gt(EVP_SKEY_export(key, OSSL_SKEYMGMT_SELECT_ALL,
+ if (!TEST_int_gt(EVP_SKEY_export(key, OSSL_SKEYMGMT_SELECT_SECRET_KEY,
ossl_pkey_todata_cb, &export_params), 0))
goto end;
return ret;
}
+#define IV_SIZE 16
+#define DATA_SIZE 32
+static int test_aes_raw_skey(void)
+{
+ const unsigned char data[DATA_SIZE] = {
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2
+ };
+ unsigned char aes_key[KEY_SIZE], aes_iv[IV_SIZE];
+ unsigned char encrypted_skey[DATA_SIZE + IV_SIZE];
+ unsigned char encrypted_raw[DATA_SIZE + IV_SIZE];
+ int enc_len, fin_len;
+ const unsigned char *export_key = NULL;
+ size_t export_length;
+ EVP_CIPHER *aes_cbc = NULL;
+ EVP_CIPHER_CTX *ctx = NULL;
+ EVP_SKEY *skey = NULL;
+ OSSL_PARAM_BLD *tmpl = NULL;
+ OSSL_PARAM *params = NULL;
+ int ret = 0;
+
+ deflprov = OSSL_PROVIDER_load(libctx, "default");
+ if (!TEST_ptr(deflprov))
+ return 0;
+
+ memset(encrypted_skey, 0, sizeof(encrypted_skey));
+ memset(encrypted_raw, 0, sizeof(encrypted_raw));
+ memset(aes_key, 1, KEY_SIZE);
+ memset(aes_iv, 2, IV_SIZE);
+
+ /* Do a direct fetch to see it works */
+ aes_cbc = EVP_CIPHER_fetch(libctx, "AES-128-CBC", "provider=default");
+ if (!TEST_ptr(aes_cbc))
+ goto end;
+
+ /* Create EVP_SKEY */
+ skey = EVP_SKEY_import_raw_key(libctx, "AES-128", aes_key, KEY_SIZE, NULL);
+ if (!TEST_ptr(skey))
+ goto end;
+
+ if (!TEST_int_gt(EVP_SKEY_get_raw_key(skey, &export_key, &export_length), 0)
+ || !TEST_mem_eq(aes_key, KEY_SIZE, export_key, export_length))
+ goto end;
+
+ enc_len = sizeof(encrypted_skey);
+ fin_len = 0;
+ if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
+ || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, aes_cbc, skey, aes_iv, IV_SIZE, 1, NULL), 0)
+ || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_skey, &enc_len, data, DATA_SIZE), 0)
+ || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_skey + enc_len, &fin_len), 0))
+ goto end;
+
+ EVP_CIPHER_CTX_free(ctx);
+ ctx = EVP_CIPHER_CTX_new();
+
+ enc_len = sizeof(encrypted_raw);
+ fin_len = 0;
+ if (!TEST_int_gt(EVP_CipherInit_ex2(ctx, aes_cbc, aes_key, aes_iv, 1, NULL), 0)
+ || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_raw, &enc_len, data, DATA_SIZE), 0)
+ || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_raw + enc_len, &fin_len), 0)
+ || !TEST_mem_eq(encrypted_skey, DATA_SIZE + IV_SIZE, encrypted_raw, DATA_SIZE + IV_SIZE))
+ goto end;
+
+ ret = 1;
+end:
+ OSSL_PARAM_free(params);
+ OSSL_PARAM_BLD_free(tmpl);
+ EVP_SKEY_free(skey);
+ EVP_CIPHER_free(aes_cbc);
+ EVP_CIPHER_CTX_free(ctx);
+ OSSL_PROVIDER_unload(deflprov);
+ return ret;
+}
+
+#ifndef OPENSSL_NO_DES
+/* DES is used to test a "skey-unware" cipher provider */
+# define DES_KEY_SIZE 24
+# define DES_IV_SIZE 8
+static int test_des_raw_skey(void)
+{
+ const unsigned char data[DATA_SIZE] = {
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2
+ };
+ unsigned char des_key[DES_KEY_SIZE], des_iv[DES_IV_SIZE];
+ unsigned char encrypted_skey[DATA_SIZE + DES_IV_SIZE];
+ unsigned char encrypted_raw[DATA_SIZE + DES_IV_SIZE];
+ int enc_len, fin_len;
+ const unsigned char *export_key = NULL;
+ size_t export_length;
+ EVP_CIPHER *des_cbc = NULL;
+ EVP_CIPHER_CTX *ctx = NULL;
+ EVP_SKEY *skey = NULL;
+ int ret = 0;
+
+ deflprov = OSSL_PROVIDER_load(libctx, "default");
+ if (!TEST_ptr(deflprov))
+ return 0;
+
+ memset(encrypted_skey, 0, sizeof(encrypted_skey));
+ memset(encrypted_raw, 0, sizeof(encrypted_raw));
+ memset(des_key, 1, DES_KEY_SIZE);
+ memset(des_iv, 2, DES_IV_SIZE);
+
+ /* Do a direct fetch to see it works */
+ des_cbc = EVP_CIPHER_fetch(libctx, "DES-EDE3-CBC", "provider=default");
+ if (!TEST_ptr(des_cbc))
+ goto end;
+
+ /* Create EVP_SKEY */
+ skey = EVP_SKEY_import_raw_key(libctx, "GENERIC-SECRET", des_key,
+ sizeof(des_key), NULL);
+ if (!TEST_ptr(skey))
+ goto end;
+
+ if (!TEST_int_gt(EVP_SKEY_get_raw_key(skey, &export_key, &export_length), 0)
+ || !TEST_mem_eq(des_key, DES_KEY_SIZE, export_key, export_length))
+ goto end;
+
+ enc_len = sizeof(encrypted_skey);
+ fin_len = 0;
+ if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
+ || !TEST_int_gt(EVP_CipherInit_SKEY(ctx, des_cbc, skey, des_iv, DES_IV_SIZE, 1, NULL), 0)
+ || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_skey, &enc_len, data, DATA_SIZE), 0)
+ || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_skey + enc_len, &fin_len), 0))
+ goto end;
+
+ EVP_CIPHER_CTX_free(ctx);
+ ctx = EVP_CIPHER_CTX_new();
+
+ enc_len = sizeof(encrypted_raw);
+ fin_len = 0;
+ if (!TEST_int_gt(EVP_CipherInit_ex2(ctx, des_cbc, des_key, des_iv, 1, NULL), 0)
+ || !TEST_int_gt(EVP_CipherUpdate(ctx, encrypted_raw, &enc_len, data, DATA_SIZE), 0)
+ || !TEST_int_gt(EVP_CipherFinal(ctx, encrypted_raw + enc_len, &fin_len), 0)
+ || !TEST_mem_eq(encrypted_skey, DATA_SIZE + DES_IV_SIZE, encrypted_raw,
+ DATA_SIZE + DES_IV_SIZE))
+ goto end;
+
+ ret = 1;
+end:
+ EVP_SKEY_free(skey);
+ EVP_CIPHER_free(des_cbc);
+ EVP_CIPHER_CTX_free(ctx);
+ OSSL_PROVIDER_unload(deflprov);
+ return ret;
+}
+#endif
+
int setup_tests(void)
{
libctx = OSSL_LIB_CTX_new();
ADD_TEST(test_skey_cipher);
+ ADD_TEST(test_aes_raw_skey);
+#ifndef OPENSSL_NO_DES
+ ADD_TEST(test_des_raw_skey);
+#endif
+
return 1;
}