From: Pauli Date: Wed, 21 Aug 2019 03:09:10 +0000 (+1000) Subject: Add KDFs to providers X-Git-Tag: openssl-3.0.0-alpha1~1485 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=e3405a4a9a5334cd636940a547a25c09ffc76009;p=oweals%2Fopenssl.git Add KDFs to providers Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/9662) --- 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/scrypt.c b/providers/common/kdfs/scrypt.c deleted file mode 100644 index 29ceeb3ad9..0000000000 --- a/providers/common/kdfs/scrypt.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the Apache License 2.0 (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include -#include -#include -#include -#include -#include -#include "internal/evp_int.h" -#include "internal/numbers.h" -#include "kdf_local.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 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); - -struct evp_kdf_impl_st { - unsigned char *pass; - size_t pass_len; - unsigned char *salt; - size_t salt_len; - uint64_t N; - uint32_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; - - 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 EVP_KDF_IMPL *kdf_scrypt_new(void) -{ - EVP_KDF_IMPL *impl; - - impl = OPENSSL_zalloc(sizeof(*impl)); - if (impl == NULL) { - KDFerr(KDF_F_KDF_SCRYPT_NEW, ERR_R_MALLOC_FAILURE); - return NULL; - } - kdf_scrypt_init(impl); - return impl; -} - -static void kdf_scrypt_free(EVP_KDF_IMPL *impl) -{ - kdf_scrypt_reset(impl); - OPENSSL_free(impl); -} - -static void kdf_scrypt_reset(EVP_KDF_IMPL *impl) -{ - OPENSSL_free(impl->salt); - OPENSSL_clear_free(impl->pass, impl->pass_len); - memset(impl, 0, sizeof(*impl)); - kdf_scrypt_init(impl); -} - -static void kdf_scrypt_init(EVP_KDF_IMPL *impl) -{ - /* 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; -} - -static int scrypt_set_membuf(unsigned char **buffer, size_t *buflen, - const unsigned char *new_buffer, - size_t new_buflen) -{ - if (new_buffer == NULL) - return 1; - - OPENSSL_clear_free(*buffer, *buflen); - - if (new_buflen > 0) { - *buffer = OPENSSL_memdup(new_buffer, new_buflen); - } else { - *buffer = OPENSSL_malloc(1); - } - if (*buffer == NULL) { - KDFerr(KDF_F_SCRYPT_SET_MEMBUF, ERR_R_MALLOC_FAILURE); - return 0; - } - - *buflen = new_buflen; - return 1; -} - -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) -{ - 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) - return 0; - - impl->r = value; - return 1; - - case EVP_KDF_CTRL_SET_SCRYPT_P: - value = va_arg(args, uint32_t); - if (value < 1) - 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) - return 0; - - impl->maxmem_bytes = u64_value; - return 1; - - default: - return -2; - } -} - -static int kdf_scrypt_ctrl_uint32(EVP_KDF_IMPL *impl, int cmd, - const char *value) -{ - int int_value = atoi(value); - - if (int_value < 0 || (uint64_t)int_value > UINT32_MAX) { - KDFerr(KDF_F_KDF_SCRYPT_CTRL_UINT32, KDF_R_VALUE_ERROR); - return 0; - } - return call_ctrl(kdf_scrypt_ctrl, impl, cmd, (uint32_t)int_value); -} - -static int kdf_scrypt_ctrl_uint64(EVP_KDF_IMPL *impl, int cmd, - const char *value) -{ - 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 int kdf_scrypt_ctrl_str(EVP_KDF_IMPL *impl, const char *type, - const char *value) -{ - 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); - - return -2; -} - -static int kdf_scrypt_derive(EVP_KDF_IMPL *impl, unsigned char *key, - size_t keylen) -{ - 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); -} - -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 -}; - -#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) -static void salsa208_word_specification(uint32_t inout[16]) -{ - int i; - uint32_t x[16]; - - memcpy(x, inout, sizeof(x)); - for (i = 8; i > 0; i -= 2) { - x[4] ^= R(x[0] + x[12], 7); - x[8] ^= R(x[4] + x[0], 9); - x[12] ^= R(x[8] + x[4], 13); - x[0] ^= R(x[12] + x[8], 18); - x[9] ^= R(x[5] + x[1], 7); - x[13] ^= R(x[9] + x[5], 9); - x[1] ^= R(x[13] + x[9], 13); - x[5] ^= R(x[1] + x[13], 18); - x[14] ^= R(x[10] + x[6], 7); - x[2] ^= R(x[14] + x[10], 9); - x[6] ^= R(x[2] + x[14], 13); - x[10] ^= R(x[6] + x[2], 18); - x[3] ^= R(x[15] + x[11], 7); - x[7] ^= R(x[3] + x[15], 9); - x[11] ^= R(x[7] + x[3], 13); - x[15] ^= R(x[11] + x[7], 18); - x[1] ^= R(x[0] + x[3], 7); - x[2] ^= R(x[1] + x[0], 9); - x[3] ^= R(x[2] + x[1], 13); - x[0] ^= R(x[3] + x[2], 18); - x[6] ^= R(x[5] + x[4], 7); - x[7] ^= R(x[6] + x[5], 9); - x[4] ^= R(x[7] + x[6], 13); - x[5] ^= R(x[4] + x[7], 18); - x[11] ^= R(x[10] + x[9], 7); - x[8] ^= R(x[11] + x[10], 9); - x[9] ^= R(x[8] + x[11], 13); - x[10] ^= R(x[9] + x[8], 18); - x[12] ^= R(x[15] + x[14], 7); - x[13] ^= R(x[12] + x[15], 9); - x[14] ^= R(x[13] + x[12], 13); - x[15] ^= R(x[14] + x[13], 18); - } - for (i = 0; i < 16; ++i) - inout[i] += x[i]; - OPENSSL_cleanse(x, sizeof(x)); -} - -static void scryptBlockMix(uint32_t *B_, uint32_t *B, uint64_t r) -{ - uint64_t i, j; - uint32_t X[16], *pB; - - memcpy(X, B + (r * 2 - 1) * 16, sizeof(X)); - pB = B; - for (i = 0; i < r * 2; i++) { - for (j = 0; j < 16; j++) - X[j] ^= *pB++; - salsa208_word_specification(X); - memcpy(B_ + (i / 2 + (i & 1) * r) * 16, X, sizeof(X)); - } - OPENSSL_cleanse(X, sizeof(X)); -} - -static void scryptROMix(unsigned char *B, uint64_t r, uint64_t N, - uint32_t *X, uint32_t *T, uint32_t *V) -{ - unsigned char *pB; - uint32_t *pV; - uint64_t i, k; - - /* Convert from little endian input */ - for (pV = V, i = 0, pB = B; i < 32 * r; i++, pV++) { - *pV = *pB++; - *pV |= *pB++ << 8; - *pV |= *pB++ << 16; - *pV |= (uint32_t)*pB++ << 24; - } - - for (i = 1; i < N; i++, pV += 32 * r) - scryptBlockMix(pV, pV - 32 * r, r); - - scryptBlockMix(X, V + (N - 1) * 32 * r, r); - - for (i = 0; i < N; i++) { - uint32_t j; - j = X[16 * (2 * r - 1)] % N; - pV = V + 32 * r * j; - for (k = 0; k < 32 * r; k++) - T[k] = X[k] ^ *pV++; - scryptBlockMix(X, T, r); - } - /* Convert output to little endian */ - for (i = 0, pB = B; i < 32 * r; i++) { - uint32_t xtmp = X[i]; - *pB++ = xtmp & 0xff; - *pB++ = (xtmp >> 8) & 0xff; - *pB++ = (xtmp >> 16) & 0xff; - *pB++ = (xtmp >> 24) & 0xff; - } -} - -#ifndef SIZE_MAX -# define SIZE_MAX ((size_t)-1) -#endif - -/* - * Maximum power of two that will fit in uint64_t: this should work on - * most (all?) platforms. - */ - -#define LOG2_UINT64_MAX (sizeof(uint64_t) * 8 - 1) - -/* - * Maximum value of p * r: - * p <= ((2^32-1) * hLen) / MFLen => - * p <= ((2^32-1) * 32) / (128 * r) => - * p * r <= (2^30-1) - */ - -#define SCRYPT_PR_MAX ((1 << 30) - 1) - -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) -{ - int rv = 0; - unsigned char *B; - uint32_t *X, *V, *T; - uint64_t i, Blen, Vlen; - - /* Sanity check parameters */ - /* initial check, r,p must be non zero, N >= 2 and a power of 2 */ - if (r == 0 || p == 0 || N < 2 || (N & (N - 1))) - return 0; - /* Check p * r < SCRYPT_PR_MAX avoiding overflow */ - if (p > SCRYPT_PR_MAX / r) { - EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); - return 0; - } - - /* - * Need to check N: if 2^(128 * r / 8) overflows limit this is - * automatically satisfied since N <= UINT64_MAX. - */ - - if (16 * r <= LOG2_UINT64_MAX) { - if (N >= (((uint64_t)1) << (16 * r))) { - EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); - return 0; - } - } - - /* Memory checks: check total allocated buffer size fits in uint64_t */ - - /* - * B size in section 5 step 1.S - * Note: we know p * 128 * r < UINT64_MAX because we already checked - * p * r < SCRYPT_PR_MAX - */ - Blen = p * 128 * r; - /* - * Yet we pass it as integer to PKCS5_PBKDF2_HMAC... [This would - * have to be revised when/if PKCS5_PBKDF2_HMAC accepts size_t.] - */ - if (Blen > INT_MAX) { - EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); - return 0; - } - - /* - * Check 32 * r * (N + 2) * sizeof(uint32_t) fits in uint64_t - * This is combined size V, X and T (section 4) - */ - i = UINT64_MAX / (32 * sizeof(uint32_t)); - if (N + 2 > i / r) { - EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); - return 0; - } - Vlen = 32 * r * (N + 2) * sizeof(uint32_t); - - /* check total allocated size fits in uint64_t */ - if (Blen > UINT64_MAX - Vlen) { - EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); - return 0; - } - - /* Check that the maximum memory doesn't exceed a size_t limits */ - if (maxmem > SIZE_MAX) - maxmem = SIZE_MAX; - - if (Blen + Vlen > maxmem) { - EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); - return 0; - } - - /* If no key return to indicate parameters are OK */ - if (key == NULL) - return 1; - - B = OPENSSL_malloc((size_t)(Blen + Vlen)); - if (B == NULL) { - EVPerr(EVP_F_SCRYPT_ALG, ERR_R_MALLOC_FAILURE); - return 0; - } - X = (uint32_t *)(B + Blen); - T = X + 32 * r; - V = T + 32 * r; - if (PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, 1, EVP_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(), - keylen, key) == 0) - goto err; - rv = 1; - err: - if (rv == 0) - EVPerr(EVP_F_SCRYPT_ALG, EVP_R_PBKDF2_ERROR); - - OPENSSL_clear_free(B, (size_t)(Blen + Vlen)); - return rv; -} - -#endif 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/common/kdfs/x942kdf.c b/providers/common/kdfs/x942kdf.c deleted file mode 100644 index ce9ad61035..0000000000 --- a/providers/common/kdfs/x942kdf.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * - * Licensed under the Apache License 2.0 (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include "e_os.h" - -#ifndef OPENSSL_NO_CMS - -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include "internal/cryptlib.h" -# include "internal/evp_int.h" -# include "kdf_local.h" - -# define X942KDF_MAX_INLEN (1 << 30) - -struct evp_kdf_impl_st { - const EVP_MD *md; - unsigned char *secret; - size_t secret_len; - int cek_nid; - unsigned char *ukm; - size_t ukm_len; - size_t dkm_len; -}; - -/* A table of allowed wrapping algorithms and the associated output lengths */ -static const struct { - int nid; - size_t keklen; /* size in bytes */ -} kek_algs[] = { - { NID_id_smime_alg_CMS3DESwrap, 24 }, - { NID_id_smime_alg_CMSRC2wrap, 16 }, - { NID_id_aes128_wrap, 16 }, - { NID_id_aes192_wrap, 24 }, - { NID_id_aes256_wrap, 32 }, - { NID_id_camellia128_wrap, 16 }, - { NID_id_camellia192_wrap, 24 }, - { NID_id_camellia256_wrap, 32 } -}; - -/* Skip past an ASN1 structure: for OBJECT skip content octets too */ -static int skip_asn1(unsigned char **pp, long *plen, int exptag) -{ - int i, tag, xclass; - long tmplen; - const unsigned char *q = *pp; - - i = ASN1_get_object(&q, &tmplen, &tag, &xclass, *plen); - if ((i & 0x80) != 0 || tag != exptag || xclass != V_ASN1_UNIVERSAL) - return 0; - if (tag == V_ASN1_OBJECT) - q += tmplen; - *pp = (unsigned char *)q; - *plen -= q - *pp; - return 1; -} - -/* - * Encode the other info structure. - * - * RFC2631 Section 2.1.2 Contains the following definition for otherinfo - * - * OtherInfo ::= SEQUENCE { - * keyInfo KeySpecificInfo, - * partyAInfo [0] OCTET STRING OPTIONAL, - * suppPubInfo [2] OCTET STRING - * } - * - * KeySpecificInfo ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * counter OCTET STRING SIZE (4..4) - * } - * - * |nid| is the algorithm object identifier. - * |keylen| is the length (in bytes) of the generated KEK. It is stored into - * suppPubInfo (in bits). - * |ukm| is the optional user keying material that is stored into partyAInfo. It - * can be NULL. - * |ukmlen| is the user keying material length (in bytes). - * |der| is the returned encoded data. It must be freed by the caller. - * |der_len| is the returned size of the encoded data. - * |out_ctr| returns a pointer to the counter data which is embedded inside the - * encoded data. This allows the counter bytes to be updated without re-encoding. - * - * Returns: 1 if successfully encoded, or 0 otherwise. - * Assumptions: |der|, |der_len| & |out_ctr| are not NULL. - */ -static int x942_encode_otherinfo(int nid, size_t keylen, - const unsigned char *ukm, size_t ukmlen, - unsigned char **der, size_t *der_len, - unsigned char **out_ctr) -{ - unsigned char *p, *encoded = NULL; - int ret = 0, encoded_len; - long tlen; - /* "magic" value to check offset is sane */ - static unsigned char ctr[4] = { 0x00, 0x00, 0x00, 0x01 }; - X509_ALGOR *ksi = NULL; - ASN1_OBJECT *alg_oid = NULL; - ASN1_OCTET_STRING *ctr_oct = NULL, *ukm_oct = NULL; - - /* set the KeySpecificInfo - which contains an algorithm oid and counter */ - ksi = X509_ALGOR_new(); - alg_oid = OBJ_dup(OBJ_nid2obj(nid)); - ctr_oct = ASN1_OCTET_STRING_new(); - if (ksi == NULL - || alg_oid == NULL - || ctr_oct == NULL - || !ASN1_OCTET_STRING_set(ctr_oct, ctr, sizeof(ctr)) - || !X509_ALGOR_set0(ksi, alg_oid, V_ASN1_OCTET_STRING, ctr_oct)) - goto err; - /* NULL these as they now belong to ksi */ - alg_oid = NULL; - ctr_oct = NULL; - - /* Set the optional partyAInfo */ - if (ukm != NULL) { - ukm_oct = ASN1_OCTET_STRING_new(); - if (ukm_oct == NULL) - goto err; - ASN1_OCTET_STRING_set(ukm_oct, (unsigned char *)ukm, ukmlen); - } - /* Generate the OtherInfo DER data */ - encoded_len = CMS_SharedInfo_encode(&encoded, ksi, ukm_oct, keylen); - if (encoded_len <= 0) - goto err; - - /* Parse the encoded data to find the offset of the counter data */ - p = encoded; - tlen = (long)encoded_len; - if (skip_asn1(&p, &tlen, V_ASN1_SEQUENCE) - && skip_asn1(&p, &tlen, V_ASN1_SEQUENCE) - && skip_asn1(&p, &tlen, V_ASN1_OBJECT) - && skip_asn1(&p, &tlen, V_ASN1_OCTET_STRING) - && CRYPTO_memcmp(p, ctr, 4) == 0) { - *out_ctr = p; - *der = encoded; - *der_len = (size_t)encoded_len; - ret = 1; - } -err: - if (ret != 1) - OPENSSL_free(encoded); - ASN1_OCTET_STRING_free(ctr_oct); - ASN1_OCTET_STRING_free(ukm_oct); - ASN1_OBJECT_free(alg_oid); - X509_ALGOR_free(ksi); - return ret; -} - -static int x942kdf_hash_kdm(const EVP_MD *kdf_md, - const unsigned char *z, size_t z_len, - const unsigned char *other, size_t other_len, - unsigned char *ctr, - unsigned char *derived_key, size_t derived_key_len) -{ - int ret = 0, hlen; - size_t counter, out_len, len = derived_key_len; - unsigned char mac[EVP_MAX_MD_SIZE]; - unsigned char *out = derived_key; - EVP_MD_CTX *ctx = NULL, *ctx_init = NULL; - - 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); - return 0; - } - - hlen = EVP_MD_size(kdf_md); - if (hlen <= 0) - return 0; - out_len = (size_t)hlen; - - ctx = EVP_MD_CTX_create(); - ctx_init = EVP_MD_CTX_create(); - if (ctx == NULL || ctx_init == NULL) - goto end; - - if (!EVP_DigestInit(ctx_init, kdf_md)) - goto end; - - for (counter = 1;; counter++) { - /* updating the ctr modifies 4 bytes in the 'other' buffer */ - ctr[0] = (unsigned char)((counter >> 24) & 0xff); - ctr[1] = (unsigned char)((counter >> 16) & 0xff); - ctr[2] = (unsigned char)((counter >> 8) & 0xff); - ctr[3] = (unsigned char)(counter & 0xff); - - if (!EVP_MD_CTX_copy_ex(ctx, ctx_init) - || !EVP_DigestUpdate(ctx, z, z_len) - || !EVP_DigestUpdate(ctx, other, other_len)) - goto end; - if (len >= out_len) { - if (!EVP_DigestFinal_ex(ctx, out, NULL)) - goto end; - out += out_len; - len -= out_len; - if (len == 0) - break; - } else { - if (!EVP_DigestFinal_ex(ctx, mac, NULL)) - goto end; - memcpy(out, mac, len); - break; - } - } - ret = 1; -end: - EVP_MD_CTX_free(ctx); - EVP_MD_CTX_free(ctx_init); - OPENSSL_cleanse(mac, sizeof(mac)); - return ret; -} - -static EVP_KDF_IMPL *x942kdf_new(void) -{ - EVP_KDF_IMPL *impl; - - if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL) - KDFerr(KDF_F_X942KDF_NEW, ERR_R_MALLOC_FAILURE); - return impl; -} - -static void x942kdf_reset(EVP_KDF_IMPL *impl) -{ - OPENSSL_clear_free(impl->secret, impl->secret_len); - OPENSSL_clear_free(impl->ukm, impl->ukm_len); - memset(impl, 0, sizeof(*impl)); -} - -static void x942kdf_free(EVP_KDF_IMPL *impl) -{ - x942kdf_reset(impl); - OPENSSL_free(impl); -} - -static int x942kdf_set_buffer(va_list args, unsigned char **out, size_t *out_len) -{ - 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; - - *out_len = len; - return 1; -} - -static int x942kdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) -{ - 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; - 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; -} - -static size_t x942kdf_size(EVP_KDF_IMPL *impl) -{ - int len; - - if (impl->md == NULL) { - KDFerr(KDF_F_X942KDF_SIZE, KDF_R_MISSING_MESSAGE_DIGEST); - return 0; - } - len = EVP_MD_size(impl->md); - return (len <= 0) ? 0 : (size_t)len; -} - -static int x942kdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, size_t keylen) -{ - 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); - return 0; - } - if (impl->md == NULL) { - KDFerr(KDF_F_X942KDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST); - return 0; - } - if (impl->cek_nid == NID_undef) { - KDFerr(KDF_F_X942KDF_DERIVE, KDF_R_MISSING_CEK_ALG); - return 0; - } - if (impl->ukm != NULL && impl->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); - return 0; - } - if (keylen != impl->dkm_len) { - KDFerr(KDF_F_X942KDF_DERIVE, KDF_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, - &der, &der_len, &ctr)) { - KDFerr(KDF_F_X942KDF_DERIVE, KDF_R_BAD_ENCODING); - return 0; - } - ret = x942kdf_hash_kdm(impl->md, impl->secret, impl->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 -}; - -#endif /* OPENSSL_NO_CMS */ 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/default/kdfs/scrypt.c b/providers/default/kdfs/scrypt.c new file mode 100644 index 0000000000..57dc317d21 --- /dev/null +++ b/providers/default/kdfs/scrypt.c @@ -0,0 +1,464 @@ +/* + * 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include "internal/evp_int.h" +#include "internal/numbers.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 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, EVP_MD *sha256); + +typedef struct { + void *provctx; + unsigned char *pass; + size_t pass_len; + unsigned char *salt; + size_t salt_len; + uint64_t N; + uint64_t r, p; + uint64_t maxmem_bytes; + EVP_MD *sha256; +} KDF_SCRYPT; + +static void kdf_scrypt_init(KDF_SCRYPT *ctx); + +static void *kdf_scrypt_new(void *provctx) +{ + KDF_SCRYPT *ctx; + + 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(ctx); + return ctx; +} + +static void kdf_scrypt_free(void *vctx) +{ + KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx; + + kdf_scrypt_reset(ctx); + EVP_MD_meth_free(ctx->sha256); + OPENSSL_free(ctx); +} + +static void kdf_scrypt_reset(void *vctx) +{ + 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(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). + */ + 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 OSSL_PARAM *p) +{ + OPENSSL_clear_free(*buffer, *buflen); + if (p->data_size == 0) { + if ((*buffer = OPENSSL_malloc(1)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + } else if (p->data != NULL) { + *buffer = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen)) + return 0; + } + return 1; +} + +static int kdf_scrypt_derive(void *vctx, unsigned char *key, + size_t keylen) +{ + KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx; + + if (ctx->pass == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS); + return 0; + } + + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT); + return 0; + } + + 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) +{ + return (value != 0) && ((value & (value - 1)) == 0); +} + +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; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) + if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) + if (!scrypt_set_membuf(&ctx->salt, &ctx->salt_len, p)) + return 0; + + 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; + } + + 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; + } + + 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 ((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 1; +} + +static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(void) +{ + 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_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_scrypt_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_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)))) +static void salsa208_word_specification(uint32_t inout[16]) +{ + int i; + uint32_t x[16]; + + memcpy(x, inout, sizeof(x)); + for (i = 8; i > 0; i -= 2) { + x[4] ^= R(x[0] + x[12], 7); + x[8] ^= R(x[4] + x[0], 9); + x[12] ^= R(x[8] + x[4], 13); + x[0] ^= R(x[12] + x[8], 18); + x[9] ^= R(x[5] + x[1], 7); + x[13] ^= R(x[9] + x[5], 9); + x[1] ^= R(x[13] + x[9], 13); + x[5] ^= R(x[1] + x[13], 18); + x[14] ^= R(x[10] + x[6], 7); + x[2] ^= R(x[14] + x[10], 9); + x[6] ^= R(x[2] + x[14], 13); + x[10] ^= R(x[6] + x[2], 18); + x[3] ^= R(x[15] + x[11], 7); + x[7] ^= R(x[3] + x[15], 9); + x[11] ^= R(x[7] + x[3], 13); + x[15] ^= R(x[11] + x[7], 18); + x[1] ^= R(x[0] + x[3], 7); + x[2] ^= R(x[1] + x[0], 9); + x[3] ^= R(x[2] + x[1], 13); + x[0] ^= R(x[3] + x[2], 18); + x[6] ^= R(x[5] + x[4], 7); + x[7] ^= R(x[6] + x[5], 9); + x[4] ^= R(x[7] + x[6], 13); + x[5] ^= R(x[4] + x[7], 18); + x[11] ^= R(x[10] + x[9], 7); + x[8] ^= R(x[11] + x[10], 9); + x[9] ^= R(x[8] + x[11], 13); + x[10] ^= R(x[9] + x[8], 18); + x[12] ^= R(x[15] + x[14], 7); + x[13] ^= R(x[12] + x[15], 9); + x[14] ^= R(x[13] + x[12], 13); + x[15] ^= R(x[14] + x[13], 18); + } + for (i = 0; i < 16; ++i) + inout[i] += x[i]; + OPENSSL_cleanse(x, sizeof(x)); +} + +static void scryptBlockMix(uint32_t *B_, uint32_t *B, uint64_t r) +{ + uint64_t i, j; + uint32_t X[16], *pB; + + memcpy(X, B + (r * 2 - 1) * 16, sizeof(X)); + pB = B; + for (i = 0; i < r * 2; i++) { + for (j = 0; j < 16; j++) + X[j] ^= *pB++; + salsa208_word_specification(X); + memcpy(B_ + (i / 2 + (i & 1) * r) * 16, X, sizeof(X)); + } + OPENSSL_cleanse(X, sizeof(X)); +} + +static void scryptROMix(unsigned char *B, uint64_t r, uint64_t N, + uint32_t *X, uint32_t *T, uint32_t *V) +{ + unsigned char *pB; + uint32_t *pV; + uint64_t i, k; + + /* Convert from little endian input */ + for (pV = V, i = 0, pB = B; i < 32 * r; i++, pV++) { + *pV = *pB++; + *pV |= *pB++ << 8; + *pV |= *pB++ << 16; + *pV |= (uint32_t)*pB++ << 24; + } + + for (i = 1; i < N; i++, pV += 32 * r) + scryptBlockMix(pV, pV - 32 * r, r); + + scryptBlockMix(X, V + (N - 1) * 32 * r, r); + + for (i = 0; i < N; i++) { + uint32_t j; + j = X[16 * (2 * r - 1)] % N; + pV = V + 32 * r * j; + for (k = 0; k < 32 * r; k++) + T[k] = X[k] ^ *pV++; + scryptBlockMix(X, T, r); + } + /* Convert output to little endian */ + for (i = 0, pB = B; i < 32 * r; i++) { + uint32_t xtmp = X[i]; + *pB++ = xtmp & 0xff; + *pB++ = (xtmp >> 8) & 0xff; + *pB++ = (xtmp >> 16) & 0xff; + *pB++ = (xtmp >> 24) & 0xff; + } +} + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t)-1) +#endif + +/* + * Maximum power of two that will fit in uint64_t: this should work on + * most (all?) platforms. + */ + +#define LOG2_UINT64_MAX (sizeof(uint64_t) * 8 - 1) + +/* + * Maximum value of p * r: + * p <= ((2^32-1) * hLen) / MFLen => + * p <= ((2^32-1) * 32) / (128 * r) => + * p * r <= (2^30-1) + */ + +#define SCRYPT_PR_MAX ((1 << 30) - 1) + +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, EVP_MD *sha256) +{ + int rv = 0; + unsigned char *B; + uint32_t *X, *V, *T; + uint64_t i, Blen, Vlen; + + /* Sanity check parameters */ + /* initial check, r,p must be non zero, N >= 2 and a power of 2 */ + if (r == 0 || p == 0 || N < 2 || (N & (N - 1))) + return 0; + /* Check p * r < SCRYPT_PR_MAX avoiding overflow */ + if (p > SCRYPT_PR_MAX / r) { + EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + + /* + * Need to check N: if 2^(128 * r / 8) overflows limit this is + * automatically satisfied since N <= UINT64_MAX. + */ + + if (16 * r <= LOG2_UINT64_MAX) { + if (N >= (((uint64_t)1) << (16 * r))) { + EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + } + + /* Memory checks: check total allocated buffer size fits in uint64_t */ + + /* + * B size in section 5 step 1.S + * Note: we know p * 128 * r < UINT64_MAX because we already checked + * p * r < SCRYPT_PR_MAX + */ + Blen = p * 128 * r; + /* + * Yet we pass it as integer to PKCS5_PBKDF2_HMAC... [This would + * have to be revised when/if PKCS5_PBKDF2_HMAC accepts size_t.] + */ + if (Blen > INT_MAX) { + EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + + /* + * Check 32 * r * (N + 2) * sizeof(uint32_t) fits in uint64_t + * This is combined size V, X and T (section 4) + */ + i = UINT64_MAX / (32 * sizeof(uint32_t)); + if (N + 2 > i / r) { + EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + Vlen = 32 * r * (N + 2) * sizeof(uint32_t); + + /* check total allocated size fits in uint64_t */ + if (Blen > UINT64_MAX - Vlen) { + EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + + /* Check that the maximum memory doesn't exceed a size_t limits */ + if (maxmem > SIZE_MAX) + maxmem = SIZE_MAX; + + if (Blen + Vlen > maxmem) { + EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + + /* If no key return to indicate parameters are OK */ + if (key == NULL) + return 1; + + B = OPENSSL_malloc((size_t)(Blen + Vlen)); + if (B == NULL) { + EVPerr(EVP_F_SCRYPT_ALG, ERR_R_MALLOC_FAILURE); + return 0; + } + X = (uint32_t *)(B + Blen); + T = X + 32 * r; + V = T + 32 * r; + 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, sha256, + keylen, key) == 0) + goto err; + rv = 1; + err: + if (rv == 0) + EVPerr(EVP_F_SCRYPT_ALG, EVP_R_PBKDF2_ERROR); + + OPENSSL_clear_free(B, (size_t)(Blen + Vlen)); + return rv; +} + +#endif 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/default/kdfs/x942kdf.c b/providers/default/kdfs/x942kdf.c new file mode 100644 index 0000000000..e8a5e4cad5 --- /dev/null +++ b/providers/default/kdfs/x942kdf.c @@ -0,0 +1,440 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "e_os.h" + +#ifndef OPENSSL_NO_CMS + +# include +# include +# include +# include +# 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" + +# define X942KDF_MAX_INLEN (1 << 30) + +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 { + int nid; + size_t keklen; /* size in bytes */ +} kek_algs[] = { + { NID_id_smime_alg_CMS3DESwrap, 24 }, + { NID_id_smime_alg_CMSRC2wrap, 16 }, + { NID_id_aes128_wrap, 16 }, + { NID_id_aes192_wrap, 24 }, + { NID_id_aes256_wrap, 32 }, + { NID_id_camellia128_wrap, 16 }, + { NID_id_camellia192_wrap, 24 }, + { NID_id_camellia256_wrap, 32 } +}; + +/* Skip past an ASN1 structure: for OBJECT skip content octets too */ +static int skip_asn1(unsigned char **pp, long *plen, int exptag) +{ + int i, tag, xclass; + long tmplen; + const unsigned char *q = *pp; + + i = ASN1_get_object(&q, &tmplen, &tag, &xclass, *plen); + if ((i & 0x80) != 0 || tag != exptag || xclass != V_ASN1_UNIVERSAL) + return 0; + if (tag == V_ASN1_OBJECT) + q += tmplen; + *pp = (unsigned char *)q; + *plen -= q - *pp; + return 1; +} + +/* + * Encode the other info structure. + * + * RFC2631 Section 2.1.2 Contains the following definition for otherinfo + * + * OtherInfo ::= SEQUENCE { + * keyInfo KeySpecificInfo, + * partyAInfo [0] OCTET STRING OPTIONAL, + * suppPubInfo [2] OCTET STRING + * } + * + * KeySpecificInfo ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * counter OCTET STRING SIZE (4..4) + * } + * + * |nid| is the algorithm object identifier. + * |keylen| is the length (in bytes) of the generated KEK. It is stored into + * suppPubInfo (in bits). + * |ukm| is the optional user keying material that is stored into partyAInfo. It + * can be NULL. + * |ukmlen| is the user keying material length (in bytes). + * |der| is the returned encoded data. It must be freed by the caller. + * |der_len| is the returned size of the encoded data. + * |out_ctr| returns a pointer to the counter data which is embedded inside the + * encoded data. This allows the counter bytes to be updated without re-encoding. + * + * Returns: 1 if successfully encoded, or 0 otherwise. + * Assumptions: |der|, |der_len| & |out_ctr| are not NULL. + */ +static int x942_encode_otherinfo(int nid, size_t keylen, + const unsigned char *ukm, size_t ukmlen, + unsigned char **der, size_t *der_len, + unsigned char **out_ctr) +{ + unsigned char *p, *encoded = NULL; + int ret = 0, encoded_len; + long tlen; + /* "magic" value to check offset is sane */ + static unsigned char ctr[4] = { 0x00, 0x00, 0x00, 0x01 }; + X509_ALGOR *ksi = NULL; + ASN1_OBJECT *alg_oid = NULL; + ASN1_OCTET_STRING *ctr_oct = NULL, *ukm_oct = NULL; + + /* set the KeySpecificInfo - which contains an algorithm oid and counter */ + ksi = X509_ALGOR_new(); + alg_oid = OBJ_dup(OBJ_nid2obj(nid)); + ctr_oct = ASN1_OCTET_STRING_new(); + if (ksi == NULL + || alg_oid == NULL + || ctr_oct == NULL + || !ASN1_OCTET_STRING_set(ctr_oct, ctr, sizeof(ctr)) + || !X509_ALGOR_set0(ksi, alg_oid, V_ASN1_OCTET_STRING, ctr_oct)) + goto err; + /* NULL these as they now belong to ksi */ + alg_oid = NULL; + ctr_oct = NULL; + + /* Set the optional partyAInfo */ + if (ukm != NULL) { + ukm_oct = ASN1_OCTET_STRING_new(); + if (ukm_oct == NULL) + goto err; + ASN1_OCTET_STRING_set(ukm_oct, (unsigned char *)ukm, ukmlen); + } + /* Generate the OtherInfo DER data */ + encoded_len = CMS_SharedInfo_encode(&encoded, ksi, ukm_oct, keylen); + if (encoded_len <= 0) + goto err; + + /* Parse the encoded data to find the offset of the counter data */ + p = encoded; + tlen = (long)encoded_len; + if (skip_asn1(&p, &tlen, V_ASN1_SEQUENCE) + && skip_asn1(&p, &tlen, V_ASN1_SEQUENCE) + && skip_asn1(&p, &tlen, V_ASN1_OBJECT) + && skip_asn1(&p, &tlen, V_ASN1_OCTET_STRING) + && CRYPTO_memcmp(p, ctr, 4) == 0) { + *out_ctr = p; + *der = encoded; + *der_len = (size_t)encoded_len; + ret = 1; + } +err: + if (ret != 1) + OPENSSL_free(encoded); + ASN1_OCTET_STRING_free(ctr_oct); + ASN1_OCTET_STRING_free(ukm_oct); + ASN1_OBJECT_free(alg_oid); + X509_ALGOR_free(ksi); + return ret; +} + +static int x942kdf_hash_kdm(const EVP_MD *kdf_md, + const unsigned char *z, size_t z_len, + const unsigned char *other, size_t other_len, + unsigned char *ctr, + unsigned char *derived_key, size_t derived_key_len) +{ + int ret = 0, hlen; + size_t counter, out_len, len = derived_key_len; + unsigned char mac[EVP_MAX_MD_SIZE]; + unsigned char *out = derived_key; + EVP_MD_CTX *ctx = NULL, *ctx_init = NULL; + + if (z_len > X942KDF_MAX_INLEN || other_len > X942KDF_MAX_INLEN + || derived_key_len > X942KDF_MAX_INLEN + || derived_key_len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); + return 0; + } + + hlen = EVP_MD_size(kdf_md); + if (hlen <= 0) + return 0; + out_len = (size_t)hlen; + + ctx = EVP_MD_CTX_create(); + ctx_init = EVP_MD_CTX_create(); + if (ctx == NULL || ctx_init == NULL) + goto end; + + if (!EVP_DigestInit(ctx_init, kdf_md)) + goto end; + + for (counter = 1;; counter++) { + /* updating the ctr modifies 4 bytes in the 'other' buffer */ + ctr[0] = (unsigned char)((counter >> 24) & 0xff); + ctr[1] = (unsigned char)((counter >> 16) & 0xff); + ctr[2] = (unsigned char)((counter >> 8) & 0xff); + ctr[3] = (unsigned char)(counter & 0xff); + + if (!EVP_MD_CTX_copy_ex(ctx, ctx_init) + || !EVP_DigestUpdate(ctx, z, z_len) + || !EVP_DigestUpdate(ctx, other, other_len)) + goto end; + if (len >= out_len) { + if (!EVP_DigestFinal_ex(ctx, out, NULL)) + goto end; + out += out_len; + len -= out_len; + if (len == 0) + break; + } else { + if (!EVP_DigestFinal_ex(ctx, mac, NULL)) + goto end; + memcpy(out, mac, len); + break; + } + } + ret = 1; +end: + EVP_MD_CTX_free(ctx); + EVP_MD_CTX_free(ctx_init); + OPENSSL_cleanse(mac, sizeof(mac)); + return ret; +} + +static void *x942kdf_new(void *provctx) +{ + KDF_X942 *ctx; + + 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(void *vctx) +{ + KDF_X942 *ctx = (KDF_X942 *)vctx; + + OPENSSL_clear_free(ctx->secret, ctx->secret_len); + OPENSSL_clear_free(ctx->ukm, ctx->ukm_len); + memset(ctx, 0, sizeof(*ctx)); +} + +static void x942kdf_free(void *vctx) +{ + KDF_X942 *ctx = (KDF_X942 *)vctx; + + x942kdf_reset(ctx); + EVP_MD_meth_free(ctx->md); + OPENSSL_free(ctx); +} + +static int x942kdf_set_buffer(unsigned char **out, size_t *out_len, + const OSSL_PARAM *p) +{ + if (p->data_size == 0 || p->data == NULL) + return 1; + + OPENSSL_free(*out); + *out = NULL; + return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len); +} + +static size_t x942kdf_size(KDF_X942 *ctx) +{ + int len; + + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + len = EVP_MD_size(ctx->md); + return (len <= 0) ? 0 : (size_t)len; +} + +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 (ctx->secret == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); + return 0; + } + if (ctx->md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + if (ctx->cek_nid == NID_undef) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG); + return 0; + } + 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. + */ + ERR_raise(ERR_LIB_PROV, PROV_R_INAVLID_UKM_LENGTH); + return 0; + } + 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(ctx->cek_nid, ctx->dkm_len, + ctx->ukm, ctx->ukm_len, + &der, &der_len, &ctr)) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_ENCODING); + return 0; + } + ret = x942kdf_hash_kdm(ctx->md, ctx->secret, ctx->secret_len, + der, der_len, ctr, key, keylen); + OPENSSL_free(der); + return ret; +} + +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; }