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

# Summary of changes

The mbedtls backend is the only TLS backend in libavformat without a trust 
store behind it. gnutls uses `gnutls_certificate_set_x509_system_trust()`, 
openssl uses `SSL_CTX_set_default_verify_paths()` and libtls uses 
`tls_default_ca_cert_file()`, but mbedtls carries no notion of a system store 
at all, so unless the caller passes `ca_file` every peer certificate fails with 
`MBEDTLS_X509_BADCERT_NOT_TRUSTED` and `https` does not work on such a build. A 
caller that opens a URL rather than a socket often has nowhere to pass the 
option: an HLS or DASH playlist opens further connections of its own, and those 
inherit no protocol options.

This loads `SSL_CERT_FILE` when it is set, which is what OpenSSL honours and 
what several applications already export, and otherwise the first of the usual 
system bundle locations that parses. It is only done when the peer certificate 
is actually verified, and a system carrying none of those files logs a warning 
and behaves exactly as before, so nothing that works today changes.

Built and tested on OpenWrt (aarch64, mbedtls 3.6, bundle at 
`/etc/ssl/certs/ca-certificates.crt`), where Kodi could not open a single 
`https` HLS stream before the change and plays them afterwards.


>From cd9100d64d021f2b659d9e783063e8da5e11e6c3 Mon Sep 17 00:00:00 2001
From: Daniel Golle <[email protected]>
Date: Thu, 17 Sep 2026 21:00:34 +0100
Subject: [PATCH] avformat/tls_mbedtls: use the system CA bundle by default

Unlike the other TLS backends, the mbedtls one has no trust store of its
own: unless the caller passes ca_file, every certificate fails to verify
with MBEDTLS_X509_BADCERT_NOT_TRUSTED. A caller that opens a URL rather
than a socket frequently has nowhere to pass it, since an HLS playlist
opens further connections of its own and those get no options, so https
does not work at all on an mbedtls build.

Look at SSL_CERT_FILE first, as OpenSSL does, then at the usual
locations of the system bundle. Nothing is loaded when the peer
certificate is not verified anyway, and a system carrying none of these
files behaves as before.

Signed-off-by: Daniel Golle <[email protected]>
---
 libavformat/tls_mbedtls.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/libavformat/tls_mbedtls.c b/libavformat/tls_mbedtls.c
index 444148be8a..fd62c103ee 100644
--- a/libavformat/tls_mbedtls.c
+++ b/libavformat/tls_mbedtls.c
@@ -44,6 +44,16 @@
 #include "libavutil/avstring.h"
 #include "libavutil/random_seed.h"
 
+#include "libavutil/getenv_utf8.h"
+
+static const char *const system_ca_files[] = {
+    "/etc/ssl/certs/ca-certificates.crt",     /* Debian, Alpine, OpenWrt */
+    "/etc/pki/tls/certs/ca-bundle.crt",       /* Fedora, RHEL */
+    "/etc/ssl/ca-bundle.pem",                 /* openSUSE */
+    "/etc/ssl/cert.pem",                      /* OpenBSD, macOS */
+    "/usr/local/share/certs/ca-root-nss.crt", /* FreeBSD */
+};
+
 static int mbedtls_x509_fingerprint(char *cert_buf, size_t cert_sz, char 
**fingerprint)
 {
     unsigned char md[32];
@@ -506,6 +516,27 @@ static int tls_handshake(URLContext *h)
     return ret;
 }
 
+static int load_system_ca(mbedtls_x509_crt *ca_cert)
+{
+    int ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
+    char *env = getenv_utf8("SSL_CERT_FILE");
+    int i;
+
+    if (env) {
+        ret = mbedtls_x509_crt_parse_file(ca_cert, env);
+        freeenv_utf8(env);
+        return ret;
+    }
+
+    for (i = 0; i < FF_ARRAY_ELEMS(system_ca_files); i++) {
+        ret = mbedtls_x509_crt_parse_file(ca_cert, system_ca_files[i]);
+        if (ret >= 0)
+            break;
+    }
+
+    return ret;
+}
+
 static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary 
**options)
 {
     TLSContext *tls_ctx = h->priv_data;
@@ -555,6 +586,9 @@ static int tls_open(URLContext *h, const char *uri, int 
flags, AVDictionary **op
             av_log(h, AV_LOG_ERROR, "mbedtls_x509_crt_parse_file for CA cert 
returned %d\n", ret);
             goto fail;
         }
+    } else if (shr->verify && load_system_ca(&tls_ctx->ca_cert) < 0) {
+        av_log(h, AV_LOG_WARNING, "No system CA certificates found, "
+                                  "peer verification will fail\n");
     }
 
     // load own certificate
-- 
2.52.0

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

Reply via email to