diff options
Diffstat (limited to 'providers/implementations/kdfs/pbkdf2.c')
-rw-r--r-- | providers/implementations/kdfs/pbkdf2.c | 172 |
1 files changed, 138 insertions, 34 deletions
diff --git a/providers/implementations/kdfs/pbkdf2.c b/providers/implementations/kdfs/pbkdf2.c index 2a0ae63acc32..b38331406412 100644 --- a/providers/implementations/kdfs/pbkdf2.c +++ b/providers/implementations/kdfs/pbkdf2.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2018-2024 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 @@ -28,15 +28,17 @@ #include "prov/providercommon.h" #include "prov/implementations.h" #include "prov/provider_util.h" +#include "prov/securitycheck.h" #include "pbkdf2.h" /* Constants specified in SP800-132 */ -#define KDF_PBKDF2_MIN_KEY_LEN_BITS 112 +#define KDF_PBKDF2_MIN_KEY_LEN_BITS 112 #define KDF_PBKDF2_MAX_KEY_LEN_DIGEST_RATIO 0xFFFFFFFF #define KDF_PBKDF2_MIN_ITERATIONS 1000 #define KDF_PBKDF2_MIN_SALT_LEN (128 / 8) static OSSL_FUNC_kdf_newctx_fn kdf_pbkdf2_new; +static OSSL_FUNC_kdf_dupctx_fn kdf_pbkdf2_dup; static OSSL_FUNC_kdf_freectx_fn kdf_pbkdf2_free; static OSSL_FUNC_kdf_reset_fn kdf_pbkdf2_reset; static OSSL_FUNC_kdf_derive_fn kdf_pbkdf2_derive; @@ -45,11 +47,6 @@ static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pbkdf2_set_ctx_params; static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pbkdf2_gettable_ctx_params; static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pbkdf2_get_ctx_params; -static int pbkdf2_derive(const char *pass, size_t passlen, - const unsigned char *salt, int saltlen, uint64_t iter, - const EVP_MD *digest, unsigned char *key, - size_t keylen, int extra_checks); - typedef struct { void *provctx; unsigned char *pass; @@ -59,11 +56,17 @@ typedef struct { uint64_t iter; PROV_DIGEST digest; int lower_bound_checks; + OSSL_FIPS_IND_DECLARE } KDF_PBKDF2; +static int pbkdf2_derive(KDF_PBKDF2 *ctx, const char *pass, size_t passlen, + const unsigned char *salt, int saltlen, uint64_t iter, + const EVP_MD *digest, unsigned char *key, + size_t keylen, int lower_bound_checks); + static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx); -static void *kdf_pbkdf2_new(void *provctx) +static void *kdf_pbkdf2_new_no_init(void *provctx) { KDF_PBKDF2 *ctx; @@ -71,19 +74,30 @@ static void *kdf_pbkdf2_new(void *provctx) return NULL; ctx = OPENSSL_zalloc(sizeof(*ctx)); - if (ctx == NULL) { - ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + if (ctx == NULL) return NULL; - } ctx->provctx = provctx; - kdf_pbkdf2_init(ctx); + OSSL_FIPS_IND_INIT(ctx); + return ctx; +} + +static void *kdf_pbkdf2_new(void *provctx) +{ + KDF_PBKDF2 *ctx = kdf_pbkdf2_new_no_init(provctx); + + if (ctx != NULL) + kdf_pbkdf2_init(ctx); return ctx; } static void kdf_pbkdf2_cleanup(KDF_PBKDF2 *ctx) { ossl_prov_digest_reset(&ctx->digest); +#ifdef OPENSSL_PEDANTIC_ZEROIZATION + OPENSSL_clear_free(ctx->salt, ctx->salt_len); +#else OPENSSL_free(ctx->salt); +#endif OPENSSL_clear_free(ctx->pass, ctx->pass_len); memset(ctx, 0, sizeof(*ctx)); } @@ -108,6 +122,31 @@ static void kdf_pbkdf2_reset(void *vctx) kdf_pbkdf2_init(ctx); } +static void *kdf_pbkdf2_dup(void *vctx) +{ + const KDF_PBKDF2 *src = (const KDF_PBKDF2 *)vctx; + KDF_PBKDF2 *dest; + + /* We need a new PBKDF2 object but uninitialised since we're filling it */ + dest = kdf_pbkdf2_new_no_init(src->provctx); + if (dest != NULL) { + if (!ossl_prov_memdup(src->salt, src->salt_len, + &dest->salt, &dest->salt_len) + || !ossl_prov_memdup(src->pass, src->pass_len, + &dest->pass, &dest->pass_len) + || !ossl_prov_digest_copy(&dest->digest, &src->digest)) + goto err; + dest->iter = src->iter; + dest->lower_bound_checks = src->lower_bound_checks; + OSSL_FIPS_IND_COPY(dest, src) + } + return dest; + + err: + kdf_pbkdf2_free(dest); + return NULL; +} + static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx) { OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; @@ -130,10 +169,8 @@ static int pbkdf2_set_membuf(unsigned char **buffer, size_t *buflen, *buflen = 0; if (p->data_size == 0) { - if ((*buffer = OPENSSL_malloc(1)) == NULL) { - ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + if ((*buffer = OPENSSL_malloc(1)) == NULL) return 0; - } } else if (p->data != NULL) { if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen)) return 0; @@ -141,6 +178,53 @@ static int pbkdf2_set_membuf(unsigned char **buffer, size_t *buflen, return 1; } +static int pbkdf2_lower_bound_check_passed(int saltlen, uint64_t iter, + size_t keylen, int *error, + const char **desc) +{ + if ((keylen * 8) < KDF_PBKDF2_MIN_KEY_LEN_BITS) { + *error = PROV_R_KEY_SIZE_TOO_SMALL; + if (desc != NULL) + *desc = "Key size"; + return 0; + } + if (saltlen < KDF_PBKDF2_MIN_SALT_LEN) { + *error = PROV_R_INVALID_SALT_LENGTH; + if (desc != NULL) + *desc = "Salt size"; + return 0; + } + if (iter < KDF_PBKDF2_MIN_ITERATIONS) { + *error = PROV_R_INVALID_ITERATION_COUNT; + if (desc != NULL) + *desc = "Iteration count"; + return 0; + } + + return 1; +} + +#ifdef FIPS_MODULE +static int fips_lower_bound_check_passed(KDF_PBKDF2 *ctx, size_t keylen) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + int error = 0; + const char *desc = NULL; + int approved = pbkdf2_lower_bound_check_passed(ctx->salt_len, ctx->iter, + keylen, &error, &desc); + + if (!approved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, libctx, + "PBKDF2", desc, + ossl_fips_config_pbkdf2_lower_bound_check)) { + ERR_raise(ERR_LIB_PROV, error); + return 0; + } + } + return 1; +} +#endif + static int kdf_pbkdf2_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { @@ -161,7 +245,7 @@ static int kdf_pbkdf2_derive(void *vctx, unsigned char *key, size_t keylen, } md = ossl_prov_digest_md(&ctx->digest); - return pbkdf2_derive((char *)ctx->pass, ctx->pass_len, + return pbkdf2_derive(ctx, (char *)ctx->pass, ctx->pass_len, ctx->salt, ctx->salt_len, ctx->iter, md, key, keylen, ctx->lower_bound_checks); } @@ -173,17 +257,30 @@ static int kdf_pbkdf2_set_ctx_params(void *vctx, const OSSL_PARAM params[]) OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); int pkcs5; uint64_t iter, min_iter; + const EVP_MD *md; - if (params == NULL) + if (ossl_param_is_empty(params)) return 1; - if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) - return 0; + if (OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST) != NULL) { + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) + return 0; + md = ossl_prov_digest_md(&ctx->digest); + if (EVP_MD_xof(md)) { + ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED); + 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; +#ifdef FIPS_MODULE + ossl_FIPS_IND_set_settable(OSSL_FIPS_IND_GET(ctx), + OSSL_FIPS_IND_SETTABLE0, + ctx->lower_bound_checks); +#endif } if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) @@ -196,7 +293,7 @@ static int kdf_pbkdf2_set_ctx_params(void *vctx, const OSSL_PARAM params[]) ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH); return 0; } - if (!pbkdf2_set_membuf(&ctx->salt, &ctx->salt_len,p)) + if (!pbkdf2_set_membuf(&ctx->salt, &ctx->salt_len, p)) return 0; } @@ -233,8 +330,12 @@ static int kdf_pbkdf2_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; + if (!OSSL_PARAM_set_size_t(p, SIZE_MAX)) + return 0; + + if (!OSSL_FIPS_IND_GET_CTX_PARAM((KDF_PBKDF2 *) vctx, params)) + return 0; + return 1; } static const OSSL_PARAM *kdf_pbkdf2_gettable_ctx_params(ossl_unused void *ctx, @@ -242,6 +343,7 @@ static const OSSL_PARAM *kdf_pbkdf2_gettable_ctx_params(ossl_unused void *ctx, { static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; @@ -249,6 +351,7 @@ static const OSSL_PARAM *kdf_pbkdf2_gettable_ctx_params(ossl_unused void *ctx, const OSSL_DISPATCH ossl_kdf_pbkdf2_functions[] = { { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pbkdf2_new }, + { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_pbkdf2_dup }, { 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 }, @@ -258,7 +361,7 @@ const OSSL_DISPATCH ossl_kdf_pbkdf2_functions[] = { { 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 } + OSSL_DISPATCH_END }; /* @@ -271,7 +374,7 @@ const OSSL_DISPATCH ossl_kdf_pbkdf2_functions[] = { * - Minimum iteration count of 1000. * - Randomly-generated portion of the salt shall be at least 128 bits. */ -static int pbkdf2_derive(const char *pass, size_t passlen, +static int pbkdf2_derive(KDF_PBKDF2 *ctx, const char *pass, size_t passlen, const unsigned char *salt, int saltlen, uint64_t iter, const EVP_MD *digest, unsigned char *key, size_t keylen, int lower_bound_checks) @@ -296,20 +399,21 @@ static int pbkdf2_derive(const char *pass, size_t passlen, return 0; } +#ifdef FIPS_MODULE + if (!fips_lower_bound_check_passed(ctx, keylen)) + return 0; +#else if (lower_bound_checks) { - if ((keylen * 8) < KDF_PBKDF2_MIN_KEY_LEN_BITS) { - ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL); - 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) { - ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT); + int error = 0; + int passed = pbkdf2_lower_bound_check_passed(saltlen, iter, keylen, + &error, NULL); + + if (!passed) { + ERR_raise(ERR_LIB_PROV, error); return 0; } } +#endif hctx_tpl = HMAC_CTX_new(); if (hctx_tpl == NULL) |