From 722fe8edf224ecc0921481b47fdd06a54d82e4ff Mon Sep 17 00:00:00 2001 From: Pauli Date: Thu, 1 Jul 2021 14:10:04 +1000 Subject: kdf: Add PVK KDF to providers. Add PIN Verification Key key derevation function to providers. Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/15968) --- .../implementations/include/prov/implementations.h | 1 + providers/implementations/include/prov/names.h | 1 + providers/implementations/kdfs/build.info | 3 + providers/implementations/kdfs/pvkkdf.c | 227 +++++++++++++++++++++ providers/legacyprov.c | 1 + 5 files changed, 233 insertions(+) create mode 100644 providers/implementations/kdfs/pvkkdf.c diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index e2573ebb4a..66817fa104 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -258,6 +258,7 @@ extern const OSSL_DISPATCH ossl_poly1305_functions[]; /* KDFs / PRFs */ extern const OSSL_DISPATCH ossl_kdf_pbkdf1_functions[]; extern const OSSL_DISPATCH ossl_kdf_pbkdf2_functions[]; +extern const OSSL_DISPATCH ossl_kdf_pvk_functions[]; extern const OSSL_DISPATCH ossl_kdf_pkcs12_functions[]; #ifndef OPENSSL_NO_SCRYPT extern const OSSL_DISPATCH ossl_kdf_scrypt_functions[]; diff --git a/providers/implementations/include/prov/names.h b/providers/implementations/include/prov/names.h index 1509598ffc..62aa7bd725 100644 --- a/providers/implementations/include/prov/names.h +++ b/providers/implementations/include/prov/names.h @@ -261,6 +261,7 @@ #define PROV_NAMES_SSKDF "SSKDF" #define PROV_NAMES_PBKDF1 "PBKDF1" #define PROV_NAMES_PBKDF2 "PBKDF2:1.2.840.113549.1.5.12" +#define PROV_NAMES_PVKKDF "PVKKDF" #define PROV_NAMES_SSHKDF "SSHKDF" #define PROV_NAMES_X963KDF "X963KDF:X942KDF-CONCAT" #define PROV_NAMES_X942KDF_ASN1 "X942KDF-ASN1:X942KDF" diff --git a/providers/implementations/kdfs/build.info b/providers/implementations/kdfs/build.info index f4620adce2..ddc3eabca2 100644 --- a/providers/implementations/kdfs/build.info +++ b/providers/implementations/kdfs/build.info @@ -7,6 +7,7 @@ $KBKDF_GOAL=../../libdefault.a ../../libfips.a $KRB5KDF_GOAL=../../libdefault.a $PBKDF1_GOAL=../../liblegacy.a $PBKDF2_GOAL=../../libdefault.a ../../libfips.a +$PVKKDF_GOAL=../../liblegacy.a $PKCS12KDF_GOAL=../../libdefault.a $SSKDF_GOAL=../../libdefault.a ../../libfips.a $SCRYPT_GOAL=../../libdefault.a @@ -28,6 +29,8 @@ SOURCE[$PBKDF2_GOAL]=pbkdf2.c # When the PBKDF2 moves to legacy, this can be removed. SOURCE[$PBKDF2_GOAL]=pbkdf2_fips.c +SOURCE[$PBKDF1_GOAL]=pvkkdf.c + SOURCE[$PKCS12KDF_GOAL]=pkcs12kdf.c SOURCE[$SSKDF_GOAL]=sskdf.c diff --git a/providers/implementations/kdfs/pvkkdf.c b/providers/implementations/kdfs/pvkkdf.c new file mode 100644 index 0000000000..2dad6309b9 --- /dev/null +++ b/providers/implementations/kdfs/pvkkdf.c @@ -0,0 +1,227 @@ +/* + * Copyright 2018-2021 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 "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" + +static OSSL_FUNC_kdf_newctx_fn kdf_pvk_new; +static OSSL_FUNC_kdf_freectx_fn kdf_pvk_free; +static OSSL_FUNC_kdf_reset_fn kdf_pvk_reset; +static OSSL_FUNC_kdf_derive_fn kdf_pvk_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pvk_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pvk_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pvk_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pvk_get_ctx_params; + +typedef struct { + void *provctx; + unsigned char *pass; + size_t pass_len; + unsigned char *salt; + size_t salt_len; + PROV_DIGEST digest; +} KDF_PVK; + +static void kdf_pvk_init(KDF_PVK *ctx); + +static void *kdf_pvk_new(void *provctx) +{ + KDF_PVK *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->provctx = provctx; + kdf_pvk_init(ctx); + return ctx; +} + +static void kdf_pvk_cleanup(KDF_PVK *ctx) +{ + ossl_prov_digest_reset(&ctx->digest); + OPENSSL_free(ctx->salt); + OPENSSL_clear_free(ctx->pass, ctx->pass_len); + OPENSSL_cleanse(ctx, sizeof(*ctx)); +} + +static void kdf_pvk_free(void *vctx) +{ + KDF_PVK *ctx = (KDF_PVK *)vctx; + + if (ctx != NULL) { + kdf_pvk_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +static void kdf_pvk_reset(void *vctx) +{ + KDF_PVK *ctx = (KDF_PVK *)vctx; + void *provctx = ctx->provctx; + + kdf_pvk_cleanup(ctx); + ctx->provctx = provctx; + kdf_pvk_init(ctx); +} + +static void kdf_pvk_init(KDF_PVK *ctx) +{ + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, + SN_sha1, 0); + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) + /* This is an error, but there is no way to indicate such directly */ + ossl_prov_digest_reset(&ctx->digest); +} + +static int pvk_set_membuf(unsigned char **buffer, size_t *buflen, + const OSSL_PARAM *p) +{ + OPENSSL_clear_free(*buffer, *buflen); + if (p->data_size == 0) { + if ((*buffer = OPENSSL_malloc(1)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + } else if (p->data != NULL) { + *buffer = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen)) + return 0; + } + return 1; +} + +static int kdf_pvk_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_PVK *ctx = (KDF_PVK *)vctx; + const EVP_MD *md; + EVP_MD_CTX *mctx; + int res; + + if (!ossl_prov_is_running() || !kdf_pvk_set_ctx_params(ctx, params)) + return 0; + + if (ctx->pass == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS); + return 0; + } + + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT); + return 0; + } + + md = ossl_prov_digest_md(&ctx->digest); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + return 0; + } + res = EVP_MD_get_size(md); + if (res <= 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); + return 0; + } + if ((size_t)res > keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE); + return 0; + } + + mctx = EVP_MD_CTX_new(); + res = mctx != NULL + && EVP_DigestInit_ex(mctx, md, NULL) + && EVP_DigestUpdate(mctx, ctx->salt, ctx->salt_len) + && EVP_DigestUpdate(mctx, ctx->pass, ctx->pass_len) + && EVP_DigestFinal_ex(mctx, key, NULL); + EVP_MD_CTX_free(mctx); + return res; +} + +static int kdf_pvk_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_PVK *ctx = vctx; + OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); + + if (params == NULL) + return 1; + + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) + if (!pvk_set_membuf(&ctx->pass, &ctx->pass_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) { + if (!pvk_set_membuf(&ctx->salt, &ctx->salt_len,p)) + return 0; + } + + return 1; +} + +static const OSSL_PARAM *kdf_pvk_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_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_PASSWORD, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_pvk_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, SIZE_MAX); + return -2; +} + +static const OSSL_PARAM *kdf_pvk_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_pvk_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pvk_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pvk_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pvk_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pvk_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pvk_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pvk_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pvk_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pvk_get_ctx_params }, + { 0, NULL } +}; diff --git a/providers/legacyprov.c b/providers/legacyprov.c index a5999c5f8b..93c4223a15 100644 --- a/providers/legacyprov.c +++ b/providers/legacyprov.c @@ -145,6 +145,7 @@ static const OSSL_ALGORITHM legacy_ciphers[] = { static const OSSL_ALGORITHM legacy_kdfs[] = { ALG(PROV_NAMES_PBKDF1, ossl_kdf_pbkdf1_functions), + ALG(PROV_NAMES_PVKKDF, ossl_kdf_pvk_functions), { NULL, NULL, NULL } }; -- cgit v1.2.1