]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Implement EVP_KDF_CTX_set_SKEY
authorSimo Sorce <simo@redhat.com>
Fri, 10 Jan 2025 22:20:59 +0000 (17:20 -0500)
committerNeil Horman <nhorman@openssl.org>
Sun, 31 Aug 2025 01:11:06 +0000 (21:11 -0400)
This allows to use a SKEY as input to a KDF derive operation.

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/kdf_lib.c
crypto/evp/kdf_meth.c
doc/man3/EVP_KDF.pod
doc/man7/provider-kdf.pod
include/crypto/evp.h
include/openssl/core_dispatch.h
include/openssl/kdf.h
providers/implementations/kdfs/pbkdf1.c.in
test/evp_kdf_test.c

index 2eb0eb1a6e91b9ea9dfa8a62dad82e3be6b7f01f..bd9564d3851d4d01656eee85f0777c39dc8a47cf 100644 (file)
@@ -19,6 +19,7 @@
 #include "internal/numbers.h"
 #include "internal/provider.h"
 #include "evp_local.h"
+#include "internal/param_build_set.h"
 
 EVP_KDF_CTX *EVP_KDF_CTX_new(EVP_KDF *kdf)
 {
@@ -144,9 +145,64 @@ int EVP_KDF_derive(EVP_KDF_CTX *ctx, unsigned char *key, size_t keylen,
     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[])
+struct convert_key {
+    const char *name;
+    OSSL_PARAM *param;
+};
+
+static int convert_key_cb(const OSSL_PARAM params[], void *arg)
+{
+    struct convert_key *ckey = arg;
+    const OSSL_PARAM *raw_bytes;
+    unsigned char *data;
+    size_t len;
+
+    raw_bytes = OSSL_PARAM_locate_const(params, OSSL_SKEY_PARAM_RAW_BYTES);
+    if (raw_bytes == NULL)
+        return 0;
+
+    if (!OSSL_PARAM_get_octet_string_ptr(raw_bytes, (const void **)&data, &len))
+        return 0;
+
+    *ckey->param = OSSL_PARAM_construct_octet_string(ckey->name, data, len);
+    return 1;
+}
+
+int EVP_KDF_CTX_set_SKEY(EVP_KDF_CTX *ctx, EVP_SKEY *key, const char *paramname)
+{
+    struct convert_key ckey;
+    OSSL_PARAM params[2] = {
+        OSSL_PARAM_END,
+        OSSL_PARAM_END,
+    };
+
+    if (ctx == NULL)
+        return 0;
+
+    ckey.name = (paramname != NULL) ? paramname : OSSL_KDF_PARAM_KEY;
+
+    if (ctx->meth->set_skey != NULL && ctx->meth->prov == key->skeymgmt->prov)
+        return ctx->meth->set_skey(ctx->algctx, key->keydata, ckey.name);
+
+    /*
+     * We can't use the opaque key directly.
+     * Let's try to export it and set the ctx params in a traditional manner.
+     */
+    ckey.param = &params[0];
+
+    if (!ctx->meth->set_ctx_params)
+        return 0;
+
+    if (EVP_SKEY_export(key, OSSL_SKEYMGMT_SELECT_SECRET_KEY,
+                        convert_key_cb, &ckey))
+        return ctx->meth->set_ctx_params(ctx->algctx, params);
+
+    return 0;
+}
+
+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[])
 {
     EVP_SKEYMGMT *skeymgmt = NULL;
     EVP_SKEY *ret = NULL;
index 233fdf25e0ad4b63965e30cbb4e5b89839c98ee2..65c875f2cc9eebf8d8344b4a17cf210df3715ff5 100644 (file)
@@ -136,6 +136,11 @@ static void *evp_kdf_from_algorithm(int name_id,
                 break;
             kdf->set_ctx_params = OSSL_FUNC_kdf_set_ctx_params(fns);
             break;
+        case OSSL_FUNC_KDF_SET_SKEY:
+            if (kdf->set_skey != NULL)
+                break;
+            kdf->set_skey = OSSL_FUNC_kdf_set_skey(fns);
+            break;
         case OSSL_FUNC_KDF_DERIVE_SKEY:
             if (kdf->derive_skey != NULL)
                 break;
index 3c87668760f205b0ff8b1b05eb63463791331bbf..0c597b38d14714bed17dd68a7ff114e2b0001b10 100644 (file)
@@ -4,7 +4,8 @@
 
 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_derive_SKEY,
+EVP_KDF_CTX_reset, EVP_KDF_derive,
+EVP_KDF_CTX_set_SKEY, 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,
@@ -64,8 +65,8 @@ 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() 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.
+EVP_KDF_CTX_set_params() or EVP_KDF_CTX_set_SKEY() before calling
+EVP_KDF_derive() or EVP_KDF_derive_SKEY() to derive the key.
 
 =head2 Types
 
@@ -118,7 +119,13 @@ 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.
+will try to perform export/import through the raw format.
+
+EVP_KDF_CTX_set_SKEY() allows setting an skey object as the input parameter for
+the derivation functions. As different KDFs may accept several parameters as
+key names, we can specify the particular parameter name we set.  If null is
+passed, the parameter B<OSSL_KDF_PARAM_KEY> is implied.  It is used when the
+input key is represented by B<EVP_SKEY> rather than raw bytes.
 
 EVP_KDF_get_params() retrieves details about the implementation
 I<kdf>.
index 4d842349af4b4bd434e14e2f8b0ad16bd0762b68..51364d33f87bea19180b6ecd490e667a45ed85ba 100644 (file)
@@ -39,6 +39,7 @@ provider-kdf - The KDF library E<lt>-E<gt> provider functions
  int OSSL_FUNC_kdf_get_params(OSSL_PARAM params[]);
  int OSSL_FUNC_kdf_get_ctx_params(void *kctx, OSSL_PARAM params[]);
  int OSSL_FUNC_kdf_set_ctx_params(void *kctx, const OSSL_PARAM params[]);
+ int OSSL_FUNC_kdf_set_skey(void *kctx, void *skeydata, const char *paramname);
 
 =head1 DESCRIPTION
 
@@ -83,6 +84,7 @@ macros in L<openssl-core_dispatch.h(7)>, as follows:
  OSSL_FUNC_kdf_gettable_params      OSSL_FUNC_KDF_GETTABLE_PARAMS
  OSSL_FUNC_kdf_gettable_ctx_params  OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS
  OSSL_FUNC_kdf_settable_ctx_params  OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS
+ OSSL_FUNC_kdf_set_skey             OSSL_FUNC_KDF_SET_SKEY
 
 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
@@ -151,6 +153,8 @@ with the provider side context I<kctx> in its current state if it is
 not NULL.  Otherwise, they return the parameters associated with the
 provider side algorithm I<provctx>.
 
+OSSL_FUNF_kdf_set_skey() sets the input key for KDF functions that take a
+key as input.
 
 Parameters currently recognised by built-in KDFs are as follows. Not all
 parameters are relevant to, or are understood by all KDFs:
@@ -334,8 +338,8 @@ OSSL_FUNC_kdf_newctx() and OSSL_FUNC_kdf_dupctx() should return the newly create
 provider side KDF context, or NULL on failure.
 
 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.
+OSSL_FUNC_kdf_get_ctx_params(), OSSL_FUNC_kdf_set_ctx_params() and
+OSSL_FUNC_kdf_set_skey() should return 1 for success or 0 on error.
 
 OSSL_FUNC_kdf_gettable_params(), OSSL_FUNC_kdf_gettable_ctx_params() and
 OSSL_FUNC_kdf_settable_ctx_params() should return a constant L<OSSL_PARAM(3)>
index 24158eee985d2f1842011cf5c7369c8654c669fc..ed867f77fbc981d2e6af276976f5f6446378e8c3 100644 (file)
@@ -247,6 +247,7 @@ struct evp_kdf_st {
     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_set_skey_fn *set_skey;
     OSSL_FUNC_kdf_derive_skey_fn *derive_skey;
 };
 
index 41c421248263c71ba798262122cab6d4df945188..d535d6b5375e91cd580b2b4ab05d7469e96cec5a 100644 (file)
@@ -562,7 +562,8 @@ OSSL_CORE_MAKE_FUNC(const char *, skeymgmt_get_key_id, (void *keydata))
 # 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
+# define OSSL_FUNC_KDF_SET_SKEY                     12
+# define OSSL_FUNC_KDF_DERIVE_SKEY                  13
 
 OSSL_CORE_MAKE_FUNC(void *, kdf_newctx, (void *provctx))
 OSSL_CORE_MAKE_FUNC(void *, kdf_dupctx, (void *src))
index 4a320007951125b522863eb1f2edc21b80b7c4fb..8fb2c63f750c9c36f101aaad6b42eb9fef9b9ca8 100644 (file)
@@ -43,9 +43,10 @@ void EVP_KDF_CTX_reset(EVP_KDF_CTX *ctx);
 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_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_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[]);
index 9602c7d6bc253384575cca4b5211cf60dcc7d8e8..be9a17514cd623934d0ffe05f5c74ffdbb7e7c15 100644 (file)
@@ -21,7 +21,9 @@ use OpenSSL::paramnames qw(produce_param_decoder);
 #include "internal/common.h"
 #include "internal/cryptlib.h"
 #include "internal/numbers.h"
+#include "internal/skey.h"
 #include "crypto/evp.h"
+#include "crypto/types.h"
 #include "prov/provider_ctx.h"
 #include "prov/providercommon.h"
 #include "prov/implementations.h"
@@ -36,6 +38,8 @@ static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pbkdf1_settable_ctx_params;
 static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pbkdf1_set_ctx_params;
 static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pbkdf1_gettable_ctx_params;
 static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pbkdf1_get_ctx_params;
+static OSSL_FUNC_kdf_set_skey_fn kdf_pbkdf1_set_skey;
+static OSSL_FUNC_kdf_derive_skey_fn kdf_pbkdf1_derive_skey;
 
 typedef struct {
     void *provctx;
@@ -178,6 +182,27 @@ static int kdf_pbkdf1_set_membuf(unsigned char **buffer, size_t *buflen,
     return 1;
 }
 
+static int kdf_pbkdf1_set_membuf_skey(unsigned char **buffer, size_t *buflen,
+                                      const PROV_SKEY *pskey)
+{
+    OPENSSL_clear_free(*buffer, *buflen);
+    *buffer = NULL;
+    *buflen = 0;
+
+    if (pskey->length == 0) {
+        if ((*buffer = OPENSSL_malloc(1)) == NULL)
+            return 0;
+    } else if (pskey->data != NULL) {
+        *buffer = OPENSSL_malloc(pskey->length);
+        if (*buffer == NULL)
+            return 0;
+
+        memcpy(*buffer, pskey->data, pskey->length);
+        *buflen = pskey->length;
+    }
+    return 1;
+}
+
 static int kdf_pbkdf1_derive(void *vctx, unsigned char *key, size_t keylen,
                              const OSSL_PARAM params[])
 {
@@ -266,6 +291,51 @@ static const OSSL_PARAM *kdf_pbkdf1_gettable_ctx_params(ossl_unused void *ctx,
     return pbkdf1_get_ctx_params_list;
 }
 
+static int kdf_pbkdf1_set_skey(void *vctx, void *skeydata, const char *paramname)
+{
+    KDF_PBKDF1 *ctx = (KDF_PBKDF1 *)vctx;
+    PROV_SKEY *pskey = (PROV_SKEY *)skeydata;
+
+    if (paramname == NULL || skeydata == NULL)
+        return 0;
+
+    if (strcmp(paramname, OSSL_KDF_PARAM_PASSWORD) == 0)
+        return kdf_pbkdf1_set_membuf_skey(&ctx->pass, &ctx->pass_len, pskey);
+
+    if (strcmp(paramname, OSSL_KDF_PARAM_SALT) == 0)
+        return kdf_pbkdf1_set_membuf_skey(&ctx->salt, &ctx->salt_len, pskey);
+
+    return 0;
+}
+
+static
+void *kdf_pbkdf1_derive_skey(void *vctx, void *provctx, OSSL_FUNC_skeymgmt_import_fn *import,
+                             size_t keylen, const OSSL_PARAM params[])
+{
+    unsigned char *key = NULL;
+    void *ret = NULL;
+    OSSL_PARAM import_params[2] = {OSSL_PARAM_END, OSSL_PARAM_END};
+
+    if (import == NULL || keylen == 0)
+        return NULL;
+
+    if ((key = OPENSSL_zalloc(keylen)) == NULL)
+        return NULL;
+
+    if (kdf_pbkdf1_derive(vctx, key, keylen, params) == 0) {
+        OPENSSL_free(key);
+        return NULL;
+    }
+
+    import_params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
+                                                         (void *)key, keylen);
+
+    ret = import(provctx, OSSL_SKEYMGMT_SELECT_SECRET_KEY, import_params);
+    OPENSSL_free(key);
+
+    return ret;
+}
+
 const OSSL_DISPATCH ossl_kdf_pbkdf1_functions[] = {
     { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pbkdf1_new },
     { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_pbkdf1_dup },
@@ -278,5 +348,7 @@ const OSSL_DISPATCH ossl_kdf_pbkdf1_functions[] = {
     { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
       (void(*)(void))kdf_pbkdf1_gettable_ctx_params },
     { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pbkdf1_get_ctx_params },
+    { OSSL_FUNC_KDF_SET_SKEY, (void(*)(void))kdf_pbkdf1_set_skey },
+    { OSSL_FUNC_KDF_DERIVE_SKEY, (void(*)(void))kdf_pbkdf1_derive_skey },
     OSSL_DISPATCH_END
 };
index 9e67641a66af70fa8111c01558b4e87455ddda18..7a07168bc6676f9f472e8dace2c9f71a512e60a8 100644 (file)
@@ -790,6 +790,67 @@ err:
     return ret;
 }
 
+static int test_kdf_pbkdf1_skey(void)
+{
+    int ret = 0;
+    EVP_KDF_CTX *kctx = NULL;
+    unsigned char out[25];
+    unsigned int iterations = 4096;
+    OSSL_LIB_CTX *libctx = NULL;
+    OSSL_PARAM *params = NULL;
+    OSSL_PROVIDER *legacyprov = NULL;
+    OSSL_PROVIDER *defprov = NULL;
+    EVP_SKEY *skey_in = NULL, *skey_out = NULL;
+    unsigned char salt[] = "saltSALTsaltSALTsaltSALTsaltSALTsalt";
+    const unsigned char expected[sizeof(out)] = {
+        0xfb, 0x83, 0x4d, 0x36, 0x6d, 0xbc, 0x53, 0x87, 0x35, 0x1b, 0x34, 0x75,
+        0x95, 0x88, 0x32, 0x4f, 0x3e, 0x82, 0x81, 0x01, 0x21, 0x93, 0x64, 0x00,
+        0xcc
+    };
+    const unsigned char *export = NULL;
+    size_t export_size = 0;
+
+    if (!TEST_ptr(libctx = OSSL_LIB_CTX_new()))
+        goto err;
+
+    /* PBKDF1 only available in the legacy provider */
+    legacyprov = OSSL_PROVIDER_load(libctx, "legacy");
+    if (legacyprov == NULL) {
+        OSSL_LIB_CTX_free(libctx);
+        return TEST_skip("PBKDF1 only available in legacy provider");
+    }
+
+    if (!TEST_ptr(defprov = OSSL_PROVIDER_load(libctx, "default")))
+        goto err;
+
+    params = construct_pbkdf1_params("passwordPASSWORDpassword", "sha256",
+                                     "saltSALT",
+                                     &iterations);
+
+    if (!TEST_ptr(params)
+        || !TEST_ptr(skey_in = EVP_SKEY_import_raw_key(libctx, OSSL_SKEY_TYPE_GENERIC,
+                                                       salt, strlen((char *)salt), NULL))
+        || !TEST_ptr(kctx = get_kdfbyname_libctx(libctx, OSSL_KDF_NAME_PBKDF1))
+        || !TEST_true(EVP_KDF_CTX_set_params(kctx, params))
+        || !TEST_true(EVP_KDF_CTX_set_SKEY(kctx, skey_in, OSSL_KDF_PARAM_SALT))
+        || !TEST_ptr(skey_out = EVP_KDF_derive_SKEY(kctx, NULL, OSSL_SKEY_TYPE_GENERIC,
+                                                    NULL, sizeof(out), NULL))
+        || !TEST_int_eq(EVP_SKEY_get0_raw_key(skey_out, &export, &export_size), 1)
+        || !TEST_mem_eq(export, export_size, expected, sizeof(expected)))
+        goto err;
+
+    ret = 1;
+err:
+    EVP_SKEY_free(skey_in);
+    EVP_SKEY_free(skey_out);
+    EVP_KDF_CTX_free(kctx);
+    OPENSSL_free(params);
+    OSSL_PROVIDER_unload(defprov);
+    OSSL_PROVIDER_unload(legacyprov);
+    OSSL_LIB_CTX_free(libctx);
+    return ret;
+}
+
 static int test_kdf_pbkdf1_key_too_long(void)
 {
     int ret = 0;
@@ -2282,6 +2343,7 @@ err:
 int setup_tests(void)
 {
     ADD_TEST(test_kdf_pbkdf1);
+    ADD_TEST(test_kdf_pbkdf1_skey);
     ADD_TEST(test_kdf_pbkdf1_key_too_long);
 #if !defined(OPENSSL_NO_CMAC) && !defined(OPENSSL_NO_CAMELLIA)
     ADD_TEST(test_kdf_kbkdf_6803_128);