• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * TLS/SSL Protocol
3  * Copyright (c) 2011 Martin Storsjo
4  * Copyright (c) 2017 sfan5 <sfan5@live.de>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "avformat.h"
24 #include "internal.h"
25 #include "network.h"
26 #include "url.h"
27 #include "tls.h"
28 #include "libavcodec/internal.h"
29 #include "libavutil/avutil.h"
30 #include "libavutil/opt.h"
31 
32 #include <tls.h>
33 
34 typedef struct TLSContext {
35     const AVClass *class;
36     TLSShared tls_shared;
37     struct tls *ctx;
38 } TLSContext;
39 
ff_tls_close(URLContext * h)40 static int ff_tls_close(URLContext *h)
41 {
42     TLSContext *p = h->priv_data;
43     if (p->ctx) {
44         tls_close(p->ctx);
45         tls_free(p->ctx);
46     }
47     ffurl_closep(&p->tls_shared.tcp);
48     return 0;
49 }
50 
tls_read_callback(struct tls * ctx,void * buf,size_t buflen,void * cb_arg)51 static ssize_t tls_read_callback(struct tls *ctx, void *buf, size_t buflen, void *cb_arg)
52 {
53     URLContext *h = (URLContext*) cb_arg;
54     int ret = ffurl_read(h, buf, buflen);
55     if (ret == AVERROR(EAGAIN))
56         return TLS_WANT_POLLIN;
57     else if (ret == AVERROR_EXIT)
58         return 0;
59     return ret >= 0 ? ret : -1;
60 }
61 
tls_write_callback(struct tls * ctx,const void * buf,size_t buflen,void * cb_arg)62 static ssize_t tls_write_callback(struct tls *ctx, const void *buf, size_t buflen, void *cb_arg)
63 {
64     URLContext *h = (URLContext*) cb_arg;
65     int ret = ffurl_write(h, buf, buflen);
66     if (ret == AVERROR(EAGAIN))
67         return TLS_WANT_POLLOUT;
68     else if (ret == AVERROR_EXIT)
69         return 0;
70     return ret >= 0 ? ret : -1;
71 }
72 
ff_tls_open(URLContext * h,const char * uri,int flags,AVDictionary ** options)73 static int ff_tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
74 {
75     TLSContext *p = h->priv_data;
76     TLSShared *c = &p->tls_shared;
77     struct tls_config *cfg = NULL;
78     int ret;
79 
80     if (tls_init() == -1) {
81         ret = AVERROR(EIO);
82         goto fail;
83     }
84 
85     if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0)
86         goto fail;
87 
88     p->ctx = !c->listen ? tls_client() : tls_server();
89     if (!p->ctx) {
90         ret = AVERROR(EIO);
91         goto fail;
92     }
93 
94     cfg = tls_config_new();
95     if (!p->ctx) {
96         ret = AVERROR(EIO);
97         goto fail;
98     }
99     if (tls_config_set_protocols(cfg, TLS_PROTOCOLS_ALL) == -1)
100         goto err_config;
101     // While TLSv1.0 and TLSv1.1 are already enabled by the above,
102     // we need to be less strict with ciphers so it works in practice.
103     if (tls_config_set_ciphers(cfg, "compat") == -1)
104         goto err_config;
105     if (c->ca_file && tls_config_set_ca_file(cfg, c->ca_file) == -1)
106         goto err_config;
107     if (c->cert_file && tls_config_set_cert_file(cfg, c->cert_file) == -1)
108         goto err_config;
109     if (c->key_file && tls_config_set_key_file(cfg, c->key_file) == -1)
110         goto err_config;
111     if (!c->verify) {
112         tls_config_insecure_noverifycert(cfg);
113         tls_config_insecure_noverifyname(cfg);
114         tls_config_insecure_noverifytime(cfg);
115     }
116     if (tls_configure(p->ctx, cfg) == -1)
117         goto err_ctx;
118 
119     if (!c->listen) {
120         ret = tls_connect_cbs(p->ctx, tls_read_callback, tls_write_callback,
121             c->tcp, c->host);
122     } else {
123         struct tls *ctx_new;
124         ret = tls_accept_cbs(p->ctx, &ctx_new, tls_read_callback,
125             tls_write_callback, c->tcp);
126         if (ret == 0) {
127             // free "server" context and replace by "connection" context
128             tls_free(p->ctx);
129             p->ctx = ctx_new;
130         }
131     }
132     if (ret == -1)
133         goto err_ctx;
134 
135     tls_config_free(cfg);
136     return 0;
137 err_config:
138     av_log(h, AV_LOG_ERROR, "%s\n", tls_config_error(cfg));
139     ret = AVERROR(EIO);
140     goto fail;
141 err_ctx:
142     av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx));
143     ret = AVERROR(EIO);
144     /* fallthrough */
145 fail:
146     if (cfg)
147         tls_config_free(cfg);
148     ff_tls_close(h);
149     return ret;
150 }
151 
ff_tls_read(URLContext * h,uint8_t * buf,int size)152 static int ff_tls_read(URLContext *h, uint8_t *buf, int size)
153 {
154     TLSContext *p = h->priv_data;
155     ssize_t ret;
156     ret = tls_read(p->ctx, buf, size);
157     if (ret > 0)
158         return ret;
159     else if (ret == 0)
160         return AVERROR_EOF;
161     av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx));
162     return AVERROR(EIO);
163 }
164 
ff_tls_write(URLContext * h,const uint8_t * buf,int size)165 static int ff_tls_write(URLContext *h, const uint8_t *buf, int size)
166 {
167     TLSContext *p = h->priv_data;
168     ssize_t ret;
169     ret = tls_write(p->ctx, buf, size);
170     if (ret > 0)
171         return ret;
172     else if (ret == 0)
173         return AVERROR_EOF;
174     av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx));
175     return AVERROR(EIO);
176 }
177 
tls_get_file_handle(URLContext * h)178 static int tls_get_file_handle(URLContext *h)
179 {
180     TLSContext *c = h->priv_data;
181     return ffurl_get_file_handle(c->tls_shared.tcp);
182 }
183 
tls_get_short_seek(URLContext * h)184 static int tls_get_short_seek(URLContext *h)
185 {
186     TLSContext *s = h->priv_data;
187     return ffurl_get_short_seek(s->tls_shared.tcp);
188 }
189 
190 static const AVOption options[] = {
191     TLS_COMMON_OPTIONS(TLSContext, tls_shared),
192     { NULL }
193 };
194 
195 static const AVClass tls_class = {
196     .class_name = "tls",
197     .item_name  = av_default_item_name,
198     .option     = options,
199     .version    = LIBAVUTIL_VERSION_INT,
200 };
201 
202 const URLProtocol ff_tls_protocol = {
203     .name           = "tls",
204     .url_open2      = ff_tls_open,
205     .url_read       = ff_tls_read,
206     .url_write      = ff_tls_write,
207     .url_close      = ff_tls_close,
208     .url_get_file_handle = tls_get_file_handle,
209     .url_get_short_seek  = tls_get_short_seek,
210     .priv_data_size = sizeof(TLSContext),
211     .flags          = URL_PROTOCOL_FLAG_NETWORK,
212     .priv_data_class = &tls_class,
213 };
214