From 5cc003b9688378f6c7934b1df0aa147e80006be4 Mon Sep 17 00:00:00 2001
From: Alexander Sosedkin <asosedkin@redhat.com>
Date: Fri, 13 Mar 2026 17:41:33 +0100
Subject: [PATCH] x509: add bare-bones awareness of SRV virtual SAN

There's no support for constraints, no certtool support, no nothing.
Just added what's easy to add because I needed a virtual SAN for them.

Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
CVE: CVE-2026-42012
Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/5cc003b9688378f6c7934b1df0aa147e80006be4]

Backport Changes:
- virt-san.c: use _gnutls_steal_datum instead of upstream _gnutls_take_datum
  (3.8.12 already provides steal_datum; take_datum is added later).

Signed-off-by: Jakub Szczudlo <jakub.szczudlo@nokia.com>
---
 lib/includes/gnutls/gnutls.h.in |  4 +++-
 lib/x509/common.h               |  1 +
 lib/x509/name_constraints.c     |  3 ++-
 lib/x509/output.c               |  6 ++++++
 lib/x509/virt-san.c             | 23 +++++++++++++++++++++++
 lib/x509/x509.c                 |  3 ++-
 6 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -2698,6 +2698,7 @@ void gnutls_psk_set_server_params_functi
  * @GNUTLS_SAN_OTHERNAME_XMPP: Virtual SAN, used by certain functions for convenience.
  * @GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL: Virtual SAN, used by certain functions for convenience.
  * @GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL: Virtual SAN, used by certain functions for convenience.
+ * @GNUTLS_SAN_OTHERNAME_SRV: Virtual SAN, used by certain functions for convenience.
  *
  * Enumeration of different subject alternative names types.
  */
@@ -2715,7 +2716,8 @@ typedef enum gnutls_x509_subject_alt_nam
 	   Used by gnutls_x509_crt_get_subject_alt_othername_oid.  */
 	GNUTLS_SAN_OTHERNAME_XMPP = 1000,
 	GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL,
-	GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL
+	GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL,
+	GNUTLS_SAN_OTHERNAME_SRV
 } gnutls_x509_subject_alt_name_t;
 
 struct gnutls_openpgp_crt_int;
diff --git a/lib/x509/common.h b/lib/x509/common.h
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -107,6 +107,7 @@
 #define XMPP_OID "1.3.6.1.5.5.7.8.5"
 #define KRB5_PRINCIPAL_OID "1.3.6.1.5.2.2"
 #define MSUSER_PRINCIPAL_NAME_OID "1.3.6.1.4.1.311.20.2.3"
+#define SRV_OID "1.3.6.1.5.5.7.8.7"
 #define PKIX1_RSA_PSS_MGF1_OID "1.2.840.113549.1.1.8"
 #define PKIX1_RSA_OAEP_P_SPECIFIED_OID "1.9"
 
diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c
--- a/lib/x509/name_constraints.c
+++ b/lib/x509/name_constraints.c
@@ -516,7 +516,8 @@ static int validate_name_constraints_nod
 	if (type != GNUTLS_SAN_DNSNAME && type != GNUTLS_SAN_RFC822NAME &&
 	    type != GNUTLS_SAN_DN && type != GNUTLS_SAN_URI &&
 	    type != GNUTLS_SAN_IPADDRESS &&
-	    type != GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL) {
+	    type != GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL &&
+	    type != GNUTLS_SAN_OTHERNAME_SRV) {
 		return gnutls_assert_val(GNUTLS_E_X509_UNKNOWN_SAN);
 	}
 
diff --git a/lib/x509/output.c b/lib/x509/output.c
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -121,6 +121,7 @@ static void print_name(gnutls_buffer_st
 	if ((type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_OTHERNAME_XMPP ||
 	     type == GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL ||
 	     type == GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL ||
+	     type == GNUTLS_SAN_OTHERNAME_SRV ||
 	     type == GNUTLS_SAN_RFC822NAME || type == GNUTLS_SAN_URI) &&
 	    sname != NULL && strlen(sname) != name->size) {
 		adds(str, _("warning: SAN contains an embedded NUL, "
@@ -180,6 +181,11 @@ static void print_name(gnutls_buffer_st
 		     name->size, NON_NULL(name->data));
 		break;
 
+	case GNUTLS_SAN_OTHERNAME_SRV:
+		addf(str, _("%sSRVName: %.*s\n"), prefix, name->size,
+		     NON_NULL(name->data));
+		break;
+
 	default:
 		addf(str, _("%sUnknown name: "), prefix);
 		_gnutls_buffer_hexprint(str, name->data, name->size);
diff --git a/lib/x509/virt-san.c b/lib/x509/virt-san.c
--- a/lib/x509/virt-san.c
+++ b/lib/x509/virt-san.c
@@ -45,6 +45,9 @@ static int san_othername_to_virtual(cons
 			 memcmp(oid, MSUSER_PRINCIPAL_NAME_OID,
 				sizeof(MSUSER_PRINCIPAL_NAME_OID) - 1) == 0)
 			return GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL;
+		else if ((unsigned)size == (sizeof(SRV_OID) - 1) &&
+			 memcmp(oid, SRV_OID, sizeof(SRV_OID) - 1) == 0)
+			return GNUTLS_SAN_OTHERNAME_SRV;
 	}
 
 	return GNUTLS_SAN_OTHERNAME;
@@ -59,6 +62,8 @@ static const char *virtual_to_othername_
 		return KRB5_PRINCIPAL_OID;
 	case GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL:
 		return MSUSER_PRINCIPAL_NAME_OID;
+	case GNUTLS_SAN_OTHERNAME_SRV:
+		return SRV_OID;
 	default:
 		return NULL;
 	}
@@ -126,6 +131,15 @@ int _gnutls_alt_name_assign_virt_type(st
 			name->type = GNUTLS_SAN_OTHERNAME;
 			break;
 
+		case GNUTLS_SAN_OTHERNAME_SRV:
+			ret = _gnutls_x509_encode_string(ASN1_ETYPE_IA5_STRING,
+							 san->data, san->size,
+							 &encoded);
+			if (ret < 0)
+				return gnutls_assert_val(ret);
+			name->san = _gnutls_steal_datum(&encoded);
+			break;
+
 		default:
 			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
 		}
@@ -187,6 +201,15 @@ int gnutls_x509_othername_to_virtual(con
 						 othername->data,
 						 othername->size, virt, 0);
 		if (ret < 0) {
+			gnutls_assert();
+			return ret;
+		}
+		return 0;
+	case GNUTLS_SAN_OTHERNAME_SRV:
+		ret = _gnutls_x509_decode_string(ASN1_ETYPE_IA5_STRING,
+						 othername->data,
+						 othername->size, virt, 0);
+		if (ret < 0) {
 			gnutls_assert();
 			return ret;
 		}
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -1562,7 +1562,8 @@ inline static int is_type_printable(int
 {
 	if (type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME ||
 	    type == GNUTLS_SAN_URI || type == GNUTLS_SAN_OTHERNAME_XMPP ||
-	    type == GNUTLS_SAN_OTHERNAME || type == GNUTLS_SAN_REGISTERED_ID)
+	    type == GNUTLS_SAN_OTHERNAME_SRV || type == GNUTLS_SAN_OTHERNAME ||
+	    type == GNUTLS_SAN_REGISTERED_ID)
 		return 1;
 	else
 		return 0;
