From patchwork Sun May 1 23:04:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Fletcher X-Patchwork-Id: 35534 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:a885:b0:7f:4be2:bd17 with SMTP id ca5csp1533639pzb; Sun, 1 May 2022 16:05:57 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzLUU2N/9QWmeO2i71U05nEb6eBF4GbhuVLb+hAXFDBU4YOQO26mwnqnFpQiZ9Hv/SQmghu X-Received: by 2002:a17:907:2cc4:b0:6ef:8108:ad11 with SMTP id hg4-20020a1709072cc400b006ef8108ad11mr8811441ejc.20.1651446356978; Sun, 01 May 2022 16:05:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1651446356; cv=none; d=google.com; s=arc-20160816; b=esBCxbYNde+WW+gHM7xOLfOOootYfT29zrov9x3xHRmNvNWwfyg0DwPw3kuyx+PTVh Y66MiOiwbmMojbfJeOPOLKPfVEsiHtimbrXAGKXs38qCmN2nPi0rZE0jWy5KHeGC8Wd3 Hnmb1Ba7NYZckID7VdybhXrIvskhixelDvwjdxTprl6Y4S2GqBfBs/Fa8AYJYczx1U2K 5WRKt9aGDrv5ZwAF4cDQ7PmQGN1ZCTdqmIQQxrXhCkcZQgEQEFpfdhZ6q/5yL/SJ5fAc FACzfIWCblZSXryVYuEc3q6eYDZatkpYyAP640OadbsmnM3S/tXYAEkg9tUybn84Tsqc CK4Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:bounce-to:from:message-id:date:to:delivered-to; bh=O5Z4VBsxGYZwTxzd7SiXsXLcKs28EnyRAn/3aqGhRwM=; b=RkJH6SEU9DvioJCveWuiLsz5b6KHceVj4FzjqPZT3+VY5XIrVVuCSmPQoKHIqIZRar NrCxqzk+PNyBpzkHXMg82AGyvZX26xAr9LYnRHsqRW/c8ujbS5S0D8XExpzABI+c0QrY LmgZdBDiX7FMIdEcp91Mf2TROB2Ev43HtwgNRfxh6cs4e/J0v4eF7yAeqr6JYIbyRpT8 Gzuwk9YVPYJ26q4agvMyB6LIBrZRPxy2/nSnRjciJbBCN8Cc/AGxYeTu8cScCES9i0z7 1s2tdz+l+oAIdO6Pjjj1sd7uQvePFKotKp8kKzNpKzvoN6yXSC7NSs7dy5hh0WroUHa4 SsLg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id w6-20020aa7cb46000000b00425bc76ecddsi10223866edt.337.2022.05.01.16.05.56; Sun, 01 May 2022 16:05:56 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 041BA68B28F; Mon, 2 May 2022 02:05:52 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from avasout-ptp-002.plus.net (avasout-ptp-002.plus.net [84.93.230.235]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 44A1A68AB71 for ; Mon, 2 May 2022 02:05:45 +0300 (EEST) Received: from sparrow.collectfair.co.uk ([80.229.167.224]) by smtp with SMTP id lId5n2NcCO2rilId7nVSf9; Mon, 02 May 2022 00:05:41 +0100 X-Clacks-Overhead: "GNU Terry Pratchett" X-CM-Score: 0.00 X-CNFS-Analysis: v=2.4 cv=Zs/+lv3G c=1 sm=1 tr=0 ts=626f1245 a=kGmXhoCkr3jB6KbzR35ddQ==:117 a=kGmXhoCkr3jB6KbzR35ddQ==:17 a=oZkIemNP1mAA:10 a=dUtWRZAB1rDCoh9MlMwA:9 a=emhf11hzAAAA:8 a=JeY4nRuWAAAA:8 a=KavMEPUI6GMiPvdm-CwA:9 a=wPNLvfGTeEIA:10 a=0L1b--ArBeoA:10 a=fHJYd22vZ_cA:10 a=Ta6bD5CYB-9pRL1bp3UA:9 a=B2y7HmGcmWMA:10 a=HLUCug_QN4oeKp6PugZw:22 a=3mYD0m367-DnXB0HWSkl:22 Received: (qmail 14839 invoked from network); 1 May 2022 23:04:24 -0000 Received: from localhost (HELO webmail.megapico.co.uk) (127.0.0.1) by sparrow.collectfair.co.uk with SMTP; 1 May 2022 23:04:24 -0000 Received: from 192.168.0.1 (auth. user dif@localhost) by webmail.megapico.co.uk with HTTP; Sun, 01 May 2022 23:04:24 +0000 To: ffmpeg-devel@ffmpeg.org Date: Sun, 01 May 2022 23:04:24 +0000 X-Mailer: IlohaMail/0.8.14 Message-ID: <16i8qcLq.1651446264.7842020.dif@localhost> From: "David Fletcher" Bounce-To: "David Fletcher" MIME-Version: 1.0 X-CMAE-Envelope: MS4xfPAiz5VRUtndoxDL5UPBN7pvQ52htkcMm/omfQiySnKrTbbq49Mev7VV6Ne3oOKSbzWqXJEt+vhQS+TQWG8SSj20GqZ+l2oUVyIIVYzR0kes9rxWB4LQ D3WCkrkRsocsKTFgY6JX/squsxW1geAKtv1piyWSU//Qd89kB5/6J3BaJMKp+imHvQj595qVSsHPbQ0waEqEXgyKZ5Sdg3Sm6/Y= Subject: [FFmpeg-devel] PATCH - wolfSSL TLS support 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: /+AETGNyLpu2 Please find attached a patch adding support for wolfSSL as a TLS backend. This is against release ffmpeg-5.0.1, and is working well with wolfSSL 5.1.1 (January 2022 release). This is based on a patch previously submitted in 2018 which never made it into the mail codebase, but now updated for ffmpeg-5.0.1. The previous version by samsamsam is at https://lists.ffmpeg.org/pipermail/ffmpeg-devel/2018-August/233802.html. Does this look useful? I developed this after identifying wolfSSL as most suitable for adding TLS capability to very resource limited hardware (Reciva internet radios, based around an ARMv4 CPU and just 32MB RAM, for context more info about this application here: http://www.megapico.co.uk/sharpfin/mediaserver.html). Best regards, David. diff -Nur ./ffmpeg-5.0.1/configure ./ffmpeg-5.0.1-wolfssl/configure --- ./ffmpeg-5.0.1/configure 2022-04-04 15:40:22.000000000 +0100 +++ ./ffmpeg-5.0.1-wolfssl/configure 2022-05-01 22:58:55.672449527 +0100 @@ -212,7 +212,7 @@ --enable-gmp enable gmp, needed for rtmp(t)e support if openssl or librtmp is not used [no] --enable-gnutls enable gnutls, needed for https support - if openssl, libtls or mbedtls is not used [no] + if openssl, libtls, wolfssl or mbedtls is not used [no] --disable-iconv disable iconv [autodetect] --enable-jni enable JNI support [no] --enable-ladspa enable LADSPA audio filtering [no] @@ -276,7 +276,7 @@ --enable-libtesseract enable Tesseract, needed for ocr filter [no] --enable-libtheora enable Theora encoding via libtheora [no] --enable-libtls enable LibreSSL (via libtls), needed for https support - if openssl, gnutls or mbedtls is not used [no] + if openssl, gnutls, wolfssl or mbedtls is not used [no] --enable-libtwolame enable MP2 encoding via libtwolame [no] --enable-libuavs3d enable AVS3 decoding via libuavs3d [no] --enable-libv4l2 enable libv4l2/v4l-utils [no] @@ -287,6 +287,8 @@ native implementation exists [no] --enable-libvpx enable VP8 and VP9 de/encoding via libvpx [no] --enable-libwebp enable WebP encoding via libwebp [no] + --enable-wolfssl enable WolfSSL), needed for https support + if openssl, gnutls, libtls or mbedtls is not used [no] --enable-libx264 enable H.264 encoding via x264 [no] --enable-libx265 enable HEVC encoding via x265 [no] --enable-libxavs enable AVS encoding via xavs [no] @@ -315,7 +317,7 @@ --enable-opencl enable OpenCL processing [no] --enable-opengl enable OpenGL rendering [no] --enable-openssl enable openssl, needed for https support - if gnutls, libtls or mbedtls is not used [no] + if gnutls, libtls, wolfssl or mbedtls is not used [no] --enable-pocketsphinx enable PocketSphinx, needed for asr filter [no] --disable-sndio disable sndio support [autodetect] --disable-schannel disable SChannel SSP, needed for TLS support on @@ -1880,6 +1882,7 @@ openssl pocketsphinx vapoursynth + wolfssl " HWACCEL_AUTODETECT_LIBRARY_LIST=" @@ -3576,7 +3579,7 @@ securetransport_conflict="openssl gnutls libtls mbedtls" srtp_protocol_select="rtp_protocol srtp" tcp_protocol_select="network" -tls_protocol_deps_any="gnutls openssl schannel securetransport libtls mbedtls" +tls_protocol_deps_any="gnutls openssl schannel securetransport libtls mbedtls wolfssl" tls_protocol_select="tcp_protocol" udp_protocol_select="network" udplite_protocol_select="network" @@ -6512,6 +6515,7 @@ enabled frei0r && require_headers "frei0r.h" enabled gmp && require gmp gmp.h mpz_export -lgmp enabled gnutls && require_pkg_config gnutls gnutls gnutls/gnutls.h gnutls_global_init +enabled wolfssl && require_pkg_config wolfssl wolfssl wolfssl/ssl.h wolfSSL_library_init enabled jni && { [ $target_os = "android" ] && check_headers jni.h && enabled pthreads || die "ERROR: jni not found"; } enabled ladspa && require_headers "ladspa.h dlfcn.h" enabled libaom && require_pkg_config libaom "aom >= 1.0.0" aom/aom_codec.h aom_codec_version diff -Nur ./ffmpeg-5.0.1/libavformat/Makefile ./ffmpeg-5.0.1-wolfssl/libavformat/Makefile --- ./ffmpeg-5.0.1/libavformat/Makefile 2022-01-14 18:45:40.000000000 +0000 +++ ./ffmpeg-5.0.1-wolfssl/libavformat/Makefile 2022-04-05 21:53:03.000000000 +0100 @@ -660,6 +660,7 @@ TLS-OBJS-$(CONFIG_LIBTLS) += tls_libtls.o TLS-OBJS-$(CONFIG_MBEDTLS) += tls_mbedtls.o TLS-OBJS-$(CONFIG_OPENSSL) += tls_openssl.o +TLS-OBJS-$(CONFIG_WOLFSSL) += tls_wolfssl.o TLS-OBJS-$(CONFIG_SECURETRANSPORT) += tls_securetransport.o TLS-OBJS-$(CONFIG_SCHANNEL) += tls_schannel.o OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o $(TLS-OBJS-yes) diff -Nur ./ffmpeg-5.0.1/libavformat/network.c ./ffmpeg-5.0.1-wolfssl/libavformat/network.c --- ./ffmpeg-5.0.1/libavformat/network.c 2021-10-21 18:06:35.000000000 +0100 +++ ./ffmpeg-5.0.1-wolfssl/libavformat/network.c 2022-04-05 21:50:42.000000000 +0100 @@ -39,6 +39,9 @@ #if CONFIG_GNUTLS ff_gnutls_init(); #endif +#if CONFIG_WOLFSSL + ff_wolfssl_init(); +#endif #endif return 0; } @@ -52,6 +55,9 @@ #if CONFIG_GNUTLS ff_gnutls_deinit(); #endif +#if CONFIG_WOLFSSL + ff_wolfssl_deinit(); +#endif #endif } diff -Nur ./ffmpeg-5.0.1/libavformat/tls.h ./ffmpeg-5.0.1-wolfssl/libavformat/tls.h --- ./ffmpeg-5.0.1/libavformat/tls.h 2021-10-24 21:47:07.000000000 +0100 +++ ./ffmpeg-5.0.1-wolfssl/libavformat/tls.h 2022-04-05 21:46:32.000000000 +0100 @@ -55,6 +55,9 @@ int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AVDictionary **options); +void ff_wolfssl_init(void); +void ff_wolfssl_deinit(void); + void ff_gnutls_init(void); void ff_gnutls_deinit(void); diff -Nur ./ffmpeg-5.0.1/libavformat/tls_wolfssl.c ./ffmpeg-5.0.1-wolfssl/libavformat/tls_wolfssl.c --- ./ffmpeg-5.0.1/libavformat/tls_wolfssl.c 1970-01-01 01:00:00.000000000 +0100 +++ ./ffmpeg-5.0.1-wolfssl/libavformat/tls_wolfssl.c 2022-04-12 15:56:38.000000000 +0100 @@ -0,0 +1,248 @@ +/* + * TLS/SSL Protocol + * Copyright (c) 2011 Martin Storsjo + * Copyright (c) 2018 samsamsam@o2.pl + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "avformat.h" +#include "internal.h" +#include "network.h" +#include "os_support.h" +#include "url.h" +#include "tls.h" +#include "libavcodec/internal.h" +#include "libavutil/avstring.h" +#include "libavutil/opt.h" +#include "libavutil/parseutils.h" + + + +#include +#include + +typedef struct TLSContext { + const AVClass *class; + TLSShared tls_shared; + WOLFSSL_CTX *ctx; + WOLFSSL *ssl; +} TLSContext; + +static int wolfssl_init; + +void ff_wolfssl_init(void) +{ + ff_lock_avformat(); + if (!wolfssl_init) { + wolfSSL_Init(); + } + wolfssl_init++; + ff_unlock_avformat(); +} + +void ff_wolfssl_deinit(void) +{ + ff_lock_avformat(); + wolfssl_init--; + if (!wolfssl_init) { + wolfSSL_Cleanup(); + } + ff_unlock_avformat(); +} + +static int print_tls_error(URLContext *h, int ret, WOLFSSL *ssl) +{ + char error_buffer[WOLFSSL_MAX_ERROR_SZ]; + av_log(h, AV_LOG_ERROR, "%i -> %s\n", wolfSSL_get_error(ssl,0), wolfSSL_ERR_error_string(wolfSSL_get_error(ssl,0), error_buffer)); + return AVERROR(EIO); +} + +static int tls_close(URLContext *h) +{ + TLSContext *c = h->priv_data; + if (c->ssl) { + wolfSSL_shutdown(c->ssl); + wolfSSL_free(c->ssl); + } + if (c->ctx) + wolfSSL_CTX_free(c->ctx); + if (c->tls_shared.tcp) + ffurl_close(c->tls_shared.tcp); + //ff_wolfssl_deinit(); + return 0; +} + +static int wolfssl_recv_callback(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + URLContext *h = (URLContext*) ctx; + int ret = ffurl_read(h, buf, sz); + if (ret >= 0) + return ret; + if (ret == AVERROR_EXIT) + return WOLFSSL_CBIO_ERR_GENERAL; + errno = EIO; + return WOLFSSL_CBIO_ERR_GENERAL; +} + +static int wolfssl_send_callback(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + URLContext *h = (URLContext*) ctx; + int ret = ffurl_write(h, buf, sz); + if (ret >= 0) + return ret; + if (ret == AVERROR_EXIT) + return WOLFSSL_CBIO_ERR_GENERAL; + errno = EIO; + return WOLFSSL_CBIO_ERR_GENERAL; +} + +static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) +{ + char error_buffer[WOLFSSL_MAX_ERROR_SZ]; + TLSContext *p = h->priv_data; + TLSShared *c = &p->tls_shared; + int ret; + + //ff_wolfssl_init(); + + if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) + goto fail; + // Modified to compile with minimal wolfSSL library which only has client methods + //p->ctx = wolfSSL_CTX_new(c->listen ? wolfSSLv23_server_method() : wolfSSLv23_client_method()); // wolfTLSv1_1_client_method + p->ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); +#ifndef NO_FILESYSTEM + if (!p->ctx) { + av_log(h, AV_LOG_ERROR, "%s\n", wolfSSL_ERR_error_string(wolfSSL_get_error(p->ssl,0), error_buffer)); + ret = AVERROR(EIO); + goto fail; + } + if (c->ca_file) { + if (!wolfSSL_CTX_load_verify_locations(p->ctx, c->ca_file, NULL)) + av_log(h, AV_LOG_ERROR, "wolfSSL_CTX_load_verify_locations %s\n", wolfSSL_ERR_error_string(wolfSSL_get_error(p->ssl,0), error_buffer)); + } + if (c->cert_file && !wolfSSL_CTX_use_certificate_chain_file(p->ctx, c->cert_file)) { + av_log(h, AV_LOG_ERROR, "Unable to load cert file %s: %s\n", + c->cert_file, wolfSSL_ERR_error_string(wolfSSL_get_error(p->ssl,0), error_buffer)); + ret = AVERROR(EIO); + goto fail; + } + if (c->key_file && !wolfSSL_CTX_use_PrivateKey_file(p->ctx, c->key_file, WOLFSSL_FILETYPE_PEM)) { + av_log(h, AV_LOG_ERROR, "Unable to load key file %s: %s\n", + c->key_file, wolfSSL_ERR_error_string(wolfSSL_get_error(p->ssl,0), error_buffer)); + ret = AVERROR(EIO); + goto fail; + } +#endif + + wolfSSL_CTX_set_verify(p->ctx, + c->verify ? WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT : + WOLFSSL_VERIFY_NONE, + NULL); + +#ifdef HAVE_SNI + if (!c->listen && !c->numerichost && !wolfSSL_CTX_UseSNI(p->ctx, WOLFSSL_SNI_HOST_NAME, c->host, + (unsigned short)strlen(c->host))) { + av_log(h, AV_LOG_ERROR, "failed to configure server name indication (SNI) %s: %ld -> %s\n", + c->host, wolfSSL_get_error(p->ssl,0), wolfSSL_ERR_error_string(wolfSSL_get_error(p->ssl,0), error_buffer)); + } +#endif + + wolfSSL_CTX_SetIORecv(p->ctx, wolfssl_recv_callback); + wolfSSL_CTX_SetIOSend(p->ctx, wolfssl_send_callback); + + p->ssl = wolfSSL_new(p->ctx); + if (!p->ssl) { + av_log(h, AV_LOG_ERROR, "%s\n", wolfSSL_ERR_error_string(wolfSSL_get_error(p->ssl,0), error_buffer)); + ret = AVERROR(EIO); + goto fail; + } + + wolfSSL_SetIOReadCtx(p->ssl, c->tcp); + wolfSSL_SetIOWriteCtx(p->ssl, c->tcp); + + // Modified to compile with minimal wolfSSL library which only has client methods + //ret = c->listen ? wolfSSL_accept(p->ssl) : wolfSSL_connect(p->ssl); + ret = wolfSSL_connect(p->ssl); + if (ret == 0) { + av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session\n"); + ret = AVERROR(EIO); + goto fail; + } else if (ret < 0) { + ret = print_tls_error(h, ret, p->ssl); + goto fail; + } + + return 0; +fail: + tls_close(h); + return ret; +} + +static int tls_read(URLContext *h, uint8_t *buf, int size) +{ + TLSContext *c = h->priv_data; + int ret = wolfSSL_read(c->ssl, buf, size); + if (ret > 0) + return ret; + if (ret == 0) + return AVERROR_EOF; + return print_tls_error(h, ret, c->ssl); +} + +static int tls_write(URLContext *h, const uint8_t *buf, int size) +{ + TLSContext *c = h->priv_data; + int ret = wolfSSL_write(c->ssl, buf, size); + if (ret > 0) + return ret; + if (ret == 0) + return AVERROR_EOF; + return print_tls_error(h, ret, c->ssl); +} + +static int tls_get_file_handle(URLContext *h) +{ + TLSContext *c = h->priv_data; + return ffurl_get_file_handle(c->tls_shared.tcp); +} + +static const AVOption options[] = { + TLS_COMMON_OPTIONS(TLSContext, tls_shared), + { NULL } +}; + +static const AVClass tls_class = { + .class_name = "tls", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const URLProtocol ff_tls_protocol = { + .name = "tls", + .url_open2 = tls_open, + .url_read = tls_read, + .url_write = tls_write, + .url_close = tls_close, + .url_get_file_handle = tls_get_file_handle, + .priv_data_size = sizeof(TLSContext), + .flags = URL_PROTOCOL_FLAG_NETWORK, + .priv_data_class = &tls_class, +};