blob: 38af8a21c00377659bf35a2a408f03f39b4e5a68
1 | /* |
2 | * TLS/SSL Protocol |
3 | * Copyright (c) 2011 Martin Storsjo |
4 | * |
5 | * This file is part of FFmpeg. |
6 | * |
7 | * FFmpeg is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * FFmpeg is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with FFmpeg; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | */ |
21 | |
22 | #include "avformat.h" |
23 | #include "internal.h" |
24 | #include "network.h" |
25 | #include "os_support.h" |
26 | #include "url.h" |
27 | #include "tls.h" |
28 | #include "libavcodec/internal.h" |
29 | #include "libavutil/avstring.h" |
30 | #include "libavutil/avutil.h" |
31 | #include "libavutil/opt.h" |
32 | #include "libavutil/parseutils.h" |
33 | #include "libavutil/thread.h" |
34 | |
35 | #include <openssl/bio.h> |
36 | #include <openssl/ssl.h> |
37 | #include <openssl/err.h> |
38 | |
39 | static int openssl_init; |
40 | |
41 | typedef struct TLSContext { |
42 | const AVClass *class; |
43 | TLSShared tls_shared; |
44 | SSL_CTX *ctx; |
45 | SSL *ssl; |
46 | #if OPENSSL_VERSION_NUMBER >= 0x1010000fL |
47 | BIO_METHOD* url_bio_method; |
48 | #endif |
49 | } TLSContext; |
50 | |
51 | #if HAVE_THREADS |
52 | #include <openssl/crypto.h> |
53 | pthread_mutex_t *openssl_mutexes; |
54 | static void openssl_lock(int mode, int type, const char *file, int line) |
55 | { |
56 | if (mode & CRYPTO_LOCK) |
57 | pthread_mutex_lock(&openssl_mutexes[type]); |
58 | else |
59 | pthread_mutex_unlock(&openssl_mutexes[type]); |
60 | } |
61 | #if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000 |
62 | static unsigned long openssl_thread_id(void) |
63 | { |
64 | return (intptr_t) pthread_self(); |
65 | } |
66 | #endif |
67 | #endif |
68 | |
69 | static int url_bio_create(BIO *b) |
70 | { |
71 | #if OPENSSL_VERSION_NUMBER >= 0x1010000fL |
72 | BIO_set_init(b, 1); |
73 | BIO_set_data(b, NULL); |
74 | BIO_set_flags(b, 0); |
75 | #else |
76 | b->init = 1; |
77 | b->ptr = NULL; |
78 | b->flags = 0; |
79 | #endif |
80 | return 1; |
81 | } |
82 | |
83 | static int url_bio_destroy(BIO *b) |
84 | { |
85 | return 1; |
86 | } |
87 | |
88 | #if OPENSSL_VERSION_NUMBER >= 0x1010000fL |
89 | #define GET_BIO_DATA(x) BIO_get_data(x) |
90 | #else |
91 | #define GET_BIO_DATA(x) (x)->ptr |
92 | #endif |
93 | |
94 | static int url_bio_bread(BIO *b, char *buf, int len) |
95 | { |
96 | URLContext *h = GET_BIO_DATA(b); |
97 | int ret = ffurl_read(h, buf, len); |
98 | if (ret >= 0) |
99 | return ret; |
100 | BIO_clear_retry_flags(b); |
101 | if (ret == AVERROR_EXIT) |
102 | return 0; |
103 | return -1; |
104 | } |
105 | |
106 | static int url_bio_bwrite(BIO *b, const char *buf, int len) |
107 | { |
108 | URLContext *h = GET_BIO_DATA(b); |
109 | int ret = ffurl_write(h, buf, len); |
110 | if (ret >= 0) |
111 | return ret; |
112 | BIO_clear_retry_flags(b); |
113 | if (ret == AVERROR_EXIT) |
114 | return 0; |
115 | return -1; |
116 | } |
117 | |
118 | static long url_bio_ctrl(BIO *b, int cmd, long num, void *ptr) |
119 | { |
120 | if (cmd == BIO_CTRL_FLUSH) { |
121 | BIO_clear_retry_flags(b); |
122 | return 1; |
123 | } |
124 | return 0; |
125 | } |
126 | |
127 | static int url_bio_bputs(BIO *b, const char *str) |
128 | { |
129 | return url_bio_bwrite(b, str, strlen(str)); |
130 | } |
131 | |
132 | #if OPENSSL_VERSION_NUMBER < 0x1010000fL |
133 | static BIO_METHOD url_bio_method = { |
134 | .type = BIO_TYPE_SOURCE_SINK, |
135 | .name = "urlprotocol bio", |
136 | .bwrite = url_bio_bwrite, |
137 | .bread = url_bio_bread, |
138 | .bputs = url_bio_bputs, |
139 | .bgets = NULL, |
140 | .ctrl = url_bio_ctrl, |
141 | .create = url_bio_create, |
142 | .destroy = url_bio_destroy, |
143 | }; |
144 | #endif |
145 | |
146 | int ff_openssl_init(void) |
147 | { |
148 | avpriv_lock_avformat(); |
149 | if (!openssl_init) { |
150 | SSL_library_init(); |
151 | SSL_load_error_strings(); |
152 | #if HAVE_THREADS |
153 | if (!CRYPTO_get_locking_callback()) { |
154 | int i; |
155 | openssl_mutexes = av_malloc_array(sizeof(pthread_mutex_t), CRYPTO_num_locks()); |
156 | if (!openssl_mutexes) { |
157 | avpriv_unlock_avformat(); |
158 | return AVERROR(ENOMEM); |
159 | } |
160 | |
161 | for (i = 0; i < CRYPTO_num_locks(); i++) |
162 | pthread_mutex_init(&openssl_mutexes[i], NULL); |
163 | CRYPTO_set_locking_callback(openssl_lock); |
164 | #if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000 |
165 | CRYPTO_set_id_callback(openssl_thread_id); |
166 | #endif |
167 | } |
168 | #endif |
169 | } |
170 | openssl_init++; |
171 | avpriv_unlock_avformat(); |
172 | |
173 | return 0; |
174 | } |
175 | |
176 | void ff_openssl_deinit(void) |
177 | { |
178 | avpriv_lock_avformat(); |
179 | openssl_init--; |
180 | if (!openssl_init) { |
181 | #if HAVE_THREADS |
182 | if (CRYPTO_get_locking_callback() == openssl_lock) { |
183 | int i; |
184 | CRYPTO_set_locking_callback(NULL); |
185 | for (i = 0; i < CRYPTO_num_locks(); i++) |
186 | pthread_mutex_destroy(&openssl_mutexes[i]); |
187 | av_free(openssl_mutexes); |
188 | } |
189 | #endif |
190 | } |
191 | avpriv_unlock_avformat(); |
192 | } |
193 | |
194 | static int print_tls_error(URLContext *h, int ret) |
195 | { |
196 | av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); |
197 | return AVERROR(EIO); |
198 | } |
199 | |
200 | static int tls_close(URLContext *h) |
201 | { |
202 | TLSContext *c = h->priv_data; |
203 | if (c->ssl) { |
204 | SSL_shutdown(c->ssl); |
205 | SSL_free(c->ssl); |
206 | } |
207 | if (c->ctx) |
208 | SSL_CTX_free(c->ctx); |
209 | if (c->tls_shared.tcp) |
210 | ffurl_close(c->tls_shared.tcp); |
211 | #if OPENSSL_VERSION_NUMBER >= 0x1010000fL |
212 | if (c->url_bio_method) |
213 | BIO_meth_free(c->url_bio_method); |
214 | #endif |
215 | ff_openssl_deinit(); |
216 | return 0; |
217 | } |
218 | |
219 | static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) |
220 | { |
221 | TLSContext *p = h->priv_data; |
222 | TLSShared *c = &p->tls_shared; |
223 | BIO *bio; |
224 | int ret; |
225 | |
226 | if ((ret = ff_openssl_init()) < 0) |
227 | return ret; |
228 | |
229 | if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) |
230 | goto fail; |
231 | |
232 | // We want to support all versions of TLS >= 1.0, but not the deprecated |
233 | // and insecure SSLv2 and SSLv3. Despite the name, SSLv23_*_method() |
234 | // enables support for all versions of SSL and TLS, and we then disable |
235 | // support for the old protocols immediately after creating the context. |
236 | p->ctx = SSL_CTX_new(c->listen ? SSLv23_server_method() : SSLv23_client_method()); |
237 | if (!p->ctx) { |
238 | av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); |
239 | ret = AVERROR(EIO); |
240 | goto fail; |
241 | } |
242 | SSL_CTX_set_options(p->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); |
243 | if (c->ca_file) { |
244 | if (!SSL_CTX_load_verify_locations(p->ctx, c->ca_file, NULL)) |
245 | av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", ERR_error_string(ERR_get_error(), NULL)); |
246 | } |
247 | if (c->cert_file && !SSL_CTX_use_certificate_chain_file(p->ctx, c->cert_file)) { |
248 | av_log(h, AV_LOG_ERROR, "Unable to load cert file %s: %s\n", |
249 | c->cert_file, ERR_error_string(ERR_get_error(), NULL)); |
250 | ret = AVERROR(EIO); |
251 | goto fail; |
252 | } |
253 | if (c->key_file && !SSL_CTX_use_PrivateKey_file(p->ctx, c->key_file, SSL_FILETYPE_PEM)) { |
254 | av_log(h, AV_LOG_ERROR, "Unable to load key file %s: %s\n", |
255 | c->key_file, ERR_error_string(ERR_get_error(), NULL)); |
256 | ret = AVERROR(EIO); |
257 | goto fail; |
258 | } |
259 | // Note, this doesn't check that the peer certificate actually matches |
260 | // the requested hostname. |
261 | if (c->verify) |
262 | SSL_CTX_set_verify(p->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); |
263 | p->ssl = SSL_new(p->ctx); |
264 | if (!p->ssl) { |
265 | av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); |
266 | ret = AVERROR(EIO); |
267 | goto fail; |
268 | } |
269 | #if OPENSSL_VERSION_NUMBER >= 0x1010000fL |
270 | p->url_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "urlprotocol bio"); |
271 | BIO_meth_set_write(p->url_bio_method, url_bio_bwrite); |
272 | BIO_meth_set_read(p->url_bio_method, url_bio_bread); |
273 | BIO_meth_set_puts(p->url_bio_method, url_bio_bputs); |
274 | BIO_meth_set_ctrl(p->url_bio_method, url_bio_ctrl); |
275 | BIO_meth_set_create(p->url_bio_method, url_bio_create); |
276 | BIO_meth_set_destroy(p->url_bio_method, url_bio_destroy); |
277 | bio = BIO_new(p->url_bio_method); |
278 | BIO_set_data(bio, c->tcp); |
279 | #else |
280 | bio = BIO_new(&url_bio_method); |
281 | bio->ptr = c->tcp; |
282 | #endif |
283 | SSL_set_bio(p->ssl, bio, bio); |
284 | if (!c->listen && !c->numerichost) |
285 | SSL_set_tlsext_host_name(p->ssl, c->host); |
286 | ret = c->listen ? SSL_accept(p->ssl) : SSL_connect(p->ssl); |
287 | if (ret == 0) { |
288 | av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session\n"); |
289 | ret = AVERROR(EIO); |
290 | goto fail; |
291 | } else if (ret < 0) { |
292 | ret = print_tls_error(h, ret); |
293 | goto fail; |
294 | } |
295 | |
296 | return 0; |
297 | fail: |
298 | tls_close(h); |
299 | return ret; |
300 | } |
301 | |
302 | static int tls_read(URLContext *h, uint8_t *buf, int size) |
303 | { |
304 | TLSContext *c = h->priv_data; |
305 | int ret = SSL_read(c->ssl, buf, size); |
306 | if (ret > 0) |
307 | return ret; |
308 | if (ret == 0) |
309 | return AVERROR_EOF; |
310 | return print_tls_error(h, ret); |
311 | } |
312 | |
313 | static int tls_write(URLContext *h, const uint8_t *buf, int size) |
314 | { |
315 | TLSContext *c = h->priv_data; |
316 | int ret = SSL_write(c->ssl, buf, size); |
317 | if (ret > 0) |
318 | return ret; |
319 | if (ret == 0) |
320 | return AVERROR_EOF; |
321 | return print_tls_error(h, ret); |
322 | } |
323 | |
324 | static int tls_get_file_handle(URLContext *h) |
325 | { |
326 | TLSContext *c = h->priv_data; |
327 | return ffurl_get_file_handle(c->tls_shared.tcp); |
328 | } |
329 | |
330 | static const AVOption options[] = { |
331 | TLS_COMMON_OPTIONS(TLSContext, tls_shared), |
332 | { NULL } |
333 | }; |
334 | |
335 | static const AVClass tls_class = { |
336 | .class_name = "tls", |
337 | .item_name = av_default_item_name, |
338 | .option = options, |
339 | .version = LIBAVUTIL_VERSION_INT, |
340 | }; |
341 | |
342 | const URLProtocol ff_tls_openssl_protocol = { |
343 | .name = "tls", |
344 | .url_open2 = tls_open, |
345 | .url_read = tls_read, |
346 | .url_write = tls_write, |
347 | .url_close = tls_close, |
348 | .url_get_file_handle = tls_get_file_handle, |
349 | .priv_data_size = sizeof(TLSContext), |
350 | .flags = URL_PROTOCOL_FLAG_NETWORK, |
351 | .priv_data_class = &tls_class, |
352 | }; |
353 |