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)
#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)
{
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 = ¶ms[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;
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;
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,
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
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>.
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
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
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:
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)>
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;
};
# 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))
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[]);
#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"
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;
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[])
{
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 },
{ 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
};
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;
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);