openssl/0078-Add-FIPS-indicator-par...

875 lines
34 KiB
Diff

From 2000eaead63732669283e6b54c8ef02e268eaeb8 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Mon, 31 Jul 2023 09:41:29 +0200
Subject: [PATCH 34/48] 0078-Add-FIPS-indicator-parameter-to-HKDF.patch
Patch-name: 0078-Add-FIPS-indicator-parameter-to-HKDF.patch
Patch-id: 78
Patch-status: |
# https://bugzilla.redhat.com/show_bug.cgi?id=2114772
From-dist-git-commit: 9409bc7044cf4b5773639cce20f51399888c45fd
---
include/crypto/evp.h | 7 ++
include/openssl/core_names.h | 1 +
include/openssl/kdf.h | 4 +
providers/implementations/kdfs/hkdf.c | 100 +++++++++++++++++++++-
providers/implementations/kdfs/kbkdf.c | 82 ++++++++++++++++--
providers/implementations/kdfs/sshkdf.c | 75 +++++++++++++++-
providers/implementations/kdfs/sskdf.c | 100 +++++++++++++++++++++-
providers/implementations/kdfs/tls1_prf.c | 74 +++++++++++++++-
providers/implementations/kdfs/x942kdf.c | 66 +++++++++++++-
9 files changed, 487 insertions(+), 22 deletions(-)
diff --git a/include/crypto/evp.h b/include/crypto/evp.h
index dbbdcccbda..aa07153441 100644
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -219,6 +219,13 @@ struct evp_mac_st {
OSSL_FUNC_mac_set_ctx_params_fn *set_ctx_params;
};
+#ifdef FIPS_MODULE
+/* According to NIST Special Publication 800-131Ar2, Section 8: Deriving
+ * Additional Keys from a Cryptographic Key, "[t]he length of the
+ * key-derivation key [i.e., the input key] shall be at least 112 bits". */
+# define EVP_KDF_FIPS_MIN_KEY_LEN (112 / 8)
+#endif
+
struct evp_kdf_st {
OSSL_PROVIDER *prov;
int name_id;
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index c0cce14297..b431b9f871 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -226,6 +226,7 @@ extern "C" {
#define OSSL_KDF_PARAM_X942_SUPP_PUBINFO "supp-pubinfo"
#define OSSL_KDF_PARAM_X942_SUPP_PRIVINFO "supp-privinfo"
#define OSSL_KDF_PARAM_X942_USE_KEYBITS "use-keybits"
+#define OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR "redhat-fips-indicator"
/* Known KDF names */
#define OSSL_KDF_NAME_HKDF "HKDF"
diff --git a/include/openssl/kdf.h b/include/openssl/kdf.h
index 0983230a48..86171635ea 100644
--- a/include/openssl/kdf.h
+++ b/include/openssl/kdf.h
@@ -63,6 +63,10 @@ int EVP_KDF_names_do_all(const EVP_KDF *kdf,
# define EVP_KDF_HKDF_MODE_EXTRACT_ONLY 1
# define EVP_KDF_HKDF_MODE_EXPAND_ONLY 2
+# define EVP_KDF_REDHAT_FIPS_INDICATOR_UNDETERMINED 0
+# define EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED 1
+# define EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED 2
+
#define EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV 65
#define EVP_KDF_SSHKDF_TYPE_INITIAL_IV_SRV_TO_CLI 66
#define EVP_KDF_SSHKDF_TYPE_ENCRYPTION_KEY_CLI_TO_SRV 67
diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c
index 5304baa6c9..f9c77f4236 100644
--- a/providers/implementations/kdfs/hkdf.c
+++ b/providers/implementations/kdfs/hkdf.c
@@ -43,6 +43,7 @@ static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_hkdf_settable_ctx_params;
static OSSL_FUNC_kdf_set_ctx_params_fn kdf_hkdf_set_ctx_params;
static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_hkdf_gettable_ctx_params;
static OSSL_FUNC_kdf_get_ctx_params_fn kdf_hkdf_get_ctx_params;
+static OSSL_FUNC_kdf_newctx_fn kdf_tls1_3_new;
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;
@@ -86,6 +87,10 @@ typedef struct {
size_t data_len;
unsigned char *info;
size_t info_len;
+ int is_tls13;
+#ifdef FIPS_MODULE
+ int fips_indicator;
+#endif /* defined(FIPS_MODULE) */
} KDF_HKDF;
static void *kdf_hkdf_new(void *provctx)
@@ -201,6 +206,11 @@ static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen,
return 0;
}
+#ifdef FIPS_MODULE
+ if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN)
+ ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+#endif /* defined(FIPS_MODULE) */
+
switch (ctx->mode) {
case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND:
default:
@@ -363,15 +373,78 @@ static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
KDF_HKDF *ctx = (KDF_HKDF *)vctx;
OSSL_PARAM *p;
+ int any_valid = 0; /* set to 1 when at least one parameter was valid */
if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) {
size_t sz = kdf_hkdf_size(ctx);
- if (sz == 0)
+ any_valid = 1;
+
+ if (sz == 0 || !OSSL_PARAM_set_size_t(p, sz))
return 0;
- return OSSL_PARAM_set_size_t(p, sz);
}
- return -2;
+
+#ifdef FIPS_MODULE
+ if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR))
+ != NULL) {
+ int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED;
+ const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
+
+ any_valid = 1;
+
+ /* According to NIST Special Publication 800-131Ar2, Section 8:
+ * Deriving Additional Keys from a Cryptographic Key, "[t]he length of
+ * the key-derivation key [i.e., the input key] shall be at least 112
+ * bits". */
+ if (ctx->key_len < EVP_KDF_FIPS_MIN_KEY_LEN)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Verification Program, Section D.B and NIST Special Publication
+ * 800-131Ar2, Section 1.2.2 say that any algorithm at a security
+ * strength < 112 bits is legacy use only, so all derived keys should
+ * be longer than that. If a derived key has ever been shorter than
+ * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we
+ * should also set the returned FIPS indicator to unapproved. */
+ if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ if (ctx->is_tls13) {
+ if (md != NULL
+ && !EVP_MD_is_a(md, "SHA2-256")
+ && !EVP_MD_is_a(md, "SHA2-384")) {
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic
+ * Module Validation Program, Section 2.4.B, (5): "The TLS 1.3
+ * key derivation function documented in Section 7.1 of RFC
+ * 8446. This is considered an approved CVL because the
+ * underlying functions performed within the TLS 1.3 KDF map to
+ * NIST approved standards, namely: SP 800-133rev2 (Section 6.3
+ * Option #3), SP 800-56Crev2, and SP 800-108."
+ *
+ * RFC 8446 appendix B.4 only lists SHA-256 and SHA-384. */
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+ }
+ } else {
+ if (md != NULL
+ && (EVP_MD_is_a(md, "SHAKE-128") ||
+ EVP_MD_is_a(md, "SHAKE-256"))) {
+ /* HKDF is a SP 800-56Cr2 TwoStep KDF, for which all SHA-1,
+ * SHA-2 and SHA-3 are approved. SHAKE is not approved, because
+ * of FIPS 140-3 IG, section C.C: "The SHAKE128 and SHAKE256
+ * extendable-output functions may only be used as the
+ * standalone algorithms." */
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+ }
+ }
+ if (!OSSL_PARAM_set_int(p, fips_indicator))
+ return 0;
+ }
+#endif /* defined(FIPS_MODULE) */
+
+ if (!any_valid)
+ return -2;
+
+ return 1;
}
static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(ossl_unused void *ctx,
@@ -379,6 +452,9 @@ static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(ossl_unused void *ctx,
{
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+#ifdef FIPS_MODULE
+ OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, NULL),
+#endif /* defined(FIPS_MODULE) */
OSSL_PARAM_END
};
return known_gettable_ctx_params;
@@ -709,6 +785,17 @@ static int prov_tls13_hkdf_generate_secret(OSSL_LIB_CTX *libctx,
return ret;
}
+static void *kdf_tls1_3_new(void *provctx)
+{
+ KDF_HKDF *hkdf = kdf_hkdf_new(provctx);
+
+ if (hkdf != NULL)
+ hkdf->is_tls13 = 1;
+
+ return hkdf;
+}
+
+
static int kdf_tls1_3_derive(void *vctx, unsigned char *key, size_t keylen,
const OSSL_PARAM params[])
{
@@ -724,6 +811,11 @@ static int kdf_tls1_3_derive(void *vctx, unsigned char *key, size_t keylen,
return 0;
}
+#ifdef FIPS_MODULE
+ if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN)
+ ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+#endif /* defined(FIPS_MODULE) */
+
switch (ctx->mode) {
default:
return 0;
@@ -801,7 +893,7 @@ static const OSSL_PARAM *kdf_tls1_3_settable_ctx_params(ossl_unused void *ctx,
}
const OSSL_DISPATCH ossl_kdf_tls1_3_kdf_functions[] = {
- { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_hkdf_new },
+ { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_tls1_3_new },
{ OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_hkdf_dup },
{ OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_hkdf_free },
{ OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_hkdf_reset },
diff --git a/providers/implementations/kdfs/kbkdf.c b/providers/implementations/kdfs/kbkdf.c
index aa3df15bc7..3f82710061 100644
--- a/providers/implementations/kdfs/kbkdf.c
+++ b/providers/implementations/kdfs/kbkdf.c
@@ -59,6 +59,9 @@ typedef struct {
kbkdf_mode mode;
EVP_MAC_CTX *ctx_init;
+ /* HMAC digest algorithm, if any; used to compute FIPS indicator */
+ PROV_DIGEST digest;
+
/* Names are lowercased versions of those found in SP800-108. */
int r;
unsigned char *ki;
@@ -72,6 +75,9 @@ typedef struct {
int use_l;
int is_kmac;
int use_separator;
+#ifdef FIPS_MODULE
+ int fips_indicator;
+#endif /* defined(FIPS_MODULE) */
} KBKDF;
/* Definitions needed for typechecking. */
@@ -143,6 +149,7 @@ static void kbkdf_reset(void *vctx)
void *provctx = ctx->provctx;
EVP_MAC_CTX_free(ctx->ctx_init);
+ ossl_prov_digest_reset(&ctx->digest);
OPENSSL_clear_free(ctx->context, ctx->context_len);
OPENSSL_clear_free(ctx->label, ctx->label_len);
OPENSSL_clear_free(ctx->ki, ctx->ki_len);
@@ -308,6 +315,11 @@ static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen,
goto done;
}
+#ifdef FIPS_MODULE
+ if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN)
+ ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+#endif /* defined(FIPS_MODULE) */
+
h = EVP_MAC_CTX_get_mac_size(ctx->ctx_init);
if (h == 0)
goto done;
@@ -381,6 +393,9 @@ static int kbkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
}
}
+ if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx))
+ return 0;
+
p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE);
if (p != NULL
&& OPENSSL_strncasecmp("counter", p->data, p->data_size) == 0) {
@@ -461,20 +476,77 @@ static const OSSL_PARAM *kbkdf_settable_ctx_params(ossl_unused void *ctx,
static int kbkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
OSSL_PARAM *p;
+ int any_valid = 0; /* set to 1 when at least one parameter was valid */
p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE);
- if (p == NULL)
+ if (p != NULL) {
+ any_valid = 1;
+
+ /* KBKDF can produce results as large as you like. */
+ if (!OSSL_PARAM_set_size_t(p, SIZE_MAX))
+ return 0;
+ }
+
+#ifdef FIPS_MODULE
+ p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR);
+ if (p != NULL) {
+ KBKDF *ctx = (KBKDF *)vctx;
+ int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED;
+
+ any_valid = 1;
+
+ /* According to NIST Special Publication 800-131Ar2, Section 8:
+ * Deriving Additional Keys from a Cryptographic Key, "[t]he length of
+ * the key-derivation key [i.e., the input key] shall be at least 112
+ * bits". */
+ if (ctx->ki_len < EVP_KDF_FIPS_MIN_KEY_LEN)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Verification Program, Section D.B and NIST Special Publication
+ * 800-131Ar2, Section 1.2.2 say that any algorithm at a security
+ * strength < 112 bits is legacy use only, so all derived keys should
+ * be longer than that. If a derived key has ever been shorter than
+ * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we
+ * should also set the returned FIPS indicator to unapproved. */
+ if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Validation Program, Section C.C: "The SHAKE128 and SHAKE256
+ * extendable-output functions may only be used as the standalone
+ * algorithms." Note that the digest is only used when the MAC
+ * algorithm is HMAC. */
+ if (ctx->ctx_init != NULL
+ && EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->ctx_init), OSSL_MAC_NAME_HMAC)) {
+ const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
+ if (md != NULL
+ && (EVP_MD_is_a(md, "SHAKE-128") || EVP_MD_is_a(md, "SHAKE-256"))) {
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+ }
+ }
+
+ if (!OSSL_PARAM_set_int(p, fips_indicator))
+ return 0;
+ }
+#endif
+
+ if (!any_valid)
return -2;
- /* KBKDF can produce results as large as you like. */
- return OSSL_PARAM_set_size_t(p, SIZE_MAX);
+ return 1;
}
static const OSSL_PARAM *kbkdf_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_END };
+ static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+#ifdef FIPS_MODULE
+ OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, NULL),
+#endif /* defined(FIPS_MODULE) */
+ OSSL_PARAM_END
+ };
return known_gettable_ctx_params;
}
diff --git a/providers/implementations/kdfs/sshkdf.c b/providers/implementations/kdfs/sshkdf.c
index 1afac4e477..389b82b714 100644
--- a/providers/implementations/kdfs/sshkdf.c
+++ b/providers/implementations/kdfs/sshkdf.c
@@ -49,6 +49,9 @@ typedef struct {
char type; /* X */
unsigned char *session_id;
size_t session_id_len;
+#ifdef FIPS_MODULE
+ int fips_indicator;
+#endif /* defined(FIPS_MODULE) */
} KDF_SSHKDF;
static void *kdf_sshkdf_new(void *provctx)
@@ -151,6 +154,12 @@ static int kdf_sshkdf_derive(void *vctx, unsigned char *key, size_t keylen,
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_TYPE);
return 0;
}
+
+#ifdef FIPS_MODULE
+ if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN)
+ ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+#endif /* defined(FIPS_MODULE) */
+
return SSHKDF(md, ctx->key, ctx->key_len,
ctx->xcghash, ctx->xcghash_len,
ctx->session_id, ctx->session_id_len,
@@ -219,10 +228,67 @@ static const OSSL_PARAM *kdf_sshkdf_settable_ctx_params(ossl_unused void *ctx,
static int kdf_sshkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
OSSL_PARAM *p;
+ int any_valid = 0; /* set to 1 when at least one parameter was valid */
- if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
- return OSSL_PARAM_set_size_t(p, SIZE_MAX);
- return -2;
+ if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) {
+ any_valid = 1;
+
+ if (!OSSL_PARAM_set_size_t(p, SIZE_MAX))
+ return 0;
+ }
+
+#ifdef FIPS_MODULE
+ p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR);
+ if (p != NULL) {
+ KDF_SSHKDF *ctx = vctx;
+ int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED;
+
+ any_valid = 1;
+
+ /* According to NIST Special Publication 800-131Ar2, Section 8:
+ * Deriving Additional Keys from a Cryptographic Key, "[t]he length of
+ * the key-derivation key [i.e., the input key] shall be at least 112
+ * bits". */
+ if (ctx->key_len < EVP_KDF_FIPS_MIN_KEY_LEN)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Verification Program, Section D.B and NIST Special Publication
+ * 800-131Ar2, Section 1.2.2 say that any algorithm at a security
+ * strength < 112 bits is legacy use only, so all derived keys should
+ * be longer than that. If a derived key has ever been shorter than
+ * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we
+ * should also set the returned FIPS indicator to unapproved. */
+ if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Validation Program, Section C.C: "The SHAKE128 and SHAKE256
+ * extendable-output functions may only be used as the standalone
+ * algorithms."
+ *
+ * Additionally, SP 800-135r1 section 5.2 specifies that the hash
+ * function used in SSHKDF "is one of the hash functions specified in
+ * FIPS 180-3.", which rules out SHA-3 and truncated variants of SHA-2.
+ * */
+ if (ctx->digest.md != NULL
+ && !EVP_MD_is_a(ctx->digest.md, "SHA-1")
+ && !EVP_MD_is_a(ctx->digest.md, "SHA2-224")
+ && !EVP_MD_is_a(ctx->digest.md, "SHA2-256")
+ && !EVP_MD_is_a(ctx->digest.md, "SHA2-384")
+ && !EVP_MD_is_a(ctx->digest.md, "SHA2-512")) {
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+ }
+
+ if (!OSSL_PARAM_set_int(p, fips_indicator))
+ return 0;
+ }
+#endif
+
+ if (!any_valid)
+ return -2;
+
+ return 1;
}
static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(ossl_unused void *ctx,
@@ -230,6 +296,9 @@ static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(ossl_unused void *ctx,
{
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+#ifdef FIPS_MODULE
+ OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, NULL),
+#endif /* defined(FIPS_MODULE) */
OSSL_PARAM_END
};
return known_gettable_ctx_params;
diff --git a/providers/implementations/kdfs/sskdf.c b/providers/implementations/kdfs/sskdf.c
index ecb98de6fd..98fcc583d8 100644
--- a/providers/implementations/kdfs/sskdf.c
+++ b/providers/implementations/kdfs/sskdf.c
@@ -63,6 +63,10 @@ typedef struct {
size_t salt_len;
size_t out_len; /* optional KMAC parameter */
int is_kmac;
+ int is_x963kdf;
+#ifdef FIPS_MODULE
+ int fips_indicator;
+#endif /* defined(FIPS_MODULE) */
} KDF_SSKDF;
#define SSKDF_MAX_INLEN (1<<30)
@@ -73,6 +77,7 @@ typedef struct {
static const unsigned char kmac_custom_str[] = { 0x4B, 0x44, 0x46 };
static OSSL_FUNC_kdf_newctx_fn sskdf_new;
+static OSSL_FUNC_kdf_newctx_fn x963kdf_new;
static OSSL_FUNC_kdf_dupctx_fn sskdf_dup;
static OSSL_FUNC_kdf_freectx_fn sskdf_free;
static OSSL_FUNC_kdf_reset_fn sskdf_reset;
@@ -297,6 +302,16 @@ static void *sskdf_new(void *provctx)
return ctx;
}
+static void *x963kdf_new(void *provctx)
+{
+ KDF_SSKDF *ctx = sskdf_new(provctx);
+
+ if (ctx)
+ ctx->is_x963kdf = 1;
+
+ return ctx;
+}
+
static void sskdf_reset(void *vctx)
{
KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
@@ -392,6 +407,11 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen,
}
md = ossl_prov_digest_md(&ctx->digest);
+#ifdef FIPS_MODULE
+ if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN)
+ ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+#endif /* defined(FIPS_MODULE) */
+
if (ctx->macctx != NULL) {
/* H(x) = KMAC or H(x) = HMAC */
int ret;
@@ -473,6 +493,11 @@ static int x963kdf_derive(void *vctx, unsigned char *key, size_t keylen,
return 0;
}
+#ifdef FIPS_MODULE
+ if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN)
+ ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+#endif /* defined(FIPS_MODULE) */
+
return SSKDF_hash_kdm(md, ctx->secret, ctx->secret_len,
ctx->info, ctx->info_len, 1, key, keylen);
}
@@ -545,10 +570,74 @@ static int sskdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
OSSL_PARAM *p;
+ int any_valid = 0; /* set to 1 when at least one parameter was valid */
+
+ if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) {
+ any_valid = 1;
+
+ if (!OSSL_PARAM_set_size_t(p, sskdf_size(ctx)))
+ return 0;
+ }
- if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
- return OSSL_PARAM_set_size_t(p, sskdf_size(ctx));
- return -2;
+#ifdef FIPS_MODULE
+ p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR);
+ if (p != NULL) {
+ int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED;
+
+ any_valid = 1;
+
+ /* According to NIST Special Publication 800-131Ar2, Section 8:
+ * Deriving Additional Keys from a Cryptographic Key, "[t]he length of
+ * the key-derivation key [i.e., the input key] shall be at least 112
+ * bits". */
+ if (ctx->secret_len < EVP_KDF_FIPS_MIN_KEY_LEN)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Verification Program, Section D.B and NIST Special Publication
+ * 800-131Ar2, Section 1.2.2 say that any algorithm at a security
+ * strength < 112 bits is legacy use only, so all derived keys should
+ * be longer than that. If a derived key has ever been shorter than
+ * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we
+ * should also set the returned FIPS indicator to unapproved. */
+ if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Validation Program, Section C.C: "The SHAKE128 and SHAKE256
+ * extendable-output functions may only be used as the standalone
+ * algorithms." */
+ if (ctx->macctx == NULL
+ || (ctx->macctx != NULL &&
+ EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->macctx), OSSL_MAC_NAME_HMAC))) {
+ if (ctx->digest.md != NULL
+ && (EVP_MD_is_a(ctx->digest.md, "SHAKE-128") ||
+ EVP_MD_is_a(ctx->digest.md, "SHAKE-256"))) {
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+ }
+
+ /* Table H-3 in ANS X9.63-2001 says that 160-bit hash functions
+ * should only be used for 80-bit key agreement, but FIPS 140-3
+ * requires a security strength of 112 bits, so SHA-1 cannot be
+ * used with X9.63. See the discussion in
+ * https://github.com/usnistgov/ACVP/issues/1403#issuecomment-1435300395.
+ */
+ if (ctx->is_x963kdf
+ && ctx->digest.md != NULL
+ && EVP_MD_is_a(ctx->digest.md, "SHA-1")) {
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+ }
+ }
+
+ if (!OSSL_PARAM_set_int(p, fips_indicator))
+ return 0;
+ }
+#endif
+
+ if (!any_valid)
+ return -2;
+
+ return 1;
}
static const OSSL_PARAM *sskdf_gettable_ctx_params(ossl_unused void *ctx,
@@ -556,6 +645,9 @@ static const OSSL_PARAM *sskdf_gettable_ctx_params(ossl_unused void *ctx,
{
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+#ifdef FIPS_MODULE
+ OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, 0),
+#endif /* defined(FIPS_MODULE) */
OSSL_PARAM_END
};
return known_gettable_ctx_params;
@@ -577,7 +669,7 @@ const OSSL_DISPATCH ossl_kdf_sskdf_functions[] = {
};
const OSSL_DISPATCH ossl_kdf_x963_kdf_functions[] = {
- { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))sskdf_new },
+ { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))x963kdf_new },
{ OSSL_FUNC_KDF_DUPCTX, (void(*)(void))sskdf_dup },
{ OSSL_FUNC_KDF_FREECTX, (void(*)(void))sskdf_free },
{ OSSL_FUNC_KDF_RESET, (void(*)(void))sskdf_reset },
diff --git a/providers/implementations/kdfs/tls1_prf.c b/providers/implementations/kdfs/tls1_prf.c
index 54124ad4cb..25a6c79a2e 100644
--- a/providers/implementations/kdfs/tls1_prf.c
+++ b/providers/implementations/kdfs/tls1_prf.c
@@ -104,6 +104,13 @@ typedef struct {
/* Buffer of concatenated seed data */
unsigned char seed[TLS1_PRF_MAXBUF];
size_t seedlen;
+
+ /* MAC digest algorithm; used to compute FIPS indicator */
+ PROV_DIGEST digest;
+
+#ifdef FIPS_MODULE
+ int fips_indicator;
+#endif /* defined(FIPS_MODULE) */
} TLS1_PRF;
static void *kdf_tls1_prf_new(void *provctx)
@@ -140,6 +147,7 @@ static void kdf_tls1_prf_reset(void *vctx)
EVP_MAC_CTX_free(ctx->P_sha1);
OPENSSL_clear_free(ctx->sec, ctx->seclen);
OPENSSL_cleanse(ctx->seed, ctx->seedlen);
+ ossl_prov_digest_reset(&ctx->digest);
memset(ctx, 0, sizeof(*ctx));
ctx->provctx = provctx;
}
@@ -194,6 +202,10 @@ static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen,
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
return 0;
}
+#ifdef FIPS_MODULE
+ if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN)
+ ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+#endif /* defined(FIPS_MODULE) */
/*
* The seed buffer is prepended with a label.
@@ -243,6 +255,9 @@ static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
}
}
+ if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx))
+ return 0;
+
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL) {
OPENSSL_clear_free(ctx->sec, ctx->seclen);
ctx->sec = NULL;
@@ -284,10 +299,60 @@ static const OSSL_PARAM *kdf_tls1_prf_settable_ctx_params(
static int kdf_tls1_prf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
OSSL_PARAM *p;
+#ifdef FIPS_MODULE
+ TLS1_PRF *ctx = vctx;
+#endif /* defined(FIPS_MODULE) */
+ int any_valid = 0; /* set to 1 when at least one parameter was valid */
+
+ if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) {
+ any_valid = 1;
+
+ if (!OSSL_PARAM_set_size_t(p, SIZE_MAX))
+ return 0;
+ }
+
+#ifdef FIPS_MODULE
+ p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR);
+ if (p != NULL) {
+ int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED;
+
+ any_valid = 1;
+
+ /* According to NIST Special Publication 800-131Ar2, Section 8:
+ * Deriving Additional Keys from a Cryptographic Key, "[t]he length of
+ * the key-derivation key [i.e., the input key] shall be at least 112
+ * bits". */
+ if (ctx->seclen < EVP_KDF_FIPS_MIN_KEY_LEN)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Verification Program, Section D.B and NIST Special Publication
+ * 800-131Ar2, Section 1.2.2 say that any algorithm at a security
+ * strength < 112 bits is legacy use only, so all derived keys should
+ * be longer than that. If a derived key has ever been shorter than
+ * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we
+ * should also set the returned FIPS indicator to unapproved. */
+ if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* SP 800-135r1 section 4.2.2 says TLS 1.2 KDF is approved when "(3)
+ * P_HASH uses either SHA-256, SHA-384 or SHA-512." */
+ if (ctx->digest.md != NULL
+ && !EVP_MD_is_a(ctx->digest.md, "SHA2-256")
+ && !EVP_MD_is_a(ctx->digest.md, "SHA2-384")
+ && !EVP_MD_is_a(ctx->digest.md, "SHA2-512")) {
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+ }
+
+ if (!OSSL_PARAM_set_int(p, fips_indicator))
+ return 0;
+ }
+#endif
- if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
- return OSSL_PARAM_set_size_t(p, SIZE_MAX);
- return -2;
+ if (!any_valid)
+ return -2;
+
+ return 1;
}
static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params(
@@ -295,6 +360,9 @@ static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params(
{
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+#ifdef FIPS_MODULE
+ OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, 0),
+#endif /* defined(FIPS_MODULE) */
OSSL_PARAM_END
};
return known_gettable_ctx_params;
diff --git a/providers/implementations/kdfs/x942kdf.c b/providers/implementations/kdfs/x942kdf.c
index 4c274fe27a..5ce23c8eb9 100644
--- a/providers/implementations/kdfs/x942kdf.c
+++ b/providers/implementations/kdfs/x942kdf.c
@@ -13,11 +13,13 @@
#include <openssl/core_dispatch.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#include <openssl/kdf.h>
#include <openssl/params.h>
#include <openssl/proverr.h>
#include "internal/packet.h"
#include "internal/der.h"
#include "internal/nelem.h"
+#include "crypto/evp.h"
#include "prov/provider_ctx.h"
#include "prov/providercommon.h"
#include "prov/implementations.h"
@@ -49,6 +51,9 @@ typedef struct {
const unsigned char *cek_oid;
size_t cek_oid_len;
int use_keybits;
+#ifdef FIPS_MODULE
+ int fips_indicator;
+#endif /* defined(FIPS_MODULE) */
} KDF_X942;
/*
@@ -497,6 +502,10 @@ static int x942kdf_derive(void *vctx, unsigned char *key, size_t keylen,
ERR_raise(ERR_LIB_PROV, PROV_R_BAD_ENCODING);
return 0;
}
+#ifdef FIPS_MODULE
+ if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN)
+ ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+#endif /* defined(FIPS_MODULE) */
ret = x942kdf_hash_kdm(md, ctx->secret, ctx->secret_len,
der, der_len, ctr, key, keylen);
OPENSSL_free(der);
@@ -600,10 +609,58 @@ static int x942kdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
KDF_X942 *ctx = (KDF_X942 *)vctx;
OSSL_PARAM *p;
+ int any_valid = 0; /* set to 1 when at least one parameter was valid */
- if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
- return OSSL_PARAM_set_size_t(p, x942kdf_size(ctx));
- return -2;
+ if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) {
+ any_valid = 1;
+
+ if (!OSSL_PARAM_set_size_t(p, x942kdf_size(ctx)))
+ return 0;
+ }
+
+#ifdef FIPS_MODULE
+ p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR);
+ if (p != NULL) {
+ int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED;
+
+ any_valid = 1;
+
+ /* According to NIST Special Publication 800-131Ar2, Section 8:
+ * Deriving Additional Keys from a Cryptographic Key, "[t]he length of
+ * the key-derivation key [i.e., the input key] shall be at least 112
+ * bits". */
+ if (ctx->secret_len < EVP_KDF_FIPS_MIN_KEY_LEN)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Verification Program, Section D.B and NIST Special Publication
+ * 800-131Ar2, Section 1.2.2 say that any algorithm at a security
+ * strength < 112 bits is legacy use only, so all derived keys should
+ * be longer than that. If a derived key has ever been shorter than
+ * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we
+ * should also set the returned FIPS indicator to unapproved. */
+ if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED)
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+
+ /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module
+ * Validation Program, Section C.C: "The SHAKE128 and SHAKE256
+ * extendable-output functions may only be used as the standalone
+ * algorithms." */
+ if (ctx->digest.md != NULL
+ && (EVP_MD_is_a(ctx->digest.md, "SHAKE-128") ||
+ EVP_MD_is_a(ctx->digest.md, "SHAKE-256"))) {
+ fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+ }
+
+ if (!OSSL_PARAM_set_int(p, fips_indicator))
+ return 0;
+ }
+#endif
+
+ if (!any_valid)
+ return -2;
+
+ return 1;
}
static const OSSL_PARAM *x942kdf_gettable_ctx_params(ossl_unused void *ctx,
@@ -611,6 +668,9 @@ static const OSSL_PARAM *x942kdf_gettable_ctx_params(ossl_unused void *ctx,
{
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+#ifdef FIPS_MODULE
+ OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, 0),
+#endif /* defined(FIPS_MODULE) */
OSSL_PARAM_END
};
return known_gettable_ctx_params;
--
2.41.0