Description: <short summary of the patch>
 TODO: Put a short summary on the line above and replace this paragraph
 with a longer explanation of this change. Complete the meta-information
 with other relevant fields (see below for details). To make it easier, the
 information below has been extracted from the changelog. Adjust it or drop
 it.
 .
 openconnect (9.12-3~eebpo120+1) bookworm-ee; urgency=medium
 .
   * Build for bookworm and fix 94e0b16c
Author: Emmanuel Lacour <elacour@easter-eggs.com>

---
The information above should follow the Patch Tagging Guidelines, please
checkout https://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: (upstream|backport|vendor|other), (<patch-url>|commit:<commit-id>)
Bug: <upstream-bugtracker-url>
Bug-Debian: https://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: (no|not-needed|<patch-forwarded-url>)
Applied-Upstream: <version>, (<commit-url>|commit:<commid-id>)
Reviewed-By: <name and email of someone who approved/reviewed the patch>
Last-Update: 2025-07-08

--- openconnect-9.12.orig/gnutls.c
+++ openconnect-9.12/gnutls.c
@@ -3176,7 +3176,25 @@ void append_strap_verify(struct openconn
 
 	/* Concatenate our Finished message with our pubkey to be signed */
 	struct oc_text_buf *nonce = buf_alloc();
-	buf_append_bytes(nonce, vpninfo->finished, vpninfo->finished_len);
+	if (gnutls_protocol_get_version(vpninfo->https_sess) <= GNUTLS_TLS1_2) {
+		/* For TLSv1.2 and earlier, use RFC5929 'tls-unique' channel binding */
+		buf_append_bytes(nonce, vpninfo->finished, vpninfo->finished_len);
+	} else {
+		/* For TLSv1.3 use RFC9266 'tls-exporter' channel binding */
+		char channel_binding_buf[TLS_EXPORTER_KEY_SIZE];
+		err = gnutls_prf(vpninfo->https_sess, TLS_EXPORTER_LABEL_SIZE, TLS_EXPORTER_LABEL,
+				 0, 0, 0, TLS_EXPORTER_KEY_SIZE, channel_binding_buf);
+		if (err) {
+			vpn_progress(vpninfo, PRG_ERR,
+				     _("Failed to generate channel bindings for STRAP key: %s\n"),
+				     gnutls_strerror(err));
+			if (!buf_error(buf))
+				buf->error = -EIO;
+			buf_free(nonce);
+			return;
+		}
+		buf_append_bytes(nonce, channel_binding_buf, TLS_EXPORTER_KEY_SIZE);
+	}
 
 	if (rekey) {
 		/* We have a copy and we don't want it freed just yet */
--- openconnect-9.12.orig/openconnect-internal.h
+++ openconnect-9.12/openconnect-internal.h
@@ -1058,6 +1058,11 @@ static inline void __monitor_fd_new(stru
 #define PSK_LABEL_SIZE (sizeof(PSK_LABEL) - 1)
 #define PSK_KEY_SIZE 32
 
+/* Key material for RFC9266 tls-exporter channel binding */
+#define TLS_EXPORTER_LABEL "EXPORTER-Channel-Binding"
+#define TLS_EXPORTER_LABEL_SIZE (sizeof(TLS_EXPORTER_LABEL) - 1)
+#define TLS_EXPORTER_KEY_SIZE 32
+
 /* Packet types */
 
 #define AC_PKT_DATA		0	/* Uncompressed data */
--- openconnect-9.12.orig/openssl.c
+++ openconnect-9.12/openssl.c
@@ -2510,14 +2510,30 @@ void append_strap_verify(struct openconn
 			 struct oc_text_buf *buf, int rekey)
 {
 	unsigned char finished[64];
-	size_t flen = SSL_get_finished(vpninfo->https_ssl, finished, sizeof(finished));
+	size_t flen;
 
-	if (flen > sizeof(finished)) {
-		vpn_progress(vpninfo, PRG_ERR,
-			     _("SSL Finished message too large (%zd bytes)\n"), flen);
-		if (!buf_error(buf))
-			buf->error = -EIO;
-		return;
+	if (SSL_SESSION_get_protocol_version(SSL_get_session(vpninfo->https_ssl)) <= TLS1_2_VERSION) {
+		/* For TLSv1.2 and earlier, use RFC5929 'tls-unique' channel binding */
+		flen = SSL_get_finished(vpninfo->https_ssl, finished, sizeof(finished));
+		if (flen > sizeof(finished)) {
+			vpn_progress(vpninfo, PRG_ERR,
+				     _("SSL Finished message too large (%zu bytes)\n"), flen);
+			if (!buf_error(buf))
+				buf->error = -EIO;
+			return;
+		}
+	} else {
+		/* For TLSv1.3 use RFC9266 'tls-exporter' channel binding */
+		if (!SSL_export_keying_material(vpninfo->https_ssl,
+						finished, TLS_EXPORTER_KEY_SIZE,
+						TLS_EXPORTER_LABEL, TLS_EXPORTER_LABEL_SIZE,
+						NULL, 0, 0)) {
+			vpn_progress(vpninfo, PRG_ERR,
+				     _("Failed to generate channel bindings for STRAP key\n"));
+			openconnect_report_ssl_errors(vpninfo);
+			return;
+		}
+		flen = TLS_EXPORTER_KEY_SIZE;
 	}
 
 	/* If we're rekeying, we need to sign the Verify header with the *old* key. */
