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