e52367a
From 9b02ad7225b74a5b9088b361caead0a41e570e93 Mon Sep 17 00:00:00 2001
e52367a
From: Dmitry Belyavskiy <dbelyavs@redhat.com>
e52367a
Date: Mon, 21 Aug 2023 16:40:56 +0200
e52367a
Subject: [PATCH 48/48] 0114-FIPS-enforce-EMS-support.patch
e52367a
e52367a
Patch-name: 0114-FIPS-enforce-EMS-support.patch
e52367a
Patch-id: 114
e52367a
Patch-status: |
e52367a
    # We believe that some changes present in CentOS are not necessary
e52367a
    # because ustream has a check for FIPS version
e52367a
---
e52367a
 doc/man3/SSL_CONF_cmd.pod                     |  3 +++
e52367a
 doc/man5/fips_config.pod                      | 13 +++++++++++
e52367a
 include/openssl/fips_names.h                  |  8 +++++++
e52367a
 include/openssl/ssl.h.in                      |  1 +
e52367a
 providers/fips/fipsprov.c                     |  2 +-
e52367a
 providers/implementations/kdfs/tls1_prf.c     | 22 +++++++++++++++++++
e52367a
 ssl/ssl_conf.c                                |  1 +
e52367a
 ssl/statem/extensions_srvr.c                  |  8 ++++++-
e52367a
 ssl/t1_enc.c                                  | 11 ++++++++--
e52367a
 .../30-test_evp_data/evpkdf_tls12_prf.txt     | 10 +++++++++
e52367a
 test/sslapitest.c                             |  2 +-
e52367a
 11 files changed, 76 insertions(+), 5 deletions(-)
e52367a
e52367a
diff --git a/doc/man3/SSL_CONF_cmd.pod b/doc/man3/SSL_CONF_cmd.pod
e52367a
index ae6ca43282..b83c04a308 100644
e52367a
--- a/doc/man3/SSL_CONF_cmd.pod
e52367a
+++ b/doc/man3/SSL_CONF_cmd.pod
e52367a
@@ -524,6 +524,9 @@ B<ExtendedMasterSecret>: use extended master secret extension, enabled by
e52367a
 default. Inverse of B<SSL_OP_NO_EXTENDED_MASTER_SECRET>: that is,
e52367a
 B<-ExtendedMasterSecret> is the same as setting B<SSL_OP_NO_EXTENDED_MASTER_SECRET>.
e52367a
 
e52367a
+B<RHNoEnforceEMSinFIPS>: allow establishing connections without EMS in FIPS mode.
e52367a
+This is a RedHat-based OS specific option, and normally it should be set up via crypto policies.
e52367a
+
e52367a
 B<CANames>: use CA names extension, enabled by
e52367a
 default. Inverse of B<SSL_OP_DISABLE_TLSEXT_CA_NAMES>: that is,
e52367a
 B<-CANames> is the same as setting B<SSL_OP_DISABLE_TLSEXT_CA_NAMES>.
e52367a
diff --git a/doc/man5/fips_config.pod b/doc/man5/fips_config.pod
e52367a
index 1c15e32a5c..f2cedaf88d 100644
e52367a
--- a/doc/man5/fips_config.pod
e52367a
+++ b/doc/man5/fips_config.pod
e52367a
@@ -15,6 +15,19 @@ for more information.
e52367a
 
e52367a
 This functionality was added in OpenSSL 3.0.
e52367a
 
e52367a
+Red Hat Enterprise Linux uses a supplementary config for FIPS module located in
e52367a
+OpenSSL configuration directory and managed by crypto policies. If present, it
e52367a
+should have format
e52367a
+
e52367a
+ [fips_sect]
e52367a
+ tls1-prf-ems-check = 0
e52367a
+ activate = 1
e52367a
+
e52367a
+The B<tls1-prf-ems-check> option specifies whether FIPS module will require the
e52367a
+presence of extended master secret or not.
e52367a
+
e52367a
+The B<activate> option enforces FIPS provider activation.
e52367a
+
e52367a
 =head1 COPYRIGHT
e52367a
 
f4c397c
 Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
e52367a
diff --git a/include/openssl/fips_names.h b/include/openssl/fips_names.h
e52367a
index 5c77f6d691..8cdd5a6bf7 100644
e52367a
--- a/include/openssl/fips_names.h
e52367a
+++ b/include/openssl/fips_names.h
e52367a
@@ -70,6 +70,14 @@ extern "C" {
e52367a
  */
e52367a
 # define OSSL_PROV_FIPS_PARAM_DRBG_TRUNC_DIGEST  "drbg-no-trunc-md"
e52367a
 
e52367a
+/*
e52367a
+ * A boolean that determines if the runtime FIPS check for TLS1_PRF EMS is performed.
e52367a
+ * This is disabled by default.
e52367a
+ *
e52367a
+ * Type: OSSL_PARAM_UTF8_STRING
e52367a
+ */
e52367a
+# define OSSL_PROV_FIPS_PARAM_TLS1_PRF_EMS_CHECK "tls1-prf-ems-check"
e52367a
+
e52367a
 # ifdef __cplusplus
e52367a
 }
e52367a
 # endif
e52367a
diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in
e52367a
index 0b6de603e2..26a69ca282 100644
e52367a
--- a/include/openssl/ssl.h.in
e52367a
+++ b/include/openssl/ssl.h.in
e52367a
@@ -415,6 +415,7 @@ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
e52367a
      * interoperability with CryptoPro CSP 3.x
e52367a
      */
e52367a
 # define SSL_OP_CRYPTOPRO_TLSEXT_BUG                     SSL_OP_BIT(31)
e52367a
+# define SSL_OP_RH_PERMIT_NOEMS_FIPS                     SSL_OP_BIT(48)
e52367a
 /*
f4c397c
  * Disable RFC8879 certificate compression
f4c397c
  * SSL_OP_NO_TX_CERTIFICATE_COMPRESSION: don't send compressed certificates,
e52367a
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
e52367a
index 5ff9872bd8..eb9653a9df 100644
e52367a
--- a/providers/fips/fipsprov.c
e52367a
+++ b/providers/fips/fipsprov.c
e52367a
@@ -105,7 +105,7 @@ void *ossl_fips_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx)
e52367a
     if (fgbl == NULL)
e52367a
         return NULL;
e52367a
     init_fips_option(&fgbl->fips_security_checks, 1);
e52367a
-    init_fips_option(&fgbl->fips_tls1_prf_ems_check, 0); /* Disabled by default */
e52367a
+    init_fips_option(&fgbl->fips_tls1_prf_ems_check, 1); /* Enabled by default */
e52367a
     init_fips_option(&fgbl->fips_restricted_drgb_digests, 0);
e52367a
     return fgbl;
e52367a
 }
e52367a
diff --git a/providers/implementations/kdfs/tls1_prf.c b/providers/implementations/kdfs/tls1_prf.c
e52367a
index 25a6c79a2e..79bc7a9719 100644
e52367a
--- a/providers/implementations/kdfs/tls1_prf.c
e52367a
+++ b/providers/implementations/kdfs/tls1_prf.c
e52367a
@@ -131,6 +131,7 @@ static void *kdf_tls1_prf_new(void *provctx)
e52367a
 static void kdf_tls1_prf_free(void *vctx)
e52367a
 {
e52367a
     TLS1_PRF *ctx = (TLS1_PRF *)vctx;
e52367a
+    OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
e52367a
 
e52367a
     if (ctx != NULL) {
e52367a
         kdf_tls1_prf_reset(ctx);
e52367a
@@ -222,6 +223,27 @@ static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen,
e52367a
         }
e52367a
     }
e52367a
 
e52367a
+    /*
e52367a
+     * The seed buffer is prepended with a label.
e52367a
+     * If EMS mode is enforced then the label "master secret" is not allowed,
e52367a
+     * We do the check this way since the PRF is used for other purposes, as well
e52367a
+     * as "extended master secret".
e52367a
+     */
e52367a
+#ifdef FIPS_MODULE
e52367a
+    if (ctx->seedlen >= TLS_MD_MASTER_SECRET_CONST_SIZE
e52367a
+            && memcmp(ctx->seed, TLS_MD_MASTER_SECRET_CONST,
e52367a
+                      TLS_MD_MASTER_SECRET_CONST_SIZE) == 0)
e52367a
+    ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED;
e52367a
+#endif /* defined(FIPS_MODULE) */
e52367a
+    if (ossl_tls1_prf_ems_check_enabled(libctx)) {
e52367a
+        if (ctx->seedlen >= TLS_MD_MASTER_SECRET_CONST_SIZE
e52367a
+                && memcmp(ctx->seed, TLS_MD_MASTER_SECRET_CONST,
e52367a
+                          TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) {
e52367a
+            ERR_raise(ERR_LIB_PROV, PROV_R_EMS_NOT_ENABLED);
e52367a
+            return 0;
e52367a
+        }
e52367a
+    }
e52367a
+
e52367a
     return tls1_prf_alg(ctx->P_hash, ctx->P_sha1,
e52367a
                         ctx->sec, ctx->seclen,
e52367a
                         ctx->seed, ctx->seedlen,
e52367a
diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c
e52367a
index 5146cedb96..086db98c33 100644
e52367a
--- a/ssl/ssl_conf.c
e52367a
+++ b/ssl/ssl_conf.c
e52367a
@@ -389,6 +389,7 @@ static int cmd_Options(SSL_CONF_CTX *cctx, const char *value)
e52367a
         SSL_FLAG_TBL("ClientRenegotiation",
e52367a
                      SSL_OP_ALLOW_CLIENT_RENEGOTIATION),
e52367a
         SSL_FLAG_TBL_INV("EncryptThenMac", SSL_OP_NO_ENCRYPT_THEN_MAC),
e52367a
+        SSL_FLAG_TBL("RHNoEnforceEMSinFIPS", SSL_OP_RH_PERMIT_NOEMS_FIPS),
e52367a
         SSL_FLAG_TBL("NoRenegotiation", SSL_OP_NO_RENEGOTIATION),
e52367a
         SSL_FLAG_TBL("AllowNoDHEKEX", SSL_OP_ALLOW_NO_DHE_KEX),
e52367a
         SSL_FLAG_TBL("PrioritizeChaCha", SSL_OP_PRIORITIZE_CHACHA),
e52367a
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
e52367a
index 00b1ee531e..22cdabb308 100644
e52367a
--- a/ssl/statem/extensions_srvr.c
e52367a
+++ b/ssl/statem/extensions_srvr.c
e52367a
@@ -11,6 +11,7 @@
e52367a
 #include "../ssl_local.h"
e52367a
 #include "statem_local.h"
e52367a
 #include "internal/cryptlib.h"
e52367a
+#include <openssl/fips.h>
e52367a
 
e52367a
 #define COOKIE_STATE_FORMAT_VERSION     1
e52367a
 
e52367a
@@ -1552,8 +1553,13 @@ EXT_RETURN tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context,
f4c397c
                                   unsigned int context,
e52367a
                                   X509 *x, size_t chainidx)
e52367a
 {
e52367a
-    if ((s->s3.flags & TLS1_FLAGS_RECEIVED_EXTMS) == 0)
e52367a
+    if ((s->s3.flags & TLS1_FLAGS_RECEIVED_EXTMS) == 0) {
f4c397c
+        if (FIPS_mode() && !(SSL_get_options(SSL_CONNECTION_GET_SSL(s)) & SSL_OP_RH_PERMIT_NOEMS_FIPS) ) {
e52367a
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, ERR_R_UNSUPPORTED);
e52367a
+            return EXT_RETURN_FAIL;
e52367a
+        }
e52367a
         return EXT_RETURN_NOT_SENT;
e52367a
+    }
e52367a
 
e52367a
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
e52367a
             || !WPACKET_put_bytes_u16(pkt, 0)) {
e52367a
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
e52367a
index 91238e6457..e8ad8ecd9e 100644
e52367a
--- a/ssl/t1_enc.c
e52367a
+++ b/ssl/t1_enc.c
e52367a
@@ -20,6 +20,7 @@
e52367a
 #include <openssl/obj_mac.h>
e52367a
 #include <openssl/core_names.h>
e52367a
 #include <openssl/trace.h>
e52367a
+#include <openssl/fips.h>
e52367a
 
e52367a
 /* seed1 through seed5 are concatenated */
f4c397c
 static int tls1_PRF(SSL_CONNECTION *s,
e52367a
@@ -75,8 +76,14 @@ static int tls1_PRF(SSL *s,
e52367a
     }
e52367a
 
e52367a
  err:
e52367a
-    if (fatal)
e52367a
-        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
e52367a
+    if (fatal) {
e52367a
+        /* The calls to this function are local so it's safe to implement the check */
e52367a
+        if (FIPS_mode() && seed1_len >= TLS_MD_MASTER_SECRET_CONST_SIZE
e52367a
+            && memcmp(seed1, TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE) == 0)
e52367a
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, ERR_R_UNSUPPORTED);
e52367a
+	else
e52367a
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
e52367a
+    }
e52367a
     else
e52367a
         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
e52367a
     EVP_KDF_CTX_free(kctx);
e52367a
diff --git a/test/recipes/30-test_evp_data/evpkdf_tls12_prf.txt b/test/recipes/30-test_evp_data/evpkdf_tls12_prf.txt
e52367a
index 44040ff66b..deb6bf3fcb 100644
e52367a
--- a/test/recipes/30-test_evp_data/evpkdf_tls12_prf.txt
e52367a
+++ b/test/recipes/30-test_evp_data/evpkdf_tls12_prf.txt
e52367a
@@ -22,6 +22,16 @@ Ctrl.client_random = hexseed:36c129d01a3200894b9179faac589d9835d58775f9b5ea3587c
e52367a
 Ctrl.server_random = hexseed:f6c9575ed7ddd73e1f7d16eca115415812a43c2b747daaaae043abfb50053fce
e52367a
 Output = 202c88c00f84a17a20027079604787461176455539e705be730890602c289a5001e34eeb3a043e5d52a65e66125188bf
e52367a
 
e52367a
+Availablein = fips
e52367a
+KDF = TLS1-PRF
e52367a
+Ctrl.digest = digest:SHA256
e52367a
+Ctrl.Secret = hexsecret:f8938ecc9edebc5030c0c6a441e213cd24e6f770a50dda07876f8d55da062bcadb386b411fd4fe4313a604fce6c17fbc
e52367a
+Ctrl.label = seed:master secret
e52367a
+Ctrl.client_random = hexseed:36c129d01a3200894b9179faac589d9835d58775f9b5ea3587cb8fd0364cae8c
e52367a
+Ctrl.server_random = hexseed:f6c9575ed7ddd73e1f7d16eca115415812a43c2b747daaaae043abfb50053fce
e52367a
+Output = 202c88c00f84a17a20027079604787461176455539e705be730890602c289a5001e34eeb3a043e5d52a65e66125188bf
e52367a
+Result = KDF_DERIVE_ERROR
e52367a
+
e52367a
 FIPSversion = <=3.1.0
e52367a
 KDF = TLS1-PRF
e52367a
 Ctrl.digest = digest:SHA256
e52367a
diff --git a/test/sslapitest.c b/test/sslapitest.c
e52367a
index 169e3c7466..e67b5bb44c 100644
e52367a
--- a/test/sslapitest.c
e52367a
+++ b/test/sslapitest.c
e52367a
@@ -574,7 +574,7 @@ static int test_client_cert_verify_cb(void)
e52367a
     STACK_OF(X509) *server_chain;
e52367a
     SSL_CTX *cctx = NULL, *sctx = NULL;
e52367a
     SSL *clientssl = NULL, *serverssl = NULL;
e52367a
-    int testresult = 0;
e52367a
+    int testresult = 0, status;
e52367a
 
e52367a
     if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
e52367a
                                        TLS_client_method(), TLS1_VERSION, 0,
e52367a
-- 
e52367a
2.41.0
e52367a