PR #24586 opened by tosiek
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24586
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24586.patch

### Description
In GnuTLS versions prior to 3.8.13, GnuTLS's client certificate selection 
heuristics can fail to automatically send the client certificate during a TLS 
handshake, even when the user explicitly provides both `cert_file` and 
`key_file` via FFmpeg options.

This change explicitly forces sending the configured client certificate during 
handshakes under GnuTLS < 3.8.13 when `cert_file` and `key_file` are set, 
bypassing the flawed client certificate lookup heuristics.

Fixes #22707

### Changes Made
- Updated `libavformat/tls_gnutls.c` to check for provided client certificate 
files.
- Enforced client certificate sending for GnuTLS versions prior to 3.8.13.

### Testing
- Tested against server setups requiring mTLS using GnuTLS builds (< 3.8.13).
- Verified client certificate is reliably transmitted during TLS handshakes.


>From 237b5a76af690632ccdf779d97c1aaef435fe5ad Mon Sep 17 00:00:00 2001
From: Your Name <[email protected]>
Date: Sun, 20 Sep 2026 16:33:28 +0200
Subject: [PATCH 1/3] avformat/tls_gnutls: force sending client cert if one is
 provided In GnuTLS versions prior to 3.8.13, client certificate selection
 heuristics can fail to send the client certificate even when the user
 explicitly supplied cert_file and key_file. Force sending the client
 certificate when one is provided. Fixes #22707

Signed-off-by: Your Name <[email protected]>
---
 libavformat/tls_gnutls.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/libavformat/tls_gnutls.c b/libavformat/tls_gnutls.c
index df251ad79c..0e8fc4df94 100644
--- a/libavformat/tls_gnutls.c
+++ b/libavformat/tls_gnutls.c
@@ -151,6 +151,7 @@ static int tls_open(URLContext *h, const char *uri, int 
flags, AVDictionary **op
 {
     TLSContext *p = h->priv_data;
     TLSShared *c = &p->tls_shared;
+    uint16_t gnutls_flags = 0;
     int ret;
 
     ff_gnutls_init();
@@ -158,9 +159,6 @@ static int tls_open(URLContext *h, const char *uri, int 
flags, AVDictionary **op
     if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0)
         goto fail;
 
-    gnutls_init(&p->session, c->listen ? GNUTLS_SERVER : GNUTLS_CLIENT);
-    if (!c->listen && !c->numerichost)
-        gnutls_server_name_set(p->session, GNUTLS_NAME_DNS, c->host, 
strlen(c->host));
     gnutls_certificate_allocate_credentials(&p->cred);
     if (c->ca_file) {
         ret = gnutls_certificate_set_x509_trust_file(p->cred, c->ca_file, 
GNUTLS_X509_FMT_PEM);
@@ -186,6 +184,20 @@ static int tls_open(URLContext *h, const char *uri, int 
flags, AVDictionary **op
         }
     } else if (c->cert_file || c->key_file)
         av_log(h, AV_LOG_ERROR, "cert and key required\n");
+
+    if (c->listen)
+        gnutls_flags |= GNUTLS_SERVER;
+    else {
+        gnutls_flags |= GNUTLS_CLIENT;
+#if defined(GNUTLS_VERSION_NUMBER) && defined(GNUTLS_FORCE_CLIENT_CERT) && 
GNUTLS_VERSION_NUMBER >= 0x030500 && GNUTLS_VERSION_NUMBER < 0x03080d
+        if (c->cert_file && c->key_file)
+            gnutls_flags |= GNUTLS_FORCE_CLIENT_CERT;
+#endif
+    }
+
+    gnutls_init(&p->session, gnutls_flags);
+    if (!c->listen && !c->numerichost)
+        gnutls_server_name_set(p->session, GNUTLS_NAME_DNS, c->host, 
strlen(c->host));
     gnutls_credentials_set(p->session, GNUTLS_CRD_CERTIFICATE, p->cred);
     gnutls_transport_set_pull_function(p->session, gnutls_url_pull);
     gnutls_transport_set_push_function(p->session, gnutls_url_push);
-- 
2.52.0


>From f59d34252b2c2edc987268095ade6a882b23a295 Mon Sep 17 00:00:00 2001
From: Your Name <[email protected]>
Date: Sun, 20 Sep 2026 16:40:01 +0200
Subject: [PATCH 2/3] avformat/tls_gnutls: force sending client cert if one is
 provided In GnuTLS versions prior to 3.8.13, client certificate selection
 heuristics can fail to send the client certificate even when the user
 explicitly supplied cert_file and key_file. Force sending the client
 certificate when one is provided under GnuTLS < 3.8.13. Fixes #22707

Signed-off-by: Your Name <[email protected]>
---
 libavformat/tls_gnutls.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libavformat/tls_gnutls.c b/libavformat/tls_gnutls.c
index 0e8fc4df94..609b31a0b4 100644
--- a/libavformat/tls_gnutls.c
+++ b/libavformat/tls_gnutls.c
@@ -190,8 +190,11 @@ static int tls_open(URLContext *h, const char *uri, int 
flags, AVDictionary **op
     else {
         gnutls_flags |= GNUTLS_CLIENT;
 #if defined(GNUTLS_VERSION_NUMBER) && defined(GNUTLS_FORCE_CLIENT_CERT) && 
GNUTLS_VERSION_NUMBER >= 0x030500 && GNUTLS_VERSION_NUMBER < 0x03080d
-        if (c->cert_file && c->key_file)
+        if (c->cert_file && c->key_file) {
+            av_log(h, AV_LOG_WARNING,
+                   "Forcing client certificate transmission due to GnuTLS < 
3.8.13\n");
             gnutls_flags |= GNUTLS_FORCE_CLIENT_CERT;
+        }
 #endif
     }
 
-- 
2.52.0


>From 247d106f50c3df4eb7988ae7e12508f24cd0aa16 Mon Sep 17 00:00:00 2001
From: Your Name <[email protected]>
Date: Sun, 20 Sep 2026 17:05:11 +0200
Subject: [PATCH 3/3] avformat/tls_gnutls: force sending client cert if one is
 provided In GnuTLS versions prior to 3.8.13, client certificate selection
 heuristics can fail to send the client certificate even when the user
 explicitly supplied cert_file and key_file. Force sending the client
 certificate when one is provided under GnuTLS < 3.8.13. Fixes #22707

Signed-off-by: Your Name <[email protected]>
---
 libavformat/tls_gnutls.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/libavformat/tls_gnutls.c b/libavformat/tls_gnutls.c
index 609b31a0b4..1631b261a2 100644
--- a/libavformat/tls_gnutls.c
+++ b/libavformat/tls_gnutls.c
@@ -189,8 +189,12 @@ static int tls_open(URLContext *h, const char *uri, int 
flags, AVDictionary **op
         gnutls_flags |= GNUTLS_SERVER;
     else {
         gnutls_flags |= GNUTLS_CLIENT;
-#if defined(GNUTLS_VERSION_NUMBER) && defined(GNUTLS_FORCE_CLIENT_CERT) && 
GNUTLS_VERSION_NUMBER >= 0x030500 && GNUTLS_VERSION_NUMBER < 0x03080d
-        if (c->cert_file && c->key_file) {
+#if defined(GNUTLS_VERSION_NUMBER) && defined(GNUTLS_FORCE_CLIENT_CERT) && 
GNUTLS_VERSION_NUMBER >= 0x030500
+        /* GnuTLS < 3.8.13 has a bug where the client certificate is silently
+         * suppressed if the server's CertificateRequest CA list or signature
+         * algorithm list doesn't match, even when the user explicitly provided
+         * cert_file and key_file. Force sending it when the library is 
affected. */
+        if (c->cert_file && c->key_file && !gnutls_check_version("3.8.13")) {
             av_log(h, AV_LOG_WARNING,
                    "Forcing client certificate transmission due to GnuTLS < 
3.8.13\n");
             gnutls_flags |= GNUTLS_FORCE_CLIENT_CERT;
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to