1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 2015 rcombs 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * This file is part of FFmpeg. 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public License 8cabdff1aSopenharmony_ci * as published by the Free Software Foundation; either 9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 10cabdff1aSopenharmony_ci * 11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14cabdff1aSopenharmony_ci * GNU Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public License 17cabdff1aSopenharmony_ci * along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 18cabdff1aSopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci#include <errno.h> 22cabdff1aSopenharmony_ci 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "avformat.h" 25cabdff1aSopenharmony_ci#include "avio_internal.h" 26cabdff1aSopenharmony_ci#include "internal.h" 27cabdff1aSopenharmony_ci#include "network.h" 28cabdff1aSopenharmony_ci#include "os_support.h" 29cabdff1aSopenharmony_ci#include "url.h" 30cabdff1aSopenharmony_ci#include "tls.h" 31cabdff1aSopenharmony_ci#include "libavcodec/internal.h" 32cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 33cabdff1aSopenharmony_ci#include "libavutil/opt.h" 34cabdff1aSopenharmony_ci#include "libavutil/parseutils.h" 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_ci#include <Security/Security.h> 37cabdff1aSopenharmony_ci#include <Security/SecureTransport.h> 38cabdff1aSopenharmony_ci#include <CoreFoundation/CoreFoundation.h> 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_ci// We use a private API call here; it's good enough for WebKit. 41cabdff1aSopenharmony_ciSecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey); 42cabdff1aSopenharmony_ci#define ioErr -36 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_citypedef struct TLSContext { 45cabdff1aSopenharmony_ci const AVClass *class; 46cabdff1aSopenharmony_ci TLSShared tls_shared; 47cabdff1aSopenharmony_ci SSLContextRef ssl_context; 48cabdff1aSopenharmony_ci CFArrayRef ca_array; 49cabdff1aSopenharmony_ci int lastErr; 50cabdff1aSopenharmony_ci} TLSContext; 51cabdff1aSopenharmony_ci 52cabdff1aSopenharmony_cistatic int print_tls_error(URLContext *h, int ret) 53cabdff1aSopenharmony_ci{ 54cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 55cabdff1aSopenharmony_ci switch (ret) { 56cabdff1aSopenharmony_ci case errSSLWouldBlock: 57cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 58cabdff1aSopenharmony_ci case errSSLXCertChainInvalid: 59cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Invalid certificate chain\n"); 60cabdff1aSopenharmony_ci return AVERROR(EIO); 61cabdff1aSopenharmony_ci case ioErr: 62cabdff1aSopenharmony_ci return c->lastErr; 63cabdff1aSopenharmony_ci default: 64cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "IO Error: %i\n", ret); 65cabdff1aSopenharmony_ci return AVERROR(EIO); 66cabdff1aSopenharmony_ci } 67cabdff1aSopenharmony_ci return AVERROR(EIO); 68cabdff1aSopenharmony_ci} 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_cistatic int import_pem(URLContext *h, char *path, CFArrayRef *array) 71cabdff1aSopenharmony_ci{ 72cabdff1aSopenharmony_ci#if !HAVE_SECITEMIMPORT 73cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 74cabdff1aSopenharmony_ci#else 75cabdff1aSopenharmony_ci AVIOContext *s = NULL; 76cabdff1aSopenharmony_ci CFDataRef data = NULL; 77cabdff1aSopenharmony_ci int64_t ret = 0; 78cabdff1aSopenharmony_ci char *buf = NULL; 79cabdff1aSopenharmony_ci SecExternalFormat format = kSecFormatPEMSequence; 80cabdff1aSopenharmony_ci SecExternalFormat type = kSecItemTypeAggregate; 81cabdff1aSopenharmony_ci CFStringRef pathStr = CFStringCreateWithCString(NULL, path, 0x08000100); 82cabdff1aSopenharmony_ci if (!pathStr) { 83cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 84cabdff1aSopenharmony_ci goto end; 85cabdff1aSopenharmony_ci } 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci if ((ret = ffio_open_whitelist(&s, path, AVIO_FLAG_READ, 88cabdff1aSopenharmony_ci &h->interrupt_callback, NULL, 89cabdff1aSopenharmony_ci h->protocol_whitelist, h->protocol_blacklist)) < 0) 90cabdff1aSopenharmony_ci goto end; 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci if ((ret = avio_size(s)) < 0) 93cabdff1aSopenharmony_ci goto end; 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci if (ret == 0) { 96cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 97cabdff1aSopenharmony_ci goto end; 98cabdff1aSopenharmony_ci } 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci if (!(buf = av_malloc(ret))) { 101cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 102cabdff1aSopenharmony_ci goto end; 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci if ((ret = avio_read(s, buf, ret)) < 0) 106cabdff1aSopenharmony_ci goto end; 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci data = CFDataCreate(kCFAllocatorDefault, buf, ret); 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_ci if (SecItemImport(data, pathStr, &format, &type, 111cabdff1aSopenharmony_ci 0, NULL, NULL, array) != noErr || !array) { 112cabdff1aSopenharmony_ci ret = AVERROR_UNKNOWN; 113cabdff1aSopenharmony_ci goto end; 114cabdff1aSopenharmony_ci } 115cabdff1aSopenharmony_ci 116cabdff1aSopenharmony_ci if (CFArrayGetCount(*array) == 0) { 117cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 118cabdff1aSopenharmony_ci goto end; 119cabdff1aSopenharmony_ci } 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ciend: 122cabdff1aSopenharmony_ci av_free(buf); 123cabdff1aSopenharmony_ci if (pathStr) 124cabdff1aSopenharmony_ci CFRelease(pathStr); 125cabdff1aSopenharmony_ci if (data) 126cabdff1aSopenharmony_ci CFRelease(data); 127cabdff1aSopenharmony_ci if (s) 128cabdff1aSopenharmony_ci avio_close(s); 129cabdff1aSopenharmony_ci return ret; 130cabdff1aSopenharmony_ci#endif 131cabdff1aSopenharmony_ci} 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_cistatic int load_ca(URLContext *h) 134cabdff1aSopenharmony_ci{ 135cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 136cabdff1aSopenharmony_ci int ret = 0; 137cabdff1aSopenharmony_ci CFArrayRef array = NULL; 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci if ((ret = import_pem(h, c->tls_shared.ca_file, &array)) < 0) 140cabdff1aSopenharmony_ci goto end; 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci if (!(c->ca_array = CFRetain(array))) { 143cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 144cabdff1aSopenharmony_ci goto end; 145cabdff1aSopenharmony_ci } 146cabdff1aSopenharmony_ci 147cabdff1aSopenharmony_ciend: 148cabdff1aSopenharmony_ci if (array) 149cabdff1aSopenharmony_ci CFRelease(array); 150cabdff1aSopenharmony_ci return ret; 151cabdff1aSopenharmony_ci} 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_cistatic int load_cert(URLContext *h) 154cabdff1aSopenharmony_ci{ 155cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 156cabdff1aSopenharmony_ci int ret = 0; 157cabdff1aSopenharmony_ci CFArrayRef certArray = NULL; 158cabdff1aSopenharmony_ci CFArrayRef keyArray = NULL; 159cabdff1aSopenharmony_ci SecIdentityRef id = NULL; 160cabdff1aSopenharmony_ci CFMutableArrayRef outArray = NULL; 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_ci if ((ret = import_pem(h, c->tls_shared.cert_file, &certArray)) < 0) 163cabdff1aSopenharmony_ci goto end; 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci if ((ret = import_pem(h, c->tls_shared.key_file, &keyArray)) < 0) 166cabdff1aSopenharmony_ci goto end; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci if (!(id = SecIdentityCreate(kCFAllocatorDefault, 169cabdff1aSopenharmony_ci (SecCertificateRef)CFArrayGetValueAtIndex(certArray, 0), 170cabdff1aSopenharmony_ci (SecKeyRef)CFArrayGetValueAtIndex(keyArray, 0)))) { 171cabdff1aSopenharmony_ci ret = AVERROR_UNKNOWN; 172cabdff1aSopenharmony_ci goto end; 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci if (!(outArray = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, certArray))) { 176cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 177cabdff1aSopenharmony_ci goto end; 178cabdff1aSopenharmony_ci } 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_ci CFArraySetValueAtIndex(outArray, 0, id); 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci SSLSetCertificate(c->ssl_context, outArray); 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ciend: 185cabdff1aSopenharmony_ci if (certArray) 186cabdff1aSopenharmony_ci CFRelease(certArray); 187cabdff1aSopenharmony_ci if (keyArray) 188cabdff1aSopenharmony_ci CFRelease(keyArray); 189cabdff1aSopenharmony_ci if (outArray) 190cabdff1aSopenharmony_ci CFRelease(outArray); 191cabdff1aSopenharmony_ci if (id) 192cabdff1aSopenharmony_ci CFRelease(id); 193cabdff1aSopenharmony_ci return ret; 194cabdff1aSopenharmony_ci} 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_cistatic OSStatus tls_read_cb(SSLConnectionRef connection, void *data, size_t *dataLength) 197cabdff1aSopenharmony_ci{ 198cabdff1aSopenharmony_ci URLContext *h = (URLContext*)connection; 199cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 200cabdff1aSopenharmony_ci size_t requested = *dataLength; 201cabdff1aSopenharmony_ci int read = ffurl_read(c->tls_shared.tcp, data, requested); 202cabdff1aSopenharmony_ci if (read <= 0) { 203cabdff1aSopenharmony_ci *dataLength = 0; 204cabdff1aSopenharmony_ci switch(AVUNERROR(read)) { 205cabdff1aSopenharmony_ci case ENOENT: 206cabdff1aSopenharmony_ci case 0: 207cabdff1aSopenharmony_ci return errSSLClosedGraceful; 208cabdff1aSopenharmony_ci case ECONNRESET: 209cabdff1aSopenharmony_ci return errSSLClosedAbort; 210cabdff1aSopenharmony_ci case EAGAIN: 211cabdff1aSopenharmony_ci return errSSLWouldBlock; 212cabdff1aSopenharmony_ci default: 213cabdff1aSopenharmony_ci c->lastErr = read; 214cabdff1aSopenharmony_ci return ioErr; 215cabdff1aSopenharmony_ci } 216cabdff1aSopenharmony_ci } else { 217cabdff1aSopenharmony_ci *dataLength = read; 218cabdff1aSopenharmony_ci if (read < requested) 219cabdff1aSopenharmony_ci return errSSLWouldBlock; 220cabdff1aSopenharmony_ci else 221cabdff1aSopenharmony_ci return noErr; 222cabdff1aSopenharmony_ci } 223cabdff1aSopenharmony_ci} 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_cistatic OSStatus tls_write_cb(SSLConnectionRef connection, const void *data, size_t *dataLength) 226cabdff1aSopenharmony_ci{ 227cabdff1aSopenharmony_ci URLContext *h = (URLContext*)connection; 228cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 229cabdff1aSopenharmony_ci int written = ffurl_write(c->tls_shared.tcp, data, *dataLength); 230cabdff1aSopenharmony_ci if (written <= 0) { 231cabdff1aSopenharmony_ci *dataLength = 0; 232cabdff1aSopenharmony_ci switch(AVUNERROR(written)) { 233cabdff1aSopenharmony_ci case EAGAIN: 234cabdff1aSopenharmony_ci return errSSLWouldBlock; 235cabdff1aSopenharmony_ci default: 236cabdff1aSopenharmony_ci c->lastErr = written; 237cabdff1aSopenharmony_ci return ioErr; 238cabdff1aSopenharmony_ci } 239cabdff1aSopenharmony_ci } else { 240cabdff1aSopenharmony_ci *dataLength = written; 241cabdff1aSopenharmony_ci return noErr; 242cabdff1aSopenharmony_ci } 243cabdff1aSopenharmony_ci} 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_cistatic int tls_close(URLContext *h) 246cabdff1aSopenharmony_ci{ 247cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 248cabdff1aSopenharmony_ci if (c->ssl_context) { 249cabdff1aSopenharmony_ci SSLClose(c->ssl_context); 250cabdff1aSopenharmony_ci CFRelease(c->ssl_context); 251cabdff1aSopenharmony_ci } 252cabdff1aSopenharmony_ci if (c->ca_array) 253cabdff1aSopenharmony_ci CFRelease(c->ca_array); 254cabdff1aSopenharmony_ci ffurl_closep(&c->tls_shared.tcp); 255cabdff1aSopenharmony_ci return 0; 256cabdff1aSopenharmony_ci} 257cabdff1aSopenharmony_ci 258cabdff1aSopenharmony_ci#define CHECK_ERROR(func, ...) do { \ 259cabdff1aSopenharmony_ci OSStatus status = func(__VA_ARGS__); \ 260cabdff1aSopenharmony_ci if (status != noErr) { \ 261cabdff1aSopenharmony_ci ret = AVERROR_UNKNOWN; \ 262cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, #func ": Error %i\n", (int)status); \ 263cabdff1aSopenharmony_ci goto fail; \ 264cabdff1aSopenharmony_ci } \ 265cabdff1aSopenharmony_ci } while (0) 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_cistatic int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) 268cabdff1aSopenharmony_ci{ 269cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 270cabdff1aSopenharmony_ci TLSShared *s = &c->tls_shared; 271cabdff1aSopenharmony_ci int ret; 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_ci if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0) 274cabdff1aSopenharmony_ci goto fail; 275cabdff1aSopenharmony_ci 276cabdff1aSopenharmony_ci c->ssl_context = SSLCreateContext(NULL, s->listen ? kSSLServerSide : kSSLClientSide, kSSLStreamType); 277cabdff1aSopenharmony_ci if (!c->ssl_context) { 278cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Unable to create SSL context\n"); 279cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 280cabdff1aSopenharmony_ci goto fail; 281cabdff1aSopenharmony_ci } 282cabdff1aSopenharmony_ci if (s->ca_file) { 283cabdff1aSopenharmony_ci if ((ret = load_ca(h)) < 0) 284cabdff1aSopenharmony_ci goto fail; 285cabdff1aSopenharmony_ci } 286cabdff1aSopenharmony_ci if (s->ca_file || !s->verify) 287cabdff1aSopenharmony_ci CHECK_ERROR(SSLSetSessionOption, c->ssl_context, kSSLSessionOptionBreakOnServerAuth, true); 288cabdff1aSopenharmony_ci if (s->cert_file) 289cabdff1aSopenharmony_ci if ((ret = load_cert(h)) < 0) 290cabdff1aSopenharmony_ci goto fail; 291cabdff1aSopenharmony_ci CHECK_ERROR(SSLSetPeerDomainName, c->ssl_context, s->host, strlen(s->host)); 292cabdff1aSopenharmony_ci CHECK_ERROR(SSLSetIOFuncs, c->ssl_context, tls_read_cb, tls_write_cb); 293cabdff1aSopenharmony_ci CHECK_ERROR(SSLSetConnection, c->ssl_context, h); 294cabdff1aSopenharmony_ci while (1) { 295cabdff1aSopenharmony_ci OSStatus status = SSLHandshake(c->ssl_context); 296cabdff1aSopenharmony_ci if (status == errSSLServerAuthCompleted) { 297cabdff1aSopenharmony_ci SecTrustRef peerTrust; 298cabdff1aSopenharmony_ci SecTrustResultType trustResult; 299cabdff1aSopenharmony_ci if (!s->verify) 300cabdff1aSopenharmony_ci continue; 301cabdff1aSopenharmony_ci 302cabdff1aSopenharmony_ci if (SSLCopyPeerTrust(c->ssl_context, &peerTrust) != noErr) { 303cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 304cabdff1aSopenharmony_ci goto fail; 305cabdff1aSopenharmony_ci } 306cabdff1aSopenharmony_ci 307cabdff1aSopenharmony_ci if (SecTrustSetAnchorCertificates(peerTrust, c->ca_array) != noErr) { 308cabdff1aSopenharmony_ci ret = AVERROR_UNKNOWN; 309cabdff1aSopenharmony_ci goto fail; 310cabdff1aSopenharmony_ci } 311cabdff1aSopenharmony_ci 312cabdff1aSopenharmony_ci if (SecTrustEvaluate(peerTrust, &trustResult) != noErr) { 313cabdff1aSopenharmony_ci ret = AVERROR_UNKNOWN; 314cabdff1aSopenharmony_ci goto fail; 315cabdff1aSopenharmony_ci } 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci if (trustResult == kSecTrustResultProceed || 318cabdff1aSopenharmony_ci trustResult == kSecTrustResultUnspecified) { 319cabdff1aSopenharmony_ci // certificate is trusted 320cabdff1aSopenharmony_ci status = errSSLWouldBlock; // so we call SSLHandshake again 321cabdff1aSopenharmony_ci } else if (trustResult == kSecTrustResultRecoverableTrustFailure) { 322cabdff1aSopenharmony_ci // not trusted, for some reason other than being expired 323cabdff1aSopenharmony_ci status = errSSLXCertChainInvalid; 324cabdff1aSopenharmony_ci } else { 325cabdff1aSopenharmony_ci // cannot use this certificate (fatal) 326cabdff1aSopenharmony_ci status = errSSLBadCert; 327cabdff1aSopenharmony_ci } 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_ci if (peerTrust) 330cabdff1aSopenharmony_ci CFRelease(peerTrust); 331cabdff1aSopenharmony_ci } 332cabdff1aSopenharmony_ci if (status == noErr) { 333cabdff1aSopenharmony_ci break; 334cabdff1aSopenharmony_ci } else if (status != errSSLWouldBlock) { 335cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status); 336cabdff1aSopenharmony_ci ret = AVERROR(EIO); 337cabdff1aSopenharmony_ci goto fail; 338cabdff1aSopenharmony_ci } 339cabdff1aSopenharmony_ci } 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_ci return 0; 342cabdff1aSopenharmony_cifail: 343cabdff1aSopenharmony_ci tls_close(h); 344cabdff1aSopenharmony_ci return ret; 345cabdff1aSopenharmony_ci} 346cabdff1aSopenharmony_ci 347cabdff1aSopenharmony_cistatic int map_ssl_error(OSStatus status, size_t processed) 348cabdff1aSopenharmony_ci{ 349cabdff1aSopenharmony_ci switch (status) { 350cabdff1aSopenharmony_ci case noErr: 351cabdff1aSopenharmony_ci return processed; 352cabdff1aSopenharmony_ci case errSSLClosedGraceful: 353cabdff1aSopenharmony_ci case errSSLClosedNoNotify: 354cabdff1aSopenharmony_ci return 0; 355cabdff1aSopenharmony_ci case errSSLWouldBlock: 356cabdff1aSopenharmony_ci if (processed > 0) 357cabdff1aSopenharmony_ci return processed; 358cabdff1aSopenharmony_ci default: 359cabdff1aSopenharmony_ci return (int)status; 360cabdff1aSopenharmony_ci } 361cabdff1aSopenharmony_ci} 362cabdff1aSopenharmony_ci 363cabdff1aSopenharmony_cistatic int tls_read(URLContext *h, uint8_t *buf, int size) 364cabdff1aSopenharmony_ci{ 365cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 366cabdff1aSopenharmony_ci size_t available = 0, processed = 0; 367cabdff1aSopenharmony_ci int ret; 368cabdff1aSopenharmony_ci SSLGetBufferedReadSize(c->ssl_context, &available); 369cabdff1aSopenharmony_ci if (available) 370cabdff1aSopenharmony_ci size = FFMIN(available, size); 371cabdff1aSopenharmony_ci ret = SSLRead(c->ssl_context, buf, size, &processed); 372cabdff1aSopenharmony_ci ret = map_ssl_error(ret, processed); 373cabdff1aSopenharmony_ci if (ret > 0) 374cabdff1aSopenharmony_ci return ret; 375cabdff1aSopenharmony_ci if (ret == 0) 376cabdff1aSopenharmony_ci return AVERROR_EOF; 377cabdff1aSopenharmony_ci return print_tls_error(h, ret); 378cabdff1aSopenharmony_ci} 379cabdff1aSopenharmony_ci 380cabdff1aSopenharmony_cistatic int tls_write(URLContext *h, const uint8_t *buf, int size) 381cabdff1aSopenharmony_ci{ 382cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 383cabdff1aSopenharmony_ci size_t processed = 0; 384cabdff1aSopenharmony_ci int ret = SSLWrite(c->ssl_context, buf, size, &processed); 385cabdff1aSopenharmony_ci ret = map_ssl_error(ret, processed); 386cabdff1aSopenharmony_ci if (ret > 0) 387cabdff1aSopenharmony_ci return ret; 388cabdff1aSopenharmony_ci if (ret == 0) 389cabdff1aSopenharmony_ci return AVERROR_EOF; 390cabdff1aSopenharmony_ci return print_tls_error(h, ret); 391cabdff1aSopenharmony_ci} 392cabdff1aSopenharmony_ci 393cabdff1aSopenharmony_cistatic int tls_get_file_handle(URLContext *h) 394cabdff1aSopenharmony_ci{ 395cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 396cabdff1aSopenharmony_ci return ffurl_get_file_handle(c->tls_shared.tcp); 397cabdff1aSopenharmony_ci} 398cabdff1aSopenharmony_ci 399cabdff1aSopenharmony_cistatic int tls_get_short_seek(URLContext *h) 400cabdff1aSopenharmony_ci{ 401cabdff1aSopenharmony_ci TLSContext *s = h->priv_data; 402cabdff1aSopenharmony_ci return ffurl_get_short_seek(s->tls_shared.tcp); 403cabdff1aSopenharmony_ci} 404cabdff1aSopenharmony_ci 405cabdff1aSopenharmony_cistatic const AVOption options[] = { 406cabdff1aSopenharmony_ci TLS_COMMON_OPTIONS(TLSContext, tls_shared), 407cabdff1aSopenharmony_ci { NULL } 408cabdff1aSopenharmony_ci}; 409cabdff1aSopenharmony_ci 410cabdff1aSopenharmony_cistatic const AVClass tls_class = { 411cabdff1aSopenharmony_ci .class_name = "tls", 412cabdff1aSopenharmony_ci .item_name = av_default_item_name, 413cabdff1aSopenharmony_ci .option = options, 414cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 415cabdff1aSopenharmony_ci}; 416cabdff1aSopenharmony_ci 417cabdff1aSopenharmony_ciconst URLProtocol ff_tls_protocol = { 418cabdff1aSopenharmony_ci .name = "tls", 419cabdff1aSopenharmony_ci .url_open2 = tls_open, 420cabdff1aSopenharmony_ci .url_read = tls_read, 421cabdff1aSopenharmony_ci .url_write = tls_write, 422cabdff1aSopenharmony_ci .url_close = tls_close, 423cabdff1aSopenharmony_ci .url_get_file_handle = tls_get_file_handle, 424cabdff1aSopenharmony_ci .url_get_short_seek = tls_get_short_seek, 425cabdff1aSopenharmony_ci .priv_data_size = sizeof(TLSContext), 426cabdff1aSopenharmony_ci .flags = URL_PROTOCOL_FLAG_NETWORK, 427cabdff1aSopenharmony_ci .priv_data_class = &tls_class, 428cabdff1aSopenharmony_ci}; 429