From e3405a4a9a5334cd636940a547a25c09ffc76009 Mon Sep 17 00:00:00 2001 From: Pauli Date: Wed, 21 Aug 2019 13:09:10 +1000 Subject: [PATCH] Add KDFs to providers Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/9662) --- providers/common/build.info | 2 +- .../common/include/internal/provider_algs.h | 37 +- providers/common/kdfs/build.info | 4 +- providers/common/kdfs/hkdf.c | 351 +++++++++------- providers/common/kdfs/pbkdf2.c | 322 +++++++------- providers/common/kdfs/sshkdf.c | 292 ------------- providers/common/kdfs/sskdf.c | 394 +++++++++--------- providers/common/kdfs/tls1_prf.c | 281 +++++++------ providers/default/build.info | 1 + providers/default/defltprov.c | 18 + providers/default/kdfs/build.info | 3 + providers/{common => default}/kdfs/scrypt.c | 336 +++++++-------- providers/default/kdfs/sshkdf.c | 297 +++++++++++++ providers/{common => default}/kdfs/x942kdf.c | 285 +++++++------ providers/fips/fipsprov.c | 15 +- 15 files changed, 1406 insertions(+), 1232 deletions(-) delete mode 100644 providers/common/kdfs/sshkdf.c create mode 100644 providers/default/kdfs/build.info rename providers/{common => default}/kdfs/scrypt.c (56%) create mode 100644 providers/default/kdfs/sshkdf.c rename providers/{common => default}/kdfs/x942kdf.c (57%) diff --git a/providers/common/build.info b/providers/common/build.info index 4c977d3f25..4d87b15e8d 100644 --- a/providers/common/build.info +++ b/providers/common/build.info @@ -1,4 +1,4 @@ -SUBDIRS=digests ciphers macs exchange keymgmt +SUBDIRS=digests ciphers macs kdfs exchange keymgmt SOURCE[../../libcrypto]=\ provider_err.c provlib.c diff --git a/providers/common/include/internal/provider_algs.h b/providers/common/include/internal/provider_algs.h index e66c0523e7..b9d257649f 100644 --- a/providers/common/include/internal/provider_algs.h +++ b/providers/common/include/internal/provider_algs.h @@ -115,17 +115,6 @@ extern const OSSL_DISPATCH camellia192ctr_functions[]; extern const OSSL_DISPATCH camellia128ctr_functions[]; #endif /* OPENSSL_NO_CAMELLIA */ -/* MACs */ -extern const OSSL_DISPATCH blake2bmac_functions[]; -extern const OSSL_DISPATCH blake2smac_functions[]; -extern const OSSL_DISPATCH cmac_functions[]; -extern const OSSL_DISPATCH gmac_functions[]; -extern const OSSL_DISPATCH hmac_functions[]; -extern const OSSL_DISPATCH kmac128_functions[]; -extern const OSSL_DISPATCH kmac256_functions[]; -extern const OSSL_DISPATCH siphash_functions[]; -extern const OSSL_DISPATCH poly1305_functions[]; - extern const OSSL_DISPATCH tdes_ede3_ecb_functions[]; extern const OSSL_DISPATCH tdes_ede3_cbc_functions[]; @@ -144,6 +133,32 @@ extern const OSSL_DISPATCH tdes_desx_cbc_functions[]; extern const OSSL_DISPATCH tdes_wrap_cbc_functions[]; #endif /* FIPS_MODE */ +/* MACs */ +extern const OSSL_DISPATCH blake2bmac_functions[]; +extern const OSSL_DISPATCH blake2smac_functions[]; +extern const OSSL_DISPATCH cmac_functions[]; +extern const OSSL_DISPATCH gmac_functions[]; +extern const OSSL_DISPATCH hmac_functions[]; +extern const OSSL_DISPATCH kmac128_functions[]; +extern const OSSL_DISPATCH kmac256_functions[]; +extern const OSSL_DISPATCH siphash_functions[]; +extern const OSSL_DISPATCH poly1305_functions[]; + +/* KDFs / PRFs */ +extern const OSSL_DISPATCH kdf_pbkdf2_functions[]; +#ifndef OPENSSL_NO_SCRYPT +extern const OSSL_DISPATCH kdf_scrypt_functions[]; +#endif +extern const OSSL_DISPATCH kdf_tls1_prf_functions[]; +extern const OSSL_DISPATCH kdf_hkdf_functions[]; +extern const OSSL_DISPATCH kdf_sshkdf_functions[]; +extern const OSSL_DISPATCH kdf_sskdf_functions[]; +extern const OSSL_DISPATCH kdf_x963_kdf_functions[]; +#ifndef OPENSSL_NO_CMS +extern const OSSL_DISPATCH kdf_x942_kdf_functions[]; +#endif + + /* Key management */ extern const OSSL_DISPATCH dh_keymgmt_functions[]; diff --git a/providers/common/kdfs/build.info b/providers/common/kdfs/build.info index 422cf7471e..a881fa00b9 100644 --- a/providers/common/kdfs/build.info +++ b/providers/common/kdfs/build.info @@ -1,7 +1,7 @@ -$COMMON=tls1_prf.c hkdf.c scrypt.c pbkdf2.c sskdf.c +$COMMON=tls1_prf.c hkdf.c pbkdf2.c sskdf.c LIBS=../../../libcrypto -SOURCE[../../../libcrypto]=$COMMON sshkdf.c x942kdf.c +SOURCE[../../../libcrypto]=$COMMON INCLUDE[../../../libcrypto]=. ../../../crypto IF[{- !$disabled{fips} -}] diff --git a/providers/common/kdfs/hkdf.c b/providers/common/kdfs/hkdf.c index 33c74da86a..f5d0295ae3 100644 --- a/providers/common/kdfs/hkdf.c +++ b/providers/common/kdfs/hkdf.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2019 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 @@ -13,14 +13,26 @@ #include #include #include +#include #include "internal/cryptlib.h" #include "internal/numbers.h" #include "internal/evp_int.h" -#include "kdf_local.h" +#include "internal/provider_ctx.h" +#include "internal/providercommonerr.h" +#include "internal/provider_algs.h" +#include "e_os.h" #define HKDF_MAXBUF 1024 -static void kdf_hkdf_reset(EVP_KDF_IMPL *impl); +static OSSL_OP_kdf_newctx_fn kdf_hkdf_new; +static OSSL_OP_kdf_freectx_fn kdf_hkdf_free; +static OSSL_OP_kdf_reset_fn kdf_hkdf_reset; +static OSSL_OP_kdf_derive_fn kdf_hkdf_derive; +static OSSL_OP_kdf_settable_ctx_params_fn kdf_hkdf_settable_ctx_params; +static OSSL_OP_kdf_set_ctx_params_fn kdf_hkdf_set_ctx_params; +static OSSL_OP_kdf_gettable_ctx_params_fn kdf_hkdf_gettable_ctx_params; +static OSSL_OP_kdf_get_ctx_params_fn kdf_hkdf_get_ctx_params; + static int HKDF(const EVP_MD *evp_md, const unsigned char *salt, size_t salt_len, const unsigned char *key, size_t key_len, @@ -35,209 +47,236 @@ static int HKDF_Expand(const EVP_MD *evp_md, const unsigned char *info, size_t info_len, unsigned char *okm, size_t okm_len); -struct evp_kdf_impl_st { +typedef struct { + void *provctx; int mode; - const EVP_MD *md; + EVP_MD *md; unsigned char *salt; size_t salt_len; unsigned char *key; size_t key_len; unsigned char info[HKDF_MAXBUF]; size_t info_len; -}; +} KDF_HKDF; -static EVP_KDF_IMPL *kdf_hkdf_new(void) +static void *kdf_hkdf_new(void *provctx) { - EVP_KDF_IMPL *impl; + KDF_HKDF *ctx; - if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL) - KDFerr(KDF_F_KDF_HKDF_NEW, ERR_R_MALLOC_FAILURE); - return impl; + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + else + ctx->provctx = provctx; + return ctx; } -static void kdf_hkdf_free(EVP_KDF_IMPL *impl) +static void kdf_hkdf_free(void *vctx) { - kdf_hkdf_reset(impl); - OPENSSL_free(impl); -} + KDF_HKDF *ctx = (KDF_HKDF *)vctx; -static void kdf_hkdf_reset(EVP_KDF_IMPL *impl) -{ - OPENSSL_free(impl->salt); - OPENSSL_clear_free(impl->key, impl->key_len); - OPENSSL_cleanse(impl->info, impl->info_len); - memset(impl, 0, sizeof(*impl)); + kdf_hkdf_reset(ctx); + EVP_MD_meth_free(ctx->md); + OPENSSL_free(ctx); } -static int kdf_hkdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) +static void kdf_hkdf_reset(void *vctx) { - const unsigned char *p; - size_t len; - const EVP_MD *md; - - switch (cmd) { - case EVP_KDF_CTRL_SET_MD: - md = va_arg(args, const EVP_MD *); - if (md == NULL) - return 0; - - impl->md = md; - return 1; - - case EVP_KDF_CTRL_SET_HKDF_MODE: - impl->mode = va_arg(args, int); - return 1; - - case EVP_KDF_CTRL_SET_SALT: - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - if (len == 0 || p == NULL) - return 1; - - OPENSSL_free(impl->salt); - impl->salt = OPENSSL_memdup(p, len); - if (impl->salt == NULL) - return 0; - - impl->salt_len = len; - return 1; - - case EVP_KDF_CTRL_SET_KEY: - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - OPENSSL_clear_free(impl->key, impl->key_len); - impl->key = OPENSSL_memdup(p, len); - if (impl->key == NULL) - return 0; - - impl->key_len = len; - return 1; - - case EVP_KDF_CTRL_RESET_HKDF_INFO: - OPENSSL_cleanse(impl->info, impl->info_len); - impl->info_len = 0; - return 1; - - case EVP_KDF_CTRL_ADD_HKDF_INFO: - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - if (len == 0 || p == NULL) - return 1; - - if (len > (HKDF_MAXBUF - impl->info_len)) - return 0; + KDF_HKDF *ctx = (KDF_HKDF *)vctx; - memcpy(impl->info + impl->info_len, p, len); - impl->info_len += len; - return 1; - - default: - return -2; - } + OPENSSL_free(ctx->salt); + OPENSSL_clear_free(ctx->key, ctx->key_len); + OPENSSL_cleanse(ctx->info, ctx->info_len); + memset(ctx, 0, sizeof(*ctx)); } -static int kdf_hkdf_ctrl_str(EVP_KDF_IMPL *impl, const char *type, - const char *value) -{ - if (strcmp(type, "mode") == 0) { - int mode; - - if (strcmp(value, "EXTRACT_AND_EXPAND") == 0) - mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND; - else if (strcmp(value, "EXTRACT_ONLY") == 0) - mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY; - else if (strcmp(value, "EXPAND_ONLY") == 0) - mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY; - else - return 0; - - return call_ctrl(kdf_hkdf_ctrl, impl, EVP_KDF_CTRL_SET_HKDF_MODE, mode); - } - - if (strcmp(type, "digest") == 0) - return kdf_md2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_MD, value); - - if (strcmp(type, "salt") == 0) - return kdf_str2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_SALT, value); - - if (strcmp(type, "hexsalt") == 0) - return kdf_hex2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_SALT, value); - - if (strcmp(type, "key") == 0) - return kdf_str2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_KEY, value); - - if (strcmp(type, "hexkey") == 0) - return kdf_hex2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_KEY, value); - - if (strcmp(type, "info") == 0) - return kdf_str2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_ADD_HKDF_INFO, - value); - - if (strcmp(type, "hexinfo") == 0) - return kdf_hex2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_ADD_HKDF_INFO, - value); - - return -2; -} - -static size_t kdf_hkdf_size(EVP_KDF_IMPL *impl) +static size_t kdf_hkdf_size(KDF_HKDF *ctx) { int sz; - if (impl->mode != EVP_KDF_HKDF_MODE_EXTRACT_ONLY) + if (ctx->mode != EVP_KDF_HKDF_MODE_EXTRACT_ONLY) return SIZE_MAX; - if (impl->md == NULL) { - KDFerr(KDF_F_KDF_HKDF_SIZE, KDF_R_MISSING_MESSAGE_DIGEST); + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); return 0; } - sz = EVP_MD_size(impl->md); + sz = EVP_MD_size(ctx->md); if (sz < 0) return 0; return sz; } -static int kdf_hkdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, - size_t keylen) +static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen) { - if (impl->md == NULL) { - KDFerr(KDF_F_KDF_HKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST); + KDF_HKDF *ctx = (KDF_HKDF *)vctx; + + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); return 0; } - if (impl->key == NULL) { - KDFerr(KDF_F_KDF_HKDF_DERIVE, KDF_R_MISSING_KEY); + if (ctx->key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); return 0; } - switch (impl->mode) { + switch (ctx->mode) { case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND: - return HKDF(impl->md, impl->salt, impl->salt_len, impl->key, - impl->key_len, impl->info, impl->info_len, key, + return HKDF(ctx->md, ctx->salt, ctx->salt_len, ctx->key, + ctx->key_len, ctx->info, ctx->info_len, key, keylen); case EVP_KDF_HKDF_MODE_EXTRACT_ONLY: - return HKDF_Extract(impl->md, impl->salt, impl->salt_len, impl->key, - impl->key_len, key, keylen); + return HKDF_Extract(ctx->md, ctx->salt, ctx->salt_len, ctx->key, + ctx->key_len, key, keylen); case EVP_KDF_HKDF_MODE_EXPAND_ONLY: - return HKDF_Expand(impl->md, impl->key, impl->key_len, impl->info, - impl->info_len, key, keylen); + return HKDF_Expand(ctx->md, ctx->key, ctx->key_len, ctx->info, + ctx->info_len, key, keylen); default: return 0; } } -const EVP_KDF hkdf_kdf_meth = { - EVP_KDF_HKDF, - kdf_hkdf_new, - kdf_hkdf_free, - kdf_hkdf_reset, - kdf_hkdf_ctrl, - kdf_hkdf_ctrl_str, - kdf_hkdf_size, - kdf_hkdf_derive +static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_HKDF *ctx = vctx; + EVP_MD *md; + int n; + const char *properties = NULL; + + /* Grab search properties, this should be before the digest lookup */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES)) + != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + properties = p->data; + } + /* Handle aliasing of digest parameter names */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), p->data, + properties); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + return 0; + } + EVP_MD_meth_free(ctx->md); + ctx->md = md; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE)) != NULL) { + if (p->data_type == OSSL_PARAM_UTF8_STRING) { + if (strcasecmp(p->data, "EXTRACT_AND_EXPAND") == 0) { + ctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND; + } else if (strcasecmp(p->data, "EXTRACT_ONLY") == 0) { + ctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY; + } else if (strcasecmp(p->data, "EXPAND_ONLY") == 0) { + ctx->mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY; + } else { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return 0; + } + } else if (OSSL_PARAM_get_int(p, &n)) { + if (n != EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND + && n != EVP_KDF_HKDF_MODE_EXTRACT_ONLY + && n != EVP_KDF_HKDF_MODE_EXPAND_ONLY) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return 0; + } + ctx->mode = n; + } else { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return 0; + } + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) { + OPENSSL_clear_free(ctx->key, ctx->key_len); + ctx->key = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->key, 0, + &ctx->key_len)) + return 0; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) { + if (p->data_size != 0 && p->data != NULL) { + OPENSSL_free(ctx->salt); + ctx->salt = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->salt, 0, + &ctx->salt_len)) + return 0; + } + } + /* The info fields concatenate, so process them all */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO)) != NULL) { + ctx->info_len = 0; + for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1, + OSSL_KDF_PARAM_INFO)) { + const void *q = ctx->info + ctx->info_len; + size_t sz = 0; + + if (p->data_size != 0 + && p->data != NULL + && !OSSL_PARAM_get_octet_string(p, (void **)&q, + HKDF_MAXBUF - ctx->info_len, + &sz)) + return 0; + ctx->info_len += sz; + } + } + return 1; +} + +static const OSSL_PARAM *kdf_hkdf_settable_ctx_params(void) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), + OSSL_PARAM_int(OSSL_KDF_PARAM_MODE, NULL), + 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_SALT, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + KDF_HKDF *ctx = (KDF_HKDF *)vctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, kdf_hkdf_size(ctx)); + return -2; +} + +static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(void) +{ + 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 kdf_hkdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_hkdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_hkdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_hkdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_hkdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_hkdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_hkdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_hkdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_hkdf_get_ctx_params }, + { 0, NULL } }; /* @@ -325,7 +364,7 @@ static int HKDF_Extract(const EVP_MD *evp_md, if (sz < 0) return 0; if (prk_len != (size_t)sz) { - KDFerr(KDF_F_HKDF_EXTRACT, KDF_R_WRONG_OUTPUT_BUFFER_SIZE); + ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE); return 0; } /* calc: PRK = HMAC-Hash(salt, IKM) */ diff --git a/providers/common/kdfs/pbkdf2.c b/providers/common/kdfs/pbkdf2.c index d41689773c..e0b4550d62 100644 --- a/providers/common/kdfs/pbkdf2.c +++ b/providers/common/kdfs/pbkdf2.c @@ -13,9 +13,13 @@ #include #include #include +#include #include "internal/cryptlib.h" +#include "internal/numbers.h" #include "internal/evp_int.h" -#include "kdf_local.h" +#include "internal/provider_ctx.h" +#include "internal/providercommonerr.h" +#include "internal/provider_algs.h" /* Constants specified in SP800-132 */ #define KDF_PBKDF2_MIN_KEY_LEN_BITS 112 @@ -32,195 +36,216 @@ # define KDF_PBKDF2_DEFAULT_CHECKS 0 #endif /* FIPS_MODE */ -static void kdf_pbkdf2_reset(EVP_KDF_IMPL *impl); -static void kdf_pbkdf2_init(EVP_KDF_IMPL *impl); +static OSSL_OP_kdf_newctx_fn kdf_pbkdf2_new; +static OSSL_OP_kdf_freectx_fn kdf_pbkdf2_free; +static OSSL_OP_kdf_reset_fn kdf_pbkdf2_reset; +static OSSL_OP_kdf_derive_fn kdf_pbkdf2_derive; +static OSSL_OP_kdf_settable_ctx_params_fn kdf_pbkdf2_settable_ctx_params; +static OSSL_OP_kdf_set_ctx_params_fn kdf_pbkdf2_set_ctx_params; + static int pbkdf2_derive(const char *pass, size_t passlen, - const unsigned char *salt, int saltlen, int iter, + const unsigned char *salt, int saltlen, uint64_t iter, const EVP_MD *digest, unsigned char *key, size_t keylen, int extra_checks); -struct evp_kdf_impl_st { +typedef struct { + void *provctx; unsigned char *pass; size_t pass_len; unsigned char *salt; size_t salt_len; - int iter; - const EVP_MD *md; + uint64_t iter; + EVP_MD *md; int lower_bound_checks; -}; +} KDF_PBKDF2; -static EVP_KDF_IMPL *kdf_pbkdf2_new(void) +static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx); + +static void *kdf_pbkdf2_new(void *provctx) { - EVP_KDF_IMPL *impl; + KDF_PBKDF2 *ctx; - impl = OPENSSL_zalloc(sizeof(*impl)); - if (impl == NULL) { - KDFerr(KDF_F_KDF_PBKDF2_NEW, ERR_R_MALLOC_FAILURE); + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return NULL; } - kdf_pbkdf2_init(impl); - return impl; + ctx->provctx = provctx; + kdf_pbkdf2_init(ctx); + return ctx; } -static void kdf_pbkdf2_free(EVP_KDF_IMPL *impl) +static void kdf_pbkdf2_free(void *vctx) { - kdf_pbkdf2_reset(impl); - OPENSSL_free(impl); + KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx; + + kdf_pbkdf2_reset(ctx); + EVP_MD_meth_free(ctx->md); + OPENSSL_free(ctx); } -static void kdf_pbkdf2_reset(EVP_KDF_IMPL *impl) +static void kdf_pbkdf2_reset(void *vctx) { - OPENSSL_free(impl->salt); - OPENSSL_clear_free(impl->pass, impl->pass_len); - memset(impl, 0, sizeof(*impl)); - kdf_pbkdf2_init(impl); + KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx; + + OPENSSL_free(ctx->salt); + OPENSSL_clear_free(ctx->pass, ctx->pass_len); + memset(ctx, 0, sizeof(*ctx)); + kdf_pbkdf2_init(ctx); } -static void kdf_pbkdf2_init(EVP_KDF_IMPL *impl) +static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx) { - impl->iter = PKCS5_DEFAULT_ITER; - impl->md = EVP_sha1(); - impl->lower_bound_checks = KDF_PBKDF2_DEFAULT_CHECKS; + ctx->iter = PKCS5_DEFAULT_ITER; + ctx->md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), SN_sha1, + NULL); + ctx->lower_bound_checks = KDF_PBKDF2_DEFAULT_CHECKS; } static int pbkdf2_set_membuf(unsigned char **buffer, size_t *buflen, - const unsigned char *new_buffer, - size_t new_buflen) + const OSSL_PARAM *p) { - if (new_buffer == NULL) - return 1; - 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_pbkdf2_derive(void *vctx, unsigned char *key, + size_t keylen) +{ + KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx; - if (new_buflen > 0) { - *buffer = OPENSSL_memdup(new_buffer, new_buflen); - } else { - *buffer = OPENSSL_malloc(1); + if (ctx->pass == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS); + return 0; } - if (*buffer == NULL) { - KDFerr(KDF_F_PBKDF2_SET_MEMBUF, ERR_R_MALLOC_FAILURE); + + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT); return 0; } - *buflen = new_buflen; - return 1; + return pbkdf2_derive((char *)ctx->pass, ctx->pass_len, + ctx->salt, ctx->salt_len, ctx->iter, + ctx->md, key, keylen, ctx->lower_bound_checks); } -static int kdf_pbkdf2_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) +static int kdf_pbkdf2_set_ctx_params(void *vctx, const OSSL_PARAM params[]) { - int iter, pkcs5, min_iter; - const unsigned char *p; - size_t len; - const EVP_MD *md; - - switch (cmd) { - case EVP_KDF_CTRL_SET_PBKDF2_PKCS5_MODE: - pkcs5 = va_arg(args, int); - impl->lower_bound_checks = (pkcs5 == 0) ? 1 : 0; - return 1; - case EVP_KDF_CTRL_SET_PASS: - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - return pbkdf2_set_membuf(&impl->pass, &impl->pass_len, p, len); - - case EVP_KDF_CTRL_SET_SALT: - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - if (impl->lower_bound_checks != 0 && len < KDF_PBKDF2_MIN_SALT_LEN) { - KDFerr(KDF_F_KDF_PBKDF2_CTRL, KDF_R_INVALID_SALT_LEN); + const OSSL_PARAM *p; + KDF_PBKDF2 *ctx = vctx; + EVP_MD *md; + int pkcs5; + uint64_t iter, min_iter; + const char *properties = NULL; + + /* Grab search properties, this should be before the digest lookup */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES)) + != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) return 0; - } - return pbkdf2_set_membuf(&impl->salt, &impl->salt_len, p, len); - - case EVP_KDF_CTRL_SET_ITER: - iter = va_arg(args, int); - min_iter = impl->lower_bound_checks != 0 ? KDF_PBKDF2_MIN_ITERATIONS : 1; - if (iter < min_iter) { - KDFerr(KDF_F_KDF_PBKDF2_CTRL, KDF_R_INVALID_ITERATION_COUNT); + properties = p->data; + } + /* Handle aliasing of digest parameter names */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) return 0; - } - impl->iter = iter; - return 1; - - case EVP_KDF_CTRL_SET_MD: - md = va_arg(args, const EVP_MD *); + md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), p->data, + properties); if (md == NULL) { - KDFerr(KDF_F_KDF_PBKDF2_CTRL, KDF_R_VALUE_MISSING); + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return 0; } - - impl->md = md; - return 1; - - default: - return -2; + EVP_MD_meth_free(ctx->md); + ctx->md = md; } -} -static int kdf_pbkdf2_ctrl_str(EVP_KDF_IMPL *impl, const char *type, - const char *value) -{ - if (value == NULL) { - KDFerr(KDF_F_KDF_PBKDF2_CTRL_STR, KDF_R_VALUE_MISSING); - return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PKCS5)) != NULL) { + if (!OSSL_PARAM_get_int(p, &pkcs5)) + return 0; + ctx->lower_bound_checks = pkcs5 == 0; } - if (strcmp(type, "pass") == 0) - return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_PASS, - value); - - if (strcmp(type, "hexpass") == 0) - return kdf_hex2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_PASS, - value); + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) + if (!pbkdf2_set_membuf(&ctx->pass, &ctx->pass_len, p)) + return 0; - if (strcmp(type, "salt") == 0) - return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_SALT, - value); + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) { + if (ctx->lower_bound_checks != 0 + && p->data_size < KDF_PBKDF2_MIN_SALT_LEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH); + return 0; + } + if (!pbkdf2_set_membuf(&ctx->salt, &ctx->salt_len,p)) + return 0; + } - if (strcmp(type, "hexsalt") == 0) - return kdf_hex2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_SALT, - value); + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_ITER)) != NULL) { + if (!OSSL_PARAM_get_uint64(p, &iter)) + return 0; + min_iter = ctx->lower_bound_checks != 0 ? KDF_PBKDF2_MIN_ITERATIONS : 1; + if (iter < min_iter) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT); + return 0; + } + ctx->iter = iter; + } + return 1; +} - if (strcmp(type, "iter") == 0) - return call_ctrl(kdf_pbkdf2_ctrl, impl, EVP_KDF_CTRL_SET_ITER, - atoi(value)); +static const OSSL_PARAM *kdf_pbkdf2_settable_ctx_params(void) +{ + 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_uint64(OSSL_KDF_PARAM_ITER, NULL), + OSSL_PARAM_int(OSSL_KDF_PARAM_PKCS5, NULL), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} - if (strcmp(type, "digest") == 0) - return kdf_md2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_MD, value); +static int kdf_pbkdf2_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; - if (strcmp(type, "pkcs5") == 0) - return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl, - EVP_KDF_CTRL_SET_PBKDF2_PKCS5_MODE, value); + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, SIZE_MAX); return -2; } -static int kdf_pbkdf2_derive(EVP_KDF_IMPL *impl, unsigned char *key, - size_t keylen) +static const OSSL_PARAM *kdf_pbkdf2_gettable_ctx_params(void) { - if (impl->pass == NULL) { - KDFerr(KDF_F_KDF_PBKDF2_DERIVE, KDF_R_MISSING_PASS); - return 0; - } - - if (impl->salt == NULL) { - KDFerr(KDF_F_KDF_PBKDF2_DERIVE, KDF_R_MISSING_SALT); - return 0; - } - - return pbkdf2_derive((char *)impl->pass, impl->pass_len, - impl->salt, impl->salt_len, impl->iter, - impl->md, key, keylen, impl->lower_bound_checks); + 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 EVP_KDF pbkdf2_kdf_meth = { - EVP_KDF_PBKDF2, - kdf_pbkdf2_new, - kdf_pbkdf2_free, - kdf_pbkdf2_reset, - kdf_pbkdf2_ctrl, - kdf_pbkdf2_ctrl_str, - NULL, - kdf_pbkdf2_derive +const OSSL_DISPATCH kdf_pbkdf2_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pbkdf2_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pbkdf2_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pbkdf2_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pbkdf2_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pbkdf2_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pbkdf2_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pbkdf2_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pbkdf2_get_ctx_params }, + { 0, NULL } }; /* @@ -234,13 +259,14 @@ const EVP_KDF pbkdf2_kdf_meth = { * - Randomly-generated portion of the salt shall be at least 128 bits. */ static int pbkdf2_derive(const char *pass, size_t passlen, - const unsigned char *salt, int saltlen, int iter, + const unsigned char *salt, int saltlen, uint64_t iter, const EVP_MD *digest, unsigned char *key, size_t keylen, int lower_bound_checks) { int ret = 0; unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4]; - int cplen, j, k, tkeylen, mdlen; + int cplen, k, tkeylen, mdlen; + uint64_t j; unsigned long i = 1; HMAC_CTX *hctx_tpl = NULL, *hctx = NULL; @@ -253,23 +279,23 @@ static int pbkdf2_derive(const char *pass, size_t passlen, * results in an overflow of the loop counter 'i'. */ if ((keylen / mdlen) >= KDF_PBKDF2_MAX_KEY_LEN_DIGEST_RATIO) { - KDFerr(KDF_F_PBKDF2_DERIVE, KDF_R_INVALID_KEY_LEN); + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LEN); return 0; } if (lower_bound_checks) { - if ((keylen * 8) < KDF_PBKDF2_MIN_KEY_LEN_BITS) { - KDFerr(KDF_F_PBKDF2_DERIVE, KDF_R_INVALID_KEY_LEN); - return 0; - } - if (saltlen < KDF_PBKDF2_MIN_SALT_LEN) { - KDFerr(KDF_F_PBKDF2_DERIVE, KDF_R_INVALID_SALT_LEN); + if ((keylen * 8) < KDF_PBKDF2_MIN_KEY_LEN_BITS) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LEN); + return 0; + } + if (saltlen < KDF_PBKDF2_MIN_SALT_LEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH); return 0; - } - if (iter < KDF_PBKDF2_MIN_ITERATIONS) { - KDFerr(KDF_F_PBKDF2_DERIVE, KDF_R_INVALID_ITERATION_COUNT); - return 0; - } + } + if (iter < KDF_PBKDF2_MIN_ITERATIONS) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT); + return 0; + } } hctx_tpl = HMAC_CTX_new(); diff --git a/providers/common/kdfs/sshkdf.c b/providers/common/kdfs/sshkdf.c deleted file mode 100644 index 4701c9cad1..0000000000 --- a/providers/common/kdfs/sshkdf.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright 2018-2018 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the OpenSSL license (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 "internal/cryptlib.h" -#include "internal/numbers.h" -#include "internal/evp_int.h" -#include "kdf_local.h" - -/* See RFC 4253, Section 7.2 */ - -static void kdf_sshkdf_reset(EVP_KDF_IMPL *impl); -static int SSHKDF(const EVP_MD *evp_md, - const unsigned char *key, size_t key_len, - const unsigned char *xcghash, size_t xcghash_len, - const unsigned char *session_id, size_t session_id_len, - char type, unsigned char *okey, size_t okey_len); - -struct evp_kdf_impl_st { - const EVP_MD *md; - unsigned char *key; /* K */ - size_t key_len; - unsigned char *xcghash; /* H */ - size_t xcghash_len; - char type; /* X */ - unsigned char *session_id; - size_t session_id_len; -}; - -static EVP_KDF_IMPL *kdf_sshkdf_new(void) -{ - EVP_KDF_IMPL *impl; - - if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL) - KDFerr(KDF_F_KDF_SSHKDF_NEW, ERR_R_MALLOC_FAILURE); - return impl; -} - -static void kdf_sshkdf_free(EVP_KDF_IMPL *impl) -{ - kdf_sshkdf_reset(impl); - OPENSSL_free(impl); -} - -static void kdf_sshkdf_reset(EVP_KDF_IMPL *impl) -{ - OPENSSL_clear_free(impl->key, impl->key_len); - OPENSSL_clear_free(impl->xcghash, impl->xcghash_len); - OPENSSL_clear_free(impl->session_id, impl->session_id_len); - memset(impl, 0, sizeof(*impl)); -} - -static int kdf_sshkdf_parse_buffer_arg(unsigned char **dst, size_t *dst_len, - va_list args) -{ - const unsigned char *p; - size_t len; - - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - OPENSSL_clear_free(*dst, *dst_len); - *dst = OPENSSL_memdup(p, len); - if (*dst == NULL) - return 0; - - *dst_len = len; - return 1; -} - -static int kdf_sshkdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) -{ - int t; - - switch (cmd) { - case EVP_KDF_CTRL_SET_MD: - impl->md = va_arg(args, const EVP_MD *); - if (impl->md == NULL) - return 0; - - return 1; - - case EVP_KDF_CTRL_SET_KEY: - return kdf_sshkdf_parse_buffer_arg(&impl->key, - &impl->key_len, args); - - case EVP_KDF_CTRL_SET_SSHKDF_XCGHASH: - return kdf_sshkdf_parse_buffer_arg(&impl->xcghash, - &impl->xcghash_len, args); - - case EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID: - return kdf_sshkdf_parse_buffer_arg(&impl->session_id, - &impl->session_id_len, args); - - case EVP_KDF_CTRL_SET_SSHKDF_TYPE: - t = va_arg(args, int); - if (t < 65 || t > 70) { - KDFerr(KDF_F_KDF_SSHKDF_CTRL, KDF_R_VALUE_ERROR); - return 0; - } - - impl->type = (char)t; - return 1; - - default: - return -2; - - } -} - -static int kdf_sshkdf_ctrl_str(EVP_KDF_IMPL *impl, const char *type, - const char *value) -{ - if (value == NULL) { - KDFerr(KDF_F_KDF_SSHKDF_CTRL_STR, KDF_R_VALUE_MISSING); - return 0; - } - - if (strcmp(type, "digest") == 0) - return kdf_md2ctrl(impl, kdf_sshkdf_ctrl, EVP_KDF_CTRL_SET_MD, value); - /* alias, for historical reasons */ - if (strcmp(type, "md") == 0) - return kdf_md2ctrl(impl, kdf_sshkdf_ctrl, EVP_KDF_CTRL_SET_MD, value); - - if (strcmp(type, "key") == 0) - return kdf_str2ctrl(impl, kdf_sshkdf_ctrl, - EVP_KDF_CTRL_SET_KEY, value); - - if (strcmp(type, "hexkey") == 0) - return kdf_hex2ctrl(impl, kdf_sshkdf_ctrl, - EVP_KDF_CTRL_SET_KEY, value); - - if (strcmp(type, "xcghash") == 0) - return kdf_str2ctrl(impl, kdf_sshkdf_ctrl, - EVP_KDF_CTRL_SET_SSHKDF_XCGHASH, value); - - if (strcmp(type, "hexxcghash") == 0) - return kdf_hex2ctrl(impl, kdf_sshkdf_ctrl, - EVP_KDF_CTRL_SET_SSHKDF_XCGHASH, value); - - if (strcmp(type, "session_id") == 0) - return kdf_str2ctrl(impl, kdf_sshkdf_ctrl, - EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID, value); - - if (strcmp(type, "hexsession_id") == 0) - return kdf_hex2ctrl(impl, kdf_sshkdf_ctrl, - EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID, value); - - if (strcmp(type, "type") == 0) { - if (strlen(value) != 1) { - KDFerr(KDF_F_KDF_SSHKDF_CTRL_STR, KDF_R_VALUE_ERROR); - return 0; - } - - return call_ctrl(kdf_sshkdf_ctrl, impl, EVP_KDF_CTRL_SET_SSHKDF_TYPE, - (int)value[0]); - } - - KDFerr(KDF_F_KDF_SSHKDF_CTRL_STR, KDF_R_UNKNOWN_PARAMETER_TYPE); - return -2; -} - -static size_t kdf_sshkdf_size(EVP_KDF_IMPL *impl) -{ - return SIZE_MAX; -} - -static int kdf_sshkdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, - size_t keylen) -{ - if (impl->md == NULL) { - KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST); - return 0; - } - if (impl->key == NULL) { - KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_KEY); - return 0; - } - if (impl->xcghash == NULL) { - KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_XCGHASH); - return 0; - } - if (impl->session_id == NULL) { - KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_SESSION_ID); - return 0; - } - if (impl->type == 0) { - KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_TYPE); - return 0; - } - return SSHKDF(impl->md, impl->key, impl->key_len, - impl->xcghash, impl->xcghash_len, - impl->session_id, impl->session_id_len, - impl->type, key, keylen); -} - -const EVP_KDF sshkdf_kdf_meth = { - EVP_KDF_SSHKDF, - kdf_sshkdf_new, - kdf_sshkdf_free, - kdf_sshkdf_reset, - kdf_sshkdf_ctrl, - kdf_sshkdf_ctrl_str, - kdf_sshkdf_size, - kdf_sshkdf_derive, -}; - -static int SSHKDF(const EVP_MD *evp_md, - const unsigned char *key, size_t key_len, - const unsigned char *xcghash, size_t xcghash_len, - const unsigned char *session_id, size_t session_id_len, - char type, unsigned char *okey, size_t okey_len) -{ - EVP_MD_CTX *md = NULL; - unsigned char digest[EVP_MAX_MD_SIZE]; - unsigned int dsize = 0; - size_t cursize = 0; - int ret = 0; - - md = EVP_MD_CTX_new(); - if (md == NULL) - return 0; - - if (!EVP_DigestInit_ex(md, evp_md, NULL)) - goto out; - - if (!EVP_DigestUpdate(md, key, key_len)) - goto out; - - if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) - goto out; - - if (!EVP_DigestUpdate(md, &type, 1)) - goto out; - - if (!EVP_DigestUpdate(md, session_id, session_id_len)) - goto out; - - if (!EVP_DigestFinal_ex(md, digest, &dsize)) - goto out; - - if (okey_len < dsize) { - memcpy(okey, digest, okey_len); - ret = 1; - goto out; - } - - memcpy(okey, digest, dsize); - - for (cursize = dsize; cursize < okey_len; cursize += dsize) { - - if (!EVP_DigestInit_ex(md, evp_md, NULL)) - goto out; - - if (!EVP_DigestUpdate(md, key, key_len)) - goto out; - - if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) - goto out; - - if (!EVP_DigestUpdate(md, okey, cursize)) - goto out; - - if (!EVP_DigestFinal_ex(md, digest, &dsize)) - goto out; - - if (okey_len < cursize + dsize) { - memcpy(okey + cursize, digest, okey_len - cursize); - ret = 1; - goto out; - } - - memcpy(okey + cursize, digest, dsize); - } - - ret = 1; - -out: - EVP_MD_CTX_free(md); - OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE); - return ret; -} - diff --git a/providers/common/kdfs/sskdf.c b/providers/common/kdfs/sskdf.c index b20eff2865..61e4607bee 100644 --- a/providers/common/kdfs/sskdf.c +++ b/providers/common/kdfs/sskdf.c @@ -43,12 +43,16 @@ #include #include #include "internal/cryptlib.h" +#include "internal/numbers.h" #include "internal/evp_int.h" -#include "kdf_local.h" +#include "internal/provider_ctx.h" +#include "internal/providercommonerr.h" +#include "internal/provider_algs.h" -struct evp_kdf_impl_st { +typedef struct { + void *provctx; EVP_MAC *mac; /* H(x) = HMAC_hash OR H(x) = KMAC */ - const EVP_MD *md; /* H(x) = hash OR when H(x) = HMAC_hash */ + EVP_MD *md; /* H(x) = hash OR when H(x) = HMAC_hash */ unsigned char *secret; size_t secret_len; unsigned char *info; @@ -56,7 +60,7 @@ struct evp_kdf_impl_st { unsigned char *salt; size_t salt_len; size_t out_len; /* optional KMAC parameter */ -}; +} KDF_SSKDF; #define SSKDF_MAX_INLEN (1<<30) #define SSKDF_KMAC128_DEFAULT_SALT_SIZE (168 - 4) @@ -65,6 +69,16 @@ struct evp_kdf_impl_st { /* KMAC uses a Customisation string of 'KDF' */ static const unsigned char kmac_custom_str[] = { 0x4B, 0x44, 0x46 }; +static OSSL_OP_kdf_newctx_fn sskdf_new; +static OSSL_OP_kdf_freectx_fn sskdf_free; +static OSSL_OP_kdf_reset_fn sskdf_reset; +static OSSL_OP_kdf_derive_fn sskdf_derive; +static OSSL_OP_kdf_derive_fn x963kdf_derive; +static OSSL_OP_kdf_settable_ctx_params_fn sskdf_settable_ctx_params; +static OSSL_OP_kdf_set_ctx_params_fn sskdf_set_ctx_params; +static OSSL_OP_kdf_gettable_ctx_params_fn sskdf_gettable_ctx_params; +static OSSL_OP_kdf_get_ctx_params_fn sskdf_get_ctx_params; + /* * Refer to https://csrc.nist.gov/publications/detail/sp/800-56c/rev-1/final * Section 4. One-Step Key Derivation using H(x) = hash(x) @@ -287,172 +301,69 @@ end: return ret; } -static EVP_KDF_IMPL *sskdf_new(void) +static void *sskdf_new(void *provctx) { - EVP_KDF_IMPL *impl; + KDF_SSKDF *ctx; - if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL) - KDFerr(KDF_F_SSKDF_NEW, ERR_R_MALLOC_FAILURE); - return impl; + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ctx->provctx = provctx; + return ctx; } -static void sskdf_reset(EVP_KDF_IMPL *impl) +static void sskdf_reset(void *vctx) { - OPENSSL_clear_free(impl->secret, impl->secret_len); - OPENSSL_clear_free(impl->info, impl->info_len); - OPENSSL_clear_free(impl->salt, impl->salt_len); - EVP_MAC_free(impl->mac); -#if 0 /* TODO(3.0) When we switch to fetched MDs */ - EVP_MD_meth_free(impl->md); -#endif - memset(impl, 0, sizeof(*impl)); -} + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; -static void sskdf_free(EVP_KDF_IMPL *impl) -{ - sskdf_reset(impl); - OPENSSL_free(impl); + OPENSSL_clear_free(ctx->secret, ctx->secret_len); + OPENSSL_clear_free(ctx->info, ctx->info_len); + OPENSSL_clear_free(ctx->salt, ctx->salt_len); + EVP_MAC_free(ctx->mac); + memset(ctx, 0, sizeof(*ctx)); } -static int sskdf_set_buffer(va_list args, unsigned char **out, size_t *out_len) +static void sskdf_free(void *vctx) { - const unsigned char *p; - size_t len; - - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - if (len == 0 || p == NULL) - return 1; + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; - OPENSSL_free(*out); - *out = OPENSSL_memdup(p, len); - if (*out == NULL) - return 0; - - *out_len = len; - return 1; + sskdf_reset(ctx); + EVP_MD_meth_free(ctx->md); + EVP_MAC_free(ctx->mac); + OPENSSL_free(ctx); } -static int sskdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) +static int sskdf_set_buffer(unsigned char **out, size_t *out_len, + const OSSL_PARAM *p) { - const EVP_MD *md; - - switch (cmd) { - case EVP_KDF_CTRL_SET_KEY: - return sskdf_set_buffer(args, &impl->secret, &impl->secret_len); - - case EVP_KDF_CTRL_SET_SSKDF_INFO: - return sskdf_set_buffer(args, &impl->info, &impl->info_len); - - case EVP_KDF_CTRL_SET_MD: - md = va_arg(args, const EVP_MD *); - if (md == NULL) - return 0; - -#if 0 /* TODO(3.0) When we switch to fetched MDs */ - EVP_MD_meth_free(impl->md); -#endif - impl->md = md; - return 1; - - case EVP_KDF_CTRL_SET_MAC: - { - const char *name; - EVP_MAC *mac; - - name = va_arg(args, const char *); - if (name == NULL) - return 0; - - EVP_MAC_free(impl->mac); - impl->mac = NULL; - - /* - * TODO(3.0) add support for OPENSSL_CTX and properties in KDFs - */ - mac = EVP_MAC_fetch(NULL, name, NULL); - if (mac == NULL) - return 0; - - impl->mac = mac; - return 1; - } - case EVP_KDF_CTRL_SET_SALT: - return sskdf_set_buffer(args, &impl->salt, &impl->salt_len); - - case EVP_KDF_CTRL_SET_MAC_SIZE: - impl->out_len = va_arg(args, size_t); + if (p->data == NULL || p->data_size == 0) return 1; - - default: - return -2; - } -} - -static int sskdf_ctrl_str(EVP_KDF_IMPL *impl, const char *type, - const char *value) -{ - if (strcmp(type, "secret") == 0 || strcmp(type, "key") == 0) - return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_KEY, - value); - - if (strcmp(type, "hexsecret") == 0 || strcmp(type, "hexkey") == 0) - return kdf_hex2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_KEY, - value); - - if (strcmp(type, "info") == 0) - return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SSKDF_INFO, - value); - - if (strcmp(type, "hexinfo") == 0) - return kdf_hex2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SSKDF_INFO, - value); - - if (strcmp(type, "digest") == 0) - return kdf_md2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_MD, value); - - if (strcmp(type, "mac") == 0) - return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_MAC, value); - - if (strcmp(type, "salt") == 0) - return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SALT, value); - - if (strcmp(type, "hexsalt") == 0) - return kdf_hex2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SALT, value); - - - if (strcmp(type, "maclen") == 0) { - int val = atoi(value); - if (val < 0) { - KDFerr(KDF_F_SSKDF_CTRL_STR, KDF_R_VALUE_ERROR); - return 0; - } - return call_ctrl(sskdf_ctrl, impl, EVP_KDF_CTRL_SET_MAC_SIZE, - (size_t)val); - } - return -2; + OPENSSL_free(*out); + *out = NULL; + return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len); } -static size_t sskdf_size(EVP_KDF_IMPL *impl) +static size_t sskdf_size(KDF_SSKDF *ctx) { int len; - if (impl->md == NULL) { - KDFerr(KDF_F_SSKDF_SIZE, KDF_R_MISSING_MESSAGE_DIGEST); + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); return 0; } - len = EVP_MD_size(impl->md); + len = EVP_MD_size(ctx->md); return (len <= 0) ? 0 : (size_t)len; } -static int sskdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, size_t keylen) +static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen) { - if (impl->secret == NULL) { - KDFerr(KDF_F_SSKDF_DERIVE, KDF_R_MISSING_SECRET); + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; + + if (ctx->secret == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); return 0; } - if (impl->mac != NULL) { + if (ctx->mac != NULL) { /* H(x) = KMAC or H(x) = HMAC */ int ret; const unsigned char *custom = NULL; @@ -465,14 +376,14 @@ static int sskdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, size_t keylen) * Why does KMAC require a salt length that's shorter than the MD * block size? */ - macname = EVP_MAC_name(impl->mac); + macname = EVP_MAC_name(ctx->mac); if (strcmp(macname, OSSL_MAC_NAME_HMAC) == 0) { /* H(x) = HMAC(x, salt, hash) */ - if (impl->md == NULL) { - KDFerr(KDF_F_SSKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST); + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); return 0; } - default_salt_len = EVP_MD_block_size(impl->md); + default_salt_len = EVP_MD_block_size(ctx->md); if (default_salt_len <= 0) return 0; } else if (strcmp(macname, OSSL_MAC_NAME_KMAC128) == 0 @@ -485,74 +396,181 @@ static int sskdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, size_t keylen) else default_salt_len = SSKDF_KMAC256_DEFAULT_SALT_SIZE; } else { - KDFerr(KDF_F_SSKDF_DERIVE, KDF_R_UNSUPPORTED_MAC_TYPE); + ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_MAC_TYPE); return 0; } /* If no salt is set then use a default_salt of zeros */ - if (impl->salt == NULL || impl->salt_len <= 0) { - impl->salt = OPENSSL_zalloc(default_salt_len); - if (impl->salt == NULL) { - KDFerr(KDF_F_SSKDF_DERIVE, ERR_R_MALLOC_FAILURE); + if (ctx->salt == NULL || ctx->salt_len <= 0) { + ctx->salt = OPENSSL_zalloc(default_salt_len); + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return 0; } - impl->salt_len = default_salt_len; + ctx->salt_len = default_salt_len; } - ret = SSKDF_mac_kdm(impl->mac, impl->md, - custom, custom_len, impl->out_len, - impl->salt, impl->salt_len, - impl->secret, impl->secret_len, - impl->info, impl->info_len, key, keylen); + ret = SSKDF_mac_kdm(ctx->mac, ctx->md, + custom, custom_len, ctx->out_len, + ctx->salt, ctx->salt_len, + ctx->secret, ctx->secret_len, + ctx->info, ctx->info_len, key, keylen); return ret; } else { /* H(x) = hash */ - if (impl->md == NULL) { - KDFerr(KDF_F_SSKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST); + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); return 0; } - return SSKDF_hash_kdm(impl->md, impl->secret, impl->secret_len, - impl->info, impl->info_len, 0, key, keylen); + return SSKDF_hash_kdm(ctx->md, ctx->secret, ctx->secret_len, + ctx->info, ctx->info_len, 0, key, keylen); } } -static int x963kdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, size_t keylen) +static int x963kdf_derive(void *vctx, unsigned char *key, size_t keylen) { - if (impl->secret == NULL) { - KDFerr(KDF_F_X963KDF_DERIVE, KDF_R_MISSING_SECRET); + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; + + if (ctx->secret == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); return 0; } - if (impl->mac != NULL) { - KDFerr(KDF_F_X963KDF_DERIVE, KDF_R_NOT_SUPPORTED); + if (ctx->mac != NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED); return 0; } else { /* H(x) = hash */ - if (impl->md == NULL) { - KDFerr(KDF_F_X963KDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST); + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + return SSKDF_hash_kdm(ctx->md, ctx->secret, ctx->secret_len, + ctx->info, ctx->info_len, 1, key, keylen); + } +} + +static int sskdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_SSKDF *ctx = vctx; + EVP_MD *md; + EVP_MAC *mac; + size_t sz; + const char *properties = NULL; + + /* Grab search properties, should be before the digest and mac lookups */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES)) + != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + properties = p->data; + } + /* Handle aliasing of digest parameter names */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), p->data, + properties); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return 0; } - return SSKDF_hash_kdm(impl->md, impl->secret, impl->secret_len, - impl->info, impl->info_len, 1, key, keylen); + EVP_MD_meth_free(ctx->md); + ctx->md = md; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MAC)) != NULL) { + EVP_MAC_free(ctx->mac); + ctx->mac = NULL; + + mac = EVP_MAC_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), p->data, + properties); + if (mac == NULL) + return 0; + EVP_MAC_free(ctx->mac); + ctx->mac = mac; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL + || (p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) + if (!sskdf_set_buffer(&ctx->secret, &ctx->secret_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO)) != NULL) + if (!sskdf_set_buffer(&ctx->info, &ctx->info_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) + if (!sskdf_set_buffer(&ctx->salt, &ctx->salt_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MAC_SIZE)) + != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz) || sz == 0) + return 0; + ctx->out_len = sz; } + return 1; +} + +static const OSSL_PARAM *sskdf_settable_ctx_params(void) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MAC, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_size_t(OSSL_KDF_PARAM_MAC_SIZE, NULL), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int sskdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, sskdf_size(ctx)); + return -2; +} + +static const OSSL_PARAM *sskdf_gettable_ctx_params(void) +{ + 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 EVP_KDF ss_kdf_meth = { - EVP_KDF_SS, - sskdf_new, - sskdf_free, - sskdf_reset, - sskdf_ctrl, - sskdf_ctrl_str, - sskdf_size, - sskdf_derive +const OSSL_DISPATCH kdf_sskdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))sskdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))sskdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))sskdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))sskdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))sskdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))sskdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))sskdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))sskdf_get_ctx_params }, + { 0, NULL } }; -const EVP_KDF x963_kdf_meth = { - EVP_KDF_X963, - sskdf_new, - sskdf_free, - sskdf_reset, - sskdf_ctrl, - sskdf_ctrl_str, - sskdf_size, - x963kdf_derive +const OSSL_DISPATCH kdf_x963_kdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))sskdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))sskdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))sskdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))x963kdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))sskdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))sskdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))sskdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))sskdf_get_ctx_params }, + { 0, NULL } }; diff --git a/providers/common/kdfs/tls1_prf.c b/providers/common/kdfs/tls1_prf.c index 3c553e8900..5d7e599e64 100644 --- a/providers/common/kdfs/tls1_prf.c +++ b/providers/common/kdfs/tls1_prf.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2019 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 @@ -48,16 +48,26 @@ #include #include #include -#include "internal/cryptlib.h" #include #include #include #include +#include "internal/cryptlib.h" +#include "internal/numbers.h" #include "internal/evp_int.h" -#include "kdf_local.h" - -static void kdf_tls1_prf_reset(EVP_KDF_IMPL *impl); -static int tls1_prf_alg(const EVP_MD *md, +#include "internal/provider_ctx.h" +#include "internal/providercommonerr.h" +#include "internal/provider_algs.h" +#include "e_os.h" + +static OSSL_OP_kdf_newctx_fn kdf_tls1_prf_new; +static OSSL_OP_kdf_freectx_fn kdf_tls1_prf_free; +static OSSL_OP_kdf_reset_fn kdf_tls1_prf_reset; +static OSSL_OP_kdf_derive_fn kdf_tls1_prf_derive; +static OSSL_OP_kdf_settable_ctx_params_fn kdf_tls1_prf_settable_ctx_params; +static OSSL_OP_kdf_set_ctx_params_fn kdf_tls1_prf_set_ctx_params; + +static int tls1_prf_alg(const EVP_MD *md, const EVP_MD *sha1, const unsigned char *sec, size_t slen, const unsigned char *seed, size_t seed_len, unsigned char *out, size_t olen); @@ -65,149 +75,184 @@ static int tls1_prf_alg(const EVP_MD *md, #define TLS1_PRF_MAXBUF 1024 /* TLS KDF kdf context structure */ - -struct evp_kdf_impl_st { +typedef struct { + void *provctx; /* Digest to use for PRF */ - const EVP_MD *md; + EVP_MD *md; + /* Second digest for the MD5/SHA-1 combined PRF */ + EVP_MD *sha1; /* Secret value to use for PRF */ unsigned char *sec; size_t seclen; /* Buffer of concatenated seed data */ unsigned char seed[TLS1_PRF_MAXBUF]; size_t seedlen; -}; +} TLS1_PRF; -static EVP_KDF_IMPL *kdf_tls1_prf_new(void) +static void *kdf_tls1_prf_new(void *provctx) { - EVP_KDF_IMPL *impl; + TLS1_PRF *ctx; - if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL) - KDFerr(KDF_F_KDF_TLS1_PRF_NEW, ERR_R_MALLOC_FAILURE); - return impl; + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ctx->provctx = provctx; + return ctx; } -static void kdf_tls1_prf_free(EVP_KDF_IMPL *impl) +static void kdf_tls1_prf_free(void *vctx) { - kdf_tls1_prf_reset(impl); - OPENSSL_free(impl); + TLS1_PRF *ctx = (TLS1_PRF *)vctx; + + kdf_tls1_prf_reset(ctx); + EVP_MD_meth_free(ctx->sha1); + EVP_MD_meth_free(ctx->md); + OPENSSL_free(ctx); } -static void kdf_tls1_prf_reset(EVP_KDF_IMPL *impl) +static void kdf_tls1_prf_reset(void *vctx) { - OPENSSL_clear_free(impl->sec, impl->seclen); - OPENSSL_cleanse(impl->seed, impl->seedlen); - memset(impl, 0, sizeof(*impl)); + TLS1_PRF *ctx = (TLS1_PRF *)vctx; + + OPENSSL_clear_free(ctx->sec, ctx->seclen); + OPENSSL_cleanse(ctx->seed, ctx->seedlen); + memset(ctx, 0, sizeof(*ctx)); } -static int kdf_tls1_prf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) +static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, + size_t keylen) { - const unsigned char *p; - size_t len; - const EVP_MD *md; - - switch (cmd) { - case EVP_KDF_CTRL_SET_MD: - md = va_arg(args, const EVP_MD *); - if (md == NULL) - return 0; + TLS1_PRF *ctx = (TLS1_PRF *)vctx; - impl->md = md; - return 1; + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + if (ctx->sec == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); + return 0; + } + if (ctx->seedlen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SEED); + return 0; + } + return tls1_prf_alg(ctx->md, ctx->sha1, ctx->sec, ctx->seclen, + ctx->seed, ctx->seedlen, + key, keylen); +} - case EVP_KDF_CTRL_SET_TLS_SECRET: - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - OPENSSL_clear_free(impl->sec, impl->seclen); - impl->sec = OPENSSL_memdup(p, len); - if (impl->sec == NULL) +static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + TLS1_PRF *ctx = vctx; + EVP_MD *md, *sha = NULL; + const char *properties = NULL, *name; + + /* Grab search properties, this should be before the digest lookup */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES)) + != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) return 0; - - impl->seclen = len; - return 1; - - /* TODO: This is only ever called from pkey_kdf and only as part of setting the TLS secret - consider merging the twe two?? */ - case EVP_KDF_CTRL_RESET_TLS_SEED: - OPENSSL_cleanse(impl->seed, impl->seedlen); - impl->seedlen = 0; - return 1; - - case EVP_KDF_CTRL_ADD_TLS_SEED: - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - if (len == 0 || p == NULL) - return 1; - - if (len > (TLS1_PRF_MAXBUF - impl->seedlen)) + properties = p->data; + } + /* Handle aliasing of digest parameter names */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) return 0; + name = p->data; + if (strcasecmp(name, SN_md5_sha1) == 0) { + sha = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), SN_sha1, + properties); + if (sha == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA1); + return 0; + } + name = SN_md5; + } + md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), name, + properties); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + EVP_MD_meth_free(sha); + return 0; + } + EVP_MD_meth_free(ctx->sha1); + EVP_MD_meth_free(ctx->md); + ctx->md = md; + ctx->sha1 = sha; + } - memcpy(impl->seed + impl->seedlen, p, len); - impl->seedlen += len; - return 1; - - default: - return -2; + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL) { + OPENSSL_clear_free(ctx->sec, ctx->seclen); + ctx->sec = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->sec, 0, &ctx->seclen)) + return 0; } + /* The seed fields concatenate, so process them all */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SEED)) != NULL) { + OPENSSL_cleanse(ctx->seed, ctx->seedlen); + ctx->seedlen = 0; + + for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1, + OSSL_KDF_PARAM_SEED)) { + const void *q = ctx->seed + ctx->seedlen; + size_t sz = 0; + + if (p->data_size != 0 + && p->data != NULL + && !OSSL_PARAM_get_octet_string(p, (void **)&q, + TLS1_PRF_MAXBUF - ctx->seedlen, + &sz)) + return 0; + ctx->seedlen += sz; + } + } + return 1; } -static int kdf_tls1_prf_ctrl_str(EVP_KDF_IMPL *impl, - const char *type, const char *value) +static const OSSL_PARAM *kdf_tls1_prf_settable_ctx_params(void) { - if (value == NULL) { - KDFerr(KDF_F_KDF_TLS1_PRF_CTRL_STR, KDF_R_VALUE_MISSING); - return 0; - } - if (strcmp(type, "digest") == 0) - return kdf_md2ctrl(impl, kdf_tls1_prf_ctrl, EVP_KDF_CTRL_SET_MD, value); - - if (strcmp(type, "secret") == 0) - return kdf_str2ctrl(impl, kdf_tls1_prf_ctrl, - EVP_KDF_CTRL_SET_TLS_SECRET, value); - - if (strcmp(type, "hexsecret") == 0) - return kdf_hex2ctrl(impl, kdf_tls1_prf_ctrl, - EVP_KDF_CTRL_SET_TLS_SECRET, value); - - if (strcmp(type, "seed") == 0) - return kdf_str2ctrl(impl, kdf_tls1_prf_ctrl, EVP_KDF_CTRL_ADD_TLS_SEED, - value); + 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_SECRET, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} - if (strcmp(type, "hexseed") == 0) - return kdf_hex2ctrl(impl, kdf_tls1_prf_ctrl, EVP_KDF_CTRL_ADD_TLS_SEED, - value); +static int kdf_tls1_prf_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 int kdf_tls1_prf_derive(EVP_KDF_IMPL *impl, unsigned char *key, - size_t keylen) +static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params(void) { - if (impl->md == NULL) { - KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST); - return 0; - } - if (impl->sec == NULL) { - KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_SECRET); - return 0; - } - if (impl->seedlen == 0) { - KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_SEED); - return 0; - } - return tls1_prf_alg(impl->md, impl->sec, impl->seclen, - impl->seed, impl->seedlen, - key, keylen); + 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 EVP_KDF tls1_prf_kdf_meth = { - EVP_KDF_TLS1_PRF, - kdf_tls1_prf_new, - kdf_tls1_prf_free, - kdf_tls1_prf_reset, - kdf_tls1_prf_ctrl, - kdf_tls1_prf_ctrl_str, - NULL, - kdf_tls1_prf_derive +const OSSL_DISPATCH kdf_tls1_prf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_tls1_prf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_tls1_prf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_tls1_prf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_tls1_prf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_tls1_prf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, + (void(*)(void))kdf_tls1_prf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_tls1_prf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, + (void(*)(void))kdf_tls1_prf_get_ctx_params }, + { 0, NULL } }; /* @@ -337,12 +382,12 @@ static int tls1_prf_P_hash(const EVP_MD *md, * * PRF(secret, label, seed) = P_(secret, label + seed) */ -static int tls1_prf_alg(const EVP_MD *md, +static int tls1_prf_alg(const EVP_MD *md, const EVP_MD *sha1, const unsigned char *sec, size_t slen, const unsigned char *seed, size_t seed_len, unsigned char *out, size_t olen) { - if (EVP_MD_type(md) == NID_md5_sha1) { + if (sha1 != NULL) { /* TLS v1.0 and TLS v1.1 */ size_t i; unsigned char *tmp; @@ -350,15 +395,15 @@ static int tls1_prf_alg(const EVP_MD *md, size_t L_S1 = (slen + 1) / 2; size_t L_S2 = L_S1; - if (!tls1_prf_P_hash(EVP_md5(), sec, L_S1, + if (!tls1_prf_P_hash(md, sec, L_S1, seed, seed_len, out, olen)) return 0; if ((tmp = OPENSSL_malloc(olen)) == NULL) { - KDFerr(KDF_F_TLS1_PRF_ALG, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return 0; } - if (!tls1_prf_P_hash(EVP_sha1(), sec + slen - L_S2, L_S2, + if (!tls1_prf_P_hash(sha1, sec + slen - L_S2, L_S2, seed, seed_len, tmp, olen)) { OPENSSL_clear_free(tmp, olen); return 0; diff --git a/providers/default/build.info b/providers/default/build.info index f0a6c5c742..ca78cce0a8 100644 --- a/providers/default/build.info +++ b/providers/default/build.info @@ -1,4 +1,5 @@ SUBDIRS=digests macs ciphers +SUBDIRS=digests kdfs macs ciphers LIBS=../../libcrypto SOURCE[../../libcrypto]=\ defltprov.c diff --git a/providers/default/defltprov.c b/providers/default/defltprov.c index c481171a78..8a950482c8 100644 --- a/providers/default/defltprov.c +++ b/providers/default/defltprov.c @@ -211,6 +211,22 @@ static const OSSL_ALGORITHM deflt_macs[] = { { NULL, NULL, NULL } }; +static const OSSL_ALGORITHM deflt_kdfs[] = { + { "HKDF", "default=yes", kdf_hkdf_functions }, + { "SSKDF", "default=yes", kdf_sskdf_functions }, + { "PBKDF2", "default=yes", kdf_pbkdf2_functions }, + { "SSHKDF", "default=yes", kdf_sshkdf_functions }, + { "X963KDF", "default=yes", kdf_x963_kdf_functions }, + { "TLS1-PRF", "default=yes", kdf_tls1_prf_functions }, +#ifndef OPENSSL_NO_CMS + { "X942KDF", "default=yes", kdf_x942_kdf_functions }, +#endif +#ifndef OPENSSL_NO_SCRYPT + { "id-scrypt", "default=yes", kdf_scrypt_functions }, +#endif + { NULL, NULL, NULL } +}; + static const OSSL_ALGORITHM deflt_keyexch[] = { #ifndef OPENSSL_NO_DH { "dhKeyAgreement", "default=yes", dh_keyexch_functions }, @@ -237,6 +253,8 @@ static const OSSL_ALGORITHM *deflt_query(OSSL_PROVIDER *prov, return deflt_ciphers; case OSSL_OP_MAC: return deflt_macs; + case OSSL_OP_KDF: + return deflt_kdfs; case OSSL_OP_KEYMGMT: return deflt_keymgmt; case OSSL_OP_KEYEXCH: diff --git a/providers/default/kdfs/build.info b/providers/default/kdfs/build.info new file mode 100644 index 0000000000..27047c5286 --- /dev/null +++ b/providers/default/kdfs/build.info @@ -0,0 +1,3 @@ +LIBS=../../../libcrypto +SOURCE[../../../libcrypto]=scrypt.c sshkdf.c x942kdf.c +INCLUDE[../../../libcrypto]=. ../../../crypto diff --git a/providers/common/kdfs/scrypt.c b/providers/default/kdfs/scrypt.c similarity index 56% rename from providers/common/kdfs/scrypt.c rename to providers/default/kdfs/scrypt.c index 29ceeb3ad9..57dc317d21 100644 --- a/providers/common/kdfs/scrypt.c +++ b/providers/default/kdfs/scrypt.c @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2017-2019 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 @@ -13,115 +13,129 @@ #include #include #include +#include #include "internal/evp_int.h" #include "internal/numbers.h" -#include "kdf_local.h" +#include "internal/provider_algs.h" +#include "internal/provider_ctx.h" +#include "internal/providercommonerr.h" +#include "internal/provider_algs.h" #ifndef OPENSSL_NO_SCRYPT -static void kdf_scrypt_reset(EVP_KDF_IMPL *impl); -static void kdf_scrypt_init(EVP_KDF_IMPL *impl); -static int atou64(const char *nptr, uint64_t *result); +static OSSL_OP_kdf_newctx_fn kdf_scrypt_new; +static OSSL_OP_kdf_freectx_fn kdf_scrypt_free; +static OSSL_OP_kdf_reset_fn kdf_scrypt_reset; +static OSSL_OP_kdf_derive_fn kdf_scrypt_derive; +static OSSL_OP_kdf_settable_ctx_params_fn kdf_scrypt_settable_ctx_params; +static OSSL_OP_kdf_set_ctx_params_fn kdf_scrypt_set_ctx_params; + static int scrypt_alg(const char *pass, size_t passlen, const unsigned char *salt, size_t saltlen, uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem, - unsigned char *key, size_t keylen); + unsigned char *key, size_t keylen, EVP_MD *sha256); -struct evp_kdf_impl_st { +typedef struct { + void *provctx; unsigned char *pass; size_t pass_len; unsigned char *salt; size_t salt_len; uint64_t N; - uint32_t r, p; + uint64_t r, p; uint64_t maxmem_bytes; -}; - -/* Custom uint64_t parser since we do not have strtoull */ -static int atou64(const char *nptr, uint64_t *result) -{ - uint64_t value = 0; - - while (*nptr) { - unsigned int digit; - uint64_t new_value; + EVP_MD *sha256; +} KDF_SCRYPT; - if ((*nptr < '0') || (*nptr > '9')) { - return 0; - } - digit = (unsigned int)(*nptr - '0'); - new_value = (value * 10) + digit; - if ((new_value < digit) || ((new_value - digit) / 10 != value)) { - /* Overflow */ - return 0; - } - value = new_value; - nptr++; - } - *result = value; - return 1; -} +static void kdf_scrypt_init(KDF_SCRYPT *ctx); -static EVP_KDF_IMPL *kdf_scrypt_new(void) +static void *kdf_scrypt_new(void *provctx) { - EVP_KDF_IMPL *impl; + KDF_SCRYPT *ctx; - impl = OPENSSL_zalloc(sizeof(*impl)); - if (impl == NULL) { - KDFerr(KDF_F_KDF_SCRYPT_NEW, ERR_R_MALLOC_FAILURE); + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->provctx = provctx; + ctx->sha256 = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(provctx), + "sha256", NULL); + if (ctx->sha256 == NULL) { + OPENSSL_free(ctx); + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA256); return NULL; } - kdf_scrypt_init(impl); - return impl; + kdf_scrypt_init(ctx); + return ctx; } -static void kdf_scrypt_free(EVP_KDF_IMPL *impl) +static void kdf_scrypt_free(void *vctx) { - kdf_scrypt_reset(impl); - OPENSSL_free(impl); + KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx; + + kdf_scrypt_reset(ctx); + EVP_MD_meth_free(ctx->sha256); + OPENSSL_free(ctx); } -static void kdf_scrypt_reset(EVP_KDF_IMPL *impl) +static void kdf_scrypt_reset(void *vctx) { - OPENSSL_free(impl->salt); - OPENSSL_clear_free(impl->pass, impl->pass_len); - memset(impl, 0, sizeof(*impl)); - kdf_scrypt_init(impl); + KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx; + + OPENSSL_free(ctx->salt); + OPENSSL_clear_free(ctx->pass, ctx->pass_len); + memset(ctx, 0, sizeof(*ctx)); + kdf_scrypt_init(ctx); } -static void kdf_scrypt_init(EVP_KDF_IMPL *impl) +static void kdf_scrypt_init(KDF_SCRYPT *ctx) { /* Default values are the most conservative recommendation given in the * original paper of C. Percival. Derivation uses roughly 1 GiB of memory * for this parameter choice (approx. 128 * r * N * p bytes). */ - impl->N = 1 << 20; - impl->r = 8; - impl->p = 1; - impl->maxmem_bytes = 1025 * 1024 * 1024; + ctx->N = 1 << 20; + ctx->r = 8; + ctx->p = 1; + ctx->maxmem_bytes = 1025 * 1024 * 1024; } static int scrypt_set_membuf(unsigned char **buffer, size_t *buflen, - const unsigned char *new_buffer, - size_t new_buflen) + const OSSL_PARAM *p) { - if (new_buffer == NULL) - return 1; - 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_scrypt_derive(void *vctx, unsigned char *key, + size_t keylen) +{ + KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx; - if (new_buflen > 0) { - *buffer = OPENSSL_memdup(new_buffer, new_buflen); - } else { - *buffer = OPENSSL_malloc(1); + if (ctx->pass == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS); + return 0; } - if (*buffer == NULL) { - KDFerr(KDF_F_SCRYPT_SET_MEMBUF, ERR_R_MALLOC_FAILURE); + + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT); return 0; } - *buflen = new_buflen; - return 1; + return scrypt_alg((char *)ctx->pass, ctx->pass_len, ctx->salt, + ctx->salt_len, ctx->N, ctx->r, ctx->p, + ctx->maxmem_bytes, key, keylen, ctx->sha256); } static int is_power_of_two(uint64_t value) @@ -129,152 +143,96 @@ static int is_power_of_two(uint64_t value) return (value != 0) && ((value & (value - 1)) == 0); } -static int kdf_scrypt_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) +static int kdf_scrypt_set_ctx_params(void *vctx, const OSSL_PARAM params[]) { + const OSSL_PARAM *p; + KDF_SCRYPT *ctx = vctx; uint64_t u64_value; - uint32_t value; - const unsigned char *p; - size_t len; - - switch (cmd) { - case EVP_KDF_CTRL_SET_PASS: - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - return scrypt_set_membuf(&impl->pass, &impl->pass_len, p, len); - - case EVP_KDF_CTRL_SET_SALT: - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - return scrypt_set_membuf(&impl->salt, &impl->salt_len, p, len); - - case EVP_KDF_CTRL_SET_SCRYPT_N: - u64_value = va_arg(args, uint64_t); - if ((u64_value <= 1) || !is_power_of_two(u64_value)) - return 0; - impl->N = u64_value; - return 1; - - case EVP_KDF_CTRL_SET_SCRYPT_R: - value = va_arg(args, uint32_t); - if (value < 1) + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) + if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p)) return 0; - impl->r = value; - return 1; - - case EVP_KDF_CTRL_SET_SCRYPT_P: - value = va_arg(args, uint32_t); - if (value < 1) + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) + if (!scrypt_set_membuf(&ctx->salt, &ctx->salt_len, p)) return 0; - impl->p = value; - return 1; - - case EVP_KDF_CTRL_SET_MAXMEM_BYTES: - u64_value = va_arg(args, uint64_t); - if (u64_value < 1) + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SCRYPT_N)) + != NULL) { + if (!OSSL_PARAM_get_uint64(p, &u64_value) + || u64_value <= 1 + || !is_power_of_two(u64_value)) return 0; + ctx->N = u64_value; + } - impl->maxmem_bytes = u64_value; - return 1; - - default: - return -2; + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SCRYPT_R)) + != NULL) { + if (!OSSL_PARAM_get_uint64(p, &u64_value) || u64_value < 1) + return 0; + ctx->r = u64_value; } -} -static int kdf_scrypt_ctrl_uint32(EVP_KDF_IMPL *impl, int cmd, - const char *value) -{ - int int_value = atoi(value); + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SCRYPT_P)) + != NULL) { + if (!OSSL_PARAM_get_uint64(p, &u64_value) || u64_value < 1) + return 0; + ctx->p = u64_value; + } - if (int_value < 0 || (uint64_t)int_value > UINT32_MAX) { - KDFerr(KDF_F_KDF_SCRYPT_CTRL_UINT32, KDF_R_VALUE_ERROR); - return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SCRYPT_MAXMEM)) + != NULL) { + if (!OSSL_PARAM_get_uint64(p, &u64_value) || u64_value < 1) + return 0; + ctx->maxmem_bytes = u64_value; } - return call_ctrl(kdf_scrypt_ctrl, impl, cmd, (uint32_t)int_value); + return 1; } -static int kdf_scrypt_ctrl_uint64(EVP_KDF_IMPL *impl, int cmd, - const char *value) +static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(void) { - uint64_t u64_value; - - if (!atou64(value, &u64_value)) { - KDFerr(KDF_F_KDF_SCRYPT_CTRL_UINT64, KDF_R_VALUE_ERROR); - return 0; - } - return call_ctrl(kdf_scrypt_ctrl, impl, cmd, u64_value); + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_N, NULL), + OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_R, NULL), + OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_P, NULL), + OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_MAXMEM, NULL), + OSSL_PARAM_END + }; + return known_settable_ctx_params; } -static int kdf_scrypt_ctrl_str(EVP_KDF_IMPL *impl, const char *type, - const char *value) +static int kdf_scrypt_get_ctx_params(void *vctx, OSSL_PARAM params[]) { - if (value == NULL) { - KDFerr(KDF_F_KDF_SCRYPT_CTRL_STR, KDF_R_VALUE_MISSING); - return 0; - } - - if (strcmp(type, "pass") == 0) - return kdf_str2ctrl(impl, kdf_scrypt_ctrl, EVP_KDF_CTRL_SET_PASS, - value); - - if (strcmp(type, "hexpass") == 0) - return kdf_hex2ctrl(impl, kdf_scrypt_ctrl, EVP_KDF_CTRL_SET_PASS, - value); - - if (strcmp(type, "salt") == 0) - return kdf_str2ctrl(impl, kdf_scrypt_ctrl, EVP_KDF_CTRL_SET_SALT, - value); - - if (strcmp(type, "hexsalt") == 0) - return kdf_hex2ctrl(impl, kdf_scrypt_ctrl, EVP_KDF_CTRL_SET_SALT, - value); - - if (strcmp(type, "N") == 0) - return kdf_scrypt_ctrl_uint64(impl, EVP_KDF_CTRL_SET_SCRYPT_N, value); - - if (strcmp(type, "r") == 0) - return kdf_scrypt_ctrl_uint32(impl, EVP_KDF_CTRL_SET_SCRYPT_R, value); - - if (strcmp(type, "p") == 0) - return kdf_scrypt_ctrl_uint32(impl, EVP_KDF_CTRL_SET_SCRYPT_P, value); - - if (strcmp(type, "maxmem_bytes") == 0) - return kdf_scrypt_ctrl_uint64(impl, EVP_KDF_CTRL_SET_MAXMEM_BYTES, - value); + 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 int kdf_scrypt_derive(EVP_KDF_IMPL *impl, unsigned char *key, - size_t keylen) +static const OSSL_PARAM *kdf_scrypt_gettable_ctx_params(void) { - if (impl->pass == NULL) { - KDFerr(KDF_F_KDF_SCRYPT_DERIVE, KDF_R_MISSING_PASS); - return 0; - } - - if (impl->salt == NULL) { - KDFerr(KDF_F_KDF_SCRYPT_DERIVE, KDF_R_MISSING_SALT); - return 0; - } - - return scrypt_alg((char *)impl->pass, impl->pass_len, impl->salt, - impl->salt_len, impl->N, impl->r, impl->p, - impl->maxmem_bytes, key, keylen); + 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 EVP_KDF scrypt_kdf_meth = { - EVP_KDF_SCRYPT, - kdf_scrypt_new, - kdf_scrypt_free, - kdf_scrypt_reset, - kdf_scrypt_ctrl, - kdf_scrypt_ctrl_str, - NULL, - kdf_scrypt_derive +const OSSL_DISPATCH kdf_scrypt_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_scrypt_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_scrypt_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_scrypt_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_scrypt_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_scrypt_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_scrypt_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_scrypt_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_scrypt_get_ctx_params }, + { 0, NULL } }; #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) @@ -400,7 +358,7 @@ static void scryptROMix(unsigned char *B, uint64_t r, uint64_t N, static int scrypt_alg(const char *pass, size_t passlen, const unsigned char *salt, size_t saltlen, uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem, - unsigned char *key, size_t keylen) + unsigned char *key, size_t keylen, EVP_MD *sha256) { int rv = 0; unsigned char *B; @@ -484,14 +442,14 @@ static int scrypt_alg(const char *pass, size_t passlen, X = (uint32_t *)(B + Blen); T = X + 32 * r; V = T + 32 * r; - if (PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, 1, EVP_sha256(), + if (PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, 1, sha256, (int)Blen, B) == 0) goto err; for (i = 0; i < p; i++) scryptROMix(B + 128 * r * i, r, N, X, T, V); - if (PKCS5_PBKDF2_HMAC(pass, passlen, B, (int)Blen, 1, EVP_sha256(), + if (PKCS5_PBKDF2_HMAC(pass, passlen, B, (int)Blen, 1, sha256, keylen, key) == 0) goto err; rv = 1; diff --git a/providers/default/kdfs/sshkdf.c b/providers/default/kdfs/sshkdf.c new file mode 100644 index 0000000000..529a98006c --- /dev/null +++ b/providers/default/kdfs/sshkdf.c @@ -0,0 +1,297 @@ +/* + * Copyright 2018-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 +#include "internal/cryptlib.h" +#include "internal/numbers.h" +#include "internal/evp_int.h" +#include "internal/provider_ctx.h" +#include "internal/providercommonerr.h" +#include "internal/provider_algs.h" + +/* See RFC 4253, Section 7.2 */ +static OSSL_OP_kdf_newctx_fn kdf_sshkdf_new; +static OSSL_OP_kdf_freectx_fn kdf_sshkdf_free; +static OSSL_OP_kdf_reset_fn kdf_sshkdf_reset; +static OSSL_OP_kdf_derive_fn kdf_sshkdf_derive; +static OSSL_OP_kdf_settable_ctx_params_fn kdf_sshkdf_settable_ctx_params; +static OSSL_OP_kdf_set_ctx_params_fn kdf_sshkdf_set_ctx_params; +static OSSL_OP_kdf_gettable_ctx_params_fn kdf_sshkdf_gettable_ctx_params; +static OSSL_OP_kdf_get_ctx_params_fn kdf_sshkdf_get_ctx_params; + +static int SSHKDF(const EVP_MD *evp_md, + const unsigned char *key, size_t key_len, + const unsigned char *xcghash, size_t xcghash_len, + const unsigned char *session_id, size_t session_id_len, + char type, unsigned char *okey, size_t okey_len); + +typedef struct { + void *provctx; + EVP_MD *md; + unsigned char *key; /* K */ + size_t key_len; + unsigned char *xcghash; /* H */ + size_t xcghash_len; + char type; /* X */ + unsigned char *session_id; + size_t session_id_len; +} KDF_SSHKDF; + +static void *kdf_sshkdf_new(void *provctx) +{ + KDF_SSHKDF *ctx; + + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ctx->provctx = provctx; + return ctx; +} + +static void kdf_sshkdf_free(void *vctx) +{ + KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx; + + kdf_sshkdf_reset(ctx); + EVP_MD_meth_free(ctx->md); + OPENSSL_free(ctx); +} + +static void kdf_sshkdf_reset(void *vctx) +{ + KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx; + + OPENSSL_clear_free(ctx->key, ctx->key_len); + OPENSSL_clear_free(ctx->xcghash, ctx->xcghash_len); + OPENSSL_clear_free(ctx->session_id, ctx->session_id_len); + memset(ctx, 0, sizeof(*ctx)); +} + +static int sshkdf_set_membuf(unsigned char **dst, size_t *dst_len, + const OSSL_PARAM *p) +{ + OPENSSL_clear_free(*dst, *dst_len); + *dst = NULL; + return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len); +} + +static int kdf_sshkdf_derive(void *vctx, unsigned char *key, + size_t keylen) +{ + KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx; + + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + if (ctx->key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return 0; + } + if (ctx->xcghash == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_XCGHASH); + return 0; + } + if (ctx->session_id == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SESSION_ID); + return 0; + } + if (ctx->type == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_TYPE); + return 0; + } + return SSHKDF(ctx->md, ctx->key, ctx->key_len, + ctx->xcghash, ctx->xcghash_len, + ctx->session_id, ctx->session_id_len, + ctx->type, key, keylen); +} + +static int kdf_sshkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_SSHKDF *ctx = vctx; + EVP_MD *md; + int t; + const char *properties = NULL; + + /* Grab search properties, this should be before the digest lookup */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES)) + != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + properties = p->data; + } + /* Handle aliasing of digest parameter names */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), p->data, + properties); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + return 0; + } + EVP_MD_meth_free(ctx->md); + ctx->md = md; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) + if (!sshkdf_set_membuf(&ctx->key, &ctx->key_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_XCGHASH)) + != NULL) + if (!sshkdf_set_membuf(&ctx->xcghash, &ctx->xcghash_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_SESSION_ID)) + != NULL) + if (!sshkdf_set_membuf(&ctx->session_id, &ctx->session_id_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_TYPE)) + != NULL) { + if (p->data == NULL || p->data_size == 0) + return 0; + t = *(unsigned char *)p->data; + if (t < 65 || t > 70) { + ERR_raise(ERR_LIB_PROV, PROV_R_VALUE_ERROR); + return 0; + } + ctx->type = (char)t; + } + return 1; +} + +static const OSSL_PARAM *kdf_sshkdf_settable_ctx_params(void) +{ + 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_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_XCGHASH, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_SESSION_ID, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_SSHKDF_TYPE, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_sshkdf_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_sshkdf_gettable_ctx_params(void) +{ + 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 kdf_sshkdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_sshkdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_sshkdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_sshkdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_sshkdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_sshkdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_sshkdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_get_ctx_params }, + { 0, NULL } +}; + +static int SSHKDF(const EVP_MD *evp_md, + const unsigned char *key, size_t key_len, + const unsigned char *xcghash, size_t xcghash_len, + const unsigned char *session_id, size_t session_id_len, + char type, unsigned char *okey, size_t okey_len) +{ + EVP_MD_CTX *md = NULL; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dsize = 0; + size_t cursize = 0; + int ret = 0; + + md = EVP_MD_CTX_new(); + if (md == NULL) + return 0; + + if (!EVP_DigestInit_ex(md, evp_md, NULL)) + goto out; + + if (!EVP_DigestUpdate(md, key, key_len)) + goto out; + + if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) + goto out; + + if (!EVP_DigestUpdate(md, &type, 1)) + goto out; + + if (!EVP_DigestUpdate(md, session_id, session_id_len)) + goto out; + + if (!EVP_DigestFinal_ex(md, digest, &dsize)) + goto out; + + if (okey_len < dsize) { + memcpy(okey, digest, okey_len); + ret = 1; + goto out; + } + + memcpy(okey, digest, dsize); + + for (cursize = dsize; cursize < okey_len; cursize += dsize) { + + if (!EVP_DigestInit_ex(md, evp_md, NULL)) + goto out; + + if (!EVP_DigestUpdate(md, key, key_len)) + goto out; + + if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) + goto out; + + if (!EVP_DigestUpdate(md, okey, cursize)) + goto out; + + if (!EVP_DigestFinal_ex(md, digest, &dsize)) + goto out; + + if (okey_len < cursize + dsize) { + memcpy(okey + cursize, digest, okey_len - cursize); + ret = 1; + goto out; + } + + memcpy(okey + cursize, digest, dsize); + } + + ret = 1; + +out: + EVP_MD_CTX_free(md); + OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE); + return ret; +} + diff --git a/providers/common/kdfs/x942kdf.c b/providers/default/kdfs/x942kdf.c similarity index 57% rename from providers/common/kdfs/x942kdf.c rename to providers/default/kdfs/x942kdf.c index ce9ad61035..e8a5e4cad5 100644 --- a/providers/common/kdfs/x942kdf.c +++ b/providers/default/kdfs/x942kdf.c @@ -21,21 +21,35 @@ # include # include # include +# include # include "internal/cryptlib.h" +# include "internal/numbers.h" # include "internal/evp_int.h" -# include "kdf_local.h" +# include "internal/provider_ctx.h" +# include "internal/providercommonerr.h" +# include "internal/provider_algs.h" # define X942KDF_MAX_INLEN (1 << 30) -struct evp_kdf_impl_st { - const EVP_MD *md; +static OSSL_OP_kdf_newctx_fn x942kdf_new; +static OSSL_OP_kdf_freectx_fn x942kdf_free; +static OSSL_OP_kdf_reset_fn x942kdf_reset; +static OSSL_OP_kdf_derive_fn x942kdf_derive; +static OSSL_OP_kdf_settable_ctx_params_fn x942kdf_settable_ctx_params; +static OSSL_OP_kdf_set_ctx_params_fn x942kdf_set_ctx_params; +static OSSL_OP_kdf_gettable_ctx_params_fn x942kdf_gettable_ctx_params; +static OSSL_OP_kdf_get_ctx_params_fn x942kdf_get_ctx_params; + +typedef struct { + void *provctx; + EVP_MD *md; unsigned char *secret; size_t secret_len; int cek_nid; unsigned char *ukm; size_t ukm_len; size_t dkm_len; -}; +} KDF_X942; /* A table of allowed wrapping algorithms and the associated output lengths */ static const struct { @@ -177,7 +191,7 @@ static int x942kdf_hash_kdm(const EVP_MD *kdf_md, if (z_len > X942KDF_MAX_INLEN || other_len > X942KDF_MAX_INLEN || derived_key_len > X942KDF_MAX_INLEN || derived_key_len == 0) { - KDFerr(KDF_F_X942KDF_HASH_KDM, KDF_R_BAD_LENGTH); + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); return 0; } @@ -227,181 +241,200 @@ end: return ret; } -static EVP_KDF_IMPL *x942kdf_new(void) +static void *x942kdf_new(void *provctx) { - EVP_KDF_IMPL *impl; + KDF_X942 *ctx; - if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL) - KDFerr(KDF_F_X942KDF_NEW, ERR_R_MALLOC_FAILURE); - return impl; + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ctx->provctx = provctx; + return ctx; } -static void x942kdf_reset(EVP_KDF_IMPL *impl) +static void x942kdf_reset(void *vctx) { - OPENSSL_clear_free(impl->secret, impl->secret_len); - OPENSSL_clear_free(impl->ukm, impl->ukm_len); - memset(impl, 0, sizeof(*impl)); -} + KDF_X942 *ctx = (KDF_X942 *)vctx; -static void x942kdf_free(EVP_KDF_IMPL *impl) -{ - x942kdf_reset(impl); - OPENSSL_free(impl); + OPENSSL_clear_free(ctx->secret, ctx->secret_len); + OPENSSL_clear_free(ctx->ukm, ctx->ukm_len); + memset(ctx, 0, sizeof(*ctx)); } -static int x942kdf_set_buffer(va_list args, unsigned char **out, size_t *out_len) +static void x942kdf_free(void *vctx) { - const unsigned char *p; - size_t len; - - p = va_arg(args, const unsigned char *); - len = va_arg(args, size_t); - if (len == 0 || p == NULL) - return 1; - - OPENSSL_free(*out); - *out = OPENSSL_memdup(p, len); - if (*out == NULL) - return 0; + KDF_X942 *ctx = (KDF_X942 *)vctx; - *out_len = len; - return 1; + x942kdf_reset(ctx); + EVP_MD_meth_free(ctx->md); + OPENSSL_free(ctx); } -static int x942kdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) +static int x942kdf_set_buffer(unsigned char **out, size_t *out_len, + const OSSL_PARAM *p) { - const EVP_MD *md; - char *alg_str = NULL; - size_t i; - - switch (cmd) { - case EVP_KDF_CTRL_SET_MD: - md = va_arg(args, const EVP_MD *); - if (md == NULL) - return 0; - - impl->md = md; + if (p->data_size == 0 || p->data == NULL) return 1; - case EVP_KDF_CTRL_SET_KEY: - return x942kdf_set_buffer(args, &impl->secret, &impl->secret_len); - - case EVP_KDF_CTRL_SET_UKM: - return x942kdf_set_buffer(args, &impl->ukm, &impl->ukm_len); - - case EVP_KDF_CTRL_SET_CEK_ALG: - alg_str = va_arg(args, char *); - if (alg_str == NULL) - return 0; - impl->cek_nid = OBJ_sn2nid(alg_str); - for (i = 0; i < (size_t)OSSL_NELEM(kek_algs); ++i) { - if (kek_algs[i].nid == impl->cek_nid) { - impl->dkm_len = kek_algs[i].keklen; - return 1; - } - } - KDFerr(KDF_F_X942KDF_CTRL, KDF_R_UNSUPPORTED_CEK_ALG); - return 0; - - default: - return -2; - } -} - -static int x942kdf_ctrl_str(EVP_KDF_IMPL *impl, const char *type, - const char *value) -{ - if (strcmp(type, "digest") == 0) - return kdf_md2ctrl(impl, x942kdf_ctrl, EVP_KDF_CTRL_SET_MD, value); - - if (strcmp(type, "secret") == 0 || strcmp(type, "key") == 0) - return kdf_str2ctrl(impl, x942kdf_ctrl, EVP_KDF_CTRL_SET_KEY, - value); - - if (strcmp(type, "hexsecret") == 0 || strcmp(type, "hexkey") == 0) - return kdf_hex2ctrl(impl, x942kdf_ctrl, EVP_KDF_CTRL_SET_KEY, - value); - - if (strcmp(type, "ukm") == 0) - return kdf_str2ctrl(impl, x942kdf_ctrl, EVP_KDF_CTRL_SET_UKM, - value); - - if (strcmp(type, "hexukm") == 0) - return kdf_hex2ctrl(impl, x942kdf_ctrl, EVP_KDF_CTRL_SET_UKM, - value); - - if (strcmp(type, "cekalg") == 0) - return kdf_str2ctrl(impl, x942kdf_ctrl, EVP_KDF_CTRL_SET_CEK_ALG, - value); - - return -2; + OPENSSL_free(*out); + *out = NULL; + return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len); } -static size_t x942kdf_size(EVP_KDF_IMPL *impl) +static size_t x942kdf_size(KDF_X942 *ctx) { int len; - if (impl->md == NULL) { - KDFerr(KDF_F_X942KDF_SIZE, KDF_R_MISSING_MESSAGE_DIGEST); + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); return 0; } - len = EVP_MD_size(impl->md); + len = EVP_MD_size(ctx->md); return (len <= 0) ? 0 : (size_t)len; } -static int x942kdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, size_t keylen) +static int x942kdf_derive(void *vctx, unsigned char *key, size_t keylen) { + KDF_X942 *ctx = (KDF_X942 *)vctx; int ret = 0; unsigned char *ctr; unsigned char *der = NULL; size_t der_len = 0; - if (impl->secret == NULL) { - KDFerr(KDF_F_X942KDF_DERIVE, KDF_R_MISSING_SECRET); + if (ctx->secret == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); return 0; } - if (impl->md == NULL) { - KDFerr(KDF_F_X942KDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST); + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); return 0; } - if (impl->cek_nid == NID_undef) { - KDFerr(KDF_F_X942KDF_DERIVE, KDF_R_MISSING_CEK_ALG); + if (ctx->cek_nid == NID_undef) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG); return 0; } - if (impl->ukm != NULL && impl->ukm_len >= X942KDF_MAX_INLEN) { + if (ctx->ukm != NULL && ctx->ukm_len >= X942KDF_MAX_INLEN) { /* * Note the ukm length MUST be 512 bits. * For backwards compatibility the old check is being done. */ - KDFerr(KDF_F_X942KDF_DERIVE, KDF_R_INAVLID_UKM_LEN); + ERR_raise(ERR_LIB_PROV, PROV_R_INAVLID_UKM_LENGTH); return 0; } - if (keylen != impl->dkm_len) { - KDFerr(KDF_F_X942KDF_DERIVE, KDF_R_MISSING_CEK_ALG); + if (keylen != ctx->dkm_len) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG); return 0; } /* generate the otherinfo der */ - if (!x942_encode_otherinfo(impl->cek_nid, impl->dkm_len, - impl->ukm, impl->ukm_len, + if (!x942_encode_otherinfo(ctx->cek_nid, ctx->dkm_len, + ctx->ukm, ctx->ukm_len, &der, &der_len, &ctr)) { - KDFerr(KDF_F_X942KDF_DERIVE, KDF_R_BAD_ENCODING); + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_ENCODING); return 0; } - ret = x942kdf_hash_kdm(impl->md, impl->secret, impl->secret_len, + ret = x942kdf_hash_kdm(ctx->md, ctx->secret, ctx->secret_len, der, der_len, ctr, key, keylen); OPENSSL_free(der); return ret; } -const EVP_KDF x942_kdf_meth = { - EVP_KDF_X942, - x942kdf_new, - x942kdf_free, - x942kdf_reset, - x942kdf_ctrl, - x942kdf_ctrl_str, - x942kdf_size, - x942kdf_derive +static int x942kdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_X942 *ctx = vctx; + EVP_MD *md; + const char *properties = NULL; + size_t i; + + /* Grab search properties, this should be before the digest lookup */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES)) + != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + properties = p->data; + } + /* Handle aliasing of digest parameter names */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), p->data, + properties); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + return 0; + } + EVP_MD_meth_free(ctx->md); + ctx->md = md; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL + || (p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) + if (!x942kdf_set_buffer(&ctx->secret, &ctx->secret_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_UKM)) != NULL) + if (!x942kdf_set_buffer(&ctx->ukm, &ctx->ukm_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + ctx->cek_nid = OBJ_sn2nid(p->data); + for (i = 0; i < OSSL_NELEM(kek_algs); i++) + if (kek_algs[i].nid == ctx->cek_nid) + goto cek_found; + ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_CEK_ALG); + return 0; +cek_found: + ctx->dkm_len = kek_algs[i].keklen; + } + return 1; +} + +static const OSSL_PARAM *x942kdf_settable_ctx_params(void) +{ + 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_SECRET, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_UKM, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int x942kdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + KDF_X942 *ctx = (KDF_X942 *)vctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, x942kdf_size(ctx)); + return -2; +} + +static const OSSL_PARAM *x942kdf_gettable_ctx_params(void) +{ + 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 kdf_x942_kdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))x942kdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))x942kdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))x942kdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))x942kdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))x942kdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))x942kdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))x942kdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))x942kdf_get_ctx_params }, + { 0, NULL } }; #endif /* OPENSSL_NO_CMS */ diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 000bf73672..59cd4080f4 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -15,6 +15,7 @@ #include #include #include +#include /* TODO(3.0): Needed for dummy_evp_call(). To be removed */ #include @@ -121,6 +122,7 @@ static int dummy_evp_call(void *provctx) OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(provctx); EVP_MD_CTX *ctx = EVP_MD_CTX_new(); EVP_MD *sha256 = EVP_MD_fetch(libctx, "SHA256", NULL); + EVP_KDF *kdf = EVP_KDF_fetch(libctx, "pbkdf2", NULL); char msg[] = "Hello World!"; const unsigned char exptd[] = { 0x7f, 0x83, 0xb1, 0x65, 0x7f, 0xf1, 0xfc, 0x53, 0xb9, 0x2d, 0xc1, 0x81, @@ -138,7 +140,7 @@ static int dummy_evp_call(void *provctx) EC_KEY *key = NULL; #endif - if (ctx == NULL || sha256 == NULL || drbg == NULL) + if (ctx == NULL || sha256 == NULL || drbg == NULL || kdf == NULL) goto err; if (!EVP_DigestInit_ex(ctx, sha256, NULL)) @@ -185,6 +187,7 @@ static int dummy_evp_call(void *provctx) BN_CTX_end(bnctx); BN_CTX_free(bnctx); + EVP_KDF_free(kdf); EVP_MD_CTX_free(ctx); EVP_MD_free(sha256); @@ -342,6 +345,14 @@ static const OSSL_ALGORITHM fips_macs[] = { { NULL, NULL, NULL } }; +static const OSSL_ALGORITHM fips_kdfs[] = { + { "HKDF", "fips=yes", kdf_hkdf_functions }, + { "SSKDF", "fips=yes", kdf_sskdf_functions }, + { "PBKDF2", "fips=yes", kdf_pbkdf2_functions }, + { "TLS1-PRF", "fips=yes", kdf_tls1_prf_functions }, + { NULL, NULL, NULL } +}; + static const OSSL_ALGORITHM *fips_query(OSSL_PROVIDER *prov, int operation_id, int *no_cache) @@ -354,6 +365,8 @@ static const OSSL_ALGORITHM *fips_query(OSSL_PROVIDER *prov, return fips_ciphers; case OSSL_OP_MAC: return fips_macs; + case OSSL_OP_KDF: + return fips_kdfs; } return NULL; } -- 2.25.1