]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Implement EVP_PKEY_derive_SKEY
authorDmitry Belyavskiy <beldmit@gmail.com>
Fri, 15 Nov 2024 15:21:04 +0000 (16:21 +0100)
committerNeil Horman <nhorman@openssl.org>
Sun, 31 Aug 2025 01:11:06 +0000 (21:11 -0400)
Signed-off-by: Dmitry Belyavskiy <beldmit@gmail.com>
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/28369)

crypto/evp/evp_local.h
crypto/evp/exchange.c
doc/man3/EVP_PKEY_derive.pod
doc/man7/provider-keyexch.pod
include/openssl/core_dispatch.h
include/openssl/evp.h
providers/implementations/exchange/ecdh_exch.c.in
test/ectest.c
test/pkey_meth_kdf_test.c

index 9a216c30c849a80514a042e82add662bc65cb961..677711ebea0decb5cab5e2a8e2ddcfd8d2bb3086 100644 (file)
@@ -156,6 +156,7 @@ struct evp_keyexch_st {
     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 {
index dae3a2c5a85c0c13d5751b206cf311739c5b4615..504458bc3eebc6c621368baae4b20a5dcdae4ec1 100644 (file)
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <openssl/core_names.h>
 #include <openssl/crypto.h>
 #include <openssl/evp.h>
 #include <openssl/err.h>
@@ -52,7 +53,7 @@ static void *evp_keyexch_from_algorithm(int name_id,
 {
     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);
@@ -87,7 +88,7 @@ static void *evp_keyexch_from_algorithm(int name_id,
             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)
@@ -126,8 +127,15 @@ static void *evp_keyexch_from_algorithm(int name_id,
                 = 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)) {
@@ -548,6 +556,108 @@ int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen)
         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;
index ec19afad52e4091c6e09bfaa0a814039baf0104b..5bc938d7e32ae3b2e99171b20219cb4ad548380c 100644 (file)
@@ -3,7 +3,8 @@
 =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
@@ -16,6 +17,9 @@ EVP_PKEY_derive_set_peer_ex, EVP_PKEY_derive_set_peer, EVP_PKEY_derive
                                  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
 
@@ -42,6 +46,14 @@ parameter should contain the length of the I<key> buffer, if the call is
 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
@@ -58,6 +70,9 @@ for success and 0 or a negative value for failure.
 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):
@@ -112,9 +127,11 @@ functions were originally added in OpenSSL 1.0.0.
 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
index 1d3604e783a358525f5b6e55262c49b0e7539108..f8fa85a24628d4c6e5f55d0d7cd9fa52cae81a95 100644 (file)
@@ -28,6 +28,9 @@ provider-keyexch - The keyexch library E<lt>-E<gt> provider functions
  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[]);
@@ -73,6 +76,7 @@ macros in L<openssl-core_dispatch.h(7)>, as follows:
  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
@@ -81,7 +85,8 @@ macros in L<openssl-core_dispatch.h(7)>, as follows:
 
 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,
@@ -133,6 +138,9 @@ The length of the shared secret should be written to I<*secretlen>.
 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
@@ -242,6 +250,7 @@ OSSL_FUNC_keyexch_newctx() and OSSL_FUNC_keyexch_dupctx() should return the newl
 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.
 
@@ -259,6 +268,8 @@ The provider KEYEXCH interface was introduced in OpenSSL 3.0.
 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.
index cc152ceeb727b5a8b2917d8a595e68686f8c1380..41c421248263c71ba798262122cab6d4df945188 100644 (file)
@@ -825,6 +825,7 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, keymgmt_export_types_ex,
 # 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,
@@ -842,6 +843,9 @@ OSSL_CORE_MAKE_FUNC(int, keyexch_get_ctx_params, (void *ctx,
                                                      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 */
 
@@ -955,52 +959,6 @@ 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 ec37c22d3f7b399a14fdb8debcbf939afdbbbd4e..61e50b266d62dbd7c9d55ae2f4e458c78396832b 100644 (file)
@@ -2067,6 +2067,9 @@ int EVP_PKEY_derive_set_peer_ex(EVP_PKEY_CTX *ctx, EVP_PKEY *peer,
                                 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,
index 16295b4ad28e6b8c2a3886084b205556e8dc4836..00f2e8101dd19b97958aa9ef23141fc371b7cfb0 100644 (file)
@@ -36,6 +36,7 @@ static OSSL_FUNC_keyexch_newctx_fn ecdh_newctx;
 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;
@@ -617,10 +618,45 @@ int ecdh_derive(void *vpecdhctx, unsigned char *secret,
     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 },
index a1bb1a57767ad40e1bcc7eacaa160a4dc9ec9cf1..d2ffc6514a1a149315cff6cee247afdfed77d719 100644 (file)
@@ -2825,6 +2825,9 @@ static int custom_params_test(int id)
     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;
@@ -3053,9 +3056,22 @@ static int custom_params_test(int id)
             || !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);
index ad58adf48261433947856a2848c6a62669293362..cf4fd6bf18b07cf5777ef52733509a7e048e4787 100644 (file)
@@ -145,7 +145,7 @@ err:
 }
 
 #ifndef OPENSSL_NO_SCRYPT
-static int test_kdf_scrypt(void)
+static int test_kdf_scrypt(int index)
 {
     int ret = 0;
     EVP_PKEY_CTX *pctx;
@@ -192,8 +192,26 @@ static int test_kdf_scrypt(void)
         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;
     }
 
@@ -229,7 +247,7 @@ int setup_tests(void)
     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;
 }