Add SSL_[CTX_]_set_compliance_policy.

These functions aid in meeting specific compliance goals and allows
configuration of things like TLS 1.3 cipher suites, which are otherwise
not configurable.

Change-Id: I668afc734a19ecd4b996eaa23be73ce259b13fa2
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/52625
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index f0ca7f7..b990b41 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -5104,6 +5104,44 @@
 OPENSSL_EXPORT uint16_t SSL_CIPHER_get_value(const SSL_CIPHER *cipher);
 
 
+// Compliance policy configurations
+//
+// A TLS connection has a large number of different parameters. Some are well
+// known, like cipher suites, but many are obscure and configuration functions
+// for them may not exist. These policy controls allow broad configuration
+// goals to be specified so that they can flow down to all the different
+// parameters of a TLS connection.
+
+enum ssl_compliance_policy_t BORINGSSL_ENUM_INT {
+  // ssl_policy_fips_202205 configures a TLS connection to use:
+  //   * TLS 1.2 or 1.3
+  //   * For TLS 1.2, only ECDHE_[RSA|ECDSA]_WITH_AES_*_GCM_SHA*.
+  //   * For TLS 1.3, only AES-GCM
+  //   * P-256 or P-384 for key agreement.
+  //   * For server signatures, only PKCS#1/PSS with SHA256/384/512, or ECDSA
+  //     with P-256 or P-384.
+  //
+  // Note: this policy can be configured even if BoringSSL has not been built in
+  // FIPS mode. Call |FIPS_mode| to check that.
+  //
+  // Note: this setting aids with compliance with NIST requirements but does not
+  // guarantee it. Careful reading of SP 800-52r2 is recommended.
+  ssl_compliance_policy_fips_202205,
+};
+
+// SSL_CTX_set_compliance_policy configures various aspects of |ctx| based on
+// the given policy requirements. Subsequently calling other functions that
+// configure |ctx| may override |policy|, or may not. This should be the final
+// configuration function called in order to have defined behaviour.
+OPENSSL_EXPORT int SSL_CTX_set_compliance_policy(
+    SSL_CTX *ctx, enum ssl_compliance_policy_t policy);
+
+// SSL_set_compliance_policy acts the same as |SSL_CTX_set_compliance_policy|,
+// but only configures a single |SSL*|.
+OPENSSL_EXPORT int SSL_set_compliance_policy(
+    SSL *ssl, enum ssl_compliance_policy_t policy);
+
+
 // Nodejs compatibility section (hidden).
 //
 // These defines exist for node.js, with the hope that we can eliminate the
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index e630121..bb2462f 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -235,7 +235,12 @@
   // Add TLS 1.3 ciphers. Order ChaCha20-Poly1305 relative to AES-GCM based on
   // hardware support.
   if (hs->max_version >= TLS1_3_VERSION) {
-    if (!EVP_has_aes_hardware() &&
+    const bool include_chacha20 = ssl_tls13_cipher_meets_policy(
+        TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff,
+        ssl->config->only_fips_cipher_suites_in_tls13);
+
+    if (!EVP_has_aes_hardware() &&  //
+        include_chacha20 &&         //
         !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
       return false;
     }
@@ -243,7 +248,8 @@
         !CBB_add_u16(&child, TLS1_CK_AES_256_GCM_SHA384 & 0xffff)) {
       return false;
     }
-    if (EVP_has_aes_hardware() &&
+    if (EVP_has_aes_hardware() &&  //
+        include_chacha20 &&        //
         !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
       return false;
     }
diff --git a/ssl/internal.h b/ssl/internal.h
index fbf9745..2400f90 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -660,10 +660,15 @@
 size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher);
 
 // ssl_choose_tls13_cipher returns an |SSL_CIPHER| corresponding with the best
-// available from |cipher_suites| compatible with |version| and |group_id|. It
-// returns NULL if there isn't a compatible cipher.
+// available from |cipher_suites| compatible with |version|, |group_id|, and
+// |only_fips|. It returns NULL if there isn't a compatible cipher.
 const SSL_CIPHER *ssl_choose_tls13_cipher(CBS cipher_suites, uint16_t version,
-                                          uint16_t group_id);
+                                          uint16_t group_id, bool only_fips);
+
+// ssl_tls13_cipher_meets_policy returns true if |cipher_id| is acceptable given
+// |only_fips|. (For now there's only a single policy and so the policy argument
+// is just a bool.)
+bool ssl_tls13_cipher_meets_policy(uint16_t cipher_id, bool only_fips);
 
 
 // Transcript layer.
@@ -3087,6 +3092,10 @@
 
   // permute_extensions is whether to permute extensions when sending messages.
   bool permute_extensions : 1;
+
+  // only_fips_cipher_suites_in_tls13 constrains the selection of cipher suites
+  // in TLS 1.3 such that only FIPS approved ones will be selected.
+  bool only_fips_cipher_suites_in_tls13 : 1;
 };
 
 // From RFC 8446, used in determining PSK modes.
@@ -3694,6 +3703,10 @@
   // If enable_early_data is true, early data can be sent and accepted.
   bool enable_early_data : 1;
 
+  // only_fips_cipher_suites_in_tls13 constrains the selection of cipher suites
+  // in TLS 1.3 such that only FIPS approved ones will be selected.
+  bool only_fips_cipher_suites_in_tls13 : 1;
+
  private:
   ~ssl_ctx_st();
   friend OPENSSL_EXPORT void SSL_CTX_free(SSL_CTX *);
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index cddeb3f..d0fc6c0 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -691,8 +691,25 @@
   const bool security_128_is_fine_;
 };
 
+bool ssl_tls13_cipher_meets_policy(uint16_t cipher_id, bool only_fips) {
+  if (!only_fips) {
+    return true;
+  }
+
+  switch (cipher_id) {
+    case TLS1_CK_AES_128_GCM_SHA256 & 0xffff:
+    case TLS1_CK_AES_256_GCM_SHA384 & 0xffff:
+      return true;
+    case TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff:
+      return false;
+    default:
+      assert(false);
+      return false;
+  }
+}
+
 const SSL_CIPHER *ssl_choose_tls13_cipher(CBS cipher_suites, uint16_t version,
-                                          uint16_t group_id) {
+                                          uint16_t group_id, bool only_fips) {
   if (CBS_len(&cipher_suites) % 2 != 0) {
     return nullptr;
   }
@@ -715,6 +732,11 @@
       continue;
     }
 
+    if (!ssl_tls13_cipher_meets_policy(SSL_CIPHER_get_protocol_id(candidate),
+                                       only_fips)) {
+      continue;
+    }
+
     const CipherScorer::Score candidate_score = scorer.Evaluate(candidate);
     // |candidate_score| must be larger to displace the current choice. That way
     // the client's order controls between ciphers with an equal score.
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 5e96bef..0b3febf 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -519,7 +519,8 @@
       allow_unknown_alpn_protos(false),
       false_start_allowed_without_alpn(false),
       handoff(false),
-      enable_early_data(false) {
+      enable_early_data(false),
+      only_fips_cipher_suites_in_tls13(false) {
   CRYPTO_MUTEX_init(&lock);
   CRYPTO_new_ex_data(&ex_data);
 }
@@ -639,6 +640,8 @@
   ssl->config->retain_only_sha256_of_client_certs =
       ctx->retain_only_sha256_of_client_certs;
   ssl->config->permute_extensions = ctx->permute_extensions;
+  ssl->config->only_fips_cipher_suites_in_tls13 =
+      ctx->only_fips_cipher_suites_in_tls13;
 
   if (!ssl->config->supported_group_list.CopyFrom(ctx->supported_group_list) ||
       !ssl->config->alpn_client_proto_list.CopyFrom(
@@ -3079,3 +3082,93 @@
   ctx->legacy_ocsp_callback_arg = arg;
   return 1;
 }
+
+namespace fips202205 {
+
+// (References are to SP 800-52r2):
+
+// Section 3.4.2.2
+// "at least one of the NIST-approved curves, P-256 (secp256r1) and P384
+// (secp384r1), shall be supported as described in RFC 8422."
+//
+// Section 3.3.1
+// "The server shall be configured to only use cipher suites that are
+// composed entirely of NIST approved algorithms"
+static const int kCurves[] = {NID_X9_62_prime256v1, NID_secp384r1};
+
+static const uint16_t kSigAlgs[] = {
+    SSL_SIGN_RSA_PKCS1_SHA256,
+    SSL_SIGN_RSA_PKCS1_SHA384,
+    SSL_SIGN_RSA_PKCS1_SHA512,
+    // Table 4.1:
+    // "The curve should be P-256 or P-384"
+    SSL_SIGN_ECDSA_SECP256R1_SHA256,
+    SSL_SIGN_ECDSA_SECP384R1_SHA384,
+    SSL_SIGN_RSA_PSS_RSAE_SHA256,
+    SSL_SIGN_RSA_PSS_RSAE_SHA384,
+    SSL_SIGN_RSA_PSS_RSAE_SHA512,
+};
+
+static const char kTLS12Ciphers[] =
+    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:"
+    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:"
+    "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:"
+    "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384";
+
+static int Configure(SSL_CTX *ctx) {
+  ctx->only_fips_cipher_suites_in_tls13 = true;
+
+  return
+      // Section 3.1:
+      // "Servers that support government-only applications shall be
+      // configured to use TLS 1.2 and should be configured to use TLS 1.3
+      // as well. These servers should not be configured to use TLS 1.1 and
+      // shall not use TLS 1.0, SSL 3.0, or SSL 2.0.
+      SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION) &&
+      SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION) &&
+      // Sections 3.3.1.1.1 and 3.3.1.1.2 are ambiguous about whether
+      // HMAC-SHA-1 cipher suites are permitted with TLS 1.2. However, later the
+      // Encrypt-then-MAC extension is required for all CBC cipher suites and so
+      // it's easier to drop them.
+      SSL_CTX_set_strict_cipher_list(ctx, kTLS12Ciphers) &&
+      SSL_CTX_set1_curves(ctx, kCurves, OPENSSL_ARRAY_SIZE(kCurves)) &&
+      SSL_CTX_set_signing_algorithm_prefs(ctx, kSigAlgs,
+                                          OPENSSL_ARRAY_SIZE(kSigAlgs)) &&
+      SSL_CTX_set_verify_algorithm_prefs(ctx, kSigAlgs,
+                                         OPENSSL_ARRAY_SIZE(kSigAlgs));
+}
+
+static int Configure(SSL *ssl) {
+  ssl->config->only_fips_cipher_suites_in_tls13 = true;
+
+  // See |Configure(SSL_CTX)|, above, for reasoning.
+  return SSL_set_min_proto_version(ssl, TLS1_2_VERSION) &&
+         SSL_set_max_proto_version(ssl, TLS1_3_VERSION) &&
+         SSL_set_strict_cipher_list(ssl, kTLS12Ciphers) &&
+         SSL_set1_curves(ssl, kCurves, OPENSSL_ARRAY_SIZE(kCurves)) &&
+         SSL_set_signing_algorithm_prefs(ssl, kSigAlgs,
+                                         OPENSSL_ARRAY_SIZE(kSigAlgs)) &&
+         SSL_set_verify_algorithm_prefs(ssl, kSigAlgs,
+                                        OPENSSL_ARRAY_SIZE(kSigAlgs));
+}
+
+}  // namespace fips202205
+
+int SSL_CTX_set_compliance_policy(SSL_CTX *ctx,
+                                  enum ssl_compliance_policy_t policy) {
+  switch (policy) {
+    case ssl_compliance_policy_fips_202205:
+      return fips202205::Configure(ctx);
+    default:
+      return 0;
+  }
+}
+
+int SSL_set_compliance_policy(SSL *ssl, enum ssl_compliance_policy_t policy) {
+  switch (policy) {
+    case ssl_compliance_policy_fips_202205:
+      return fips202205::Configure(ssl);
+    default:
+      return 0;
+  }
+}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 4c1c955..65ed278 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -19032,6 +19032,197 @@
 	}
 }
 
+func addCompliancePolicyTests() {
+	for _, protocol := range []protocol{tls, quic} {
+		for _, suite := range testCipherSuites {
+			var isFIPSCipherSuite bool
+			switch suite.id {
+			case TLS_AES_128_GCM_SHA256,
+				TLS_AES_256_GCM_SHA384,
+				TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+				TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+				TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+				TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+				isFIPSCipherSuite = true
+			}
+
+			var certFile string
+			var keyFile string
+			var certs []Certificate
+			if hasComponent(suite.name, "ECDSA") {
+				certFile = ecdsaP256CertificateFile
+				keyFile = ecdsaP256KeyFile
+				certs = []Certificate{ecdsaP256Certificate}
+			} else {
+				certFile = rsaCertificateFile
+				keyFile = rsaKeyFile
+				certs = []Certificate{rsaCertificate}
+			}
+
+			maxVersion := uint16(VersionTLS13)
+			if !isTLS13Suite(suite.name) {
+				if protocol == quic {
+					continue
+				}
+				maxVersion = VersionTLS12
+			}
+
+			testCases = append(testCases, testCase{
+				testType: serverTest,
+				protocol: protocol,
+				name:     "Compliance-fips202205-" + protocol.String() + "-Server-" + suite.name,
+				config: Config{
+					MinVersion:   VersionTLS12,
+					MaxVersion:   maxVersion,
+					CipherSuites: []uint16{suite.id},
+				},
+				certFile: certFile,
+				keyFile:  keyFile,
+				flags: []string{
+					"-fips-202205",
+				},
+				shouldFail: !isFIPSCipherSuite,
+			})
+
+			testCases = append(testCases, testCase{
+				testType: clientTest,
+				protocol: protocol,
+				name:     "Compliance-fips202205-" + protocol.String() + "-Client-" + suite.name,
+				config: Config{
+					MinVersion:   VersionTLS12,
+					MaxVersion:   maxVersion,
+					CipherSuites: []uint16{suite.id},
+					Certificates: certs,
+				},
+				flags: []string{
+					"-fips-202205",
+				},
+				shouldFail: !isFIPSCipherSuite,
+			})
+		}
+
+		// Check that a TLS 1.3 client won't accept ChaCha20 even if the server
+		// picks it without it being in the client's cipher list.
+		testCases = append(testCases, testCase{
+			testType: clientTest,
+			protocol: protocol,
+			name:     "Compliance-fips202205-" + protocol.String() + "-Client-ReallyWontAcceptChaCha",
+			config: Config{
+				MinVersion: VersionTLS12,
+				MaxVersion: maxVersion,
+				Bugs: ProtocolBugs{
+					SendCipherSuite: TLS_CHACHA20_POLY1305_SHA256,
+				},
+			},
+			flags: []string{
+				"-fips-202205",
+			},
+			shouldFail:    true,
+			expectedError: ":WRONG_CIPHER_RETURNED:",
+		})
+
+		for _, curve := range testCurves {
+			var isFIPSCurve bool
+			switch curve.id {
+			case CurveP256, CurveP384:
+				isFIPSCurve = true
+			}
+
+			testCases = append(testCases, testCase{
+				testType: serverTest,
+				protocol: protocol,
+				name:     "Compliance-fips202205-" + protocol.String() + "-Server-" + curve.name,
+				config: Config{
+					MinVersion:       VersionTLS12,
+					MaxVersion:       VersionTLS13,
+					CurvePreferences: []CurveID{curve.id},
+				},
+				flags: []string{
+					"-fips-202205",
+				},
+				shouldFail: !isFIPSCurve,
+			})
+
+			testCases = append(testCases, testCase{
+				testType: clientTest,
+				protocol: protocol,
+				name:     "Compliance-fips202205-" + protocol.String() + "-Client-" + curve.name,
+				config: Config{
+					MinVersion:       VersionTLS12,
+					MaxVersion:       VersionTLS13,
+					CurvePreferences: []CurveID{curve.id},
+				},
+				flags: []string{
+					"-fips-202205",
+				},
+				shouldFail: !isFIPSCurve,
+			})
+		}
+
+		for _, sigalg := range testSignatureAlgorithms {
+			var isFIPSSigAlg bool
+			switch sigalg.id {
+			case signatureRSAPKCS1WithSHA256,
+				signatureRSAPKCS1WithSHA384,
+				signatureRSAPKCS1WithSHA512,
+				signatureECDSAWithP256AndSHA256,
+				signatureECDSAWithP384AndSHA384,
+				signatureRSAPSSWithSHA256,
+				signatureRSAPSSWithSHA384,
+				signatureRSAPSSWithSHA512:
+				isFIPSSigAlg = true
+			}
+
+			if sigalg.cert == testCertECDSAP224 {
+				// This can work in TLS 1.2, but not with TLS 1.3.
+				// For consistency it's not permitted in FIPS mode.
+				isFIPSSigAlg = false
+			}
+
+			maxVersion := uint16(VersionTLS13)
+			if hasComponent(sigalg.name, "PKCS1") {
+				if protocol == quic {
+					continue
+				}
+				maxVersion = VersionTLS12
+			}
+
+			testCases = append(testCases, testCase{
+				testType: serverTest,
+				protocol: protocol,
+				name:     "Compliance-fips202205-" + protocol.String() + "-Server-" + sigalg.name,
+				config: Config{
+					MinVersion:                VersionTLS12,
+					MaxVersion:                maxVersion,
+					VerifySignatureAlgorithms: []signatureAlgorithm{sigalg.id},
+				},
+				flags: []string{
+					"-fips-202205",
+					"-cert-file", path.Join(*resourceDir, getShimCertificate(sigalg.cert)),
+					"-key-file", path.Join(*resourceDir, getShimKey(sigalg.cert)),
+				},
+				shouldFail: !isFIPSSigAlg,
+			})
+
+			testCases = append(testCases, testCase{
+				testType: clientTest,
+				protocol: protocol,
+				name:     "Compliance-fips202205-" + protocol.String() + "-Client-" + sigalg.name,
+				config: Config{
+					MinVersion:              VersionTLS12,
+					MaxVersion:              maxVersion,
+					SignSignatureAlgorithms: []signatureAlgorithm{sigalg.id},
+					Certificates:            []Certificate{getRunnerCertificate(sigalg.cert)},
+				},
+				flags: []string{
+					"-fips-202205",
+				},
+				shouldFail: !isFIPSSigAlg,
+			})
+		}
+	}
+}
+
 func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
@@ -19274,6 +19465,7 @@
 	addDelegatedCredentialTests()
 	addEncryptedClientHelloTests()
 	addHintMismatchTests()
+	addCompliancePolicyTests()
 
 	toAppend, err := convertToSplitHandshakeTests(testCases)
 	if err != nil {
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index a6409d6..2c7fa08 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -385,6 +385,7 @@
                  &TestConfig::quic_early_data_context),
       IntFlag("-early-write-after-message",
               &TestConfig::early_write_after_message),
+      BoolFlag("-fips-202205", &TestConfig::fips_202205),
   };
   std::sort(flags.begin(), flags.end(), [](const Flag &a, const Flag &b) {
     return strcmp(a.name, b.name) < 0;
@@ -1765,6 +1766,11 @@
   if (enable_ech_grease) {
     SSL_set_enable_ech_grease(ssl.get(), 1);
   }
+  if (fips_202205 && !SSL_set_compliance_policy(
+                         ssl.get(), ssl_compliance_policy_fips_202205)) {
+    fprintf(stderr, "SSL_set_compliance_policy failed\n");
+    return nullptr;
+  }
   if (!ech_config_list.empty() &&
       !SSL_set1_ech_config_list(
           ssl.get(), reinterpret_cast<const uint8_t *>(ech_config_list.data()),
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index f1e26ff..1a21ac1 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -193,6 +193,7 @@
   bool wait_for_debugger = false;
   std::string quic_early_data_context;
   int early_write_after_message = 0;
+  bool fips_202205 = false;
 
   int argc;
   char **argv;
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index af2120c..bd0f820 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -192,11 +192,15 @@
   }
 
   // The cipher suite must be one we offered. We currently offer all supported
-  // TLS 1.3 ciphers, so check the version.
+  // TLS 1.3 ciphers unless policy controls limited it. So we check the version
+  // and that it's ok per policy.
   const SSL_CIPHER *cipher = SSL_get_cipher_by_value(server_hello.cipher_suite);
   if (cipher == nullptr ||
       SSL_CIPHER_get_min_version(cipher) > ssl_protocol_version(ssl) ||
-      SSL_CIPHER_get_max_version(cipher) < ssl_protocol_version(ssl)) {
+      SSL_CIPHER_get_max_version(cipher) < ssl_protocol_version(ssl) ||
+      !ssl_tls13_cipher_meets_policy(
+          SSL_CIPHER_get_value(cipher),
+          ssl->config->only_fips_cipher_suites_in_tls13)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
     return ssl_hs_error;
@@ -372,7 +376,7 @@
   }
 
   // Check the cipher suite, in case this is after HelloRetryRequest.
-  if (SSL_CIPHER_get_value(hs->new_cipher) != server_hello.cipher_suite) {
+  if (SSL_CIPHER_get_protocol_id(hs->new_cipher) != server_hello.cipher_suite) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
     return ssl_hs_error;
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index 9a65e0f..eca63f7 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -116,7 +116,8 @@
 
   const uint16_t version = ssl_protocol_version(ssl);
 
-  return ssl_choose_tls13_cipher(cipher_suites, version, group_id);
+  return ssl_choose_tls13_cipher(cipher_suites, version, group_id,
+                                 ssl->config->only_fips_cipher_suites_in_tls13);
 }
 
 static bool add_new_session_tickets(SSL_HANDSHAKE *hs, bool *out_sent_tickets) {