FFmpeg
Loading...
Searching...
No Matches
tls_gnutls.c
Go to the documentation of this file.
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 <errno.h>
23
24#include <gnutls/gnutls.h>
25#include <gnutls/dtls.h>
26#include <gnutls/x509.h>
27
28#include "config_components.h"
29
30#include "avformat.h"
31#include "network.h"
32#include "os_support.h"
33#include "url.h"
34#include "tls.h"
36#include "libavutil/mem.h"
37#include "libavutil/opt.h"
38#include "libavutil/thread.h"
40
41#ifndef GNUTLS_VERSION_NUMBER
42#define GNUTLS_VERSION_NUMBER LIBGNUTLS_VERSION_NUMBER
43#endif
44
45#if HAVE_THREADS && GNUTLS_VERSION_NUMBER <= 0x020b00
46#include <gcrypt.h>
47GCRY_THREAD_OPTION_PTHREAD_IMPL;
48#endif
49
50#define MAX_MD_SIZE 64
51
52static int pkey_to_pem_string(gnutls_x509_privkey_t key, char *out, size_t out_sz)
53{
54 size_t required_sz = out_sz - 1;
55 int ret = 0;
56
57 if (!out || !out_sz)
58 return AVERROR(EINVAL);
59
60 ret = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, out, &required_sz);
61 if (ret < 0) {
62 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
64 "TLS: Buffer size %zu is not enough to store private key PEM (need %zu)\n",
65 out_sz, required_sz + 1);
66 return AVERROR(EINVAL);
67 }
68 out[required_sz] = '\0';
69 return required_sz;
70}
71
72static int crt_to_pem_string(gnutls_x509_crt_t crt, char *out, size_t out_sz)
73{
74 size_t required_sz = out_sz - 1;
75 int ret = 0;
76
77 if (!out || !out_sz)
78 return AVERROR(EINVAL);
79
80 ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, out, &required_sz);
81 if (ret < 0) {
82 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
84 "TLS: Buffer size %zu is not enough to store certificate PEM (need %zu)\n",
85 out_sz, required_sz + 1);
86 return AVERROR(EINVAL);
87 }
88 out[required_sz] = '\0';
89 return required_sz;
90}
91
92static int gnutls_x509_fingerprint(gnutls_x509_crt_t cert, char **fingerprint)
93{
94 unsigned char md[MAX_MD_SIZE];
95 size_t n = sizeof(md);
96 AVBPrint buf;
97 int ret;
98
99 ret = gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, md, &n);
100 if (ret < 0) {
101 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint, %s\n",
102 gnutls_strerror(ret));
103 return AVERROR(EINVAL);
104 }
105
106 av_bprint_init(&buf, n*3, n*3);
107
108 for (int i = 0; i < n - 1; i++)
109 av_bprintf(&buf, "%02X:", md[i]);
110 av_bprintf(&buf, "%02X", md[n - 1]);
111
112 return av_bprint_finalize(&buf, fingerprint);
113}
114
115int ff_ssl_read_key_cert(char *key_url, char *crt_url, char *key_buf, size_t key_sz, char *crt_buf, size_t crt_sz, char **fingerprint)
116{
117 int ret = 0;
118 AVBPrint key_bp, crt_bp;
119 gnutls_x509_crt_t crt = NULL;
120 gnutls_x509_privkey_t key = NULL;
121 gnutls_datum_t tmp;
122
125
126 ret = ff_url_read_all(key_url, &key_bp);
127 if (ret < 0) {
128 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to open key file %s\n", key_url);
129 goto end;
130 }
131
132 ret = ff_url_read_all(crt_url, &crt_bp);
133 if (ret < 0) {
134 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to open certificate file %s\n", crt_url);
135 goto end;
136 }
137
138 ret = gnutls_x509_privkey_init(&key);
139 if (ret < 0) {
140 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to init private key: %s\n", gnutls_strerror(ret));
141 goto end;
142 }
143
144 ret = gnutls_x509_crt_init(&crt);
145 if (ret < 0) {
146 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to init certificate: %s\n", gnutls_strerror(ret));
147 goto end;
148 }
149
150 tmp.data = key_bp.str;
151 tmp.size = key_bp.len;
152 ret = gnutls_x509_privkey_import(key, &tmp, GNUTLS_X509_FMT_PEM);
153 if (ret < 0) {
154 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to import private key: %s\n", gnutls_strerror(ret));
155 goto end;
156 }
157
158 tmp.data = crt_bp.str;
159 tmp.size = crt_bp.len;
160 ret = gnutls_x509_crt_import(crt, &tmp, GNUTLS_X509_FMT_PEM);
161 if (ret < 0) {
162 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to import certificate: %s\n", gnutls_strerror(ret));
163 goto end;
164 }
165
166 ret = pkey_to_pem_string(key, key_buf, key_sz);
167 if (ret < 0) {
168 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to converter private key to PEM string\n");
169 goto end;
170 }
171
172 ret = crt_to_pem_string(crt, crt_buf, crt_sz);
173 if (ret < 0) {
174 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to converter certificate to PEM string\n");
175 goto end;
176 }
177
178 ret = gnutls_x509_fingerprint(crt, fingerprint);
179 if (ret < 0)
180 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint\n");
181
182end:
183 av_bprint_finalize(&key_bp, NULL);
184 av_bprint_finalize(&crt_bp, NULL);
185 if (crt)
186 gnutls_x509_crt_deinit(crt);
187 if (key)
188 gnutls_x509_privkey_deinit(key);
189 return ret;
190}
191
192static int gnutls_gen_private_key(gnutls_x509_privkey_t *key)
193{
194 int ret = 0;
195
196 ret = gnutls_x509_privkey_init(key);
197 if (ret < 0) {
198 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to init private key: %s\n", gnutls_strerror(ret));
199 goto einval_end;
200 }
201
202 ret = gnutls_x509_privkey_generate(*key, GNUTLS_PK_ECDSA,
203 GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_SECP256R1), 0);
204 if (ret < 0) {
205 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate private key: %s\n", gnutls_strerror(ret));
206 goto einval_end;
207 }
208
209 goto end;
210einval_end:
211 ret = AVERROR(EINVAL);
212 gnutls_x509_privkey_deinit(*key);
213 *key = NULL;
214end:
215 return ret;
216}
217
218static int gnutls_gen_certificate(gnutls_x509_privkey_t key, gnutls_x509_crt_t *crt, char **fingerprint)
219{
220 int ret = 0;
221 uint64_t serial;
222 unsigned char buf[8];
223 const char *dn = "CN=lavf";
224
225 ret = gnutls_x509_crt_init(crt);
226 if (ret < 0) {
227 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to init certificate: %s\n", gnutls_strerror(ret));
228 goto einval_end;
229 }
230
231 ret = gnutls_x509_crt_set_version(*crt, 3);
232 if (ret < 0) {
233 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to set certificate version: %s\n", gnutls_strerror(ret));
234 goto einval_end;
235 }
236
237 /**
238 * See https://gnutls.org/manual/gnutls.html#gnutls_005fx509_005fcrt_005fset_005fserial-1
239 * The provided serial should be a big-endian positive number (i.e. its leftmost bit should be zero).
240 */
241 serial = av_get_random_seed();
242 AV_WB64(buf, serial);
243 buf[0] &= 0x7F;
244 ret = gnutls_x509_crt_set_serial(*crt, buf, sizeof(buf));
245 if (ret < 0) {
246 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to set certificate serial: %s\n", gnutls_strerror(ret));
247 goto einval_end;
248 }
249
250 ret = gnutls_x509_crt_set_activation_time(*crt, time(NULL));
251 if (ret < 0) {
252 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to set certificate activation time: %s\n", gnutls_strerror(ret));
253 goto einval_end;
254 }
255
256 ret = gnutls_x509_crt_set_expiration_time(*crt, time(NULL) + 365 * 24 * 60 * 60);
257 if (ret < 0) {
258 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to set certificate expiration time: %s\n", gnutls_strerror(ret));
259 goto einval_end;
260 }
261
262 ret = gnutls_x509_crt_set_dn(*crt, dn, NULL);
263 if (ret < 0) {
264 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to set certificate dn: %s\n", gnutls_strerror(ret));
265 goto einval_end;
266 }
267
268 ret = gnutls_x509_crt_set_issuer_dn(*crt, dn, NULL);
269 if (ret < 0) {
270 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to set certificate issuer dn: %s\n", gnutls_strerror(ret));
271 goto einval_end;
272 }
273
274 ret = gnutls_x509_crt_set_key(*crt, key);
275 if (ret < 0) {
276 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to set key: %s\n", gnutls_strerror(ret));
277 goto einval_end;
278 }
279
280 ret = gnutls_x509_crt_sign2(*crt, *crt, key, GNUTLS_DIG_SHA256, 0);
281 if (ret < 0) {
282 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to sign certificate: %s\n", gnutls_strerror(ret));
283 goto einval_end;
284 }
285
286 ret = gnutls_x509_fingerprint(*crt, fingerprint);
287 if (ret < 0)
288 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint\n");
289
290 goto end;
291einval_end:
292 ret = AVERROR(EINVAL);
293 gnutls_x509_crt_deinit(*crt);
294 *crt = NULL;
295end:
296 return ret;
297}
298
299int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
300{
301 int ret;
302 gnutls_x509_crt_t crt = NULL;
303 gnutls_x509_privkey_t key = NULL;
304
306 if (ret < 0) {
307 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate private key\n");
308 goto end;
309 }
310
311 ret = gnutls_gen_certificate(key, &crt, fingerprint);
312 if (ret < 0) {
313 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate certificate\n");
314 goto end;
315 }
316
317 ret = pkey_to_pem_string(key, key_buf, key_sz);
318 if (ret < 0) {
319 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to convert private key to PEM string\n");
320 goto end;
321 }
322
323 ret = crt_to_pem_string(crt, cert_buf, cert_sz);
324 if (ret < 0) {
325 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to convert certificate to PEM string\n");
326 goto end;
327 }
328end:
329 if (crt)
330 gnutls_x509_crt_deinit(crt);
331 if (key)
332 gnutls_x509_privkey_deinit(key);
333 return ret;
334}
335
336typedef struct TLSContext {
338 gnutls_session_t session;
339 gnutls_certificate_credentials_t cred;
343 socklen_t dest_addr_len;
344} TLSContext;
345
347
349{
351#if HAVE_THREADS && GNUTLS_VERSION_NUMBER < 0x020b00
352 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
353 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
354#endif
355 gnutls_global_init();
357}
358
360{
362 gnutls_global_deinit();
364}
365
367{
368 TLSContext *c = h->priv_data;
369 TLSShared *s = &c->tls_shared;
370
371 if (s->is_dtls)
372 s->udp = sock;
373 else
374 s->tcp = sock;
375
376 return 0;
377}
378
379int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
380{
381 int ret = 0;
382 TLSContext *c = h->priv_data;
383
384 ret = gnutls_srtp_get_keys(c->session, dtls_srtp_materials, materials_sz, NULL, NULL, NULL, NULL);
385 if (ret < 0) {
386 av_log(c, AV_LOG_ERROR, "Failed to export SRTP material: %s\n", gnutls_strerror(ret));
387 return -1;
388 }
389 return 0;
390}
391
392static int print_tls_error(URLContext *h, int ret)
393{
394 TLSContext *c = h->priv_data;
395 switch (ret) {
396 case GNUTLS_E_AGAIN:
397 return AVERROR(EAGAIN);
398 case GNUTLS_E_INTERRUPTED:
399#ifdef GNUTLS_E_PREMATURE_TERMINATION
400 case GNUTLS_E_PREMATURE_TERMINATION:
401#endif
402 break;
403 case GNUTLS_E_WARNING_ALERT_RECEIVED:
404 av_log(h, AV_LOG_WARNING, "%s\n", gnutls_strerror(ret));
405 break;
406 default:
407 av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
408 break;
409 }
410 if (c->io_err) {
411 av_log(h, AV_LOG_ERROR, "IO error: %s\n", av_err2str(c->io_err));
412 ret = c->io_err;
413 c->io_err = 0;
414 return ret;
415 }
416 return AVERROR(EIO);
417}
418
420{
421 TLSContext *c = h->priv_data;
422 TLSShared *s = &c->tls_shared;
423 if (c->need_shutdown)
424 gnutls_bye(c->session, GNUTLS_SHUT_WR);
425 if (c->session)
426 gnutls_deinit(c->session);
427 if (c->cred)
428 gnutls_certificate_free_credentials(c->cred);
429 if (!s->external_sock)
430 ffurl_closep(s->is_dtls ? &s->udp : &s->tcp);
432 return 0;
433}
434
435static ssize_t gnutls_url_pull(gnutls_transport_ptr_t transport,
436 void *buf, size_t len)
437{
438 TLSContext *c = (TLSContext*) transport;
439 TLSShared *s = &c->tls_shared;
440 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
441 int ret = ffurl_read(uc, buf, len);
442 if (ret >= 0) {
443#if CONFIG_UDP_PROTOCOL
444 if (s->is_dtls && s->listen && !c->dest_addr_len) {
445 int err_ret;
446
447 ff_udp_get_last_recv_addr(s->udp, &c->dest_addr, &c->dest_addr_len);
448 err_ret = ff_udp_set_remote_addr(s->udp, (struct sockaddr *)&c->dest_addr, c->dest_addr_len, 1);
449 if (err_ret < 0) {
450 av_log(c, AV_LOG_ERROR, "Failed connecting udp context\n");
451 return err_ret;
452 }
453 av_log(c, AV_LOG_TRACE, "Set UDP remote addr on UDP socket, now 'connected'\n");
454 }
455#endif
456 return ret;
457 }
458 if (ret == AVERROR_EXIT)
459 return 0;
460 if (ret == AVERROR(EAGAIN)) {
461 errno = EAGAIN;
462 } else {
463 errno = EIO;
464 c->io_err = ret;
465 }
466 return -1;
467}
468
469static ssize_t gnutls_url_push(gnutls_transport_ptr_t transport,
470 const void *buf, size_t len)
471{
472 TLSContext *c = (TLSContext*) transport;
473 TLSShared *s = &c->tls_shared;
474 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
475 int ret = ffurl_write(uc, buf, len);
476 if (ret >= 0)
477 return ret;
478 if (ret == AVERROR_EXIT)
479 return 0;
480 if (ret == AVERROR(EAGAIN)) {
481 errno = EAGAIN;
482 } else {
483 errno = EIO;
484 c->io_err = ret;
485 }
486 return -1;
487}
488
489static int gnutls_pull_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
490{
491 TLSContext *c = (TLSContext*) ptr;
492 TLSShared *s = &c->tls_shared;
493 int ret;
494 int sockfd = ffurl_get_file_handle(s->udp);
495 struct pollfd pfd = { .fd = sockfd, .events = POLLIN, .revents = 0 };
496
497 if (sockfd < 0)
498 return 0;
499
500 ret = poll(&pfd, 1, ms);
501 if (ret <= 0)
502 return ret;
503 return 1;
504}
505
507{
508 TLSContext *c = h->priv_data;
509 TLSShared *s = &c->tls_shared;
510 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
511 int ret;
512
514
515 do {
516 if (ff_check_interrupt(&h->interrupt_callback)) {
517 ret = AVERROR_EXIT;
518 goto end;
519 }
520
521 ret = gnutls_handshake(c->session);
522 if (gnutls_error_is_fatal(ret)) {
523 ret = print_tls_error(h, ret);
524 goto end;
525 }
526 } while (ret);
527
528end:
529 return ret;
530}
531
532static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
533{
534 TLSContext *c = h->priv_data;
535 TLSShared *s = &c->tls_shared;
536 uint16_t gnutls_flags = 0;
537 gnutls_x509_crt_t cert = NULL;
538 gnutls_x509_privkey_t pkey = NULL;
539 int have_cert_pkey = 0;
540 int ret;
541
543
544 if (!s->external_sock) {
545 if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
546 goto fail;
547 } else if (!s->host) {
548 if ((ret = ff_tls_parse_host(s, s->underlying_host, sizeof(s->underlying_host), NULL, uri)) < 0)
549 goto fail;
550 }
551
552 gnutls_certificate_allocate_credentials(&c->cred);
553 if (s->ca_file) {
554 ret = gnutls_certificate_set_x509_trust_file(c->cred, s->ca_file, GNUTLS_X509_FMT_PEM);
555 if (ret < 0)
556 av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
557 }
558#if GNUTLS_VERSION_NUMBER >= 0x030020
559 else
560 gnutls_certificate_set_x509_system_trust(c->cred);
561#endif
562 gnutls_certificate_set_verify_flags(c->cred, s->verify ?
563 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT : 0);
564 if (s->cert_file && s->key_file) {
565 ret = gnutls_certificate_set_x509_key_file(c->cred,
566 s->cert_file, s->key_file,
567 GNUTLS_X509_FMT_PEM);
568 if (ret < 0) {
570 "Unable to set cert/key files %s and %s: %s\n",
571 s->cert_file, s->key_file, gnutls_strerror(ret));
572 ret = AVERROR(EIO);
573 goto fail;
574 }
575 have_cert_pkey = 1;
576 } else if (s->cert_file || s->key_file) {
577 av_log(h, AV_LOG_ERROR, "cert and key required\n");
578 } else if (s->cert_buf && s->key_buf) {
579 gnutls_datum_t cert_data = { .data = s->cert_buf, .size = strlen(s->cert_buf)};
580 gnutls_datum_t pkey_data = { .data = s->key_buf, .size = strlen(s->key_buf)};
581 ret = gnutls_certificate_set_x509_key_mem(c->cred, &cert_data, &pkey_data, GNUTLS_X509_FMT_PEM);
582 if (ret < 0) {
583 av_log(h, AV_LOG_ERROR, "Unable to set cert/key memory: %s\n", gnutls_strerror(ret));
584 ret = AVERROR(EINVAL);
585 goto fail;
586 }
587 have_cert_pkey = 1;
588 } else if (s->cert_buf || s->key_buf) {
589 av_log(h, AV_LOG_ERROR, "cert and key required\n");
590 }
591
592 if (s->listen && !s->cert_file && !s->cert_buf && !s->key_file && !s->key_buf) {
593 av_log(h, AV_LOG_VERBOSE, "No server certificate provided, using self-signed\n");
594
595 ret = gnutls_gen_private_key(&pkey);
596 if (ret < 0)
597 goto fail;
598
599 ret = gnutls_gen_certificate(pkey, &cert, NULL);
600 if (ret < 0)
601 goto fail;
602
603 ret = gnutls_certificate_set_x509_key(c->cred, &cert, 1, pkey);
604 if (ret < 0) {
605 av_log(h, AV_LOG_ERROR, "Unable to set self-signed certificate: %s\n", gnutls_strerror(ret));
606 ret = AVERROR(EINVAL);
607 goto fail;
608 }
609
610 have_cert_pkey = 1;
611 }
612
613 if (s->is_dtls)
614 gnutls_flags |= GNUTLS_DATAGRAM;
615
616 if (s->listen)
617 gnutls_flags |= GNUTLS_SERVER;
618 else {
619 gnutls_flags |= GNUTLS_CLIENT;
620#if GNUTLS_VERSION_NUMBER >= 0x030500
621 if (have_cert_pkey)
622 gnutls_flags |= GNUTLS_FORCE_CLIENT_CERT;
623#endif
624 }
625
626 gnutls_init(&c->session, gnutls_flags);
627
628 if (!s->listen && !s->numerichost)
629 gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, s->host, strlen(s->host));
630 gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred);
631 gnutls_transport_set_pull_function(c->session, gnutls_url_pull);
632 gnutls_transport_set_push_function(c->session, gnutls_url_push);
633 gnutls_transport_set_ptr(c->session, c);
634 if (s->is_dtls) {
635 gnutls_transport_set_pull_timeout_function(c->session, gnutls_pull_timeout);
636 if (s->mtu)
637 gnutls_dtls_set_mtu(c->session, s->mtu);
638 }
639 gnutls_set_default_priority(c->session);
640
641 if (s->use_srtp) {
642 ret = gnutls_srtp_set_profile(c->session, GNUTLS_SRTP_AES128_CM_HMAC_SHA1_80);
643 if (ret < 0) {
644 av_log(c, AV_LOG_ERROR, "Unable to set SRTP profile: %s\n", gnutls_strerror(ret));
645 ret = AVERROR(EINVAL);
646 goto fail;
647 }
648 }
649
650 if (!s->external_sock) {
651 ret = tls_handshake(h);
652 if (ret < 0)
653 goto fail;
654 }
655 c->need_shutdown = 1;
656 if (s->verify) {
657 unsigned int status, cert_list_size;
658 gnutls_x509_crt_t cert;
659 const gnutls_datum_t *cert_list;
660 if ((ret = gnutls_certificate_verify_peers2(c->session, &status)) < 0) {
661 av_log(h, AV_LOG_ERROR, "Unable to verify peer certificate: %s\n",
662 gnutls_strerror(ret));
663 ret = AVERROR(EIO);
664 goto fail;
665 }
666 if (status & GNUTLS_CERT_INVALID) {
667 av_log(h, AV_LOG_ERROR, "Peer certificate failed verification\n");
668 ret = AVERROR(EIO);
669 goto fail;
670 }
671 if (gnutls_certificate_type_get(c->session) != GNUTLS_CRT_X509) {
672 av_log(h, AV_LOG_ERROR, "Unsupported certificate type\n");
673 ret = AVERROR(EIO);
674 goto fail;
675 }
676 gnutls_x509_crt_init(&cert);
677 cert_list = gnutls_certificate_get_peers(c->session, &cert_list_size);
678 gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER);
679 ret = gnutls_x509_crt_check_hostname(cert, s->host);
680 gnutls_x509_crt_deinit(cert);
681 if (!ret) {
683 "The certificate's owner does not match hostname %s\n", s->host);
684 ret = AVERROR(EIO);
685 goto fail;
686 }
687 }
688
689 return 0;
690fail:
691 if (cert)
692 gnutls_x509_crt_deinit(cert);
693 if (pkey)
694 gnutls_x509_privkey_deinit(pkey);
695 tls_close(h);
696 return ret;
697}
698
699static int dtls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
700{
701 TLSContext *c = h->priv_data;
702 TLSShared *s = &c->tls_shared;
703 s->is_dtls = 1;
704 return tls_open(h, uri, flags, options);
705}
706
707static int tls_read(URLContext *h, uint8_t *buf, int size)
708{
709 TLSContext *c = h->priv_data;
710 TLSShared *s = &c->tls_shared;
711 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
712 int ret;
713 // Set or clear the AVIO_FLAG_NONBLOCK on the underlying socket
715 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
716 ret = gnutls_record_recv(c->session, buf, size);
717 if (ret > 0)
718 return ret;
719 if (ret == 0)
720 return AVERROR_EOF;
721 return print_tls_error(h, ret);
722}
723
724static int tls_write(URLContext *h, const uint8_t *buf, int size)
725{
726 TLSContext *c = h->priv_data;
727 TLSShared *s = &c->tls_shared;
728 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
729 int ret;
730 // Set or clear the AVIO_FLAG_NONBLOCK on the underlying socket
732 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
733
734 if (s->is_dtls) {
735 const size_t mtu_size = gnutls_dtls_get_data_mtu(c->session);
736 size = FFMIN(size, mtu_size);
737 }
738
739 ret = gnutls_record_send(c->session, buf, size);
740 if (ret > 0)
741 return ret;
742 if (ret == 0)
743 return AVERROR_EOF;
744 return print_tls_error(h, ret);
745}
746
748{
749 TLSContext *c = h->priv_data;
750 return ffurl_get_file_handle(c->tls_shared.tcp);
751}
752
754{
755 TLSContext *s = h->priv_data;
756 return ffurl_get_short_seek(s->tls_shared.tcp);
757}
758
759static const AVOption options[] = {
760 TLS_COMMON_OPTIONS(TLSContext, tls_shared),
761 { NULL }
762};
763
764static const AVClass tls_class = {
765 .class_name = "tls",
766 .item_name = av_default_item_name,
767 .option = options,
768 .version = LIBAVUTIL_VERSION_INT,
769};
770
772 .name = "tls",
773 .url_open2 = tls_open,
774 .url_read = tls_read,
775 .url_write = tls_write,
776 .url_close = tls_close,
777 .url_get_file_handle = tls_get_file_handle,
778 .url_get_short_seek = tls_get_short_seek,
779 .priv_data_size = sizeof(TLSContext),
781 .priv_data_class = &tls_class,
782};
783
784static const AVClass dtls_class = {
785 .class_name = "dtls",
786 .item_name = av_default_item_name,
787 .option = options,
788 .version = LIBAVUTIL_VERSION_INT,
789};
790
792 .name = "dtls",
793 .url_open2 = dtls_open,
794 .url_handshake = tls_handshake,
795 .url_read = tls_read,
796 .url_write = tls_write,
797 .url_close = tls_close,
798 .url_get_file_handle = tls_get_file_handle,
799 .url_get_short_seek = tls_get_short_seek,
800 .priv_data_size = sizeof(TLSContext),
802 .priv_data_class = &dtls_class,
803};
Main libavformat public API header.
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrupt a blocking function associated with cb.
Definition avio.c:922
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition avio.c:656
int ffurl_get_short_seek(void *urlcontext)
Return the current short seek threshold value for this URL.
Definition avio.c:906
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition avio.c:882
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition avio.h:636
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
const char * key
#define fail
Definition test.h:479
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:235
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition error.h:58
#define AVERROR_EOF
End of file.
Definition error.h:57
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition log.h:236
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define AV_WB64(p, v)
#define AV_MUTEX_INITIALIZER
Definition thread.h:185
static int ff_mutex_unlock(AVMutex *mutex)
Definition thread.h:189
static int ff_mutex_lock(AVMutex *mutex)
Definition thread.h:188
#define AVMutex
Definition thread.h:184
#define FFMIN(a, b)
Definition macros.h:49
Memory handling functions.
int ff_udp_set_remote_addr(URLContext *h, const struct sockaddr *dest_addr, socklen_t dest_addr_len, int do_connect)
This function is identical to ff_udp_set_remote_url, except that it takes a sockaddr directly.
Definition udp.c:472
void ff_udp_get_last_recv_addr(URLContext *h, struct sockaddr_storage *addr, socklen_t *addr_len)
Definition udp.c:510
AVOptions.
miscellaneous OS support macros and functions.
const URLProtocol ff_dtls_protocol
Definition tls_gnutls.c:791
const URLProtocol ff_tls_protocol
Definition tls_gnutls.c:771
Describe the class of an AVClass context structure.
Definition log.h:76
AVOption.
Definition opt.h:428
socklen_t dest_addr_len
Definition tls_gnutls.c:343
gnutls_session_t session
Definition tls_gnutls.c:338
struct sockaddr_storage dest_addr
Definition tls_gnutls.c:342
gnutls_certificate_credentials_t cred
Definition tls_gnutls.c:339
int need_shutdown
Definition tls_gnutls.c:340
TLSShared tls_shared
Definition tls_gnutls.c:337
int flags
Definition url.h:40
#define av_log(a,...)
static uint8_t tmp[40]
Definition aes_ctr.c:52
static FILE * out
Definition movenc.c:55
int ff_url_read_all(const char *url, AVBPrint *bp)
Read all data from the given URL url and store it in the given buffer bp.
Definition tls.c:128
int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AVDictionary **options)
Definition tls.c:54
int ff_tls_parse_host(TLSShared *s, char *hostname, int hostname_size, int *port_ptr, const char *uri)
Definition tls.c:35
#define MAX_CERTIFICATE_SIZE
Maximum size limit of a certificate and private key size.
Definition tls.h:34
#define TLS_COMMON_OPTIONS(pstruct, options_field)
Definition tls.h:101
static int tls_handshake(URLContext *h)
Definition tls_gnutls.c:506
void ff_gnutls_deinit(void)
Definition tls_gnutls.c:359
static int tls_close(URLContext *h)
Definition tls_gnutls.c:419
static const AVClass tls_class
Definition tls_gnutls.c:764
static ssize_t gnutls_url_push(gnutls_transport_ptr_t transport, const void *buf, size_t len)
Definition tls_gnutls.c:469
void ff_gnutls_init(void)
Definition tls_gnutls.c:348
int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
Definition tls_gnutls.c:299
static ssize_t gnutls_url_pull(gnutls_transport_ptr_t transport, void *buf, size_t len)
Definition tls_gnutls.c:435
static int tls_read(URLContext *h, uint8_t *buf, int size)
Definition tls_gnutls.c:707
#define MAX_MD_SIZE
Definition tls_gnutls.c:50
static int dtls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition tls_gnutls.c:699
int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
Definition tls_gnutls.c:379
static int gnutls_gen_certificate(gnutls_x509_privkey_t key, gnutls_x509_crt_t *crt, char **fingerprint)
Definition tls_gnutls.c:218
static int crt_to_pem_string(gnutls_x509_crt_t crt, char *out, size_t out_sz)
Definition tls_gnutls.c:72
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition tls_gnutls.c:532
static int pkey_to_pem_string(gnutls_x509_privkey_t key, char *out, size_t out_sz)
Definition tls_gnutls.c:52
static int tls_get_short_seek(URLContext *h)
Definition tls_gnutls.c:753
static int tls_write(URLContext *h, const uint8_t *buf, int size)
Definition tls_gnutls.c:724
static const AVClass dtls_class
Definition tls_gnutls.c:784
static int print_tls_error(URLContext *h, int ret)
Definition tls_gnutls.c:392
static int gnutls_x509_fingerprint(gnutls_x509_crt_t cert, char **fingerprint)
Definition tls_gnutls.c:92
static int tls_get_file_handle(URLContext *h)
Definition tls_gnutls.c:747
int ff_ssl_read_key_cert(char *key_url, char *crt_url, char *key_buf, size_t key_sz, char *crt_buf, size_t crt_sz, char **fingerprint)
Definition tls_gnutls.c:115
int ff_tls_set_external_socket(URLContext *h, URLContext *sock)
Definition tls_gnutls.c:366
static int gnutls_pull_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
Definition tls_gnutls.c:489
static AVMutex gnutls_mutex
Definition tls_gnutls.c:346
static int gnutls_gen_private_key(gnutls_x509_privkey_t *key)
Definition tls_gnutls.c:192
int size
unbuffered private I/O API
static int ffurl_write(URLContext *h, const uint8_t *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition url.h:204
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition url.h:183
#define URL_PROTOCOL_FLAG_NETWORK
Definition url.h:33
#define md
int len
static double c[64]