Add GREASE for signature_algorithms

This adds `SSL_CTX_set_grease_sigalgs_enabled`, which enables adding a
GREASE value in signature_algorithms extensions (for a client only, for
now).

This functionality will be folded into `SSL_CTX_set_grease_enabled` at a
later time, once it has been safely deployed.

Bug: 526597789
Change-Id: I792304a78706d72f910dbeac6873748c6a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/97987
Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Lily Chen <chlily@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/include/openssl/prefix_symbols.h b/include/openssl/prefix_symbols.h
index 703383c..48d5081 100644
--- a/include/openssl/prefix_symbols.h
+++ b/include/openssl/prefix_symbols.h
@@ -2018,6 +2018,7 @@
 #pragma redefine_extname SSL_CTX_set_ex_data BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set_ex_data)
 #pragma redefine_extname SSL_CTX_set_false_start_allowed_without_alpn BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set_false_start_allowed_without_alpn)
 #pragma redefine_extname SSL_CTX_set_grease_enabled BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set_grease_enabled)
+#pragma redefine_extname SSL_CTX_set_grease_sigalgs_enabled BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set_grease_sigalgs_enabled)
 #pragma redefine_extname SSL_CTX_set_info_callback BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set_info_callback)
 #pragma redefine_extname SSL_CTX_set_keylog_callback BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set_keylog_callback)
 #pragma redefine_extname SSL_CTX_set_max_cert_list BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_CTX_set_max_cert_list)
@@ -5136,6 +5137,7 @@
 #define SSL_CTX_set_ex_data BORINGSSL_ADD_PREFIX(SSL_CTX_set_ex_data)
 #define SSL_CTX_set_false_start_allowed_without_alpn BORINGSSL_ADD_PREFIX(SSL_CTX_set_false_start_allowed_without_alpn)
 #define SSL_CTX_set_grease_enabled BORINGSSL_ADD_PREFIX(SSL_CTX_set_grease_enabled)
+#define SSL_CTX_set_grease_sigalgs_enabled BORINGSSL_ADD_PREFIX(SSL_CTX_set_grease_sigalgs_enabled)
 #define SSL_CTX_set_info_callback BORINGSSL_ADD_PREFIX(SSL_CTX_set_info_callback)
 #define SSL_CTX_set_keylog_callback BORINGSSL_ADD_PREFIX(SSL_CTX_set_keylog_callback)
 #define SSL_CTX_set_max_cert_list BORINGSSL_ADD_PREFIX(SSL_CTX_set_max_cert_list)
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 8c81152..eb4e772 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -5515,6 +5515,16 @@
 // GREASE. See RFC 8701.
 OPENSSL_EXPORT void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled);
 
+// SSL_CTX_set_grease_sigalgs_enabled configures whether sockets on `ctx` should
+// send a GREASE value in signature_algorithms extensions in ClientHello
+// messages. See RFC 8701.
+// TODO(crbug.com/526597789): Fold this functionality into
+// `SSL_CTX_set_grease_enabled` once deployed safely.
+// TODO(crbug.com/529360100): signature_algorithms extensions in
+// CertificateRequest messages should also be GREASE'd.
+OPENSSL_EXPORT void SSL_CTX_set_grease_sigalgs_enabled(SSL_CTX *ctx,
+                                                       int enabled);
+
 // SSL_CTX_set_permute_extensions configures whether sockets on `ctx` should
 // permute extensions. For now, this is only implemented for the ClientHello.
 OPENSSL_EXPORT void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled);
diff --git a/ssl/extensions.cc b/ssl/extensions.cc
index 64152ec..1f29be1 100644
--- a/ssl/extensions.cc
+++ b/ssl/extensions.cc
@@ -1030,8 +1030,16 @@
   CBB contents, sigalgs_cbb;
   if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_signature_algorithms) ||
       !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
-      !CBB_add_u16_length_prefixed(&contents, &sigalgs_cbb) ||
-      !tls12_add_verify_sigalgs(hs, &sigalgs_cbb) ||
+      !CBB_add_u16_length_prefixed(&contents, &sigalgs_cbb)) {
+        return false;
+  }
+  // Add a fake signature algorithm. See RFC 8701.
+  if (hs->ssl->ctx->grease_sigalgs_enabled &&
+      !CBB_add_u16(&sigalgs_cbb,
+                   ssl_get_grease_value(hs, ssl_grease_signature_algorithm))) {
+    return false;
+  }
+  if (!tls12_add_verify_sigalgs(hs, &sigalgs_cbb) ||
       !CBB_flush(out_compressible)) {
     return false;
   }
diff --git a/ssl/internal.h b/ssl/internal.h
index c8d5330..bdd6320 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1665,7 +1665,8 @@
   ssl_grease_version,
   ssl_grease_ticket_extension,
   ssl_grease_ech_config_id,
-  ssl_grease_last_index = ssl_grease_ech_config_id,
+  ssl_grease_signature_algorithm,
+  ssl_grease_last_index = ssl_grease_signature_algorithm,
 };
 
 enum tls12_server_hs_state_t {
@@ -4160,6 +4161,11 @@
   // grease_enabled is whether GREASE (RFC 8701) is enabled.
   bool grease_enabled : 1;
 
+  // grease_sigalgs_enabled controls whether GREASE signature algorithms may be
+  // sent.
+  // TODO(crbug.com/526597789): Fold into `grease_enabled` once deployed safely.
+  bool grease_sigalgs_enabled : 1;
+
   // permute_extensions is whether to permute extensions when sending messages.
   bool permute_extensions : 1;
 
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index f5f7df0..fd287f5 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -388,6 +388,7 @@
       signed_cert_timestamps_enabled(false),
       channel_id_enabled(false),
       grease_enabled(false),
+      grease_sigalgs_enabled(false),
       permute_extensions(false),
       allow_unknown_alpn_protos(false),
       false_start_allowed_without_alpn(false),
@@ -3171,6 +3172,10 @@
   FromOpaque(ctx)->grease_enabled = !!enabled;
 }
 
+void SSL_CTX_set_grease_sigalgs_enabled(SSL_CTX *ctx, int enabled) {
+  FromOpaque(ctx)->grease_sigalgs_enabled = !!enabled;
+}
+
 void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled) {
   FromOpaque(ctx)->permute_extensions = !!enabled;
 }
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index c5e3d6e..ff2a825 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -2745,6 +2745,12 @@
 	return slices.ContainsFunc(values, isGREASEValue)
 }
 
+func containsSigAlgsGREASE(values []signatureAlgorithm) bool {
+	return slices.ContainsFunc(values, func(s signatureAlgorithm) bool {
+		return isGREASEValue(uint16(s))
+	})
+}
+
 func isAllZero(v []byte) bool {
 	for _, b := range v {
 		if b != 0 {
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 181c538..0f1fb47 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -379,6 +379,10 @@
 		return fmt.Errorf("tls: client included signature_algorithms before TLS 1.2")
 	}
 
+	if config.Bugs.ExpectGREASE && !containsSigAlgsGREASE(hs.clientHello.signatureAlgorithms) {
+		return fmt.Errorf("tls: no GREASE signature_algorithms value found")
+	}
+
 	// Check the client cipher list is consistent with the version.
 	if clientVersOK && clientVers.protocolVersion() < VersionTLS12 && slices.ContainsFunc(hs.clientHello.cipherSuites, isTLS12Cipher) {
 		return fmt.Errorf("tls: client offered TLS 1.2 cipher before TLS 1.2")
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 4f3e790..58f0c01 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -2120,6 +2120,7 @@
 
   if (enable_grease) {
     SSL_CTX_set_grease_enabled(ssl_ctx.get(), 1);
+    SSL_CTX_set_grease_sigalgs_enabled(ssl_ctx.get(), 1);
   }
 
   if (permute_extensions) {