From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.ffmpeg.org (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id B47174CD28 for ; Sat, 9 Aug 2025 09:18:17 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id ABBD968CE02; Sat, 9 Aug 2025 12:18:11 +0300 (EEST) Received: from 0f9ae49ae7c8 (code.ffmpeg.org [188.245.149.3]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTPS id 967F968CD75 for ; Sat, 9 Aug 2025 12:18:09 +0300 (EEST) MIME-Version: 1.0 From: Jack Lau To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] =?utf-8?q?=5BPATCH=5D_avformat/tls=5Fopenssl=3A_c?= =?utf-8?q?leanup_code_and_add_doc_for_dtls_=28PR_=2320193=29?= X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Message-Id: <20250809091811.ABBD968CE02@ffbox0-bg.ffmpeg.org> Date: Sat, 9 Aug 2025 12:18:11 +0300 (EEST) Archived-At: List-Archive: List-Post: PR #20193 opened by Jack Lau (JackLau) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20193 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20193.patch These patches were split from https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20030 to make the patchset smaller and easier to review. >From 0922698158d4b8a8bf778b12b872c58ac28a2c27 Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Tue, 22 Jul 2025 12:53:28 +0800 Subject: [PATCH 1/5] avformat/tls_openssl: cleanup the pointer name of TLSContext and TLSShared Signed-off-by: Jack Lau --- libavformat/tls_openssl.c | 231 +++++++++++++++++++------------------- 1 file changed, 116 insertions(+), 115 deletions(-) diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index 9f7b46c3ca..d6d8afd96b 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -500,16 +500,16 @@ typedef struct TLSContext { * to a human-readable string, and stores it in the TLSContext's error_message field. * The error queue is then cleared using ERR_clear_error(). */ -static const char* openssl_get_error(TLSContext *ctx) +static const char* openssl_get_error(TLSContext *c) { int r2 = ERR_get_error(); if (r2) { - ERR_error_string_n(r2, ctx->error_message, sizeof(ctx->error_message)); + ERR_error_string_n(r2, c->error_message, sizeof(c->error_message)); } else - ctx->error_message[0] = '\0'; + c->error_message[0] = '\0'; ERR_clear_error(); - return ctx->error_message; + return c->error_message; } int ff_tls_set_external_socket(URLContext *h, URLContext *sock) @@ -661,24 +661,24 @@ static int url_bio_bputs(BIO *b, const char *str) static av_cold void init_bio_method(URLContext *h) { - TLSContext *p = h->priv_data; + TLSContext *c = h->priv_data; BIO *bio; - p->url_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "urlprotocol bio"); - BIO_meth_set_write(p->url_bio_method, url_bio_bwrite); - BIO_meth_set_read(p->url_bio_method, url_bio_bread); - BIO_meth_set_puts(p->url_bio_method, url_bio_bputs); - BIO_meth_set_ctrl(p->url_bio_method, url_bio_ctrl); - BIO_meth_set_create(p->url_bio_method, url_bio_create); - BIO_meth_set_destroy(p->url_bio_method, url_bio_destroy); - bio = BIO_new(p->url_bio_method); - BIO_set_data(bio, p); + c->url_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "urlprotocol bio"); + BIO_meth_set_write(c->url_bio_method, url_bio_bwrite); + BIO_meth_set_read(c->url_bio_method, url_bio_bread); + BIO_meth_set_puts(c->url_bio_method, url_bio_bputs); + BIO_meth_set_ctrl(c->url_bio_method, url_bio_ctrl); + BIO_meth_set_create(c->url_bio_method, url_bio_create); + BIO_meth_set_destroy(c->url_bio_method, url_bio_destroy); + bio = BIO_new(c->url_bio_method); + BIO_set_data(bio, c); - SSL_set_bio(p->ssl, bio, bio); + SSL_set_bio(c->ssl, bio, bio); } static void openssl_info_callback(const SSL *ssl, int where, int ret) { const char *method = "undefined"; - TLSContext *ctx = (TLSContext*)SSL_get_ex_data(ssl, 0); + TLSContext *c = (TLSContext*)SSL_get_ex_data(ssl, 0); if (where & SSL_ST_CONNECT) { method = "SSL_connect"; @@ -686,11 +686,11 @@ static void openssl_info_callback(const SSL *ssl, int where, int ret) { method = "SSL_accept"; if (where & SSL_CB_LOOP) { - av_log(ctx, AV_LOG_DEBUG, "Info method=%s state=%s(%s), where=%d, ret=%d\n", + av_log(c, AV_LOG_DEBUG, "Info method=%s state=%s(%s), where=%d, ret=%d\n", method, SSL_state_string(ssl), SSL_state_string_long(ssl), where, ret); } else if (where & SSL_CB_ALERT) { method = (where & SSL_CB_READ) ? "read":"write"; - av_log(ctx, AV_LOG_DEBUG, "Alert method=%s state=%s(%s), where=%d, ret=%d\n", + av_log(c, AV_LOG_DEBUG, "Alert method=%s state=%s(%s), where=%d, ret=%d\n", method, SSL_state_string(ssl), SSL_state_string_long(ssl), where, ret); } } @@ -698,29 +698,29 @@ static void openssl_info_callback(const SSL *ssl, int where, int ret) { static int dtls_handshake(URLContext *h) { int ret = 1, r0, r1; - TLSContext *p = h->priv_data; + TLSContext *c = h->priv_data; - p->tls_shared.udp->flags &= ~AVIO_FLAG_NONBLOCK; + c->tls_shared.udp->flags &= ~AVIO_FLAG_NONBLOCK; - r0 = SSL_do_handshake(p->ssl); + r0 = SSL_do_handshake(c->ssl); if (r0 <= 0) { - r1 = SSL_get_error(p->ssl, r0); + r1 = SSL_get_error(c->ssl, r0); if (r1 != SSL_ERROR_WANT_READ && r1 != SSL_ERROR_WANT_WRITE && r1 != SSL_ERROR_ZERO_RETURN) { - av_log(p, AV_LOG_ERROR, "Handshake failed, r0=%d, r1=%d\n", r0, r1); + av_log(c, AV_LOG_ERROR, "Handshake failed, r0=%d, r1=%d\n", r0, r1); ret = print_ssl_error(h, r0); goto end; } } else { - av_log(p, AV_LOG_TRACE, "Handshake success, r0=%d\n", r0); + av_log(c, AV_LOG_TRACE, "Handshake success, r0=%d\n", r0); } /* Check whether the handshake is completed. */ - if (SSL_is_init_finished(p->ssl) != TLS_ST_OK) + if (SSL_is_init_finished(c->ssl) != TLS_ST_OK) goto end; ret = 0; - p->tls_shared.state = DTLS_STATE_FINISHED; + c->tls_shared.state = DTLS_STATE_FINISHED; end: return ret; } @@ -728,57 +728,57 @@ end: static av_cold int openssl_init_ca_key_cert(URLContext *h) { int ret; - TLSContext *p = h->priv_data; - TLSShared *c = &p->tls_shared; + TLSContext *c = h->priv_data; + TLSShared *s = &c->tls_shared; EVP_PKEY *pkey = NULL; X509 *cert = NULL; /* setup ca, private key, certificate */ - if (c->ca_file) { - if (!SSL_CTX_load_verify_locations(p->ctx, c->ca_file, NULL)) - av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", openssl_get_error(p)); + if (s->ca_file) { + if (!SSL_CTX_load_verify_locations(c->ctx, s->ca_file, NULL)) + av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", openssl_get_error(c)); } else { - if (!SSL_CTX_set_default_verify_paths(p->ctx)) { + if (!SSL_CTX_set_default_verify_paths(c->ctx)) { // Only log the failure but do not error out, as this is not fatal av_log(h, AV_LOG_WARNING, "Failure setting default verify locations: %s\n", - openssl_get_error(p)); + openssl_get_error(c)); } } - if (c->cert_file) { - ret = SSL_CTX_use_certificate_chain_file(p->ctx, c->cert_file); + if (s->cert_file) { + ret = SSL_CTX_use_certificate_chain_file(c->ctx, s->cert_file); if (ret <= 0) { av_log(h, AV_LOG_ERROR, "Unable to load cert file %s: %s\n", - c->cert_file, openssl_get_error(p)); + s->cert_file, openssl_get_error(c)); ret = AVERROR(EIO); goto fail; } - } else if (c->cert_buf) { - cert = cert_from_pem_string(c->cert_buf); - if (SSL_CTX_use_certificate(p->ctx, cert) != 1) { - av_log(p, AV_LOG_ERROR, "SSL: Init SSL_CTX_use_certificate failed, %s\n", openssl_get_error(p)); + } else if (s->cert_buf) { + cert = cert_from_pem_string(s->cert_buf); + if (SSL_CTX_use_certificate(c->ctx, cert) != 1) { + av_log(c, AV_LOG_ERROR, "SSL: Init SSL_CTX_use_certificate failed, %s\n", openssl_get_error(c)); ret = AVERROR(EINVAL); goto fail; } } - if (c->key_file) { - ret = SSL_CTX_use_PrivateKey_file(p->ctx, c->key_file, SSL_FILETYPE_PEM); + if (s->key_file) { + ret = SSL_CTX_use_PrivateKey_file(c->ctx, s->key_file, SSL_FILETYPE_PEM); if (ret <= 0) { av_log(h, AV_LOG_ERROR, "Unable to load key file %s: %s\n", - c->key_file, openssl_get_error(p)); + s->key_file, openssl_get_error(c)); ret = AVERROR(EIO); goto fail; } - } else if (c->key_buf) { - pkey = pkey_from_pem_string(c->key_buf, 1); - if (SSL_CTX_use_PrivateKey(p->ctx, pkey) != 1) { - av_log(p, AV_LOG_ERROR, "Init SSL_CTX_use_PrivateKey failed, %s\n", openssl_get_error(p)); + } else if (s->key_buf) { + pkey = pkey_from_pem_string(s->key_buf, 1); + if (SSL_CTX_use_PrivateKey(c->ctx, pkey) != 1) { + av_log(c, AV_LOG_ERROR, "Init SSL_CTX_use_PrivateKey failed, %s\n", openssl_get_error(c)); ret = AVERROR(EINVAL); goto fail; } } - if (c->listen && !c->cert_file && !c->cert_buf && !c->key_file && !c->key_buf) { + if (s->listen && !s->cert_file && !s->cert_buf && !s->key_file && !s->key_buf) { av_log(h, AV_LOG_VERBOSE, "No server certificate provided, using self-signed\n"); ret = openssl_gen_private_key(&pkey); @@ -789,14 +789,14 @@ static av_cold int openssl_init_ca_key_cert(URLContext *h) if (ret < 0) goto fail; - if (SSL_CTX_use_certificate(p->ctx, cert) != 1) { - av_log(p, AV_LOG_ERROR, "SSL_CTX_use_certificate failed for self-signed cert, %s\n", openssl_get_error(p)); + if (SSL_CTX_use_certificate(c->ctx, cert) != 1) { + av_log(c, AV_LOG_ERROR, "SSL_CTX_use_certificate failed for self-signed cert, %s\n", openssl_get_error(c)); ret = AVERROR(EINVAL); goto fail; } - if (SSL_CTX_use_PrivateKey(p->ctx, pkey) != 1) { - av_log(p, AV_LOG_ERROR, "SSL_CTX_use_PrivateKey failed for self-signed cert, %s\n", openssl_get_error(p)); + if (SSL_CTX_use_PrivateKey(c->ctx, pkey) != 1) { + av_log(c, AV_LOG_ERROR, "SSL_CTX_use_PrivateKey failed for self-signed cert, %s\n", openssl_get_error(c)); ret = AVERROR(EINVAL); goto fail; } @@ -815,10 +815,10 @@ fail: */ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary **options) { - TLSContext *p = h->priv_data; - TLSShared *c = &p->tls_shared; + TLSContext *c = h->priv_data; + TLSShared *s = &c->tls_shared; int ret = 0; - c->is_dtls = 1; + s->is_dtls = 1; /** * The profile for OpenSSL's SRTP is SRTP_AES128_CM_SHA1_80, see ssl/d1_srtp.c. @@ -826,8 +826,8 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary ** */ const char* profiles = "SRTP_AES128_CM_SHA1_80"; - p->ctx = SSL_CTX_new(c->listen ? DTLS_server_method() : DTLS_client_method()); - if (!p->ctx) { + c->ctx = SSL_CTX_new(s->listen ? DTLS_server_method() : DTLS_client_method()); + if (!c->ctx) { ret = AVERROR(ENOMEM); goto fail; } @@ -836,53 +836,54 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary ** if (ret < 0) goto fail; /* Note, this doesn't check that the peer certificate actually matches the requested hostname. */ - if (c->verify) - SSL_CTX_set_verify(p->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + if (s->verify) + SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); /* Setup the SRTP context */ - if (SSL_CTX_set_tlsext_use_srtp(p->ctx, profiles)) { - av_log(p, AV_LOG_ERROR, "Init SSL_CTX_set_tlsext_use_srtp failed, profiles=%s, %s\n", - profiles, openssl_get_error(p)); + if (SSL_CTX_set_tlsext_use_srtp(c->ctx, profiles)) { + av_log(c, AV_LOG_ERROR, "Init SSL_CTX_set_tlsext_use_srtp failed, profiles=%s, %s\n", + profiles, openssl_get_error(c)); ret = AVERROR(EINVAL); return ret; } /* The ssl should not be created unless the ctx has been initialized. */ - p->ssl = SSL_new(p->ctx); - if (!p->ssl) { + c->ssl = SSL_new(c->ctx); + if (!c->ssl) { ret = AVERROR(ENOMEM); goto fail; } - if (!c->listen && !c->numerichost) - SSL_set_tlsext_host_name(p->ssl, c->host); + if (!s->listen && !s->numerichost) + SSL_set_tlsext_host_name(c->ssl, s->host); /* Setup the callback for logging. */ - SSL_set_ex_data(p->ssl, 0, p); - SSL_CTX_set_info_callback(p->ctx, openssl_info_callback); + SSL_set_ex_data(c->ssl, 0, c); + SSL_CTX_set_info_callback(c->ctx, openssl_info_callback); /** * We have set the MTU to fragment the DTLS packet. It is important to note that the * packet is split to ensure that each handshake packet is smaller than the MTU. */ - if (c->mtu <= 0) - c->mtu = 1096; - SSL_set_options(p->ssl, SSL_OP_NO_QUERY_MTU); - SSL_set_mtu(p->ssl, c->mtu); - DTLS_set_link_mtu(p->ssl, c->mtu); + if (s->mtu <= 0) + s->mtu = 1096; + SSL_set_options(c->ssl, SSL_OP_NO_QUERY_MTU); + SSL_set_mtu(c->ssl, s->mtu); + DTLS_set_link_mtu(c->ssl, s->mtu); init_bio_method(h); - if (p->tls_shared.external_sock != 1) { - if ((ret = ff_tls_open_underlying(&p->tls_shared, h, url, options)) < 0) { - av_log(p, AV_LOG_ERROR, "Failed to connect %s\n", url); + + if (c->tls_shared.external_sock != 1) { + if ((ret = ff_tls_open_underlying(&c->tls_shared, h, url, options)) < 0) { + av_log(c, AV_LOG_ERROR, "Failed to connect %s\n", url); return ret; } } /* This seems to be necessary despite explicitly setting client/server method above. */ - if (c->listen) - SSL_set_accept_state(p->ssl); + if (s->listen) + SSL_set_accept_state(c->ssl); else - SSL_set_connect_state(p->ssl); + SSL_set_connect_state(c->ssl); /** * During initialization, we only need to call SSL_do_handshake once because SSL_read consumes @@ -895,16 +896,16 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary ** * * The SSL_do_handshake can't be called if DTLS hasn't prepare for udp. */ - if (p->tls_shared.external_sock != 1) { + if (c->tls_shared.external_sock != 1) { ret = dtls_handshake(h); // Fatal SSL error, for example, no available suite when peer is DTLS 1.0 while we are DTLS 1.2. if (ret < 0) { - av_log(p, AV_LOG_ERROR, "Failed to drive SSL context, ret=%d\n", ret); + av_log(c, AV_LOG_ERROR, "Failed to drive SSL context, ret=%d\n", ret); return AVERROR(EIO); } } - av_log(p, AV_LOG_VERBOSE, "Setup ok, MTU=%d\n", p->tls_shared.mtu); + av_log(c, AV_LOG_VERBOSE, "Setup ok, MTU=%d\n", c->tls_shared.mtu); ret = 0; fail: @@ -913,24 +914,24 @@ fail: static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { - TLSContext *p = h->priv_data; - TLSShared *c = &p->tls_shared; + TLSContext *c = h->priv_data; + TLSShared *s = &c->tls_shared; int ret; - if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) + if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0) goto fail; // We want to support all versions of TLS >= 1.0, but not the deprecated // and insecure SSLv2 and SSLv3. Despite the name, TLS_*_method() // enables support for all versions of SSL and TLS, and we then disable // support for the old protocols immediately after creating the context. - p->ctx = SSL_CTX_new(c->listen ? TLS_server_method() : TLS_client_method()); - if (!p->ctx) { - av_log(h, AV_LOG_ERROR, "%s\n", openssl_get_error(p)); + c->ctx = SSL_CTX_new(s->listen ? TLS_server_method() : TLS_client_method()); + if (!c->ctx) { + av_log(h, AV_LOG_ERROR, "%s\n", openssl_get_error(c)); ret = AVERROR(EIO); goto fail; } - if (!SSL_CTX_set_min_proto_version(p->ctx, TLS1_VERSION)) { + if (!SSL_CTX_set_min_proto_version(c->ctx, TLS1_VERSION)) { av_log(h, AV_LOG_ERROR, "Failed to set minimum TLS version to TLSv1\n"); ret = AVERROR_EXTERNAL; goto fail; @@ -938,33 +939,33 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op ret = openssl_init_ca_key_cert(h); if (ret < 0) goto fail; - if (c->verify) - SSL_CTX_set_verify(p->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); - p->ssl = SSL_new(p->ctx); - if (!p->ssl) { - av_log(h, AV_LOG_ERROR, "%s\n", openssl_get_error(p)); + if (s->verify) + SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + c->ssl = SSL_new(c->ctx); + if (!c->ssl) { + av_log(h, AV_LOG_ERROR, "%s\n", openssl_get_error(c)); ret = AVERROR(EIO); goto fail; } - SSL_set_ex_data(p->ssl, 0, p); - SSL_CTX_set_info_callback(p->ctx, openssl_info_callback); + SSL_set_ex_data(c->ssl, 0, c); + SSL_CTX_set_info_callback(c->ctx, openssl_info_callback); init_bio_method(h); - if (!c->listen && !c->numerichost) { + if (!s->listen && !s->numerichost) { // By default OpenSSL does too lax wildcard matching - SSL_set_hostflags(p->ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); - if (!SSL_set1_host(p->ssl, c->host)) { + SSL_set_hostflags(c->ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + if (!SSL_set1_host(c->ssl, s->host)) { av_log(h, AV_LOG_ERROR, "Failed to set hostname for TLS/SSL verification: %s\n", - openssl_get_error(p)); + openssl_get_error(c)); ret = AVERROR_EXTERNAL; goto fail; } - if (!SSL_set_tlsext_host_name(p->ssl, c->host)) { - av_log(h, AV_LOG_ERROR, "Failed to set hostname for SNI: %s\n", openssl_get_error(p)); + if (!SSL_set_tlsext_host_name(c->ssl, s->host)) { + av_log(h, AV_LOG_ERROR, "Failed to set hostname for SNI: %s\n", openssl_get_error(c)); ret = AVERROR_EXTERNAL; goto fail; } } - ret = c->listen ? SSL_accept(p->ssl) : SSL_connect(p->ssl); + ret = s->listen ? SSL_accept(c->ssl) : SSL_connect(c->ssl); if (ret == 0) { av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session\n"); ret = AVERROR(EIO); @@ -983,10 +984,10 @@ fail: static int tls_read(URLContext *h, uint8_t *buf, int size) { TLSContext *c = h->priv_data; - URLContext *uc = c->tls_shared.is_dtls ? c->tls_shared.udp - : c->tls_shared.tcp; + TLSShared *s = &c->tls_shared; + URLContext *uc = s->is_dtls ? s->udp : s->tcp; int ret; - // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp + // Set or clear the AVIO_FLAG_NONBLOCK on the underlying socket uc->flags &= ~AVIO_FLAG_NONBLOCK; uc->flags |= h->flags & AVIO_FLAG_NONBLOCK; ret = SSL_read(c->ssl, buf, size); @@ -1000,15 +1001,15 @@ static int tls_read(URLContext *h, uint8_t *buf, int size) static int tls_write(URLContext *h, const uint8_t *buf, int size) { TLSContext *c = h->priv_data; - URLContext *uc = c->tls_shared.is_dtls ? c->tls_shared.udp - : c->tls_shared.tcp; + TLSShared *s = &c->tls_shared; + URLContext *uc = s->is_dtls ? s->udp : s->tcp; int ret; // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp uc->flags &= ~AVIO_FLAG_NONBLOCK; uc->flags |= h->flags & AVIO_FLAG_NONBLOCK; - if (c->tls_shared.is_dtls) + if (s->is_dtls) size = FFMIN(size, DTLS_get_data_mtu(c->ssl)); ret = SSL_write(c->ssl, buf, size); @@ -1021,16 +1022,16 @@ static int tls_write(URLContext *h, const uint8_t *buf, int size) static int tls_get_file_handle(URLContext *h) { - TLSContext *p = h->priv_data; - TLSShared *c = &p->tls_shared; - return ffurl_get_file_handle(c->is_dtls ? c->udp : c->tcp); + TLSContext *c = h->priv_data; + TLSShared *s = &c->tls_shared; + return ffurl_get_file_handle(s->is_dtls ? s->udp : s->tcp); } static int tls_get_short_seek(URLContext *h) { - TLSContext *p = h->priv_data; - TLSShared *c = &p->tls_shared; - return ffurl_get_short_seek(c->is_dtls ? c->udp : c->tcp); + TLSContext *c = h->priv_data; + TLSShared *s = &c->tls_shared; + return ffurl_get_short_seek(s->is_dtls ? s->udp : s->tcp); } static const AVOption options[] = { -- 2.49.1 >From 1f84ec51ffc2e12ca726bb5c9ee69af71c61d510 Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Mon, 4 Aug 2025 15:49:11 +0800 Subject: [PATCH 2/5] avformat/tls_openssl: simplify the external_sock check Signed-off-by: Jack Lau --- libavformat/tls_openssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index d6d8afd96b..3df6e3f0a1 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -872,7 +872,7 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary ** DTLS_set_link_mtu(c->ssl, s->mtu); init_bio_method(h); - if (c->tls_shared.external_sock != 1) { + if (!c->tls_shared.external_sock) { if ((ret = ff_tls_open_underlying(&c->tls_shared, h, url, options)) < 0) { av_log(c, AV_LOG_ERROR, "Failed to connect %s\n", url); return ret; @@ -896,7 +896,7 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary ** * * The SSL_do_handshake can't be called if DTLS hasn't prepare for udp. */ - if (c->tls_shared.external_sock != 1) { + if (!c->tls_shared.external_sock) { ret = dtls_handshake(h); // Fatal SSL error, for example, no available suite when peer is DTLS 1.0 while we are DTLS 1.2. if (ret < 0) { -- 2.49.1 >From d4047873dc06300a649071ff64a8695bde80cc3d Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Thu, 7 Aug 2025 10:51:01 +0800 Subject: [PATCH 3/5] avformat/tls_openssl: add check to avoid tls_shared is null Signed-off-by: Jack Lau --- libavformat/tls_openssl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index 3df6e3f0a1..554dff711a 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -818,6 +818,9 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary ** TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; int ret = 0; + + if (!s) + return AVERROR(EINVAL); s->is_dtls = 1; /** @@ -918,6 +921,9 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op TLSShared *s = &c->tls_shared; int ret; + if (!s) + return AVERROR(EINVAL); + if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0) goto fail; -- 2.49.1 >From 7c89bcce9d7c883f2797e0ffb638bd54fcf2bea0 Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Sat, 9 Aug 2025 16:52:46 +0800 Subject: [PATCH 4/5] avformat/tls: add new option use_srtp to control whether enable it Signed-off-by: Jack Lau --- libavformat/tls.h | 2 ++ libavformat/tls_openssl.c | 24 ++++++++++++------------ libavformat/whip.c | 1 + 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libavformat/tls.h b/libavformat/tls.h index 0c02a4ab27..5f09357d8a 100644 --- a/libavformat/tls.h +++ b/libavformat/tls.h @@ -62,6 +62,7 @@ typedef struct TLSShared { URLContext *tcp; int is_dtls; + int use_srtp; enum DTLSState state; @@ -90,6 +91,7 @@ typedef struct TLSShared { {"listen", "Listen for incoming connections", offsetof(pstruct, options_field . listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = TLS_OPTFL }, \ {"http_proxy", "Set proxy to tunnel through", offsetof(pstruct, options_field . http_proxy), AV_OPT_TYPE_STRING, .flags = TLS_OPTFL }, \ {"external_sock", "Use external socket", offsetof(pstruct, options_field . external_sock), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = TLS_OPTFL }, \ + {"use_srtp", "Enable use_srtp DTLS extension", offsetof(pstruct, options_field . use_srtp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = TLS_OPTFL }, \ {"mtu", "Maximum Transmission Unit", offsetof(pstruct, options_field . mtu), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = TLS_OPTFL}, \ {"cert_pem", "Certificate PEM string", offsetof(pstruct, options_field . cert_buf), AV_OPT_TYPE_STRING, .flags = TLS_OPTFL }, \ {"key_pem", "Private key PEM string", offsetof(pstruct, options_field . key_buf), AV_OPT_TYPE_STRING, .flags = TLS_OPTFL }, \ diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index 554dff711a..67d8b33d5c 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -823,12 +823,6 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary ** return AVERROR(EINVAL); s->is_dtls = 1; - /** - * The profile for OpenSSL's SRTP is SRTP_AES128_CM_SHA1_80, see ssl/d1_srtp.c. - * The profile for FFmpeg's SRTP is SRTP_AES128_CM_HMAC_SHA1_80, see libavformat/srtp.c. - */ - const char* profiles = "SRTP_AES128_CM_SHA1_80"; - c->ctx = SSL_CTX_new(s->listen ? DTLS_server_method() : DTLS_client_method()); if (!c->ctx) { ret = AVERROR(ENOMEM); @@ -842,12 +836,18 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary ** if (s->verify) SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); - /* Setup the SRTP context */ - if (SSL_CTX_set_tlsext_use_srtp(c->ctx, profiles)) { - av_log(c, AV_LOG_ERROR, "Init SSL_CTX_set_tlsext_use_srtp failed, profiles=%s, %s\n", - profiles, openssl_get_error(c)); - ret = AVERROR(EINVAL); - return ret; + if (s->use_srtp) { + /** + * The profile for OpenSSL's SRTP is SRTP_AES128_CM_SHA1_80, see ssl/d1_srtp.c. + * The profile for FFmpeg's SRTP is SRTP_AES128_CM_HMAC_SHA1_80, see libavformat/srtp.c. + */ + const char* profiles = "SRTP_AES128_CM_SHA1_80"; + if (SSL_CTX_set_tlsext_use_srtp(c->ctx, profiles)) { + av_log(c, AV_LOG_ERROR, "Init SSL_CTX_set_tlsext_use_srtp failed, profiles=%s, %s\n", + profiles, openssl_get_error(c)); + ret = AVERROR(EINVAL); + goto fail; + } } /* The ssl should not be created unless the ctx has been initialized. */ diff --git a/libavformat/whip.c b/libavformat/whip.c index 256ea14d2c..65fd3b39b2 100644 --- a/libavformat/whip.c +++ b/libavformat/whip.c @@ -1303,6 +1303,7 @@ next_packet: } else av_dict_set(&opts, "key_pem", whip->key_buf, 0); av_dict_set_int(&opts, "external_sock", 1, 0); + av_dict_set_int(&opts, "use_srtp", 1, 0); av_dict_set_int(&opts, "listen", 1, 0); /* If got the first binding response, start DTLS handshake. */ ret = ffurl_open_whitelist(&whip->dtls_uc, buf, AVIO_FLAG_READ_WRITE, &s->interrupt_callback, -- 2.49.1 >From a1f9d7631bcf6c5f56968ee591db8ff11062f9d2 Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Sat, 9 Aug 2025 16:55:45 +0800 Subject: [PATCH 5/5] doc/protocols: add doc for dtls Signed-off-by: Jack Lau --- doc/protocols.texi | 78 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/doc/protocols.texi b/doc/protocols.texi index 089f917dcc..4f164983c7 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -2028,6 +2028,84 @@ To play back a stream from the TLS/SSL server using @command{ffplay}: ffplay tls://@var{hostname}:@var{port} @end example +@section dtls + +Datagram Transport Layer Security (DTLS) + +The required syntax for a DTLS URL is: +@example +dtls://@var{hostname}:@var{port} +@end example + +DTLS shares most options with TLS, but operates over UDP instead of TCP. +The following parameters can be set via command line options +(or in code via @code{AVOption}s): + +@table @option + +@item ca_file, cafile=@var{filename} +A file containing certificate authority (CA) root certificates to treat +as trusted. If the linked TLS library contains a default this might not +need to be specified for verification to work, but not all libraries and +setups have defaults built in. +The file must be in OpenSSL PEM format. + +@item tls_verify=@var{1|0} +If enabled, try to verify the peer that we are communicating with. +Note, if using OpenSSL, this currently only makes sure that the +peer certificate is signed by one of the root certificates in the CA +database, but it does not validate that the certificate actually +matches the host name we are trying to connect to. + +This is disabled by default since it requires a CA database to be +provided by the caller in many cases. + +@item cert_file, cert=@var{filename} +A file containing a certificate to use in the handshake with the peer. +(When operating as server, in listen mode, this is more often required +by the peer, while client certificates only are mandated in certain +setups.) + +@item key_file, key=@var{filename} +A file containing the private key for the certificate. + +@item cert_pem=@var{string} +Certificate PEM string + +@item key_pem=@var{string} +Private key PEM string + +@item listen=@var{1|0} +If enabled, listen for connections on the provided port, and assume +the server role in the handshake instead of the client role. + +@item mtu=@var{size} +Set the Maximum Transmission Unit (MTU) for DTLS packets. + +@item use_srtp=@var{1|0} +Enable the use_srtp DTLS extension. +This is used in WebRTC applications to establish SRTP encryption keys +through the DTLS handshake. Default is disabled. + +@item external_sock=@var{1|0} +Use an external socket instead of creating a new one. Default is disabled. + +@end table + +Example command lines: + +To create a DTLS server: + +@example +ffmpeg -listen 1 -i dtls://@var{hostname}:@var{port} @var{output} +@end example + +To create a DTLS client and send data to server: + +@example +ffmpeg -i @var{input} -f @var{format} dtls://@var{hostname}:@var{port} +@end example + @section udp User Datagram Protocol. -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".