return ctx->meth->derive(ctx->algctx, key, keylen, params);
}
+EVP_SKEY *EVP_KDF_derive_SKEY(EVP_KDF_CTX *ctx, const char *key_type,
+ size_t keylen, const char *propquery,
+ const OSSL_PARAM params[])
+{
+ EVP_SKEYMGMT *skeymgmt = NULL;
+ EVP_SKEY *ret = NULL;
+
+ if (ctx == NULL || key_type == NULL) {
+ ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+
+ if (mgmt != NULL) {
+ skeymgmt = mgmt;
+ } else {
+ skeymgmt = evp_skeymgmt_fetch_from_prov(ctx->meth->prov,
+ key_type, propquery);
+ if (skeymgmt == NULL) {
+ /*
+ * The provider does not support skeymgmt, let's try to fallback
+ * to a provider that supports it
+ */
+ skeymgmt = EVP_SKEYMGMT_fetch(ossl_provider_libctx(ctx->meth->prov),
+ key_type, propquery);
+ }
+
+ if (skeymgmt == NULL) {
+ ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
+ return NULL;
+ }
+ }
+
+ /* Fallback to raw derive + import if necessary */
+ if (skeymgmt->prov != ctx->meth->prov ||
+ ctx->meth->derive_skey == NULL) {
+ unsigned char *key = NULL;
+ OSSL_PARAM import_params[2] = {OSSL_PARAM_END, OSSL_PARAM_END};
+
+ if (ctx->meth->derive == NULL) {
+ ERR_raise(ERR_R_EVP_LIB, ERR_R_UNSUPPORTED);
+ return NULL;
+ }
+
+ key = OPENSSL_zalloc(keylen);
+ if (!key)
+ return NULL;
+
+ if (!ctx->meth->derive(ctx->algctx, key, keylen, params)) {
+ OPENSSL_free(key);
+ return NULL;
+ }
+ import_params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
+ key, keylen);
+
+ ret = EVP_SKEY_import_SKEYMGMT(ossl_provider_libctx(ctx->meth->prov), skeymgmt,
+ OSSL_SKEYMGMT_SELECT_SECRET_KEY, import_params);
+
+ if (mgmt != skeymgmt)
+ EVP_SKEYMGMT_free(skeymgmt);
+
+ OPENSSL_clear_free(key, keylen);
+ return ret;
+ }
+
+ ret = evp_skey_alloc(skeymgmt);
+ if (ret == NULL) {
+ if (mgmt != skeymgmt)
+ EVP_SKEYMGMT_free(skeymgmt);
+ return NULL;
+ }
+
+ ret->keydata = ctx->meth->derive_skey(ctx->algctx, ossl_provider_ctx(skeymgmt->prov),
+ skeymgmt->import, keylen, params);
+ if (ret->keydata == NULL) {
+ EVP_SKEY_free(ret);
+ ret = NULL;
+ }
+
+ if (mgmt != skeymgmt)
+ EVP_SKEYMGMT_free(skeymgmt);
+ return ret;
+}
+
/*
* The {get,set}_params functions return 1 if there is no corresponding
* function in the implementation. This is the same as if there was one,
break;
kdf->set_ctx_params = OSSL_FUNC_kdf_set_ctx_params(fns);
break;
+ case OSSL_FUNC_KDF_DERIVE_SKEY:
+ if (kdf->derive_skey != NULL)
+ break;
+ kdf->derive_skey = OSSL_FUNC_kdf_derive_skey(fns);
+ break;
}
}
if (fnkdfcnt != 1 || fnctxcnt != 2) {
EVP_KDF, EVP_KDF_fetch, EVP_KDF_free, EVP_KDF_up_ref,
EVP_KDF_CTX, EVP_KDF_CTX_new, EVP_KDF_CTX_free, EVP_KDF_CTX_dup,
-EVP_KDF_CTX_reset, EVP_KDF_derive,
+EVP_KDF_CTX_reset, EVP_KDF_derive, EVP_KDF_derive_SKEY,
EVP_KDF_CTX_get_kdf_size,
EVP_KDF_get0_provider, EVP_KDF_CTX_kdf, EVP_KDF_is_a,
EVP_KDF_get0_name, EVP_KDF_names_do_all, EVP_KDF_get0_description,
size_t EVP_KDF_CTX_get_kdf_size(EVP_KDF_CTX *ctx);
int EVP_KDF_derive(EVP_KDF_CTX *ctx, unsigned char *key, size_t keylen,
const OSSL_PARAM params[]);
+ int EVP_KDF_CTX_set_SKEY(EVP_KDF_CTX *ctx, EVP_SKEY *key, const char *paramname);
+ EVP_SKEY *EVP_KDF_derive_SKEY(EVP_KDF_CTX *ctx, EVP_SKEYMGMT *mgmt,
+ const char *key_type, const char *propquery,
+ size_t keylen, const OSSL_PARAM params[]);
int EVP_KDF_up_ref(EVP_KDF *kdf);
void EVP_KDF_free(EVP_KDF *kdf);
EVP_KDF *EVP_KDF_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
algorithms and should be used instead of algorithm-specific functions.
After creating a B<EVP_KDF_CTX> for the required algorithm using
-EVP_KDF_CTX_new(), inputs to the algorithm are supplied either by
-passing them as part of the EVP_KDF_derive() call or using calls
-to EVP_KDF_CTX_set_params() before calling EVP_KDF_derive() to derive
-the key.
+EVP_KDF_CTX_new(), inputs to the algorithm are supplied either by passing them
+as part of the EVP_KDF_derive() or EVP_KDF_derive_SKEY() call or using calls to
+EVP_KDF_CTX_set_params() before calling EVP_KDF_derive() or
+EVP_KDF_derive_SKEY() to derive the key.
=head2 Types
occur unless the I<keylen> parameter is equal to that output size,
as returned by EVP_KDF_CTX_get_kdf_size().
+EVP_KDF_derive_SKEY() behaves similarly except it returns an B<EVP_SKEY>
+object. If the I<skeymgmt> argument is explicitly passed, it will be used for
+the generated key. If the I<skeymgmt> argument is NULL, the I<key_type> and
+I<propquery> will be used for fetching the B<EVP_SKEYMGMT> object linked to the
+key. If the KDF doesn't support dealing with opaque keys or the passed
+B<EVP_SKEYMGMT> is from a different provider than the KDF method, the operation
+will fail.
+
EVP_KDF_get_params() retrieves details about the implementation
I<kdf>.
The set of parameters given with I<params> determine exactly what
EVP_KDF_names_do_all() returns 1 if the callback was called for all names. A
return value of 0 means that the callback was not called for any names.
+EVP_KDF_derive_SKEY() returns the B<EVP_SKEY> object on success or NULL on failure.
+
The remaining functions return 1 for success and 0 for failure.
=head1 NOTES
This functionality was added in OpenSSL 3.0.
+EVP_KDF_derive_SKEY() and EVP_KDF_CTX_set_SKEY() functions were introduced in
+OpenSSL 3.6.
+
=head1 COPYRIGHT
Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
int OSSL_FUNC_kdf_reset(void *kctx);
int OSSL_FUNC_kdf_derive(void *kctx, unsigned char *key, size_t keylen,
const OSSL_PARAM params[]);
+ void *OSSL_FUNC_kdf_derive_skey(void *ctx, void *provctx,
+ OSSL_FUNC_skeymgmt_import_fn *import,
+ size_t keylen, const OSSL_PARAM params[]);
/* KDF parameter descriptors */
const OSSL_PARAM *OSSL_FUNC_kdf_gettable_params(void *provctx);
OSSL_FUNC_kdf_reset OSSL_FUNC_KDF_RESET
OSSL_FUNC_kdf_derive OSSL_FUNC_KDF_DERIVE
+ OSSL_FUNC_kdf_derive_skey OSSL_FUNC_KDF_DERIVE_SKEY
OSSL_FUNC_kdf_get_params OSSL_FUNC_KDF_GET_PARAMS
OSSL_FUNC_kdf_get_ctx_params OSSL_FUNC_KDF_GET_CTX_PARAMS
A KDF algorithm implementation may not implement all of these functions.
In order to be a consistent set of functions, at least the following functions
must be implemented: OSSL_FUNC_kdf_newctx(), OSSL_FUNC_kdf_freectx(),
-OSSL_FUNC_kdf_set_ctx_params(), OSSL_FUNC_kdf_derive().
+OSSL_FUNC_kdf_set_ctx_params(), and at least one of
+OSSL_FUNC_kdf_derive() or OSSL_FUNC_kdf_derive_skey().
All other functions are optional.
=head2 Context Management Functions
If the algorithm does not support the requested I<keylen> the function must
return error.
+OSSL_FUNC_kdf_derive_skey() is similar to OSSL_FUNC_kdf_derive() but uses an
+opaque object for storing the derived key.
+
=head2 KDF Parameters
See L<OSSL_PARAM(3)> for further details on the parameters structure used by
OSSL_FUNC_kdf_newctx() and OSSL_FUNC_kdf_dupctx() should return the newly created
provider side KDF context, or NULL on failure.
-OSSL_FUNC_kdf_derive(), OSSL_FUNC_kdf_get_params(),
+OSSL_FUNC_kdf_derive(), OSSL_FUNC_kdf_derive_skey(), OSSL_FUNC_kdf_get_params(),
OSSL_FUNC_kdf_get_ctx_params() and OSSL_FUNC_kdf_set_ctx_params() should return 1 for
success or 0 on error.
The provider KDF interface was introduced in OpenSSL 3.0.
+OSSL_FUNC_kdf_derive_skey() and OSSL_FUNC_kdf_set_skey() were added in OpenSSL 3.6.
+
=head1 COPYRIGHT
Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved.
OSSL_FUNC_kdf_get_params_fn *get_params;
OSSL_FUNC_kdf_get_ctx_params_fn *get_ctx_params;
OSSL_FUNC_kdf_set_ctx_params_fn *set_ctx_params;
+ OSSL_FUNC_kdf_derive_skey_fn *derive_skey;
};
#define EVP_ORIG_DYNAMIC 0
(void *mctx, const OSSL_PARAM params[]))
OSSL_CORE_MAKE_FUNC(int, mac_init_skey, (void *mctx, void *key, const OSSL_PARAM params[]))
+/*-
+ * 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))
+
/* KDFs and PRFs */
# define OSSL_FUNC_KDF_NEWCTX 1
# define OSSL_FUNC_KDF_GET_PARAMS 9
# define OSSL_FUNC_KDF_GET_CTX_PARAMS 10
# define OSSL_FUNC_KDF_SET_CTX_PARAMS 11
+# define OSSL_FUNC_KDF_DERIVE_SKEY 12
OSSL_CORE_MAKE_FUNC(void *, kdf_newctx, (void *provctx))
OSSL_CORE_MAKE_FUNC(void *, kdf_dupctx, (void *src))
(void *kctx, OSSL_PARAM params[]))
OSSL_CORE_MAKE_FUNC(int, kdf_set_ctx_params,
(void *kctx, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(int, kdf_set_skey,
+ (void *kctx, void *skeydata, const char *paramname))
+OSSL_CORE_MAKE_FUNC(void *, kdf_derive_skey, (void *ctx, void *provctx,
+ OSSL_FUNC_skeymgmt_import_fn *import,
+ size_t keylen, const OSSL_PARAM params[]))
/* RAND */
size_t EVP_KDF_CTX_get_kdf_size(EVP_KDF_CTX *ctx);
int EVP_KDF_derive(EVP_KDF_CTX *ctx, unsigned char *key, size_t keylen,
const OSSL_PARAM params[]);
+EVP_SKEY *EVP_KDF_derive_SKEY(EVP_KDF_CTX *ctx, const char *key_type,
+ size_t keylen, const char *propquery,
+ const OSSL_PARAM params[]);
int EVP_KDF_get_params(EVP_KDF *kdf, OSSL_PARAM params[]);
int EVP_KDF_CTX_get_params(EVP_KDF_CTX *ctx, OSSL_PARAM params[]);
int EVP_KDF_CTX_set_params(EVP_KDF_CTX *ctx, const OSSL_PARAM params[]);
return ret;
}
+static int test_kdf_tls1_prf_set_skey(void)
+{
+ int ret;
+ EVP_KDF_CTX *kctx = NULL;
+ unsigned char out[16];
+ OSSL_PARAM params[3] = {OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END};
+ OSSL_PARAM *p = params;
+ static const unsigned char expected[sizeof(out)] = {
+ 0x8e, 0x4d, 0x93, 0x25, 0x30, 0xd7, 0x65, 0xa0,
+ 0xaa, 0xe9, 0x74, 0xc3, 0x04, 0x73, 0x5e, 0xcc
+ };
+ EVP_SKEY *skey = NULL;
+
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
+ "sha256", 0);
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET,
+ "secret", 6);
+ skey = EVP_SKEY_import_raw_key(NULL, OSSL_SKEY_TYPE_GENERIC,
+ (unsigned char *)"seed", 4, NULL);
+ if (skey == NULL)
+ return 0;
+
+ ret = TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF))
+ && TEST_int_gt(EVP_KDF_CTX_set_SKEY(kctx, skey, OSSL_KDF_PARAM_SEED), 0)
+ && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0)
+ && TEST_mem_eq(out, sizeof(out), expected, sizeof(expected));
+
+ EVP_KDF_CTX_free(kctx);
+ EVP_SKEY_free(skey);
+ return ret;
+}
+
+static int test_kdf_tls1_prf_derive_skey(void)
+{
+ int ret;
+ EVP_KDF_CTX *kctx = NULL;
+ unsigned char out[16];
+ OSSL_PARAM *params;
+ static const unsigned char expected[sizeof(out)] = {
+ 0x8e, 0x4d, 0x93, 0x25, 0x30, 0xd7, 0x65, 0xa0,
+ 0xaa, 0xe9, 0x74, 0xc3, 0x04, 0x73, 0x5e, 0xcc
+ };
+ const unsigned char *export = NULL;
+ size_t export_size = 0;
+ EVP_SKEY *skey = NULL;
+
+ params = construct_tls1_prf_params("sha256", "secret", "seed");
+
+ ret = TEST_ptr(params)
+ && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF))
+ && TEST_ptr(skey = EVP_KDF_derive_SKEY(kctx, NULL, OSSL_SKEY_TYPE_GENERIC,
+ NULL, sizeof(expected), params))
+ && TEST_int_eq(EVP_SKEY_get0_raw_key(skey, &export, &export_size), 1)
+ && TEST_mem_eq(export, export_size, expected, sizeof(expected));
+
+ EVP_SKEY_free(skey);
+ EVP_KDF_CTX_free(kctx);
+ OPENSSL_free(params);
+ return ret;
+}
+
static int test_kdf_tls1_prf_invalid_digest(void)
{
int ret;
ADD_TEST(test_kdf_kbkdf_kmac);
ADD_TEST(test_kdf_get_kdf);
ADD_TEST(test_kdf_tls1_prf);
+ ADD_TEST(test_kdf_tls1_prf_set_skey);
+ ADD_TEST(test_kdf_tls1_prf_derive_skey);
ADD_TEST(test_kdf_tls1_prf_invalid_digest);
ADD_TEST(test_kdf_tls1_prf_zero_output_size);
ADD_TEST(test_kdf_tls1_prf_empty_secret);