1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 2015 Hendrik Leppkes 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 8cabdff1aSopenharmony_ci * License 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 GNU 14cabdff1aSopenharmony_ci * Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci/** Based on the CURL SChannel module */ 22cabdff1aSopenharmony_ci 23cabdff1aSopenharmony_ci#include "avformat.h" 24cabdff1aSopenharmony_ci#include "internal.h" 25cabdff1aSopenharmony_ci#include "network.h" 26cabdff1aSopenharmony_ci#include "os_support.h" 27cabdff1aSopenharmony_ci#include "url.h" 28cabdff1aSopenharmony_ci#include "tls.h" 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_ci#define SECURITY_WIN32 31cabdff1aSopenharmony_ci#include <windows.h> 32cabdff1aSopenharmony_ci#include <security.h> 33cabdff1aSopenharmony_ci#include <schnlsp.h> 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci#define SCHANNEL_INITIAL_BUFFER_SIZE 4096 36cabdff1aSopenharmony_ci#define SCHANNEL_FREE_BUFFER_SIZE 1024 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_ci/* mingw does not define this symbol */ 39cabdff1aSopenharmony_ci#ifndef SECBUFFER_ALERT 40cabdff1aSopenharmony_ci#define SECBUFFER_ALERT 17 41cabdff1aSopenharmony_ci#endif 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_citypedef struct TLSContext { 44cabdff1aSopenharmony_ci const AVClass *class; 45cabdff1aSopenharmony_ci TLSShared tls_shared; 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_ci CredHandle cred_handle; 48cabdff1aSopenharmony_ci TimeStamp cred_timestamp; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci CtxtHandle ctxt_handle; 51cabdff1aSopenharmony_ci TimeStamp ctxt_timestamp; 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci ULONG request_flags; 54cabdff1aSopenharmony_ci ULONG context_flags; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci uint8_t *enc_buf; 57cabdff1aSopenharmony_ci int enc_buf_size; 58cabdff1aSopenharmony_ci int enc_buf_offset; 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci uint8_t *dec_buf; 61cabdff1aSopenharmony_ci int dec_buf_size; 62cabdff1aSopenharmony_ci int dec_buf_offset; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci SecPkgContext_StreamSizes sizes; 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_ci int connected; 67cabdff1aSopenharmony_ci int connection_closed; 68cabdff1aSopenharmony_ci int sspi_close_notify; 69cabdff1aSopenharmony_ci} TLSContext; 70cabdff1aSopenharmony_ci 71cabdff1aSopenharmony_cistatic void init_sec_buffer(SecBuffer *buffer, unsigned long type, 72cabdff1aSopenharmony_ci void *data, unsigned long size) 73cabdff1aSopenharmony_ci{ 74cabdff1aSopenharmony_ci buffer->cbBuffer = size; 75cabdff1aSopenharmony_ci buffer->BufferType = type; 76cabdff1aSopenharmony_ci buffer->pvBuffer = data; 77cabdff1aSopenharmony_ci} 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_cistatic void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers, 80cabdff1aSopenharmony_ci unsigned long buffer_count) 81cabdff1aSopenharmony_ci{ 82cabdff1aSopenharmony_ci desc->ulVersion = SECBUFFER_VERSION; 83cabdff1aSopenharmony_ci desc->pBuffers = buffers; 84cabdff1aSopenharmony_ci desc->cBuffers = buffer_count; 85cabdff1aSopenharmony_ci} 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_cistatic int tls_shutdown_client(URLContext *h) 88cabdff1aSopenharmony_ci{ 89cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 90cabdff1aSopenharmony_ci TLSShared *s = &c->tls_shared; 91cabdff1aSopenharmony_ci int ret; 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci if (c->connected) { 94cabdff1aSopenharmony_ci SecBufferDesc BuffDesc; 95cabdff1aSopenharmony_ci SecBuffer Buffer; 96cabdff1aSopenharmony_ci SECURITY_STATUS sspi_ret; 97cabdff1aSopenharmony_ci SecBuffer outbuf; 98cabdff1aSopenharmony_ci SecBufferDesc outbuf_desc; 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci DWORD dwshut = SCHANNEL_SHUTDOWN; 101cabdff1aSopenharmony_ci init_sec_buffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); 102cabdff1aSopenharmony_ci init_sec_buffer_desc(&BuffDesc, &Buffer, 1); 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_ci sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc); 105cabdff1aSopenharmony_ci if (sspi_ret != SEC_E_OK) 106cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n"); 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); 109cabdff1aSopenharmony_ci init_sec_buffer_desc(&outbuf_desc, &outbuf, 1); 110cabdff1aSopenharmony_ci 111cabdff1aSopenharmony_ci sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host, 112cabdff1aSopenharmony_ci c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle, 113cabdff1aSopenharmony_ci &outbuf_desc, &c->context_flags, &c->ctxt_timestamp); 114cabdff1aSopenharmony_ci if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_CONTEXT_EXPIRED) { 115cabdff1aSopenharmony_ci ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer); 116cabdff1aSopenharmony_ci FreeContextBuffer(outbuf.pvBuffer); 117cabdff1aSopenharmony_ci if (ret < 0 || ret != outbuf.cbBuffer) 118cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Failed to send close message\n"); 119cabdff1aSopenharmony_ci } 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ci c->connected = 0; 122cabdff1aSopenharmony_ci } 123cabdff1aSopenharmony_ci return 0; 124cabdff1aSopenharmony_ci} 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_cistatic int tls_close(URLContext *h) 127cabdff1aSopenharmony_ci{ 128cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_ci tls_shutdown_client(h); 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci DeleteSecurityContext(&c->ctxt_handle); 133cabdff1aSopenharmony_ci FreeCredentialsHandle(&c->cred_handle); 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci av_freep(&c->enc_buf); 136cabdff1aSopenharmony_ci c->enc_buf_size = c->enc_buf_offset = 0; 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ci av_freep(&c->dec_buf); 139cabdff1aSopenharmony_ci c->dec_buf_size = c->dec_buf_offset = 0; 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_ci ffurl_closep(&c->tls_shared.tcp); 142cabdff1aSopenharmony_ci return 0; 143cabdff1aSopenharmony_ci} 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_cistatic int tls_client_handshake_loop(URLContext *h, int initial) 146cabdff1aSopenharmony_ci{ 147cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 148cabdff1aSopenharmony_ci TLSShared *s = &c->tls_shared; 149cabdff1aSopenharmony_ci SECURITY_STATUS sspi_ret; 150cabdff1aSopenharmony_ci SecBuffer outbuf[3] = { 0 }; 151cabdff1aSopenharmony_ci SecBufferDesc outbuf_desc; 152cabdff1aSopenharmony_ci SecBuffer inbuf[2]; 153cabdff1aSopenharmony_ci SecBufferDesc inbuf_desc; 154cabdff1aSopenharmony_ci int i, ret = 0, read_data = initial; 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci if (c->enc_buf == NULL) { 157cabdff1aSopenharmony_ci c->enc_buf_offset = 0; 158cabdff1aSopenharmony_ci ret = av_reallocp(&c->enc_buf, SCHANNEL_INITIAL_BUFFER_SIZE); 159cabdff1aSopenharmony_ci if (ret < 0) 160cabdff1aSopenharmony_ci goto fail; 161cabdff1aSopenharmony_ci c->enc_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE; 162cabdff1aSopenharmony_ci } 163cabdff1aSopenharmony_ci 164cabdff1aSopenharmony_ci if (c->dec_buf == NULL) { 165cabdff1aSopenharmony_ci c->dec_buf_offset = 0; 166cabdff1aSopenharmony_ci ret = av_reallocp(&c->dec_buf, SCHANNEL_INITIAL_BUFFER_SIZE); 167cabdff1aSopenharmony_ci if (ret < 0) 168cabdff1aSopenharmony_ci goto fail; 169cabdff1aSopenharmony_ci c->dec_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE; 170cabdff1aSopenharmony_ci } 171cabdff1aSopenharmony_ci 172cabdff1aSopenharmony_ci while (1) { 173cabdff1aSopenharmony_ci if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) { 174cabdff1aSopenharmony_ci c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE; 175cabdff1aSopenharmony_ci ret = av_reallocp(&c->enc_buf, c->enc_buf_size); 176cabdff1aSopenharmony_ci if (ret < 0) { 177cabdff1aSopenharmony_ci c->enc_buf_size = c->enc_buf_offset = 0; 178cabdff1aSopenharmony_ci goto fail; 179cabdff1aSopenharmony_ci } 180cabdff1aSopenharmony_ci } 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci if (read_data) { 183cabdff1aSopenharmony_ci ret = ffurl_read(c->tls_shared.tcp, c->enc_buf + c->enc_buf_offset, 184cabdff1aSopenharmony_ci c->enc_buf_size - c->enc_buf_offset); 185cabdff1aSopenharmony_ci if (ret < 0) { 186cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n"); 187cabdff1aSopenharmony_ci goto fail; 188cabdff1aSopenharmony_ci } 189cabdff1aSopenharmony_ci c->enc_buf_offset += ret; 190cabdff1aSopenharmony_ci } 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci /* input buffers */ 193cabdff1aSopenharmony_ci init_sec_buffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset); 194cabdff1aSopenharmony_ci init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); 195cabdff1aSopenharmony_ci init_sec_buffer_desc(&inbuf_desc, inbuf, 2); 196cabdff1aSopenharmony_ci 197cabdff1aSopenharmony_ci if (inbuf[0].pvBuffer == NULL) { 198cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Failed to allocate input buffer\n"); 199cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 200cabdff1aSopenharmony_ci goto fail; 201cabdff1aSopenharmony_ci } 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci memcpy(inbuf[0].pvBuffer, c->enc_buf, c->enc_buf_offset); 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_ci /* output buffers */ 206cabdff1aSopenharmony_ci init_sec_buffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0); 207cabdff1aSopenharmony_ci init_sec_buffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0); 208cabdff1aSopenharmony_ci init_sec_buffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0); 209cabdff1aSopenharmony_ci init_sec_buffer_desc(&outbuf_desc, outbuf, 3); 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_ci sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host, c->request_flags, 212cabdff1aSopenharmony_ci 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc, &c->context_flags, 213cabdff1aSopenharmony_ci &c->ctxt_timestamp); 214cabdff1aSopenharmony_ci av_freep(&inbuf[0].pvBuffer); 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) { 217cabdff1aSopenharmony_ci av_log(h, AV_LOG_DEBUG, "Received incomplete handshake, need more data\n"); 218cabdff1aSopenharmony_ci read_data = 1; 219cabdff1aSopenharmony_ci continue; 220cabdff1aSopenharmony_ci } 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_ci /* remote requests a client certificate - attempt to continue without one anyway */ 223cabdff1aSopenharmony_ci if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS && 224cabdff1aSopenharmony_ci !(c->request_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { 225cabdff1aSopenharmony_ci av_log(h, AV_LOG_VERBOSE, "Client certificate has been requested, ignoring\n"); 226cabdff1aSopenharmony_ci c->request_flags |= ISC_REQ_USE_SUPPLIED_CREDS; 227cabdff1aSopenharmony_ci read_data = 0; 228cabdff1aSopenharmony_ci continue; 229cabdff1aSopenharmony_ci } 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci /* continue handshake */ 232cabdff1aSopenharmony_ci if (sspi_ret == SEC_I_CONTINUE_NEEDED || sspi_ret == SEC_E_OK) { 233cabdff1aSopenharmony_ci for (i = 0; i < 3; i++) { 234cabdff1aSopenharmony_ci if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { 235cabdff1aSopenharmony_ci ret = ffurl_write(c->tls_shared.tcp, outbuf[i].pvBuffer, outbuf[i].cbBuffer); 236cabdff1aSopenharmony_ci if (ret < 0 || ret != outbuf[i].cbBuffer) { 237cabdff1aSopenharmony_ci av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n"); 238cabdff1aSopenharmony_ci ret = AVERROR(EIO); 239cabdff1aSopenharmony_ci goto fail; 240cabdff1aSopenharmony_ci } 241cabdff1aSopenharmony_ci } 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci if (outbuf[i].pvBuffer != NULL) { 244cabdff1aSopenharmony_ci FreeContextBuffer(outbuf[i].pvBuffer); 245cabdff1aSopenharmony_ci outbuf[i].pvBuffer = NULL; 246cabdff1aSopenharmony_ci } 247cabdff1aSopenharmony_ci } 248cabdff1aSopenharmony_ci } else { 249cabdff1aSopenharmony_ci if (sspi_ret == SEC_E_WRONG_PRINCIPAL) 250cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "SNI or certificate check failed\n"); 251cabdff1aSopenharmony_ci else 252cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Creating security context failed (0x%lx)\n", sspi_ret); 253cabdff1aSopenharmony_ci ret = AVERROR_UNKNOWN; 254cabdff1aSopenharmony_ci goto fail; 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_ci if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { 258cabdff1aSopenharmony_ci if (c->enc_buf_offset > inbuf[1].cbBuffer) { 259cabdff1aSopenharmony_ci memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer, 260cabdff1aSopenharmony_ci inbuf[1].cbBuffer); 261cabdff1aSopenharmony_ci c->enc_buf_offset = inbuf[1].cbBuffer; 262cabdff1aSopenharmony_ci if (sspi_ret == SEC_I_CONTINUE_NEEDED) { 263cabdff1aSopenharmony_ci read_data = 0; 264cabdff1aSopenharmony_ci continue; 265cabdff1aSopenharmony_ci } 266cabdff1aSopenharmony_ci } 267cabdff1aSopenharmony_ci } else { 268cabdff1aSopenharmony_ci c->enc_buf_offset = 0; 269cabdff1aSopenharmony_ci } 270cabdff1aSopenharmony_ci 271cabdff1aSopenharmony_ci if (sspi_ret == SEC_I_CONTINUE_NEEDED) { 272cabdff1aSopenharmony_ci read_data = 1; 273cabdff1aSopenharmony_ci continue; 274cabdff1aSopenharmony_ci } 275cabdff1aSopenharmony_ci 276cabdff1aSopenharmony_ci break; 277cabdff1aSopenharmony_ci } 278cabdff1aSopenharmony_ci 279cabdff1aSopenharmony_ci return 0; 280cabdff1aSopenharmony_ci 281cabdff1aSopenharmony_cifail: 282cabdff1aSopenharmony_ci /* free any remaining output data */ 283cabdff1aSopenharmony_ci for (i = 0; i < 3; i++) { 284cabdff1aSopenharmony_ci if (outbuf[i].pvBuffer != NULL) { 285cabdff1aSopenharmony_ci FreeContextBuffer(outbuf[i].pvBuffer); 286cabdff1aSopenharmony_ci outbuf[i].pvBuffer = NULL; 287cabdff1aSopenharmony_ci } 288cabdff1aSopenharmony_ci } 289cabdff1aSopenharmony_ci 290cabdff1aSopenharmony_ci return ret; 291cabdff1aSopenharmony_ci} 292cabdff1aSopenharmony_ci 293cabdff1aSopenharmony_cistatic int tls_client_handshake(URLContext *h) 294cabdff1aSopenharmony_ci{ 295cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 296cabdff1aSopenharmony_ci TLSShared *s = &c->tls_shared; 297cabdff1aSopenharmony_ci SecBuffer outbuf; 298cabdff1aSopenharmony_ci SecBufferDesc outbuf_desc; 299cabdff1aSopenharmony_ci SECURITY_STATUS sspi_ret; 300cabdff1aSopenharmony_ci int ret; 301cabdff1aSopenharmony_ci 302cabdff1aSopenharmony_ci init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); 303cabdff1aSopenharmony_ci init_sec_buffer_desc(&outbuf_desc, &outbuf, 1); 304cabdff1aSopenharmony_ci 305cabdff1aSopenharmony_ci c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | 306cabdff1aSopenharmony_ci ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | 307cabdff1aSopenharmony_ci ISC_REQ_STREAM; 308cabdff1aSopenharmony_ci 309cabdff1aSopenharmony_ci sspi_ret = InitializeSecurityContext(&c->cred_handle, NULL, s->host, c->request_flags, 0, 0, 310cabdff1aSopenharmony_ci NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags, 311cabdff1aSopenharmony_ci &c->ctxt_timestamp); 312cabdff1aSopenharmony_ci if (sspi_ret != SEC_I_CONTINUE_NEEDED) { 313cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Unable to create initial security context (0x%lx)\n", sspi_ret); 314cabdff1aSopenharmony_ci ret = AVERROR_UNKNOWN; 315cabdff1aSopenharmony_ci goto fail; 316cabdff1aSopenharmony_ci } 317cabdff1aSopenharmony_ci 318cabdff1aSopenharmony_ci ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer); 319cabdff1aSopenharmony_ci FreeContextBuffer(outbuf.pvBuffer); 320cabdff1aSopenharmony_ci if (ret < 0 || ret != outbuf.cbBuffer) { 321cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Failed to send initial handshake data\n"); 322cabdff1aSopenharmony_ci ret = AVERROR(EIO); 323cabdff1aSopenharmony_ci goto fail; 324cabdff1aSopenharmony_ci } 325cabdff1aSopenharmony_ci 326cabdff1aSopenharmony_ci return tls_client_handshake_loop(h, 1); 327cabdff1aSopenharmony_ci 328cabdff1aSopenharmony_cifail: 329cabdff1aSopenharmony_ci DeleteSecurityContext(&c->ctxt_handle); 330cabdff1aSopenharmony_ci return ret; 331cabdff1aSopenharmony_ci} 332cabdff1aSopenharmony_ci 333cabdff1aSopenharmony_cistatic int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) 334cabdff1aSopenharmony_ci{ 335cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 336cabdff1aSopenharmony_ci TLSShared *s = &c->tls_shared; 337cabdff1aSopenharmony_ci SECURITY_STATUS sspi_ret; 338cabdff1aSopenharmony_ci SCHANNEL_CRED schannel_cred = { 0 }; 339cabdff1aSopenharmony_ci int ret; 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_ci if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0) 342cabdff1aSopenharmony_ci goto fail; 343cabdff1aSopenharmony_ci 344cabdff1aSopenharmony_ci if (s->listen) { 345cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "TLS Listen Sockets with SChannel is not implemented.\n"); 346cabdff1aSopenharmony_ci ret = AVERROR(EINVAL); 347cabdff1aSopenharmony_ci goto fail; 348cabdff1aSopenharmony_ci } 349cabdff1aSopenharmony_ci 350cabdff1aSopenharmony_ci /* SChannel Options */ 351cabdff1aSopenharmony_ci schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; 352cabdff1aSopenharmony_ci 353cabdff1aSopenharmony_ci if (s->verify) 354cabdff1aSopenharmony_ci schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION | 355cabdff1aSopenharmony_ci SCH_CRED_REVOCATION_CHECK_CHAIN; 356cabdff1aSopenharmony_ci else 357cabdff1aSopenharmony_ci schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | 358cabdff1aSopenharmony_ci SCH_CRED_IGNORE_NO_REVOCATION_CHECK | 359cabdff1aSopenharmony_ci SCH_CRED_IGNORE_REVOCATION_OFFLINE; 360cabdff1aSopenharmony_ci 361cabdff1aSopenharmony_ci /* Get credential handle */ 362cabdff1aSopenharmony_ci sspi_ret = AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND, 363cabdff1aSopenharmony_ci NULL, &schannel_cred, NULL, NULL, &c->cred_handle, 364cabdff1aSopenharmony_ci &c->cred_timestamp); 365cabdff1aSopenharmony_ci if (sspi_ret != SEC_E_OK) { 366cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Unable to acquire security credentials (0x%lx)\n", sspi_ret); 367cabdff1aSopenharmony_ci ret = AVERROR_UNKNOWN; 368cabdff1aSopenharmony_ci goto fail; 369cabdff1aSopenharmony_ci } 370cabdff1aSopenharmony_ci 371cabdff1aSopenharmony_ci ret = tls_client_handshake(h); 372cabdff1aSopenharmony_ci if (ret < 0) 373cabdff1aSopenharmony_ci goto fail; 374cabdff1aSopenharmony_ci 375cabdff1aSopenharmony_ci c->connected = 1; 376cabdff1aSopenharmony_ci 377cabdff1aSopenharmony_ci return 0; 378cabdff1aSopenharmony_ci 379cabdff1aSopenharmony_cifail: 380cabdff1aSopenharmony_ci tls_close(h); 381cabdff1aSopenharmony_ci return ret; 382cabdff1aSopenharmony_ci} 383cabdff1aSopenharmony_ci 384cabdff1aSopenharmony_cistatic int tls_read(URLContext *h, uint8_t *buf, int len) 385cabdff1aSopenharmony_ci{ 386cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 387cabdff1aSopenharmony_ci TLSShared *s = &c->tls_shared; 388cabdff1aSopenharmony_ci SECURITY_STATUS sspi_ret = SEC_E_OK; 389cabdff1aSopenharmony_ci SecBuffer inbuf[4]; 390cabdff1aSopenharmony_ci SecBufferDesc inbuf_desc; 391cabdff1aSopenharmony_ci int size, ret; 392cabdff1aSopenharmony_ci int min_enc_buf_size = len + SCHANNEL_FREE_BUFFER_SIZE; 393cabdff1aSopenharmony_ci 394cabdff1aSopenharmony_ci /* If we have some left-over data from previous network activity, 395cabdff1aSopenharmony_ci * return it first in case it is enough. It may contain 396cabdff1aSopenharmony_ci * data that is required to know whether this connection 397cabdff1aSopenharmony_ci * is still required or not, esp. in case of HTTP keep-alive 398cabdff1aSopenharmony_ci * connections. */ 399cabdff1aSopenharmony_ci if (c->dec_buf_offset > 0) 400cabdff1aSopenharmony_ci goto cleanup; 401cabdff1aSopenharmony_ci 402cabdff1aSopenharmony_ci if (c->sspi_close_notify) 403cabdff1aSopenharmony_ci goto cleanup; 404cabdff1aSopenharmony_ci 405cabdff1aSopenharmony_ci if (!c->connection_closed) { 406cabdff1aSopenharmony_ci size = c->enc_buf_size - c->enc_buf_offset; 407cabdff1aSopenharmony_ci if (size < SCHANNEL_FREE_BUFFER_SIZE || c->enc_buf_size < min_enc_buf_size) { 408cabdff1aSopenharmony_ci c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE; 409cabdff1aSopenharmony_ci if (c->enc_buf_size < min_enc_buf_size) 410cabdff1aSopenharmony_ci c->enc_buf_size = min_enc_buf_size; 411cabdff1aSopenharmony_ci ret = av_reallocp(&c->enc_buf, c->enc_buf_size); 412cabdff1aSopenharmony_ci if (ret < 0) { 413cabdff1aSopenharmony_ci c->enc_buf_size = c->enc_buf_offset = 0; 414cabdff1aSopenharmony_ci return ret; 415cabdff1aSopenharmony_ci } 416cabdff1aSopenharmony_ci } 417cabdff1aSopenharmony_ci 418cabdff1aSopenharmony_ci ret = ffurl_read(s->tcp, c->enc_buf + c->enc_buf_offset, 419cabdff1aSopenharmony_ci c->enc_buf_size - c->enc_buf_offset); 420cabdff1aSopenharmony_ci if (ret == AVERROR_EOF) { 421cabdff1aSopenharmony_ci c->connection_closed = 1; 422cabdff1aSopenharmony_ci ret = 0; 423cabdff1aSopenharmony_ci } else if (ret < 0) { 424cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Unable to read from socket\n"); 425cabdff1aSopenharmony_ci return ret; 426cabdff1aSopenharmony_ci } 427cabdff1aSopenharmony_ci 428cabdff1aSopenharmony_ci c->enc_buf_offset += ret; 429cabdff1aSopenharmony_ci } 430cabdff1aSopenharmony_ci 431cabdff1aSopenharmony_ci while (c->enc_buf_offset > 0 && sspi_ret == SEC_E_OK) { 432cabdff1aSopenharmony_ci /* input buffer */ 433cabdff1aSopenharmony_ci init_sec_buffer(&inbuf[0], SECBUFFER_DATA, c->enc_buf, c->enc_buf_offset); 434cabdff1aSopenharmony_ci 435cabdff1aSopenharmony_ci /* additional buffers for possible output */ 436cabdff1aSopenharmony_ci init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); 437cabdff1aSopenharmony_ci init_sec_buffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0); 438cabdff1aSopenharmony_ci init_sec_buffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); 439cabdff1aSopenharmony_ci init_sec_buffer_desc(&inbuf_desc, inbuf, 4); 440cabdff1aSopenharmony_ci 441cabdff1aSopenharmony_ci sspi_ret = DecryptMessage(&c->ctxt_handle, &inbuf_desc, 0, NULL); 442cabdff1aSopenharmony_ci if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_RENEGOTIATE || 443cabdff1aSopenharmony_ci sspi_ret == SEC_I_CONTEXT_EXPIRED) { 444cabdff1aSopenharmony_ci /* handle decrypted data */ 445cabdff1aSopenharmony_ci if (inbuf[1].BufferType == SECBUFFER_DATA) { 446cabdff1aSopenharmony_ci /* grow buffer if needed */ 447cabdff1aSopenharmony_ci size = inbuf[1].cbBuffer > SCHANNEL_FREE_BUFFER_SIZE ? 448cabdff1aSopenharmony_ci inbuf[1].cbBuffer : SCHANNEL_FREE_BUFFER_SIZE; 449cabdff1aSopenharmony_ci if (c->dec_buf_size - c->dec_buf_offset < size || c->dec_buf_size < len) { 450cabdff1aSopenharmony_ci c->dec_buf_size = c->dec_buf_offset + size; 451cabdff1aSopenharmony_ci if (c->dec_buf_size < len) 452cabdff1aSopenharmony_ci c->dec_buf_size = len; 453cabdff1aSopenharmony_ci ret = av_reallocp(&c->dec_buf, c->dec_buf_size); 454cabdff1aSopenharmony_ci if (ret < 0) { 455cabdff1aSopenharmony_ci c->dec_buf_size = c->dec_buf_offset = 0; 456cabdff1aSopenharmony_ci return ret; 457cabdff1aSopenharmony_ci } 458cabdff1aSopenharmony_ci } 459cabdff1aSopenharmony_ci 460cabdff1aSopenharmony_ci /* copy decrypted data to buffer */ 461cabdff1aSopenharmony_ci size = inbuf[1].cbBuffer; 462cabdff1aSopenharmony_ci if (size) { 463cabdff1aSopenharmony_ci memcpy(c->dec_buf + c->dec_buf_offset, inbuf[1].pvBuffer, size); 464cabdff1aSopenharmony_ci c->dec_buf_offset += size; 465cabdff1aSopenharmony_ci } 466cabdff1aSopenharmony_ci } 467cabdff1aSopenharmony_ci if (inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) { 468cabdff1aSopenharmony_ci if (c->enc_buf_offset > inbuf[3].cbBuffer) { 469cabdff1aSopenharmony_ci memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[3].cbBuffer, 470cabdff1aSopenharmony_ci inbuf[3].cbBuffer); 471cabdff1aSopenharmony_ci c->enc_buf_offset = inbuf[3].cbBuffer; 472cabdff1aSopenharmony_ci } 473cabdff1aSopenharmony_ci } else 474cabdff1aSopenharmony_ci c->enc_buf_offset = 0; 475cabdff1aSopenharmony_ci 476cabdff1aSopenharmony_ci if (sspi_ret == SEC_I_RENEGOTIATE) { 477cabdff1aSopenharmony_ci if (c->enc_buf_offset) { 478cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Cannot renegotiate, encrypted data buffer not empty\n"); 479cabdff1aSopenharmony_ci ret = AVERROR_UNKNOWN; 480cabdff1aSopenharmony_ci goto cleanup; 481cabdff1aSopenharmony_ci } 482cabdff1aSopenharmony_ci 483cabdff1aSopenharmony_ci av_log(h, AV_LOG_VERBOSE, "Re-negotiating security context\n"); 484cabdff1aSopenharmony_ci ret = tls_client_handshake_loop(h, 0); 485cabdff1aSopenharmony_ci if (ret < 0) { 486cabdff1aSopenharmony_ci goto cleanup; 487cabdff1aSopenharmony_ci } 488cabdff1aSopenharmony_ci sspi_ret = SEC_E_OK; 489cabdff1aSopenharmony_ci continue; 490cabdff1aSopenharmony_ci } else if (sspi_ret == SEC_I_CONTEXT_EXPIRED) { 491cabdff1aSopenharmony_ci c->sspi_close_notify = 1; 492cabdff1aSopenharmony_ci if (!c->connection_closed) { 493cabdff1aSopenharmony_ci c->connection_closed = 1; 494cabdff1aSopenharmony_ci av_log(h, AV_LOG_VERBOSE, "Server closed the connection\n"); 495cabdff1aSopenharmony_ci } 496cabdff1aSopenharmony_ci ret = 0; 497cabdff1aSopenharmony_ci goto cleanup; 498cabdff1aSopenharmony_ci } 499cabdff1aSopenharmony_ci } else if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) { 500cabdff1aSopenharmony_ci ret = AVERROR(EAGAIN); 501cabdff1aSopenharmony_ci goto cleanup; 502cabdff1aSopenharmony_ci } else { 503cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Unable to decrypt message (error 0x%x)\n", (unsigned)sspi_ret); 504cabdff1aSopenharmony_ci ret = AVERROR(EIO); 505cabdff1aSopenharmony_ci goto cleanup; 506cabdff1aSopenharmony_ci } 507cabdff1aSopenharmony_ci } 508cabdff1aSopenharmony_ci 509cabdff1aSopenharmony_ci ret = 0; 510cabdff1aSopenharmony_ci 511cabdff1aSopenharmony_cicleanup: 512cabdff1aSopenharmony_ci size = FFMIN(len, c->dec_buf_offset); 513cabdff1aSopenharmony_ci if (size) { 514cabdff1aSopenharmony_ci memcpy(buf, c->dec_buf, size); 515cabdff1aSopenharmony_ci memmove(c->dec_buf, c->dec_buf + size, c->dec_buf_offset - size); 516cabdff1aSopenharmony_ci c->dec_buf_offset -= size; 517cabdff1aSopenharmony_ci 518cabdff1aSopenharmony_ci return size; 519cabdff1aSopenharmony_ci } 520cabdff1aSopenharmony_ci 521cabdff1aSopenharmony_ci if (ret == 0 && !c->connection_closed) 522cabdff1aSopenharmony_ci ret = AVERROR(EAGAIN); 523cabdff1aSopenharmony_ci 524cabdff1aSopenharmony_ci return ret < 0 ? ret : AVERROR_EOF; 525cabdff1aSopenharmony_ci} 526cabdff1aSopenharmony_ci 527cabdff1aSopenharmony_cistatic int tls_write(URLContext *h, const uint8_t *buf, int len) 528cabdff1aSopenharmony_ci{ 529cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 530cabdff1aSopenharmony_ci TLSShared *s = &c->tls_shared; 531cabdff1aSopenharmony_ci SECURITY_STATUS sspi_ret; 532cabdff1aSopenharmony_ci int ret = 0, data_size; 533cabdff1aSopenharmony_ci uint8_t *data = NULL; 534cabdff1aSopenharmony_ci SecBuffer outbuf[4]; 535cabdff1aSopenharmony_ci SecBufferDesc outbuf_desc; 536cabdff1aSopenharmony_ci 537cabdff1aSopenharmony_ci if (c->sizes.cbMaximumMessage == 0) { 538cabdff1aSopenharmony_ci sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->sizes); 539cabdff1aSopenharmony_ci if (sspi_ret != SEC_E_OK) 540cabdff1aSopenharmony_ci return AVERROR_UNKNOWN; 541cabdff1aSopenharmony_ci } 542cabdff1aSopenharmony_ci 543cabdff1aSopenharmony_ci /* limit how much data we can consume */ 544cabdff1aSopenharmony_ci len = FFMIN(len, c->sizes.cbMaximumMessage); 545cabdff1aSopenharmony_ci 546cabdff1aSopenharmony_ci data_size = c->sizes.cbHeader + len + c->sizes.cbTrailer; 547cabdff1aSopenharmony_ci data = av_malloc(data_size); 548cabdff1aSopenharmony_ci if (data == NULL) 549cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 550cabdff1aSopenharmony_ci 551cabdff1aSopenharmony_ci init_sec_buffer(&outbuf[0], SECBUFFER_STREAM_HEADER, 552cabdff1aSopenharmony_ci data, c->sizes.cbHeader); 553cabdff1aSopenharmony_ci init_sec_buffer(&outbuf[1], SECBUFFER_DATA, 554cabdff1aSopenharmony_ci data + c->sizes.cbHeader, len); 555cabdff1aSopenharmony_ci init_sec_buffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, 556cabdff1aSopenharmony_ci data + c->sizes.cbHeader + len, 557cabdff1aSopenharmony_ci c->sizes.cbTrailer); 558cabdff1aSopenharmony_ci init_sec_buffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); 559cabdff1aSopenharmony_ci init_sec_buffer_desc(&outbuf_desc, outbuf, 4); 560cabdff1aSopenharmony_ci 561cabdff1aSopenharmony_ci memcpy(outbuf[1].pvBuffer, buf, len); 562cabdff1aSopenharmony_ci 563cabdff1aSopenharmony_ci sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0); 564cabdff1aSopenharmony_ci if (sspi_ret == SEC_E_OK) { 565cabdff1aSopenharmony_ci len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; 566cabdff1aSopenharmony_ci ret = ffurl_write(s->tcp, data, len); 567cabdff1aSopenharmony_ci if (ret < 0 || ret != len) { 568cabdff1aSopenharmony_ci ret = AVERROR(EIO); 569cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n"); 570cabdff1aSopenharmony_ci goto done; 571cabdff1aSopenharmony_ci } 572cabdff1aSopenharmony_ci } else { 573cabdff1aSopenharmony_ci av_log(h, AV_LOG_ERROR, "Encrypting data failed\n"); 574cabdff1aSopenharmony_ci if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY) 575cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 576cabdff1aSopenharmony_ci else 577cabdff1aSopenharmony_ci ret = AVERROR(EIO); 578cabdff1aSopenharmony_ci goto done; 579cabdff1aSopenharmony_ci } 580cabdff1aSopenharmony_ci 581cabdff1aSopenharmony_cidone: 582cabdff1aSopenharmony_ci av_freep(&data); 583cabdff1aSopenharmony_ci return ret < 0 ? ret : outbuf[1].cbBuffer; 584cabdff1aSopenharmony_ci} 585cabdff1aSopenharmony_ci 586cabdff1aSopenharmony_cistatic int tls_get_file_handle(URLContext *h) 587cabdff1aSopenharmony_ci{ 588cabdff1aSopenharmony_ci TLSContext *c = h->priv_data; 589cabdff1aSopenharmony_ci return ffurl_get_file_handle(c->tls_shared.tcp); 590cabdff1aSopenharmony_ci} 591cabdff1aSopenharmony_ci 592cabdff1aSopenharmony_cistatic int tls_get_short_seek(URLContext *h) 593cabdff1aSopenharmony_ci{ 594cabdff1aSopenharmony_ci TLSContext *s = h->priv_data; 595cabdff1aSopenharmony_ci return ffurl_get_short_seek(s->tls_shared.tcp); 596cabdff1aSopenharmony_ci} 597cabdff1aSopenharmony_ci 598cabdff1aSopenharmony_cistatic const AVOption options[] = { 599cabdff1aSopenharmony_ci TLS_COMMON_OPTIONS(TLSContext, tls_shared), 600cabdff1aSopenharmony_ci { NULL } 601cabdff1aSopenharmony_ci}; 602cabdff1aSopenharmony_ci 603cabdff1aSopenharmony_cistatic const AVClass tls_class = { 604cabdff1aSopenharmony_ci .class_name = "tls", 605cabdff1aSopenharmony_ci .item_name = av_default_item_name, 606cabdff1aSopenharmony_ci .option = options, 607cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 608cabdff1aSopenharmony_ci}; 609cabdff1aSopenharmony_ci 610cabdff1aSopenharmony_ciconst URLProtocol ff_tls_protocol = { 611cabdff1aSopenharmony_ci .name = "tls", 612cabdff1aSopenharmony_ci .url_open2 = tls_open, 613cabdff1aSopenharmony_ci .url_read = tls_read, 614cabdff1aSopenharmony_ci .url_write = tls_write, 615cabdff1aSopenharmony_ci .url_close = tls_close, 616cabdff1aSopenharmony_ci .url_get_file_handle = tls_get_file_handle, 617cabdff1aSopenharmony_ci .url_get_short_seek = tls_get_short_seek, 618cabdff1aSopenharmony_ci .priv_data_size = sizeof(TLSContext), 619cabdff1aSopenharmony_ci .flags = URL_PROTOCOL_FLAG_NETWORK, 620cabdff1aSopenharmony_ci .priv_data_class = &tls_class, 621cabdff1aSopenharmony_ci}; 622