Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 145 additions & 75 deletions src/wp_kdf_exch.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,35 @@
#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>
#include <openssl/params.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>

#include <wolfprovider/alg_funcs.h>


/**
* Key Derivation Function (KDF) context.
*
* Calls through to EVP API.
* Drives the wolfProvider KDF implementation directly through its dispatch
* table so the derivation cannot be satisfied by another provider.
*/
typedef struct wp_KdfCtx {
/** Provider context - useful for duplication. */
WOLFPROV_CTX* provCtx;

/** EVP KDF context object. */
EVP_KDF_CTX* kdfCtx;
/** wolfProvider KDF dispatch table - useful for duplication. */
const OSSL_DISPATCH* kdfDisp;
/** wolfProvider KDF implementation context object. */
void* kctx;
/** Free the wolfProvider KDF context. */
OSSL_FUNC_kdf_freectx_fn* freeCtx;
/** Derive a key with the wolfProvider KDF. */
OSSL_FUNC_kdf_derive_fn* derive;
/** Set parameters into the wolfProvider KDF context. */
OSSL_FUNC_kdf_set_ctx_params_fn* setParams;
/** Get parameters from the wolfProvider KDF context. */
OSSL_FUNC_kdf_get_ctx_params_fn* getParams;
/** Get the list of gettable parameters from the wolfProvider KDF. */
OSSL_FUNC_kdf_gettable_ctx_params_fn* gettableParams;

/** Dummy KDF key. */
wp_Kdf* key;
/** Name of KDF. */
Expand All @@ -52,47 +63,90 @@ typedef struct wp_KdfCtx {
static int wp_kdf_set_ctx_params(wp_KdfCtx* ctx, const OSSL_PARAM params[]);


/**
* Resolve the wolfProvider KDF implementation from its dispatch table.
*
* Creates the backing KDF context so the derivation is always performed by
* wolfProvider, never delegated to another provider via an EVP fetch.
*
* @param [in, out] ctx KDF key exchange context object.
* @param [in] kdfDisp wolfProvider KDF dispatch table.
* @return 1 on success.
* @return 0 when a required function is missing or context creation fails.
*/
static int wp_kdf_ctx_load(wp_KdfCtx* ctx, const OSSL_DISPATCH* kdfDisp)
{
int ok = 1;
OSSL_FUNC_kdf_newctx_fn* newCtx = NULL;
const OSSL_DISPATCH* d;

for (d = kdfDisp; d->function_id != 0; d++) {
switch (d->function_id) {
case OSSL_FUNC_KDF_NEWCTX:
newCtx = OSSL_FUNC_kdf_newctx(d);
break;
case OSSL_FUNC_KDF_FREECTX:
ctx->freeCtx = OSSL_FUNC_kdf_freectx(d);
break;
case OSSL_FUNC_KDF_DERIVE:
ctx->derive = OSSL_FUNC_kdf_derive(d);
break;
case OSSL_FUNC_KDF_SET_CTX_PARAMS:
ctx->setParams = OSSL_FUNC_kdf_set_ctx_params(d);
break;
case OSSL_FUNC_KDF_GET_CTX_PARAMS:
ctx->getParams = OSSL_FUNC_kdf_get_ctx_params(d);
break;
case OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS:
ctx->gettableParams = OSSL_FUNC_kdf_gettable_ctx_params(d);
break;
default:
break;
}
}

if ((newCtx == NULL) || (ctx->freeCtx == NULL) || (ctx->derive == NULL) ||
(ctx->setParams == NULL) || (ctx->getParams == NULL)) {
ok = 0;
}
if (ok) {
ctx->kdfDisp = kdfDisp;
ctx->kctx = newCtx(ctx->provCtx);
if (ctx->kctx == NULL) {
ok = 0;
}
}

return ok;
}

/**
* Create a new KDF key exchange context object.
*
* @param [in] provCtx Provider context.
* @param [in] name Name of KDF.
* @param [in] kdfDisp wolfProvider KDF dispatch table for name.
* @return KDF key exchange object on success.
* @return NULL on failure.
*/
static wp_KdfCtx* wp_kdf_ctx_new(WOLFPROV_CTX* provCtx, const char* name)
static wp_KdfCtx* wp_kdf_ctx_new(WOLFPROV_CTX* provCtx, const char* name,
const OSSL_DISPATCH* kdfDisp)
{
wp_KdfCtx* ctx = NULL;
EVP_KDF* kdf = NULL;

if (wolfssl_prov_is_running()) {
ctx = OPENSSL_zalloc(sizeof(*ctx));
}
if (ctx != NULL) {
int ok = 1;

kdf = EVP_KDF_fetch(provCtx->libCtx, name, NULL);
if (kdf == NULL) {
ok = 0;
}
if (ok) {
ctx->kdfCtx = EVP_KDF_CTX_new(kdf);
if (ctx->kdfCtx == NULL) {
ok = 0;
}
}
if (ok) {
ctx->provCtx = provCtx;
ctx->name = name;
}

if (!ok) {
}
if (ctx != NULL) {
ctx->provCtx = provCtx;
ctx->name = name;
/* On load failure kctx is always NULL, so there is nothing to free. */
if (!wp_kdf_ctx_load(ctx, kdfDisp)) {
OPENSSL_free(ctx);
ctx = NULL;
}
}

EVP_KDF_free(kdf);
return ctx;
}

Expand All @@ -105,7 +159,9 @@ static void wp_kdf_ctx_free(wp_KdfCtx* ctx)
{
if (ctx != NULL) {
wp_kdf_free(ctx->key);
EVP_KDF_CTX_free(ctx->kdfCtx);
if ((ctx->freeCtx != NULL) && (ctx->kctx != NULL)) {
ctx->freeCtx(ctx->kctx);
}
OPENSSL_free(ctx);
}
}
Expand All @@ -122,7 +178,7 @@ static wp_KdfCtx* wp_kdf_ctx_dup(wp_KdfCtx* src)
wp_KdfCtx* dst = NULL;

if (wolfssl_prov_is_running()) {
dst = wp_kdf_ctx_new(src->provCtx, src->name);
dst = wp_kdf_ctx_new(src->provCtx, src->name, src->kdfDisp);
}
if (dst != NULL) {
int ok = 1;
Comment thread
yosuke-wolfssl marked this conversation as resolved.
Expand Down Expand Up @@ -201,9 +257,19 @@ static int wp_kdf_derive(wp_KdfCtx* ctx, unsigned char* secret, size_t* secLen,
}

if (ok && (secret == NULL)) {
*secLen = EVP_KDF_CTX_get_kdf_size(ctx->kdfCtx);
OSSL_PARAM params[2];
size_t sz = 0;

params[0] = OSSL_PARAM_construct_size_t(OSSL_KDF_PARAM_SIZE, &sz);
params[1] = OSSL_PARAM_construct_end();
if (!ctx->getParams(ctx->kctx, params)) {
ok = 0;
}
else {
*secLen = sz;
}
}
else if (ok && !EVP_KDF_derive(ctx->kdfCtx, secret, secSize, NULL)) {
else if (ok && !ctx->derive(ctx->kctx, secret, secSize, NULL)) {
ok = 0;
}

Expand All @@ -221,7 +287,7 @@ static int wp_kdf_derive(wp_KdfCtx* ctx, unsigned char* secret, size_t* secLen,
*/
static int wp_kdf_set_ctx_params(wp_KdfCtx* ctx, const OSSL_PARAM params[])
{
return EVP_KDF_CTX_set_params(ctx->kdfCtx, params);
return ctx->setParams(ctx->kctx, params);
}

/**
Expand All @@ -241,7 +307,7 @@ static int wp_kdf_get_ctx_params(wp_KdfCtx* ctx, OSSL_PARAM params[])
if (!wolfssl_prov_is_running()) {
ok = 0;
}
if (ok && !EVP_KDF_CTX_get_params(ctx->kdfCtx, params)) {
if (ok && !ctx->getParams(ctx->kctx, params)) {
ok = 0;
}

Expand All @@ -262,11 +328,11 @@ static const OSSL_PARAM* wp_kdf_gettable_ctx_params(wp_KdfCtx* ctx,
{
const OSSL_PARAM* params = NULL;

(void)provCtx;
(void)kdfName;

if (wolfssl_prov_is_running() && ctx != NULL && ctx->kdfCtx != NULL) {
params = EVP_KDF_CTX_gettable_params(ctx->kdfCtx);
if (wolfssl_prov_is_running() && (ctx != NULL) && (ctx->kctx != NULL) &&
(ctx->gettableParams != NULL)) {
params = ctx->gettableParams(ctx->kctx, provCtx);
}

return params;
Expand Down Expand Up @@ -297,28 +363,6 @@ static const OSSL_PARAM* wp_hkdf_settable_ctx_params(wp_KdfCtx* ctx,
return settable_ctx_params;
}

/**
* Return an array of supported settable parameters for the HKDF ke context.
*
* @param [in] ctx ECDH key exchange context object. Unused.
* @param [in] provCtx Provider context object. Unused.
* @return Array of parameters with data type.
*/
static const OSSL_PARAM* wp_tls1_prf_settable_ctx_params(wp_KdfCtx* ctx,
WOLFPROV_CTX* provCtx)
{
(void)ctx;
(void)provCtx;
static const OSSL_PARAM settable_ctx_params[] = {
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0),
OSSL_PARAM_END
};
return settable_ctx_params;
}

/**
* Return an array of supported gettable parameters for the HKDF ke context.
*
Expand All @@ -332,19 +376,6 @@ static const OSSL_PARAM* wp_hkdf_gettable_ctx_params(wp_KdfCtx* ctx,
return wp_kdf_gettable_ctx_params(ctx, provCtx, "HKDF");
}

/**
* Return an array of supported gettable parameters for the TLS1-PRF ke context.
*
* @param [in] ctx KDF key exchange context object. Unused.
* @param [in] provCtx Provider context object.
* @return Array of parameters with data type.
*/
static const OSSL_PARAM* wp_tls1_prf_gettable_ctx_params(wp_KdfCtx* ctx,
WOLFPROV_CTX* provCtx)
{
return wp_kdf_gettable_ctx_params(ctx, provCtx, "TLS1-PRF");
}

/*
* HKDF
*/
Expand All @@ -358,7 +389,7 @@ static const OSSL_PARAM* wp_tls1_prf_gettable_ctx_params(wp_KdfCtx* ctx,
*/
static wp_KdfCtx* wp_hkdf_ctx_new(WOLFPROV_CTX* provCtx)
{
return wp_kdf_ctx_new(provCtx, "HKDF");
return wp_kdf_ctx_new(provCtx, "HKDF", wp_kdf_hkdf_functions);
}

/** Dispatch table for HKDF key exchange. */
Expand All @@ -381,6 +412,43 @@ const OSSL_DISPATCH wp_hkdf_keyexch_functions[] = {
* TLS1 PRF
*/

#ifdef WP_HAVE_TLS1_PRF

/**
* Return an array of supported settable parameters for the TLS1-PRF ke context.
*
* @param [in] ctx ECDH key exchange context object. Unused.
* @param [in] provCtx Provider context object. Unused.
* @return Array of parameters with data type.
*/
static const OSSL_PARAM* wp_tls1_prf_settable_ctx_params(wp_KdfCtx* ctx,
WOLFPROV_CTX* provCtx)
{
(void)ctx;
(void)provCtx;
static const OSSL_PARAM settable_ctx_params[] = {
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0),
OSSL_PARAM_END
};
return settable_ctx_params;
}

/**
* Return an array of supported gettable parameters for the TLS1-PRF ke context.
*
* @param [in] ctx KDF key exchange context object. Unused.
* @param [in] provCtx Provider context object.
* @return Array of parameters with data type.
*/
static const OSSL_PARAM* wp_tls1_prf_gettable_ctx_params(wp_KdfCtx* ctx,
WOLFPROV_CTX* provCtx)
{
return wp_kdf_gettable_ctx_params(ctx, provCtx, "TLS1-PRF");
}

/**
* Create a new TLS1 PRF key exchange context object.
*
Expand All @@ -390,7 +458,7 @@ const OSSL_DISPATCH wp_hkdf_keyexch_functions[] = {
*/
static wp_KdfCtx* wp_tls1_prf_ctx_new(WOLFPROV_CTX* provCtx)
{
return wp_kdf_ctx_new(provCtx, "TLS1-PRF");
return wp_kdf_ctx_new(provCtx, "TLS1-PRF", wp_kdf_tls1_prf_functions);
}

/** Dispatch table for TLS1 PRF key exchange. */
Expand All @@ -409,3 +477,5 @@ const OSSL_DISPATCH wp_tls1_prf_keyexch_functions[] = {
{ 0, NULL }
};

#endif /* WP_HAVE_TLS1_PRF */

Loading
Loading