From ac2d58c72b4dc4a8c74eef893000306bf78a30fd Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 3 Jul 2020 16:18:03 +0100 Subject: Implement a EVP_PKEY KDF to KDF provider bridge Some KDF implementations were available before the current EVP_KDF API. They were used via EVP_PKEY_derive. There exists a bridge between the old API and the EVP_KDF API however this bridge itself uses a legacy EVP_PKEY_METHOD. This commit implements a provider side bridge without having to use any legacy code. Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/12573) --- providers/implementations/exchange/build.info | 3 + providers/implementations/exchange/kdf_exch.c | 148 ++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 providers/implementations/exchange/kdf_exch.c (limited to 'providers/implementations/exchange') diff --git a/providers/implementations/exchange/build.info b/providers/implementations/exchange/build.info index 3127f9a3e7..92932b9d28 100644 --- a/providers/implementations/exchange/build.info +++ b/providers/implementations/exchange/build.info @@ -4,6 +4,7 @@ $DH_GOAL=../../libimplementations.a $ECX_GOAL=../../libimplementations.a $ECDH_GOAL=../../libimplementations.a +$KDF_GOAL=../../libimplementations.a IF[{- !$disabled{dh} -}] SOURCE[$DH_GOAL]=dh_exch.c @@ -25,3 +26,5 @@ IF[{- !$disabled{ec} -}] SOURCE[../../libfips.a]=ecdh_exch.c SOURCE[../../libnonfips.a]=ecdh_exch.c ENDIF + +SOURCE[$KDF_GOAL]=kdf_exch.c diff --git a/providers/implementations/exchange/kdf_exch.c b/providers/implementations/exchange/kdf_exch.c new file mode 100644 index 0000000000..41278e6389 --- /dev/null +++ b/providers/implementations/exchange/kdf_exch.c @@ -0,0 +1,148 @@ +/* + * Copyright 2020 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/kdfexchange.h" + +static OSSL_FUNC_keyexch_newctx_fn kdf_newctx; +static OSSL_FUNC_keyexch_init_fn kdf_init; +static OSSL_FUNC_keyexch_derive_fn kdf_derive; +static OSSL_FUNC_keyexch_freectx_fn kdf_freectx; +static OSSL_FUNC_keyexch_dupctx_fn kdf_dupctx; +static OSSL_FUNC_keyexch_set_ctx_params_fn kdf_set_ctx_params; +static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_settable_ctx_params; + +typedef struct { + void *provctx; + EVP_KDF_CTX *kdfctx; + KDF_DATA *kdfdata; +} PROV_KDF_CTX; + +static void *kdf_newctx(void *provctx) +{ + PROV_KDF_CTX *kdfctx = OPENSSL_zalloc(sizeof(PROV_KDF_CTX)); + EVP_KDF *kdf = NULL; + + if (kdfctx == NULL) + return NULL; + + kdfctx->provctx = provctx; + + kdf = EVP_KDF_fetch(PROV_LIBRARY_CONTEXT_OF(provctx), "TLS1-PRF", NULL); + if (kdf == NULL) + goto err; + kdfctx->kdfctx = EVP_KDF_new_ctx(kdf); + EVP_KDF_free(kdf); + + if (kdfctx->kdfctx == NULL) + goto err; + + return kdfctx; + err: + OPENSSL_free(kdfctx); + return NULL; +} + +static int kdf_init(void *vpkdfctx, void *vkdf) +{ + PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx; + + if (pkdfctx == NULL || vkdf == NULL || !kdf_data_up_ref(vkdf)) + return 0; + pkdfctx->kdfdata = vkdf; + + return 1; +} + +static int kdf_derive(void *vpkdfctx, unsigned char *secret, size_t *secretlen, + size_t outlen) +{ + PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx; + + return EVP_KDF_derive(pkdfctx->kdfctx, secret, *secretlen); +} + +static void kdf_freectx(void *vpkdfctx) +{ + PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx; + + EVP_KDF_CTX_free(pkdfctx->kdfctx); + kdf_data_free(pkdfctx->kdfdata); + + OPENSSL_free(pkdfctx); +} + +static void *kdf_dupctx(void *vpkdfctx) +{ + PROV_KDF_CTX *srcctx = (PROV_KDF_CTX *)vpkdfctx; + PROV_KDF_CTX *dstctx; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + + dstctx->kdfctx = EVP_KDF_dup_ctx(srcctx->kdfctx); + if (dstctx->kdfctx == NULL) { + OPENSSL_free(dstctx); + return NULL; + } + if (!kdf_data_up_ref(dstctx->kdfdata)) { + EVP_KDF_CTX_free(dstctx->kdfctx); + OPENSSL_free(dstctx); + return NULL; + } + + return dstctx; +} + +static int kdf_set_ctx_params(void *vpkdfctx, const OSSL_PARAM params[]) +{ + PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx; + + return EVP_KDF_set_ctx_params(pkdfctx->kdfctx, params); +} + + +static const OSSL_PARAM *kdf_settable_ctx_params(void) +{ + /* + * TODO(3.0): FIXME FIXME!! These settable_ctx_params functions should + * should have a provctx argument so we can get hold of the libctx. + */ + EVP_KDF *kdf = EVP_KDF_fetch(NULL, "TLS1-PRF", NULL); + const OSSL_PARAM *params; + + if (kdf == NULL) + return NULL; + + params = EVP_KDF_settable_ctx_params(kdf); + EVP_KDF_free(kdf); + + return params; +} + +const OSSL_DISPATCH kdf_keyexch_functions[] = { + { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))kdf_newctx }, + { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))kdf_init }, + { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))kdf_derive }, + { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))kdf_freectx }, + { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))kdf_dupctx }, + { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))kdf_set_ctx_params }, + { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, + (void (*)(void))kdf_settable_ctx_params }, + { 0, NULL } +}; -- cgit v1.2.3