OSSL_FUNC_keyexch_settable_ctx_params_fn *settable_ctx_params;
OSSL_FUNC_keyexch_get_ctx_params_fn *get_ctx_params;
OSSL_FUNC_keyexch_gettable_ctx_params_fn *gettable_ctx_params;
+ OSSL_FUNC_keyexch_derive_skey_fn *derive_skey;
} /* EVP_KEYEXCH */;
struct evp_signature_st {
* https://www.openssl.org/source/license.html
*/
+#include <openssl/core_names.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/err.h>
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_KEYEXCH *exchange = NULL;
- int fncnt = 0, sparamfncnt = 0, gparamfncnt = 0;
+ int fncnt = 0, sparamfncnt = 0, gparamfncnt = 0, derive_found = 0;
if ((exchange = evp_keyexch_new(prov)) == NULL) {
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
if (exchange->derive != NULL)
break;
exchange->derive = OSSL_FUNC_keyexch_derive(fns);
- fncnt++;
+ derive_found = 1;
break;
case OSSL_FUNC_KEYEXCH_FREECTX:
if (exchange->freectx != NULL)
= OSSL_FUNC_keyexch_settable_ctx_params(fns);
sparamfncnt++;
break;
+ case OSSL_FUNC_KEYEXCH_DERIVE_SKEY:
+ if (exchange->derive_skey != NULL)
+ break;
+ exchange->derive_skey = OSSL_FUNC_keyexch_derive_skey(fns);
+ derive_found = 1;
+ break;
}
}
+ fncnt += derive_found;
if (fncnt != 4
|| (gparamfncnt != 0 && gparamfncnt != 2)
|| (sparamfncnt != 0 && sparamfncnt != 2)) {
return ctx->pmeth->derive(ctx, key, pkeylen);
}
+EVP_SKEY *EVP_PKEY_derive_SKEY(EVP_PKEY_CTX *ctx, EVP_SKEYMGMT *mgmt,
+ const char *key_type, const char *propquery,
+ size_t keylen, 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 (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
+ return NULL;
+ }
+
+ if (ctx->op.kex.algctx == NULL) {
+ ERR_raise(ERR_R_EVP_LIB, ERR_R_UNSUPPORTED);
+ return NULL;
+ }
+
+ if (mgmt != NULL) {
+ skeymgmt = mgmt;
+ } else {
+ skeymgmt = evp_skeymgmt_fetch_from_prov(ctx->op.kex.exchange->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(ctx->libctx, 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->op.kex.exchange->prov ||
+ ctx->op.kex.exchange->derive_skey == NULL) {
+ size_t tmplen = keylen;
+ unsigned char *key = NULL;
+ OSSL_PARAM import_params[2] = {OSSL_PARAM_END, OSSL_PARAM_END};
+
+ if (ctx->op.kex.exchange->derive == NULL) {
+ ERR_raise(ERR_R_EVP_LIB, ERR_R_UNSUPPORTED);
+ return NULL;
+ }
+
+ key = OPENSSL_zalloc(keylen);
+ if (key == NULL) {
+ ERR_raise(ERR_R_EVP_LIB, ERR_R_CRYPTO_LIB);
+ return NULL;
+ }
+
+ if (!ctx->op.kex.exchange->derive(ctx->op.kex.algctx, key, &tmplen,
+ tmplen)) {
+ OPENSSL_free(key);
+ return NULL;
+ }
+
+ if (keylen != tmplen) {
+ OPENSSL_free(key);
+ ERR_raise(ERR_R_EVP_LIB, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+ import_params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
+ key, keylen);
+
+ ret = EVP_SKEY_import_SKEYMGMT(ctx->libctx, skeymgmt,
+ OSSL_SKEYMGMT_SELECT_SECRET_KEY, import_params);
+ OPENSSL_clear_free(key, keylen);
+ if (mgmt != skeymgmt)
+ EVP_SKEYMGMT_free(skeymgmt);
+ return ret;
+ }
+
+ ret = evp_skey_alloc(skeymgmt);
+ if (ret == NULL) {
+ if (mgmt != skeymgmt)
+ EVP_SKEYMGMT_free(skeymgmt);
+ return NULL;
+ }
+
+ ret->keydata = ctx->op.kex.exchange->derive_skey(ctx->op.kex.algctx,
+ ossl_provider_ctx(skeymgmt->prov),
+ skeymgmt->import, keylen, params);
+
+ if (mgmt != skeymgmt)
+ EVP_SKEYMGMT_free(skeymgmt);
+
+ if (ret->keydata == NULL) {
+ EVP_SKEY_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
int evp_keyexch_get_number(const EVP_KEYEXCH *keyexch)
{
return keyexch->name_id;
=head1 NAME
EVP_PKEY_derive_init, EVP_PKEY_derive_init_ex,
-EVP_PKEY_derive_set_peer_ex, EVP_PKEY_derive_set_peer, EVP_PKEY_derive
+EVP_PKEY_derive_set_peer_ex, EVP_PKEY_derive_set_peer, EVP_PKEY_derive,
+EVP_PKEY_derive_SKEY
- derive public key algorithm shared secret
=head1 SYNOPSIS
int validate_peer);
int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer);
int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
+ EVP_SKEY *EVP_PKEY_derive_SKEY(EVP_PKEY_CTX *ctx, EVP_SKEYMGMT *mgmt,
+ const char *key_type, const char *propquery,
+ size_t keylen, const OSSL_PARAM params[]);
=head1 DESCRIPTION
successful the shared secret is written to I<key> and the amount of data
written to I<keylen>.
+EVP_PKEY_derive_SKEY() is similar to EVP_PKEY_derive() but returns an
+B<EVP_SKEY> object that stores the opaque data for the derived key. If
+B<EVP_SKEYMGMT> argument is passed, it would be explicitly used for the
+B<EVP_SKEY> creation. Otherwise the B<EVP_SKEYMGMT> object used for B<EVP_SKEY>
+will be fetched according to I<skeymgmtname> and I<propquery>. If
+I<skeymgmtname> is NULL, the name matching the key exchange method name is
+assumed.
+
=head1 NOTES
After the call to EVP_PKEY_derive_init(), algorithm
In particular a return value of -2 indicates the operation is not supported by
the public key algorithm.
+EVP_PKEY_derive_SKEY() returns a freshly created B<EVP_SKEY> object on success
+or NULL on failure.
+
=head1 EXAMPLES
Derive shared secret (for example DH or EC keys):
The EVP_PKEY_derive_init_ex() and EVP_PKEY_derive_set_peer_ex() functions were
added in OpenSSL 3.0.
+The EVP_PKEY_derive_SKEY() function was added in OpenSSL 3.6.
+
=head1 COPYRIGHT
-Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2006-2024 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
int OSSL_FUNC_keyexch_set_peer(void *ctx, void *provkey);
int OSSL_FUNC_keyexch_derive(void *ctx, unsigned char *secret, size_t *secretlen,
size_t outlen);
+ int OSSL_FUNC_keyexch_derive_skey(void *ctx, void *provctx,
+ OSSL_FUNC_skeymgmt_import_fn *import,
+ size_t keylen, const OSSL_PARAM params[]);
/* Key Exchange parameters */
int OSSL_FUNC_keyexch_set_ctx_params(void *ctx, const OSSL_PARAM params[]);
OSSL_FUNC_keyexch_init OSSL_FUNC_KEYEXCH_INIT
OSSL_FUNC_keyexch_set_peer OSSL_FUNC_KEYEXCH_SET_PEER
OSSL_FUNC_keyexch_derive OSSL_FUNC_KEYEXCH_DERIVE
+ OSSL_FUNC_keyexch_derive_skey OSSL_FUNC_KEYEXCH_DERIVE_SKEY
OSSL_FUNC_keyexch_set_ctx_params OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS
OSSL_FUNC_keyexch_settable_ctx_params OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS
A key exchange algorithm implementation may not implement all of these functions.
In order to be a consistent set of functions a provider must implement
-OSSL_FUNC_keyexch_newctx, OSSL_FUNC_keyexch_freectx, OSSL_FUNC_keyexch_init and OSSL_FUNC_keyexch_derive.
+OSSL_FUNC_keyexch_newctx, OSSL_FUNC_keyexch_freectx, OSSL_FUNC_keyexch_init and at least one
+of OSSL_FUNC_keyexch_derive and OSSL_FUNC_keyexch_derive_skey.
All other functions are optional.
A key exchange algorithm must also implement some mechanism for generating,
If I<secret> is NULL then the maximum length of the shared secret should be
written to I<*secretlen>.
+OSSL_FUNC_keyexch_derive_skey() is similar to OSSL_FUNC_keyexch_derive() but works
+with an opaque provider-specific object instead of raw bytes buffer.
+
=head2 Key Exchange Parameters Functions
OSSL_FUNC_keyexch_set_ctx_params() sets key exchange parameters associated with the
provider side key exchange context, or NULL on failure.
OSSL_FUNC_keyexch_init(), OSSL_FUNC_keyexch_set_peer(), OSSL_FUNC_keyexch_derive(),
+OSSL_FUNC_keyexch_derive_skey(),
OSSL_FUNC_keyexch_set_params(), and OSSL_FUNC_keyexch_get_params() should return 1 for success
or 0 on error.
The Key Exchange Parameters "fips-indicator", "key-check" and "digest-check"
were added in OpenSSL 3.4.
+The OSSL_FUNC_keyexch_derive_skey() function was added in OpenSSL 3.6.
+
=head1 COPYRIGHT
Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
# define OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS 8
# define OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS 9
# define OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS 10
+# define OSSL_FUNC_KEYEXCH_DERIVE_SKEY 11
OSSL_CORE_MAKE_FUNC(void *, keyexch_newctx, (void *provctx))
OSSL_CORE_MAKE_FUNC(int, keyexch_init, (void *ctx, void *provkey,
OSSL_PARAM params[]))
OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, keyexch_gettable_ctx_params,
(void *ctx, void *provctx))
+OSSL_CORE_MAKE_FUNC(void *, keyexch_derive_skey, (void *ctx, void *provctx,
+ OSSL_FUNC_skeymgmt_import_fn *import,
+ size_t keylen, const OSSL_PARAM params[]))
/* Signature */
(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
int validate_peer);
int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer);
int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
+EVP_SKEY *EVP_PKEY_derive_SKEY(EVP_PKEY_CTX *ctx, EVP_SKEYMGMT *mgmt,
+ const char *key_type, const char *propquery,
+ size_t keylen, const OSSL_PARAM params[]);
int EVP_PKEY_encapsulate_init(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]);
int EVP_PKEY_auth_encapsulate_init(EVP_PKEY_CTX *ctx, EVP_PKEY *authpriv,
static OSSL_FUNC_keyexch_init_fn ecdh_init;
static OSSL_FUNC_keyexch_set_peer_fn ecdh_set_peer;
static OSSL_FUNC_keyexch_derive_fn ecdh_derive;
+static OSSL_FUNC_keyexch_derive_skey_fn ecdh_derive_skey;
static OSSL_FUNC_keyexch_freectx_fn ecdh_freectx;
static OSSL_FUNC_keyexch_dupctx_fn ecdh_dupctx;
static OSSL_FUNC_keyexch_set_ctx_params_fn ecdh_set_ctx_params;
return 0;
}
+static
+void *ecdh_derive_skey(void *vpecdhctx, void *provctx, OSSL_FUNC_skeymgmt_import_fn *import,
+ size_t outlen, const OSSL_PARAM params_in[] ossl_unused)
+{
+ unsigned char *secret = NULL;
+ size_t secretlen = 0;
+ void *ret = NULL;
+ OSSL_PARAM params[2] = {OSSL_PARAM_END, OSSL_PARAM_END};
+
+ if (import == NULL || outlen == 0)
+ return NULL;
+
+ if (ecdh_derive(vpecdhctx, secret, &secretlen, outlen) == 0)
+ return NULL;
+
+ if ((secret = OPENSSL_malloc(secretlen)) == NULL)
+ return NULL;
+
+ if (ecdh_derive(vpecdhctx, secret, &secretlen, outlen) == 0
+ || secretlen != outlen) {
+ OPENSSL_clear_free(secret, secretlen);
+ return NULL;
+ }
+
+ params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
+ (void *)secret, outlen);
+
+ /* This is mandatory, no need to check for its presence */
+ ret = import(provctx, OSSL_SKEYMGMT_SELECT_SECRET_KEY, params);
+ OPENSSL_clear_free(secret, secretlen);
+
+ return ret;
+}
+
const OSSL_DISPATCH ossl_ecdh_keyexch_functions[] = {
{ OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx },
{ OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init },
{ OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive },
+ { OSSL_FUNC_KEYEXCH_DERIVE_SKEY, (void (*)(void))ecdh_derive_skey },
{ OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdh_set_peer },
{ OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdh_freectx },
{ OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecdh_dupctx },
unsigned char *pub1 = NULL , *pub2 = NULL;
OSSL_PARAM_BLD *param_bld = NULL;
OSSL_PARAM *params1 = NULL, *params2 = NULL;
+ const unsigned char *export = NULL;
+ size_t export_size = 0;
+ EVP_SKEY *skey = NULL;
/* Do some setup */
nid = curves[id].nid;
|| !TEST_mem_eq(buf1, t, buf2, sslen))
goto err;
+ /* compute keyexchange once more using the EVP_SKEY export */
+ EVP_PKEY_CTX_free(pctx1);
+ if (!TEST_ptr(pctx1 = EVP_PKEY_CTX_new(pkey1, NULL))
+ || !TEST_int_eq(EVP_PKEY_derive_init(pctx1), 1)
+ || !TEST_int_eq(EVP_PKEY_derive_set_peer(pctx1, pkey2), 1)
+ || !TEST_ptr(skey = EVP_PKEY_derive_SKEY(pctx1, NULL, OSSL_SKEY_TYPE_GENERIC,
+ NULL, t, NULL))
+ || !TEST_int_eq(EVP_SKEY_get0_raw_key(skey, &export, &export_size), 1)
+ /* compare with previous result */
+ || !TEST_mem_eq(export, export_size, buf2, sslen))
+ goto err;
+
ret = 1;
err:
+ EVP_SKEY_free(skey);
BN_CTX_end(ctx);
BN_CTX_free(ctx);
OSSL_PARAM_BLD_free(param_bld);
}
#ifndef OPENSSL_NO_SCRYPT
-static int test_kdf_scrypt(void)
+static int test_kdf_scrypt(int index)
{
int ret = 0;
EVP_PKEY_CTX *pctx;
TEST_error("EVP_PKEY_CTX_set_maxmem_bytes");
goto err;
}
- if (EVP_PKEY_derive(pctx, out, &outlen) <= 0) {
- TEST_error("EVP_PKEY_derive");
+ if (index == 0) {
+ if (EVP_PKEY_derive(pctx, out, &outlen) <= 0) {
+ TEST_error("EVP_PKEY_derive");
+ goto err;
+ }
+ } else if (index == 1) {
+ EVP_SKEY *skey = NULL;
+ const unsigned char *key = NULL;
+ size_t keysize = 0;
+
+ if ((skey = EVP_PKEY_derive_SKEY(pctx, NULL, "GENERIC", NULL,
+ outlen, NULL)) == NULL) {
+ TEST_error("EVP_PKEY_derive_SKEY");
+ goto err;
+ }
+ if (!TEST_int_gt(EVP_SKEY_get0_raw_key(skey, &key, &keysize), 0))
+ goto err;
+ memcpy(out, key, keysize);
+ EVP_SKEY_free(skey);
+ } else {
goto err;
}
ADD_ALL_TESTS(test_kdf_tls1_prf, tests);
ADD_ALL_TESTS(test_kdf_hkdf, tests);
#ifndef OPENSSL_NO_SCRYPT
- ADD_TEST(test_kdf_scrypt);
+ ADD_ALL_TESTS(test_kdf_scrypt, 1);
#endif
return 1;
}