From 4a2239bd7d444c30c55b20ea8b4aeadafdfe1afd Mon Sep 17 00:00:00 2001
From: Clemens Lang <cllang@redhat.com>
Date: Fri, 22 Jul 2022 13:59:37 +0200
Subject: [PATCH] FIPS: Use OAEP in KATs, support fixed OAEP seed

Review by our lab for FIPS 140-3 certification expects the RSA
encryption and decryption tests to use a supported padding mode, not raw
RSA signatures. Switch to RSA-OAEP for the self tests to fulfill that.

The FIPS 140-3 Implementation Guidance specifies in section 10.3.A
"Cryptographic Algorithm Self-Test Requirements" that a self-test may be
a known-answer test, a comparison test, or a fault-detection test.

Comparison tests are not an option, because they would require
a separate implementation of RSA-OAEP, which we do not have. Fault
detection tests require implementing fault detection mechanisms into the
cryptographic algorithm implementation, we we also do not have.

As a consequence, a known-answer test must be used to test RSA
encryption and decryption, but RSA encryption with OAEP padding is not
deterministic, and thus encryption will always yield different results
that could not be compared to known answers. For this reason, this
change explicitly sets the seed in OAEP (see RFC 8017 section 7.1.1),
which is the source of randomness for RSA-OAEP, to a fixed value. This
setting is only available during self-test execution, and the parameter
set using EVP_PKEY_CTX_set_params() will be ignored otherwise.

Signed-off-by: Clemens Lang <cllang@redhat.com>
---
 crypto/rsa/rsa_local.h                        |  8 ++
 crypto/rsa/rsa_oaep.c                         | 34 ++++++--
 providers/fips/self_test_data.inc             | 83 +++++++++++--------
 providers/fips/self_test_kats.c               |  7 ++
 .../implementations/asymciphers/rsa_enc.c     | 41 +++++++++-
 util/perl/OpenSSL/paramnames.pm               |  1 +
 6 files changed, 126 insertions(+), 44 deletions(-)

diff --git a/crypto/rsa/rsa_local.h b/crypto/rsa/rsa_local.h
index ea70da05ad..dde57a1a0e 100644
--- a/crypto/rsa/rsa_local.h
+++ b/crypto/rsa/rsa_local.h
@@ -193,4 +193,12 @@ int ossl_rsa_padding_add_PKCS1_type_2_ex(OSSL_LIB_CTX *libctx, unsigned char *to
                                          int tlen, const unsigned char *from,
                                          int flen);
 
+int ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex2(OSSL_LIB_CTX *libctx,
+                                             unsigned char *to, int tlen,
+                                             const unsigned char *from, int flen,
+                                             const unsigned char *param,
+                                             int plen, const EVP_MD *md,
+                                             const EVP_MD *mgf1md,
+                                             const char *redhat_st_seed);
+
 #endif /* OSSL_CRYPTO_RSA_LOCAL_H */
diff --git a/crypto/rsa/rsa_oaep.c b/crypto/rsa/rsa_oaep.c
index d9be1a4f98..b2f7f7dc4b 100644
--- a/crypto/rsa/rsa_oaep.c
+++ b/crypto/rsa/rsa_oaep.c
@@ -44,6 +44,10 @@ int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen,
                                                    param, plen, NULL, NULL);
 }
 
+#ifdef FIPS_MODULE
+extern int REDHAT_FIPS_asym_cipher_st;
+#endif /* FIPS_MODULE */
+
 /*
  * Perform the padding as per NIST 800-56B 7.2.2.3
  *      from (K) is the key material.
@@ -51,12 +55,13 @@ int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen,
  * Step numbers are included here but not in the constant time inverse below
  * to avoid complicating an already difficult enough function.
  */
-int ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex(OSSL_LIB_CTX *libctx,
-                                            unsigned char *to, int tlen,
-                                            const unsigned char *from, int flen,
-                                            const unsigned char *param,
-                                            int plen, const EVP_MD *md,
-                                            const EVP_MD *mgf1md)
+int ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex2(OSSL_LIB_CTX *libctx,
+                                             unsigned char *to, int tlen,
+                                             const unsigned char *from, int flen,
+                                             const unsigned char *param,
+                                             int plen, const EVP_MD *md,
+                                             const EVP_MD *mgf1md,
+                                             const char *redhat_st_seed)
 {
     int rv = 0;
     int i, emlen = tlen - 1;
@@ -107,6 +112,11 @@ int ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex(OSSL_LIB_CTX *libctx,
     db[emlen - flen - mdlen - 1] = 0x01;
     memcpy(db + emlen - flen - mdlen, from, (unsigned int)flen);
     /* step 3d: generate random byte string */
+#ifdef FIPS_MODULE
+    if (redhat_st_seed != NULL && REDHAT_FIPS_asym_cipher_st) {
+        memcpy(seed, redhat_st_seed, mdlen);
+    } else
+#endif
     if (RAND_bytes_ex(libctx, seed, mdlen, 0) <= 0)
         goto err;
 
@@ -138,6 +148,18 @@ int ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex(OSSL_LIB_CTX *libctx,
     return rv;
 }
 
+int ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex(OSSL_LIB_CTX *libctx,
+                                            unsigned char *to, int tlen,
+                                            const unsigned char *from, int flen,
+                                            const unsigned char *param,
+                                            int plen, const EVP_MD *md,
+                                            const EVP_MD *mgf1md)
+{
+    return ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex2(libctx, to, tlen, from,
+                                                    flen, param, plen, md,
+                                                    mgf1md, NULL);
+}
+
 int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
                                     const unsigned char *from, int flen,
                                     const unsigned char *param, int plen,
diff --git a/providers/fips/self_test_data.inc b/providers/fips/self_test_data.inc
index 4e30ec56dd..0103c87528 100644
--- a/providers/fips/self_test_data.inc
+++ b/providers/fips/self_test_data.inc
@@ -1294,15 +1294,22 @@ static const ST_KAT_PARAM rsa_priv_key[] = {
     ST_KAT_PARAM_END()
 };
 
-/*-
- * Using OSSL_PKEY_RSA_PAD_MODE_NONE directly in the expansion of the
- * ST_KAT_PARAM_UTF8STRING macro below causes a failure on ancient
- * HP/UX PA-RISC compilers.
- */
-static const char pad_mode_none[] = OSSL_PKEY_RSA_PAD_MODE_NONE;
-
+/*-
+ * Using OSSL_PKEY_RSA_PAD_MODE_OAEP directly in the expansion of the
+ * ST_KAT_PARAM_UTF8STRING macro below causes a failure on ancient
+ * HP/UX PA-RISC compilers.
+ */
+static const char pad_mode_oaep[] = OSSL_PKEY_RSA_PAD_MODE_OAEP;
+static const char oaep_fixed_seed[] = {
+    0xf6, 0x10, 0xef, 0x0a, 0x97, 0xbf, 0x91, 0x25,
+    0x97, 0xcf, 0x8e, 0x0a, 0x75, 0x51, 0x2f, 0xab,
+    0x2e, 0x4b, 0x2c, 0xe6
+};
+
 static const ST_KAT_PARAM rsa_enc_params[] = {
-    ST_KAT_PARAM_UTF8STRING(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, pad_mode_none),
+    ST_KAT_PARAM_UTF8STRING(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, pad_mode_oaep),
+    ST_KAT_PARAM_OCTET(OSSL_ASYM_CIPHER_PARAM_REDHAT_KAT_OEAP_SEED,
+                       oaep_fixed_seed),
     ST_KAT_PARAM_END()
 };
 
@@ -1335,43 +1348,43 @@ static const unsigned char rsa_expected_sig[256] = {
     0x2c, 0x68, 0xf0, 0x37, 0xa9, 0xd2, 0x56, 0xd6
 };
 
-static const unsigned char rsa_asym_plaintext_encrypt[256] = {
+static const unsigned char rsa_asym_plaintext_encrypt[208] = {
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
    0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
 };
 static const unsigned char rsa_asym_expected_encrypt[256] = {
-    0x54, 0xac, 0x23, 0x96, 0x1d, 0x82, 0x5d, 0x8b,
-    0x8f, 0x36, 0x33, 0xd0, 0xf4, 0x02, 0xa2, 0x61,
-    0xb1, 0x13, 0xd4, 0x4a, 0x46, 0x06, 0x37, 0x3c,
-    0xbf, 0x40, 0x05, 0x3c, 0xc6, 0x3b, 0x64, 0xdc,
-    0x22, 0x22, 0xaf, 0x36, 0x79, 0x62, 0x45, 0xf0,
-    0x97, 0x82, 0x22, 0x44, 0x86, 0x4a, 0x7c, 0xfa,
-    0xac, 0x03, 0x21, 0x84, 0x3f, 0x31, 0xad, 0x2a,
-    0xa4, 0x6e, 0x7a, 0xc5, 0x93, 0xf3, 0x0f, 0xfc,
-    0xf1, 0x62, 0xce, 0x82, 0x12, 0x45, 0xc9, 0x35,
-    0xb0, 0x7a, 0xcd, 0x99, 0x8c, 0x91, 0x6b, 0x5a,
-    0xd3, 0x46, 0xdb, 0xf9, 0x9e, 0x52, 0x49, 0xbd,
-    0x1e, 0xe8, 0xda, 0xac, 0x61, 0x47, 0xc2, 0xda,
-    0xfc, 0x1e, 0xfb, 0x74, 0xd7, 0xd6, 0xc1, 0x18,
-    0x86, 0x3e, 0x20, 0x9c, 0x7a, 0xe1, 0x04, 0xb7,
-    0x38, 0x43, 0xb1, 0x4e, 0xa0, 0xd8, 0xc1, 0x39,
-    0x4d, 0xe1, 0xd3, 0xb0, 0xb3, 0xf1, 0x82, 0x87,
-    0x1f, 0x74, 0xb5, 0x69, 0xfd, 0x33, 0xd6, 0x21,
-    0x7c, 0x61, 0x60, 0x28, 0xca, 0x70, 0xdb, 0xa0,
-    0xbb, 0xc8, 0x73, 0xa9, 0x82, 0xf8, 0x6b, 0xd8,
-    0xf0, 0xc9, 0x7b, 0x20, 0xdf, 0x9d, 0xfb, 0x8c,
-    0xd4, 0xa2, 0x89, 0xe1, 0x9b, 0x04, 0xad, 0xaa,
-    0x11, 0x6c, 0x8f, 0xce, 0x83, 0x29, 0x56, 0x69,
-    0xbb, 0x00, 0x3b, 0xef, 0xca, 0x2d, 0xcd, 0x52,
-    0xc8, 0xf1, 0xb3, 0x9b, 0xb4, 0x4f, 0x6d, 0x9c,
-    0x3d, 0x69, 0xcc, 0x6d, 0x1f, 0x38, 0x4d, 0xe6,
-    0xbb, 0x0c, 0x87, 0xdc, 0x5f, 0xa9, 0x24, 0x93,
-    0x03, 0x46, 0xa2, 0x33, 0x6c, 0xf4, 0xd8, 0x5d,
-    0x68, 0xf3, 0xd3, 0xe0, 0xf2, 0x30, 0xdb, 0xf5,
-    0x4f, 0x0f, 0xad, 0xc7, 0xd0, 0xaa, 0x47, 0xd9,
-    0x9f, 0x85, 0x1b, 0x2e, 0x6c, 0x3c, 0x57, 0x04,
-    0x29, 0xf4, 0xf5, 0x66, 0x7d, 0x93, 0x4a, 0xaa,
-    0x05, 0x52, 0x55, 0xc1, 0xc6, 0x06, 0x90, 0xab,
+    0x6c, 0x21, 0xc1, 0x9e, 0x94, 0xee, 0xdf, 0x74,
+    0x3a, 0x3c, 0x7c, 0x04, 0x1a, 0x53, 0x9e, 0x7c,
+    0x42, 0xac, 0x7e, 0x28, 0x9a, 0xb7, 0xe2, 0x4e,
+    0x87, 0xd4, 0x00, 0x69, 0x71, 0xf0, 0x3e, 0x0b,
+    0xc1, 0xda, 0xd6, 0xbd, 0x21, 0x39, 0x4f, 0x25,
+    0x22, 0x1f, 0x76, 0x0d, 0x62, 0x1f, 0xa2, 0x89,
+    0xdb, 0x38, 0x32, 0x88, 0x21, 0x1d, 0x89, 0xf1,
+    0xe0, 0x14, 0xd4, 0xb7, 0x90, 0xfc, 0xbc, 0x50,
+    0xb0, 0x8d, 0x5c, 0x2f, 0x49, 0x9e, 0x90, 0x17,
+    0x9e, 0x60, 0x9f, 0xe1, 0x77, 0x4f, 0x11, 0xa2,
+    0xcf, 0x16, 0x65, 0x2d, 0x4a, 0x2c, 0x12, 0xcb,
+    0x1e, 0x3c, 0x29, 0x8b, 0xdc, 0x27, 0x06, 0x9d,
+    0xf4, 0x0d, 0xe1, 0xc9, 0xeb, 0x14, 0x6a, 0x7e,
+    0xfd, 0xa7, 0xa8, 0xa7, 0x51, 0x82, 0x62, 0x0f,
+    0x29, 0x8d, 0x8c, 0x5e, 0xf2, 0xb8, 0xcd, 0xd3,
+    0x51, 0x92, 0xa7, 0x25, 0x39, 0x9d, 0xdd, 0x06,
+    0xff, 0xb1, 0xb0, 0xd5, 0x61, 0x03, 0x8f, 0x25,
+    0x5c, 0x49, 0x12, 0xc1, 0x50, 0x67, 0x61, 0x78,
+    0xb3, 0xe3, 0xc4, 0xf6, 0x36, 0x16, 0xa9, 0x04,
+    0x91, 0x0a, 0x4b, 0x27, 0x28, 0x97, 0x50, 0x7c,
+    0x65, 0x2d, 0xd0, 0x08, 0x71, 0x84, 0xe7, 0x47,
+    0x79, 0x83, 0x91, 0x46, 0xd9, 0x8f, 0x79, 0xce,
+    0x49, 0xcb, 0xcd, 0x8b, 0x34, 0xac, 0x61, 0xe0,
+    0xe6, 0x55, 0xbf, 0x10, 0xe4, 0xac, 0x9a, 0xd6,
+    0xed, 0xc1, 0xc2, 0xb6, 0xb6, 0xf7, 0x41, 0x99,
+    0xde, 0xfa, 0xde, 0x11, 0x16, 0xa2, 0x18, 0x30,
+    0x30, 0xdc, 0x95, 0x76, 0x2f, 0x46, 0x43, 0x20,
+    0xc4, 0xe7, 0x50, 0xb9, 0x1e, 0xcd, 0x69, 0xbb,
+    0x29, 0x94, 0x27, 0x9c, 0xc9, 0xab, 0xb4, 0x27,
+    0x8b, 0x4d, 0xe1, 0xcb, 0xc1, 0x04, 0x2c, 0x66,
+    0x41, 0x3a, 0x4d, 0xeb, 0x61, 0x4c, 0x77, 0x5a,
+    0xee, 0xb0, 0xca, 0x99, 0x0e, 0x7f, 0xbe, 0x06
 };
 
 #ifndef OPENSSL_NO_EC
diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c
index 064794d9bf..b6d5e8e134 100644
--- a/providers/fips/self_test_kats.c
+++ b/providers/fips/self_test_kats.c
@@ -647,14 +647,21 @@ static int self_test_ciphers(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     return ret;
 }
 
+int REDHAT_FIPS_asym_cipher_st = 0;
+
 static int self_test_asym_ciphers(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
 {
     int i, ret = 1;
 
+    REDHAT_FIPS_asym_cipher_st = 1;
+
     for (i = 0; i < (int)OSSL_NELEM(st_kat_asym_cipher_tests); ++i) {
         if (!self_test_asym_cipher(&st_kat_asym_cipher_tests[i], st, libctx))
             ret = 0;
     }
+
+    REDHAT_FIPS_asym_cipher_st = 0;
+
     return ret;
 }
 
diff --git a/providers/implementations/asymciphers/rsa_enc.c b/providers/implementations/asymciphers/rsa_enc.c
index 00cf65fcd6..83be3d8ede 100644
--- a/providers/implementations/asymciphers/rsa_enc.c
+++ b/providers/implementations/asymciphers/rsa_enc.c
@@ -30,6 +30,9 @@
 #include "prov/implementations.h"
 #include "prov/providercommon.h"
 #include "prov/securitycheck.h"
+#ifdef FIPS_MODULE
+# include "crypto/rsa/rsa_local.h"
+#endif
 
 #include <stdlib.h>
 
@@ -75,6 +78,9 @@ typedef struct {
     /* TLS padding */
     unsigned int client_version;
     unsigned int alt_version;
+#ifdef FIPS_MODULE
+    char *redhat_st_oaep_seed;
+#endif /* FIPS_MODULE */
     /* PKCS#1 v1.5 decryption mode */
     unsigned int implicit_rejection;
 } PROV_RSA_CTX;
@@ -190,12 +196,21 @@ static int rsa_encrypt(void *vprsactx, unsigned char *out, size_t *outlen,
             }
         }
         ret =
-            ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex(prsactx->libctx, tbuf,
+#ifdef FIPS_MODULE
+            ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex2(
+#else
+            ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex(
+#endif
+                                                    prsactx->libctx, tbuf,
                                                     rsasize, in, inlen,
                                                     prsactx->oaep_label,
                                                     prsactx->oaep_labellen,
                                                     prsactx->oaep_md,
-                                                    prsactx->mgf1_md);
+                                                    prsactx->mgf1_md
+#ifdef FIPS_MODULE
+                                                    , prsactx->redhat_st_oaep_seed
+#endif
+                                                    );
 
         if (!ret) {
             OPENSSL_free(tbuf);
@@ -326,6 +341,9 @@ static void rsa_freectx(void *vprsactx)
     EVP_MD_free(prsactx->oaep_md);
     EVP_MD_free(prsactx->mgf1_md);
     OPENSSL_free(prsactx->oaep_label);
+#ifdef FIPS_MODULE
+    OPENSSL_free(prsactx->redhat_st_oaep_seed);
+#endif /* FIPS_MODULE */
 
     OPENSSL_free(prsactx);
 }
@@ -445,6 +463,9 @@ static const OSSL_PARAM known_gettable_ctx_params[] = {
                     NULL, 0),
     OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL),
     OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL),
+#ifdef FIPS_MODULE
+    OSSL_PARAM_octet_string(OSSL_ASYM_CIPHER_PARAM_REDHAT_KAT_OEAP_SEED, NULL, 0),
+#endif /* FIPS_MODULE */
     OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION, NULL),
     OSSL_PARAM_END
 };
@@ -454,6 +475,10 @@ static const OSSL_PARAM *rsa_gettable_ctx_params(ossl_unused void *vprsactx,
     return known_gettable_ctx_params;
 }
 
+#ifdef FIPS_MODULE
+extern int REDHAT_FIPS_asym_cipher_st;
+#endif /* FIPS_MODULE */
+
 static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
 {
     PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
@@ -563,6 +588,18 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
         prsactx->oaep_labellen = tmp_labellen;
     }
 
+#ifdef FIPS_MODULE
+    p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_REDHAT_KAT_OEAP_SEED);
+    if (p != NULL && REDHAT_FIPS_asym_cipher_st) {
+        void *tmp_oaep_seed = NULL;
+
+        if (!OSSL_PARAM_get_octet_string(p, &tmp_oaep_seed, 0, NULL))
+            return 0;
+        OPENSSL_free(prsactx->redhat_st_oaep_seed);
+        prsactx->redhat_st_oaep_seed = (char *)tmp_oaep_seed;
+    }
+#endif /* FIPS_MODULE */
+
     p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION);
     if (p != NULL) {
         unsigned int client_version;
diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm
index c37ed7815f..70f7c50fe4 100644
--- a/util/perl/OpenSSL/paramnames.pm
+++ b/util/perl/OpenSSL/paramnames.pm
@@ -401,6 +401,7 @@ my %params = (
     'ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION' =>       "tls-client-version",
     'ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION' =>   "tls-negotiated-version",
     'ASYM_CIPHER_PARAM_IMPLICIT_REJECTION' =>       "implicit-rejection",
+    'ASYM_CIPHER_PARAM_REDHAT_KAT_OEAP_SEED' =>     "redhat-kat-oaep-seed",
 
 # Encoder / decoder parameters
 
-- 
2.37.1

