Skip to content

Commit

Permalink
Restrict digest in set_ctx_params
Browse files Browse the repository at this point in the history
In this commit, we also return different error if the digest is XOF.

Reviewed-by: Shane Lontis <[email protected]>
Reviewed-by: Paul Dale <[email protected]>
(Merged from openssl#23889)
  • Loading branch information
0140454 authored and paulidale committed Jul 24, 2024
1 parent 5e25b8a commit 14e4660
Show file tree
Hide file tree
Showing 17 changed files with 311 additions and 218 deletions.
16 changes: 0 additions & 16 deletions doc/man7/EVP_KDF-SS.pod
Original file line number Diff line number Diff line change
Expand Up @@ -61,22 +61,6 @@ This parameter set the shared secret that is used for key derivation.

This parameter sets an optional value for fixedinfo, also known as otherinfo.

=item "fips-indicator" (B<OSSL_KDF_PARAM_FIPS_APPROVED_INDICATOR>) <int>

A getter that returns 1 if the operation is FIPS approved, or 0 otherwise.
This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check"
related parameter is set to 0 and the check fails.
This option is used by the OpenSSL FIPS provider.

=item "digest-check" (B<OSSL_KDF_PARAM_FIPS_DIGEST_CHECK>) <int>

The default value of 1 causes an error during EVP_KDF_derive() if
used digest is not approved.
Setting this to zero will ignore the error and set the approved
"fips-indicator" to 0.
This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if
set to 0.

=back

=head1 NOTES
Expand Down
2 changes: 1 addition & 1 deletion doc/man7/EVP_KDF-SSHKDF.pod
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ A single char of value 70 (ASCII char 'F').
=item "fips-indicator" (B<OSSL_KDF_PARAM_FIPS_APPROVED_INDICATOR>) <int>

A getter that returns 1 if the operation is FIPS approved, or 0 otherwise.
This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check"
This may be used after calling EVP_KDF_derive. It returns 0 if any "***-check"
related parameter is set to 0 and the check fails.
This option is used by the OpenSSL FIPS provider.

Expand Down
2 changes: 1 addition & 1 deletion doc/man7/EVP_KDF-TLS13_KDF.pod
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ There are two modes that are currently defined:
=item "fips-indicator" (B<OSSL_KDF_PARAM_FIPS_APPROVED_INDICATOR>) <int>

A getter that returns 1 if the operation is FIPS approved, or 0 otherwise.
This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check"
This may be used after calling EVP_KDF_derive. It returns 0 if any "***-check"
related parameter is set to 0 and the check fails.
This option is used by the OpenSSL FIPS provider.

Expand Down
2 changes: 1 addition & 1 deletion doc/man7/EVP_KDF-TLS1_PRF.pod
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ this should be more than enough for any normal use of the TLS PRF.
=item "fips-indicator" (B<OSSL_KDF_PARAM_FIPS_APPROVED_INDICATOR>) <integer>

A getter that returns 1 if the operation is FIPS approved, or 0 otherwise.
This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check"
This may be used after calling EVP_KDF_derive. It returns 0 if any "***-check"
related parameter is set to 0 and the check fails.
This option is used by the OpenSSL FIPS provider.

Expand Down
2 changes: 1 addition & 1 deletion doc/man7/EVP_KDF-X963.pod
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ This parameter specifies an optional value for shared info.
=item "fips-indicator" (B<OSSL_KDF_PARAM_FIPS_APPROVED_INDICATOR>) <int>

A getter that returns 1 if the operation is FIPS approved, or 0 otherwise.
This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check"
This may be used after calling EVP_KDF_derive. It returns 0 if any "***-check"
related parameter is set to 0 and the check fails.
This option is used by the OpenSSL FIPS provider.

Expand Down
146 changes: 85 additions & 61 deletions providers/implementations/kdfs/hkdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ static OSSL_FUNC_kdf_get_ctx_params_fn kdf_hkdf_get_ctx_params;
static OSSL_FUNC_kdf_derive_fn kdf_tls1_3_derive;
static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_tls1_3_settable_ctx_params;
static OSSL_FUNC_kdf_set_ctx_params_fn kdf_tls1_3_set_ctx_params;
static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_tls1_3_gettable_ctx_params;
static OSSL_FUNC_kdf_get_ctx_params_fn kdf_tls1_3_get_ctx_params;

static int HKDF(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md,
const unsigned char *salt, size_t salt_len,
Expand All @@ -66,13 +68,18 @@ static int HKDF_Expand(const EVP_MD *evp_md,
unsigned char *okm, size_t okm_len);

/* Settable context parameters that are common across HKDF and the TLS KDF */
#define HKDF_COMMON_SETTABLES \
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_KEY, NULL, 0), \
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0)
#define HKDF_COMMON_SETTABLES \
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_KEY, NULL, 0), \
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0)

/* Gettable context parameters that are common across HKDF and the TLS KDF */
#define HKDF_COMMON_GETTABLES \
OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), \
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0)

typedef struct {
void *provctx;
Expand Down Expand Up @@ -187,33 +194,6 @@ static size_t kdf_hkdf_size(KDF_HKDF *ctx)
return sz;
}

#ifdef FIPS_MODULE
static int fips_hkdf_digest_check_passed(KDF_HKDF *ctx)
{
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
/*
* Perform digest check
*
* HKDF is a TwoStep KDF defined in SP 800-56Cr2. According to section 7,
* the valid hash functions are specified in FIPS 180 and FIPS 202.
* However, it only lists SHA-1, SHA-2 and SHA-3 in the table in section
* 5.2. ACVP also only lists the same set of hash functions.
*/
int digest_unapproved = ((EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0);

if (digest_unapproved) {
if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0,
libctx, "HKDF", "Digest",
FIPS_hkdf_digest_check)) {
ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED);
return 0;
}
}
return 1;
}
#endif

static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen,
const OSSL_PARAM params[])
{
Expand All @@ -238,11 +218,6 @@ static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen,
return 0;
}

#ifdef FIPS_MODULE
if (!fips_hkdf_digest_check_passed(ctx))
return 0;
#endif

switch (ctx->mode) {
case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND:
default:
Expand All @@ -268,8 +243,18 @@ static int hkdf_common_set_ctx_params(KDF_HKDF *ctx, const OSSL_PARAM params[])
if (params == NULL)
return 1;

if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx))
return 0;
if (OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST) != NULL) {
const EVP_MD *md = NULL;

if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx))
return 0;

md = ossl_prov_digest_md(&ctx->digest);
if ((EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
return 0;
}
}

if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE)) != NULL) {
if (p->data_type == OSSL_PARAM_UTF8_STRING) {
Expand Down Expand Up @@ -325,10 +310,6 @@ static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
if (params == NULL)
return 1;

if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params,
OSSL_KDF_PARAM_FIPS_DIGEST_CHECK))
return 0;

if (!hkdf_common_set_ctx_params(ctx, params))
return 0;

Expand All @@ -346,17 +327,18 @@ static const OSSL_PARAM *kdf_hkdf_settable_ctx_params(ossl_unused void *ctx,
static const OSSL_PARAM known_settable_ctx_params[] = {
HKDF_COMMON_SETTABLES,
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0),
OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_DIGEST_CHECK)
OSSL_PARAM_END
};
return known_settable_ctx_params;
}

static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
static int hkdf_common_get_ctx_params(KDF_HKDF *ctx, OSSL_PARAM params[])
{
KDF_HKDF *ctx = (KDF_HKDF *)vctx;
OSSL_PARAM *p;

if (params == NULL)
return 1;

if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) {
size_t sz = kdf_hkdf_size(ctx);

Expand All @@ -365,24 +347,35 @@ static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
if (!OSSL_PARAM_set_size_t(p, sz))
return 0;
}

if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_INFO)) != NULL) {
if (ctx->info == NULL || ctx->info_len == 0)
p->return_size = 0;
else if (!OSSL_PARAM_set_octet_string(p, ctx->info, ctx->info_len))
return 0;
}
if (!OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params))

return 1;
}

static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
KDF_HKDF *ctx = (KDF_HKDF *)vctx;

if (params == NULL)
return 1;

if (!hkdf_common_get_ctx_params(ctx, params))
return 0;

return 1;
}

static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(ossl_unused void *ctx,
ossl_unused void *provctx)
{
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0),
OSSL_FIPS_IND_GETTABLE_CTX_PARAM()
HKDF_COMMON_GETTABLES,
OSSL_PARAM_END
};
return known_gettable_ctx_params;
Expand Down Expand Up @@ -714,10 +707,9 @@ static int prov_tls13_hkdf_generate_secret(OSSL_LIB_CTX *libctx,
}

#ifdef FIPS_MODULE
static int fips_tls1_3_digest_check_passed(KDF_HKDF *ctx)
static int fips_tls1_3_digest_check_passed(KDF_HKDF *ctx, const EVP_MD *md)
{
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
/*
* Perform digest check
*
Expand Down Expand Up @@ -755,11 +747,6 @@ static int kdf_tls1_3_derive(void *vctx, unsigned char *key, size_t keylen,
return 0;
}

#ifdef FIPS_MODULE
if (!fips_tls1_3_digest_check_passed(ctx))
return 0;
#endif

switch (ctx->mode) {
default:
return 0;
Expand Down Expand Up @@ -824,6 +811,16 @@ static int kdf_tls1_3_set_ctx_params(void *vctx, const OSSL_PARAM params[])
&& !OSSL_PARAM_get_octet_string(p, (void **)&ctx->data, 0,
&ctx->data_len))
return 0;

#ifdef FIPS_MODULE
if (OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST) != NULL) {
const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);

if (!fips_tls1_3_digest_check_passed(ctx, md))
return 0;
}
#endif

return 1;
}

Expand All @@ -841,6 +838,33 @@ static const OSSL_PARAM *kdf_tls1_3_settable_ctx_params(ossl_unused void *ctx,
return known_settable_ctx_params;
}

static int kdf_tls1_3_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
KDF_HKDF *ctx = (KDF_HKDF *)vctx;

if (params == NULL)
return 1;

if (!hkdf_common_get_ctx_params(ctx, params))
return 0;

if (!OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params))
return 0;

return 1;
}

static const OSSL_PARAM *kdf_tls1_3_gettable_ctx_params(ossl_unused void *ctx,
ossl_unused void *provctx)
{
static const OSSL_PARAM known_gettable_ctx_params[] = {
HKDF_COMMON_GETTABLES,
OSSL_FIPS_IND_GETTABLE_CTX_PARAM()
OSSL_PARAM_END
};
return known_gettable_ctx_params;
}

const OSSL_DISPATCH ossl_kdf_tls1_3_kdf_functions[] = {
{ OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_hkdf_new },
{ OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_hkdf_dup },
Expand All @@ -851,7 +875,7 @@ const OSSL_DISPATCH ossl_kdf_tls1_3_kdf_functions[] = {
(void(*)(void))kdf_tls1_3_settable_ctx_params },
{ OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_tls1_3_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 },
(void(*)(void))kdf_tls1_3_gettable_ctx_params },
{ OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_tls1_3_get_ctx_params },
OSSL_DISPATCH_END
};
28 changes: 18 additions & 10 deletions providers/implementations/kdfs/sshkdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,9 @@ static int sshkdf_set_membuf(unsigned char **dst, size_t *dst_len,
}

#ifdef FIPS_MODULE
static int fips_digest_check_passed(KDF_SSHKDF *ctx)
static int fips_digest_check_passed(KDF_SSHKDF *ctx, const EVP_MD *md)
{
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
/*
* Perform digest check
*
Expand Down Expand Up @@ -187,11 +186,6 @@ static int kdf_sshkdf_derive(void *vctx, unsigned char *key, size_t keylen,
return 0;
}

#ifdef FIPS_MODULE
if (!fips_digest_check_passed(ctx))
return 0;
#endif

return SSHKDF(md, ctx->key, ctx->key_len,
ctx->xcghash, ctx->xcghash_len,
ctx->session_id, ctx->session_id_len,
Expand All @@ -211,8 +205,23 @@ static int kdf_sshkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
OSSL_KDF_PARAM_FIPS_DIGEST_CHECK))
return 0;

if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx))
return 0;
if (OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST) != NULL) {
const EVP_MD *md = NULL;

if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx))
return 0;

md = ossl_prov_digest_md(&ctx->digest);
if ((EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
return 0;
}

#ifdef FIPS_MODULE
if (!fips_digest_check_passed(ctx, md))
return 0;
#endif
}

if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL)
if (!sshkdf_set_membuf(&ctx->key, &ctx->key_len, p))
Expand Down Expand Up @@ -376,4 +385,3 @@ static int SSHKDF(const EVP_MD *evp_md,
OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE);
return ret;
}

Loading

0 comments on commit 14e4660

Please sign in to comment.