Add explicit indicator & clamp default PSS salt len

FIPS 186-4 section 5 "The RSA Digital Signature Algorithm", subsection
5.5 "PKCS #1" says: "For RSASSA-PSS […] the length (in bytes) of the
salt (sLen) shall satisfy 0 ≤ sLen ≤ hLen, where hLen is the length of
the hash function output block (in bytes)."

It is not exactly clear from this text whether hLen refers to the
message digest or the hash function used for the mask generation
function MGF1. PKCS#1 v2.1 suggests it is the former:

| Typical salt lengths in octets are hLen (the length of the output of
| the hash function Hash) and 0. In both cases the security of
| RSASSA-PSS can be closely related to the hardness of inverting RSAVP1.
| Bellare and Rogaway [4] give a tight lower bound for the security of
| the original RSA-PSS scheme, which corresponds roughly to the former
| case, while Coron [12] gives a lower bound for the related Full Domain
| Hashing scheme, which corresponds roughly to the latter case. In [13]
| Coron provides a general treatment with various salt lengths ranging
| from 0 to hLen; see [27] for discussion. See also [31], which adapts
| the security proofs in [4][13] to address the differences between the
| original and the present version of RSA-PSS as listed in Note 1 above.

Since OpenSSL defaults to creating signatures with the maximum salt
length, blocking the use of longer salts would probably lead to
significant problems in practice. Instead, introduce an explicit
indicator that can be obtained from the EVP_PKEY_CTX object using
EVP_PKEY_CTX_get_params() with the
  OSSL_SIGNATURE_PARAM_REDHAT_FIPS_INDICATOR
parameter.

Change the default automatic behavior when signing to use at most the
digest size as salt length.

Signed-off-by: Clemens Lang <cllang@redhat.com>
Resolves: rhbz#2144012
This commit is contained in:
Clemens Lang 2022-11-17 19:50:30 +01:00
parent fe09690308
commit 80de7ffd9c
3 changed files with 271 additions and 0 deletions

View File

@ -0,0 +1,110 @@
From 02612d36c664e03821ed80a205fdca80232afd64 Mon Sep 17 00:00:00 2001
From: Clemens Lang <cllang@redhat.com>
Date: Thu, 17 Nov 2022 19:33:02 +0100
Subject: [PATCH 1/2] signature: Add indicator for PSS salt length
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
FIPS 186-4 section 5 "The RSA Digital Signature Algorithm", subsection
5.5 "PKCS #1" says: "For RSASSA-PSS […] the length (in bytes) of the
salt (sLen) shall satisfy 0 ≤ sLen ≤ hLen, where hLen is the length of
the hash function output block (in bytes)."
It is not exactly clear from this text whether hLen refers to the
message digest or the hash function used for the mask generation
function MGF1. PKCS#1 v2.1 suggests it is the former:
| Typical salt lengths in octets are hLen (the length of the output of
| the hash function Hash) and 0. In both cases the security of
| RSASSA-PSS can be closely related to the hardness of inverting RSAVP1.
| Bellare and Rogaway [4] give a tight lower bound for the security of
| the original RSA-PSS scheme, which corresponds roughly to the former
| case, while Coron [12] gives a lower bound for the related Full Domain
| Hashing scheme, which corresponds roughly to the latter case. In [13]
| Coron provides a general treatment with various salt lengths ranging
| from 0 to hLen; see [27] for discussion. See also [31], which adapts
| the security proofs in [4][13] to address the differences between the
| original and the present version of RSA-PSS as listed in Note 1 above.
Since OpenSSL defaults to creating signatures with the maximum salt
length, blocking the use of longer salts would probably lead to
significant problems in practice. Instead, introduce an explicit
indicator that can be obtained from the EVP_PKEY_CTX object using
EVP_PKEY_CTX_get_params() with the
OSSL_SIGNATURE_PARAM_REDHAT_FIPS_INDICATOR
parameter.
Signed-off-by: Clemens Lang <cllang@redhat.com>
---
include/openssl/core_names.h | 1 +
include/openssl/evp.h | 4 ++++
providers/implementations/signature/rsa_sig.c | 18 ++++++++++++++++++
3 files changed, 23 insertions(+)
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index 94fab83193..69c59f0b46 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -453,6 +453,7 @@ extern "C" {
#define OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES \
OSSL_PKEY_PARAM_MGF1_PROPERTIES
#define OSSL_SIGNATURE_PARAM_DIGEST_SIZE OSSL_PKEY_PARAM_DIGEST_SIZE
+#define OSSL_SIGNATURE_PARAM_REDHAT_FIPS_INDICATOR "redhat-fips-indicator"
/* Asym cipher parameters */
#define OSSL_ASYM_CIPHER_PARAM_DIGEST OSSL_PKEY_PARAM_DIGEST
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index a5e78efd6e..f239200465 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -797,6 +797,10 @@ __owur int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm,
__owur int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm,
int *outl);
+# define EVP_SIGNATURE_REDHAT_FIPS_INDICATOR_UNDETERMINED 0
+# define EVP_SIGNATURE_REDHAT_FIPS_INDICATOR_APPROVED 1
+# define EVP_SIGNATURE_REDHAT_FIPS_INDICATOR_NOT_APPROVED 2
+
__owur int EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s,
EVP_PKEY *pkey);
__owur int EVP_SignFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s,
diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c
index 49e7f9158a..f905fd6a04 100644
--- a/providers/implementations/signature/rsa_sig.c
+++ b/providers/implementations/signature/rsa_sig.c
@@ -1127,6 +1127,21 @@ static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params)
}
}
+#ifdef FIPS_MODULE
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_REDHAT_FIPS_INDICATOR);
+ if (p != NULL) {
+ int fips_indicator = EVP_SIGNATURE_REDHAT_FIPS_INDICATOR_APPROVED;
+ if (prsactx->pad_mode == RSA_PKCS1_PSS_PADDING) {
+ if (prsactx->md == NULL) {
+ fips_indicator = EVP_SIGNATURE_REDHAT_FIPS_INDICATOR_UNDETERMINED;
+ } else if (prsactx->saltlen > EVP_MD_get_size(prsactx->md)) {
+ fips_indicator = EVP_SIGNATURE_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
+ }
+ }
+ return OSSL_PARAM_set_int(p, fips_indicator);
+ }
+#endif
+
return 1;
}
@@ -1136,6 +1151,9 @@ static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0),
+#ifdef FIPS_MODULE
+ OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_REDHAT_FIPS_INDICATOR, NULL),
+#endif
OSSL_PARAM_END
};
--
2.38.1

View File

@ -0,0 +1,153 @@
From 39a91c33e2b89a0fe42e3791d3dc304519a52182 Mon Sep 17 00:00:00 2001
From: Clemens Lang <cllang@redhat.com>
Date: Fri, 18 Nov 2022 12:35:33 +0100
Subject: [PATCH] signature: Clamp PSS salt len to MD len
Since FIPS 186-4 subsection 5.5 limits the acceptable PSS salt length to
the size of the message digest, change the default automatic behavior
when signing to use at most the digest size as salt length. Shorter
values are still possible when long hashes are used with short keys.
Signed-off-by: Clemens Lang <cllang@redhat.com>
---
crypto/rsa/rsa_ameth.c | 19 +++++++++++++++++--
crypto/rsa/rsa_pss.c | 11 +++++++++++
doc/man3/EVP_PKEY_CTX_ctrl.pod | 4 +++-
providers/implementations/signature/rsa_sig.c | 18 ++++++++++++++++--
4 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index b1580ca..dc81627 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -449,6 +449,7 @@ static RSA_PSS_PARAMS *rsa_ctx_to_pss(EVP_PKEY_CTX *pkctx)
const EVP_MD *sigmd, *mgf1md;
EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx);
int saltlen;
+ int saltlenMax = -1;
if (EVP_PKEY_CTX_get_signature_md(pkctx, &sigmd) <= 0)
return NULL;
@@ -456,14 +457,28 @@ static RSA_PSS_PARAMS *rsa_ctx_to_pss(EVP_PKEY_CTX *pkctx)
return NULL;
if (!EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen))
return NULL;
- if (saltlen == -1) {
+ if (saltlen == RSA_PSS_SALTLEN_DIGEST) {
saltlen = EVP_MD_get_size(sigmd);
- } else if (saltlen == -2 || saltlen == -3) {
+ } else if (saltlen == RSA_PSS_SALTLEN_AUTO) {
+ /* FIPS 186-4 section 5 "The RSA Digital Signature Algorithm",
+ * subsection 5.5 "PKCS #1" says: "For RSASSA-PSS […] the length (in
+ * bytes) of the salt (sLen) shall satisfy 0 ≤ sLen ≤ hLen, where hLen
+ * is the length of the hash function output block (in bytes)."
+ *
+ * Switch the meaning of RSA_PSS_SALTLEN_AUTO to use at most the digest
+ * length in FIPS mode, so that the default does not violate FIPS
+ * 186-4. */
+ saltlen = RSA_PSS_SALTLEN_MAX;
+ saltlenMax = EVP_MD_get_size(sigmd);
+ }
+ if (saltlen == RSA_PSS_SALTLEN_MAX) {
saltlen = EVP_PKEY_get_size(pk) - EVP_MD_get_size(sigmd) - 2;
if ((EVP_PKEY_get_bits(pk) & 0x7) == 1)
saltlen--;
if (saltlen < 0)
return NULL;
+ if (saltlenMax >= 0 && saltlen > saltlenMax)
+ saltlen = saltlenMax;
}
return ossl_rsa_pss_params_create(sigmd, mgf1md, saltlen);
diff --git a/crypto/rsa/rsa_pss.c b/crypto/rsa/rsa_pss.c
index e8681b0..d8f9207 100644
--- a/crypto/rsa/rsa_pss.c
+++ b/crypto/rsa/rsa_pss.c
@@ -168,6 +168,7 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
int hLen, maskedDBLen, MSBits, emLen;
unsigned char *H, *salt = NULL, *p;
EVP_MD_CTX *ctx = NULL;
+ int sLenMax = -1;
if (mgf1Hash == NULL)
mgf1Hash = Hash;
@@ -190,10 +191,18 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
* -3 same as above (on signing)
* -N reserved
*/
+ /* FIPS 186-4 section 5 "The RSA Digital Signature Algorithm", subsection
+ * 5.5 "PKCS #1" says: "For RSASSA-PSS […] the length (in bytes) of the
+ * salt (sLen) shall satisfy 0 ≤ sLen ≤ hLen, where hLen is the length of
+ * the hash function output block (in bytes)."
+ *
+ * Switch the meaning of RSA_PSS_SALTLEN_AUTO to use at most the digest
+ * length in FIPS mode, so that the default does not violate FIPS 186-4. */
if (sLen == RSA_PSS_SALTLEN_DIGEST) {
sLen = hLen;
} else if (sLen == RSA_PSS_SALTLEN_MAX_SIGN) {
sLen = RSA_PSS_SALTLEN_MAX;
+ sLenMax = hLen;
} else if (sLen < RSA_PSS_SALTLEN_MAX) {
ERR_raise(ERR_LIB_RSA, RSA_R_SLEN_CHECK_FAILED);
goto err;
@@ -211,6 +220,8 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
}
if (sLen == RSA_PSS_SALTLEN_MAX) {
sLen = emLen - hLen - 2;
+ if (sLenMax >= 0 && sLen > sLenMax)
+ sLen = sLenMax;
} else if (sLen > emLen - hLen - 2) {
ERR_raise(ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
goto err;
diff --git a/doc/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod
index 3075eaa..5463472 100644
--- a/doc/man3/EVP_PKEY_CTX_ctrl.pod
+++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod
@@ -287,7 +287,9 @@ sets the salt length to the maximum permissible value.
causes the salt length to be automatically determined based on the
B<PSS> block structure when verifying. When signing, it has the same
-meaning as B<RSA_PSS_SALTLEN_MAX>.
+meaning as B<RSA_PSS_SALTLEN_MAX> up to a maximum of the digest length to
+comply with FIPS 186-4 section 5.5. This maximum is specific to Red Hat,
+upstream also uses larger values.
=back
diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c
index 3ce5efd..519c6a2 100644
--- a/providers/implementations/signature/rsa_sig.c
+++ b/providers/implementations/signature/rsa_sig.c
@@ -200,13 +200,27 @@ static void *rsa_newctx(void *provctx, const char *propq)
static int rsa_pss_compute_saltlen(PROV_RSA_CTX *ctx)
{
int saltlen = ctx->saltlen;
-
+ int saltlenMax = -1;
+
+ /* FIPS 186-4 section 5 "The RSA Digital Signature Algorithm", subsection
+ * 5.5 "PKCS #1" says: "For RSASSA-PSS […] the length (in bytes) of the
+ * salt (sLen) shall satisfy 0 ≤ sLen ≤ hLen, where hLen is the length of
+ * the hash function output block (in bytes)."
+ *
+ * Switch the meaning of RSA_PSS_SALTLEN_AUTO to use at most the digest
+ * length in FIPS mode, so that the default does not violate FIPS 186-4. */
if (saltlen == RSA_PSS_SALTLEN_DIGEST) {
saltlen = EVP_MD_get_size(ctx->md);
- } else if (saltlen == RSA_PSS_SALTLEN_AUTO || saltlen == RSA_PSS_SALTLEN_MAX) {
+ } else if (saltlen == RSA_PSS_SALTLEN_AUTO) {
+ saltlen = RSA_PSS_SALTLEN_MAX;
+ saltlenMax = EVP_MD_get_size(ctx->md);
+ }
+ if (saltlen == RSA_PSS_SALTLEN_MAX) {
saltlen = RSA_size(ctx->rsa) - EVP_MD_get_size(ctx->md) - 2;
if ((RSA_bits(ctx->rsa) & 0x7) == 1)
saltlen--;
+ if (saltlenMax >= 0 && saltlen > saltlenMax)
+ saltlen = saltlenMax;
}
if (saltlen < 0) {
ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
--
2.38.1

View File

@ -180,6 +180,10 @@ Patch85: 0085-FIPS-RSA-disable-shake.patch
Patch86: 0086-avoid-bio-memleak.patch
#https://github.com/openssl/openssl/pull/19501
Patch87: 0087-FIPS-RSA-selftest-params.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2142087
Patch88: 0088-signature-Add-indicator-for-PSS-salt-length.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2142087
Patch89: 0089-signature-Clamp-PSS-salt-len-to-MD-len.patch
License: ASL 2.0
URL: http://www.openssl.org/
@ -527,6 +531,10 @@ install -m644 %{SOURCE9} \
Resolves: rhbz#2144000
- Set minimum password length for PBKDF2 in FIPS mode
Resolves: rhbz#2144003
- Add explicit indicator for PSS salt length in FIPS mode
Resolves: rhbz#2144012
- Clamp default PSS salt length to digest size for FIPS 186-4 compliance
Related: rhbz#2144012
* Tue Nov 01 2022 Dmitry Belyavskiy <dbelyavs@redhat.com> - 1:3.0.1-43
- CVE-2022-3602: X.509 Email Address Buffer Overflow