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 /* Use EINTR, not 0: returning 0 would cause GnuTLS to busy-spin. */
480 errno = EINTR;
481 } else if (ret == AVERROR(EAGAIN)) {
482 errno = EAGAIN;
483 } else {
484 errno = EIO;
485 c->io_err = ret;
486 }
487 return -1;
488}
489
490static int gnutls_pull_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
491{
492 TLSContext *c = (TLSContext*) ptr;
493 TLSShared *s = &c->tls_shared;
494 int ret;
495 int sockfd = ffurl_get_file_handle(s->udp);
496 struct pollfd pfd = { .fd = sockfd, .events = POLLIN, .revents = 0 };
497
498 if (sockfd < 0)
499 return 0;
500
501 ret = poll(&pfd, 1, ms);
502 if (ret <= 0)
503 return ret;
504 return 1;
505}
506
508{
509 TLSContext *c = h->priv_data;
510 TLSShared *s = &c->tls_shared;
511 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
512 int ret;
513
515
516 do {
517 if (ff_check_interrupt(&h->interrupt_callback)) {
518 ret = AVERROR_EXIT;
519 goto end;
520 }
521
522 ret = gnutls_handshake(c->session);
523 if (gnutls_error_is_fatal(ret)) {
524 ret = print_tls_error(h, ret);
525 goto end;
526 }
527 } while (ret);
528
529end:
530 return ret;
531}
532
533static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
534{
535 TLSContext *c = h->priv_data;
536 TLSShared *s = &c->tls_shared;
537 uint16_t gnutls_flags = 0;
538 gnutls_x509_crt_t cert = NULL;
539 gnutls_x509_privkey_t pkey = NULL;
540 int have_cert_pkey = 0;
541 int ret;
542
544
545 if (!s->external_sock) {
546 if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
547 goto fail;
548 } else if (!s->host) {
549 if ((ret = ff_tls_parse_host(s, s->underlying_host, sizeof(s->underlying_host), NULL, uri)) < 0)
550 goto fail;
551 }
552
553 gnutls_certificate_allocate_credentials(&c->cred);
554 if (s->ca_file) {
555 ret = gnutls_certificate_set_x509_trust_file(c->cred, s->ca_file, GNUTLS_X509_FMT_PEM);
556 if (ret < 0)
557 av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
558 }
559#if GNUTLS_VERSION_NUMBER >= 0x030020
560 else
561 gnutls_certificate_set_x509_system_trust(c->cred);
562#endif
563 gnutls_certificate_set_verify_flags(c->cred, s->verify ?
564 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT : 0);
565 if (s->cert_file && s->key_file) {
566 ret = gnutls_certificate_set_x509_key_file(c->cred,
567 s->cert_file, s->key_file,
568 GNUTLS_X509_FMT_PEM);
569 if (ret < 0) {
571 "Unable to set cert/key files %s and %s: %s\n",
572 s->cert_file, s->key_file, gnutls_strerror(ret));
573 ret = AVERROR(EIO);
574 goto fail;
575 }
576 have_cert_pkey = 1;
577 } else if (s->cert_file || s->key_file) {
578 av_log(h, AV_LOG_ERROR, "cert and key required\n");
579 } else if (s->cert_buf && s->key_buf) {
580 gnutls_datum_t cert_data = { .data = s->cert_buf, .size = strlen(s->cert_buf)};
581 gnutls_datum_t pkey_data = { .data = s->key_buf, .size = strlen(s->key_buf)};
582 ret = gnutls_certificate_set_x509_key_mem(c->cred, &cert_data, &pkey_data, GNUTLS_X509_FMT_PEM);
583 if (ret < 0) {
584 av_log(h, AV_LOG_ERROR, "Unable to set cert/key memory: %s\n", gnutls_strerror(ret));
585 ret = AVERROR(EINVAL);
586 goto fail;
587 }
588 have_cert_pkey = 1;
589 } else if (s->cert_buf || s->key_buf) {
590 av_log(h, AV_LOG_ERROR, "cert and key required\n");
591 }
592
593 if (s->listen && !s->cert_file && !s->cert_buf && !s->key_file && !s->key_buf) {
594 av_log(h, AV_LOG_VERBOSE, "No server certificate provided, using self-signed\n");
595
596 ret = gnutls_gen_private_key(&pkey);
597 if (ret < 0)
598 goto fail;
599
600 ret = gnutls_gen_certificate(pkey, &cert, NULL);
601 if (ret < 0)
602 goto fail;
603
604 ret = gnutls_certificate_set_x509_key(c->cred, &cert, 1, pkey);
605 if (ret < 0) {
606 av_log(h, AV_LOG_ERROR, "Unable to set self-signed certificate: %s\n", gnutls_strerror(ret));
607 ret = AVERROR(EINVAL);
608 goto fail;
609 }
610
611 have_cert_pkey = 1;
612 }
613
614 if (s->is_dtls)
615 gnutls_flags |= GNUTLS_DATAGRAM;
616
617 if (s->listen)
618 gnutls_flags |= GNUTLS_SERVER;
619 else {
620 gnutls_flags |= GNUTLS_CLIENT;
621#if GNUTLS_VERSION_NUMBER >= 0x030500
622 if (have_cert_pkey)
623 gnutls_flags |= GNUTLS_FORCE_CLIENT_CERT;
624#endif
625 }
626
627 gnutls_init(&c->session, gnutls_flags);
628
629 if (!s->listen && !s->numerichost)
630 gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, s->host, strlen(s->host));
631 gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred);
632 gnutls_transport_set_pull_function(c->session, gnutls_url_pull);
633 gnutls_transport_set_push_function(c->session, gnutls_url_push);
634 gnutls_transport_set_ptr(c->session, c);
635 if (s->is_dtls) {
636 gnutls_transport_set_pull_timeout_function(c->session, gnutls_pull_timeout);
637 if (s->mtu)
638 gnutls_dtls_set_mtu(c->session, s->mtu);
639 }
640 gnutls_set_default_priority(c->session);
641
642 if (s->use_srtp) {
643 ret = gnutls_srtp_set_profile(c->session, GNUTLS_SRTP_AES128_CM_HMAC_SHA1_80);
644 if (ret < 0) {
645 av_log(c, AV_LOG_ERROR, "Unable to set SRTP profile: %s\n", gnutls_strerror(ret));
646 ret = AVERROR(EINVAL);
647 goto fail;
648 }
649 }
650
651 if (!s->external_sock) {
652 ret = tls_handshake(h);
653 if (ret < 0)
654 goto fail;
655 }
656 c->need_shutdown = 1;
657 if (s->verify) {
658 unsigned int status, cert_list_size;
659 gnutls_x509_crt_t cert;
660 const gnutls_datum_t *cert_list;
661 if ((ret = gnutls_certificate_verify_peers2(c->session, &status)) < 0) {
662 av_log(h, AV_LOG_ERROR, "Unable to verify peer certificate: %s\n",
663 gnutls_strerror(ret));
664 ret = AVERROR(EIO);
665 goto fail;
666 }
667 if (status & GNUTLS_CERT_INVALID) {
668 av_log(h, AV_LOG_ERROR, "Peer certificate failed verification\n");
669 ret = AVERROR(EIO);
670 goto fail;
671 }
672 if (gnutls_certificate_type_get(c->session) != GNUTLS_CRT_X509) {
673 av_log(h, AV_LOG_ERROR, "Unsupported certificate type\n");
674 ret = AVERROR(EIO);
675 goto fail;
676 }
677 gnutls_x509_crt_init(&cert);
678 cert_list = gnutls_certificate_get_peers(c->session, &cert_list_size);
679 gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER);
680 ret = gnutls_x509_crt_check_hostname(cert, s->host);
681 gnutls_x509_crt_deinit(cert);
682 if (!ret) {
684 "The certificate's owner does not match hostname %s\n", s->host);
685 ret = AVERROR(EIO);
686 goto fail;
687 }
688 }
689
690 return 0;
691fail:
692 if (cert)
693 gnutls_x509_crt_deinit(cert);
694 if (pkey)
695 gnutls_x509_privkey_deinit(pkey);
696 tls_close(h);
697 return ret;
698}
699
700static int dtls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
701{
702 TLSContext *c = h->priv_data;
703 TLSShared *s = &c->tls_shared;
704 s->is_dtls = 1;
705 return tls_open(h, uri, flags, options);
706}
707
708static int tls_read(URLContext *h, uint8_t *buf, int size)
709{
710 TLSContext *c = h->priv_data;
711 TLSShared *s = &c->tls_shared;
712 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
713 int ret;
714 // Set or clear the AVIO_FLAG_NONBLOCK on the underlying socket
716 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
717 ret = gnutls_record_recv(c->session, buf, size);
718 if (ret > 0)
719 return ret;
720 if (ret == 0)
721 return AVERROR_EOF;
722 return print_tls_error(h, ret);
723}
724
725static int tls_write(URLContext *h, const uint8_t *buf, int size)
726{
727 TLSContext *c = h->priv_data;
728 TLSShared *s = &c->tls_shared;
729 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
730 int ret;
731 // Set or clear the AVIO_FLAG_NONBLOCK on the underlying socket
733 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
734
735 if (s->is_dtls) {
736 const size_t mtu_size = gnutls_dtls_get_data_mtu(c->session);
737 size = FFMIN(size, mtu_size);
738 }
739
740 ret = gnutls_record_send(c->session, buf, size);
741 if (ret > 0)
742 return ret;
743 if (ret == 0)
744 return AVERROR_EOF;
745 return print_tls_error(h, ret);
746}
747
749{
750 TLSContext *c = h->priv_data;
751 return ffurl_get_file_handle(c->tls_shared.tcp);
752}
753
755{
756 TLSContext *s = h->priv_data;
757 return ffurl_get_short_seek(s->tls_shared.tcp);
758}
759
760static const AVOption options[] = {
761 TLS_COMMON_OPTIONS(TLSContext, tls_shared),
762 { NULL }
763};
764
765static const AVClass tls_class = {
766 .class_name = "tls",
767 .item_name = av_default_item_name,
768 .option = options,
769 .version = LIBAVUTIL_VERSION_INT,
770};
771
773 .name = "tls",
774 .url_open2 = tls_open,
775 .url_read = tls_read,
776 .url_write = tls_write,
777 .url_close = tls_close,
778 .url_get_file_handle = tls_get_file_handle,
779 .url_get_short_seek = tls_get_short_seek,
780 .priv_data_size = sizeof(TLSContext),
782 .priv_data_class = &tls_class,
783};
784
785static const AVClass dtls_class = {
786 .class_name = "dtls",
787 .item_name = av_default_item_name,
788 .option = options,
789 .version = LIBAVUTIL_VERSION_INT,
790};
791
793 .name = "dtls",
794 .url_open2 = dtls_open,
795 .url_handshake = tls_handshake,
796 .url_read = tls_read,
797 .url_write = tls_write,
798 .url_close = tls_close,
799 .url_get_file_handle = tls_get_file_handle,
800 .url_get_short_seek = tls_get_short_seek,
801 .priv_data_size = sizeof(TLSContext),
803 .priv_data_class = &dtls_class,
804};
static FILE * out
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:929
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition avio.c:663
int ffurl_get_short_seek(void *urlcontext)
Return the current short seek threshold value for this URL.
Definition avio.c:913
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition avio.c:889
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition avio.h:636
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:121
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:68
#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:234
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:792
const URLProtocol ff_tls_protocol
Definition tls_gnutls.c:772
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
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:507
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:765
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:708
#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:700
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:533
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:754
static int tls_write(URLContext *h, const uint8_t *buf, int size)
Definition tls_gnutls.c:725
static const AVClass dtls_class
Definition tls_gnutls.c:785
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:748
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:490
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:205
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:184
#define URL_PROTOCOL_FLAG_NETWORK
Definition url.h:33
#define md
int len
static double c[64]