aboutsummaryrefslogtreecommitdiff
path: root/providers/implementations/kdfs/pbkdf2.c
diff options
context:
space:
mode:
Diffstat (limited to 'providers/implementations/kdfs/pbkdf2.c')
-rw-r--r--providers/implementations/kdfs/pbkdf2.c172
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)