0bb701
From 339bef12f478b3a12c59571c53645e31280baf7e Mon Sep 17 00:00:00 2001
0bb701
From: Daiki Ueno <ueno@gnu.org>
0bb701
Date: Fri, 14 May 2021 15:59:37 +0200
0bb701
Subject: [PATCH] cert auth: filter out unsupported cert types from TLS 1.2 CR
0bb701
0bb701
When the server is advertising signature algorithms in TLS 1.2
0bb701
CertificateRequest, it shouldn't send certificate_types not backed by
0bb701
any of those algorithms.
0bb701
0bb701
Signed-off-by: Daiki Ueno <ueno@gnu.org>
0bb701
---
0bb701
 lib/auth/cert.c                         | 76 +++++++++++++++++++++++--
0bb701
 tests/suite/tls-fuzzer/gnutls-cert.json | 19 +++++++
0bb701
 2 files changed, 89 insertions(+), 6 deletions(-)
0bb701
0bb701
diff --git a/lib/auth/cert.c b/lib/auth/cert.c
0bb701
index 3073a33d3..0b0f04b2b 100644
0bb701
--- a/lib/auth/cert.c
0bb701
+++ b/lib/auth/cert.c
0bb701
@@ -64,6 +64,16 @@ typedef enum CertificateSigType { RSA_SIGN = 1, DSA_SIGN = 2, ECDSA_SIGN = 64,
0bb701
 #endif
0bb701
 } CertificateSigType;
0bb701
 
0bb701
+enum CertificateSigTypeFlags {
0bb701
+	RSA_SIGN_FLAG = 1,
0bb701
+	DSA_SIGN_FLAG = 1 << 1,
0bb701
+	ECDSA_SIGN_FLAG = 1 << 2,
0bb701
+#ifdef ENABLE_GOST
0bb701
+	GOSTR34102012_256_SIGN_FLAG = 1 << 3,
0bb701
+	GOSTR34102012_512_SIGN_FLAG = 1 << 4
0bb701
+#endif
0bb701
+};
0bb701
+
0bb701
 /* Moves data from an internal certificate struct (gnutls_pcert_st) to
0bb701
  * another internal certificate struct (cert_auth_info_t), and deinitializes
0bb701
  * the former.
0bb701
@@ -1281,6 +1291,7 @@ _gnutls_gen_cert_server_cert_req(gnutls_session_t session,
0bb701
 	uint8_t tmp_data[CERTTYPE_SIZE];
0bb701
 	const version_entry_st *ver = get_version(session);
0bb701
 	unsigned init_pos = data->length;
0bb701
+	enum CertificateSigTypeFlags flags;
0bb701
 
0bb701
 	if (unlikely(ver == NULL))
0bb701
 		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
0bb701
@@ -1297,18 +1308,71 @@ _gnutls_gen_cert_server_cert_req(gnutls_session_t session,
0bb701
 		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
0bb701
 	}
0bb701
 
0bb701
-	i = 1;
0bb701
+	if (_gnutls_version_has_selectable_sighash(ver)) {
0bb701
+		size_t j;
0bb701
+
0bb701
+		flags = 0;
0bb701
+		for (j = 0; j < session->internals.priorities->sigalg.size; j++) {
0bb701
+			const gnutls_sign_entry_st *se =
0bb701
+				session->internals.priorities->sigalg.entry[j];
0bb701
+			switch (se->pk) {
0bb701
+			case GNUTLS_PK_RSA:
0bb701
+			case GNUTLS_PK_RSA_PSS:
0bb701
+				flags |= RSA_SIGN_FLAG;
0bb701
+				break;
0bb701
+			case GNUTLS_PK_DSA:
0bb701
+				flags |= DSA_SIGN_FLAG;
0bb701
+				break;
0bb701
+			case GNUTLS_PK_ECDSA:
0bb701
+				flags |= ECDSA_SIGN_FLAG;
0bb701
+				break;
0bb701
 #ifdef ENABLE_GOST
0bb701
-	if (_gnutls_kx_is_vko_gost(session->security_parameters.cs->kx_algorithm)) {
0bb701
-		tmp_data[i++] = GOSTR34102012_256_SIGN;
0bb701
-		tmp_data[i++] = GOSTR34102012_512_SIGN;
0bb701
-	} else
0bb701
+			case GNUTLS_PK_GOST_12_256:
0bb701
+				flags |= GOSTR34102012_256_SIGN_FLAG;
0bb701
+				break;
0bb701
+			case GNUTLS_PK_GOST_12_512:
0bb701
+				flags |= GOSTR34102012_512_SIGN_FLAG;
0bb701
+				break;
0bb701
+#endif
0bb701
+			default:
0bb701
+				gnutls_assert();
0bb701
+				_gnutls_debug_log(
0bb701
+					"%s is unsupported for cert request\n",
0bb701
+					gnutls_pk_get_name(se->pk));
0bb701
+			}
0bb701
+		}
0bb701
+
0bb701
+	} else {
0bb701
+#ifdef ENABLE_GOST
0bb701
+		if (_gnutls_kx_is_vko_gost(session->security_parameters.
0bb701
+					   cs->kx_algorithm)) {
0bb701
+			flags = GOSTR34102012_256_SIGN_FLAG |
0bb701
+				GOSTR34102012_512_SIGN_FLAG;
0bb701
+		} else
0bb701
 #endif
0bb701
-	{
0bb701
+		{
0bb701
+			flags = RSA_SIGN_FLAG | DSA_SIGN_FLAG | ECDSA_SIGN_FLAG;
0bb701
+		}
0bb701
+	}
0bb701
+
0bb701
+	i = 1;
0bb701
+	if (flags & RSA_SIGN_FLAG) {
0bb701
 		tmp_data[i++] = RSA_SIGN;
0bb701
+	}
0bb701
+	if (flags & DSA_SIGN_FLAG) {
0bb701
 		tmp_data[i++] = DSA_SIGN;
0bb701
+	}
0bb701
+	if (flags & ECDSA_SIGN_FLAG) {
0bb701
 		tmp_data[i++] = ECDSA_SIGN;
0bb701
 	}
0bb701
+#ifdef ENABLE_GOST
0bb701
+	if (flags & GOSTR34102012_256_SIGN_FLAG) {
0bb701
+		tmp_data[i++] = GOSTR34102012_256_SIGN;
0bb701
+	}
0bb701
+	if (flags & GOSTR34102012_512_SIGN_FLAG) {
0bb701
+		tmp_data[i++] = GOSTR34102012_512_SIGN;
0bb701
+	}
0bb701
+#endif
0bb701
 	tmp_data[0] = i - 1;
0bb701
 
0bb701
 	ret = _gnutls_buffer_append_data(data, tmp_data, i);
0bb701
-- 
0bb701
2.31.1
0bb701