FFmpeg
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"
35 #include "libavutil/intreadwrite.h"
36 #include "libavutil/mem.h"
37 #include "libavutil/opt.h"
38 #include "libavutil/thread.h"
39 #include "libavutil/random_seed.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>
47 GCRY_THREAD_OPTION_PTHREAD_IMPL;
48 #endif
49 
50 #define MAX_MD_SIZE 64
51 
52 static 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 
72 static 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 
92 static 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 
115 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)
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 
182 end:
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 
192 static 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;
210 einval_end:
211  ret = AVERROR(EINVAL);
212  gnutls_x509_privkey_deinit(*key);
213  *key = NULL;
214 end:
215  return ret;
216 }
217 
218 static 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;
291 einval_end:
292  ret = AVERROR(EINVAL);
293  gnutls_x509_crt_deinit(*crt);
294  *crt = NULL;
295 end:
296  return ret;
297 }
298 
299 int 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  }
328 end:
329  if (crt)
330  gnutls_x509_crt_deinit(crt);
331  if (key)
332  gnutls_x509_privkey_deinit(key);
333  return ret;
334 }
335 
336 typedef struct TLSContext {
338  gnutls_session_t session;
339  gnutls_certificate_credentials_t cred;
341  int io_err;
343  socklen_t dest_addr_len;
344 } TLSContext;
345 
347 
348 void ff_gnutls_init(void)
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 
379 int 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 
392 static 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 
419 static int tls_close(URLContext *h)
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 
435 static 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 
469 static 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 
489 static 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 
513  uc->flags &= ~AVIO_FLAG_NONBLOCK;
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 
528 end:
529  return ret;
530 }
531 
532 static 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 
542  ff_gnutls_init();
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;
690 fail:
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 
699 static 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 
707 static 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
714  uc->flags &= ~AVIO_FLAG_NONBLOCK;
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 
724 static 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
731  uc->flags &= ~AVIO_FLAG_NONBLOCK;
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 
759 static const AVOption options[] = {
760  TLS_COMMON_OPTIONS(TLSContext, tls_shared),
761  { NULL }
762 };
763 
764 static 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 
784 static 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 };
ff_gnutls_init
void ff_gnutls_init(void)
Definition: tls_gnutls.c:348
flags
const SwsFlags flags[]
Definition: swscale.c:85
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
TLSContext
Definition: tls_gnutls.c:336
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
gnutls_x509_fingerprint
static int gnutls_x509_fingerprint(gnutls_x509_crt_t cert, char **fingerprint)
Definition: tls_gnutls.c:92
ff_ssl_gen_key_cert
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
URL_PROTOCOL_FLAG_NETWORK
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:33
out
static FILE * out
Definition: movenc.c:55
gnutls_url_pull
static ssize_t gnutls_url_pull(gnutls_transport_ptr_t transport, void *buf, size_t len)
Definition: tls_gnutls.c:435
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
thread.h
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
ffurl_write
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:202
md
#define md
Definition: vf_colormatrix.c:101
ff_ssl_read_key_cert
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
print_tls_error
static int print_tls_error(URLContext *h, int ret)
Definition: tls_gnutls.c:392
AVOption
AVOption.
Definition: opt.h:429
ff_dtls_export_materials
int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
Definition: tls_gnutls.c:379
tls_class
static const AVClass tls_class
Definition: tls_gnutls.c:764
ff_tls_set_external_socket
int ff_tls_set_external_socket(URLContext *h, URLContext *sock)
Definition: tls_gnutls.c:366
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
tls_write
static int tls_write(URLContext *h, const uint8_t *buf, int size)
Definition: tls_gnutls.c:724
AVDictionary
Definition: dict.c:32
URLProtocol
Definition: url.h:51
os_support.h
AV_WB64
#define AV_WB64(p, v)
Definition: intreadwrite.h:429
sockaddr_storage
Definition: network.h:111
av_get_random_seed
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
Definition: random_seed.c:196
ff_mutex_unlock
static int ff_mutex_unlock(AVMutex *mutex)
Definition: thread.h:189
TLSContext::cred
gnutls_certificate_credentials_t cred
Definition: tls_gnutls.c:339
TLS_COMMON_OPTIONS
#define TLS_COMMON_OPTIONS(pstruct, options_field)
Definition: tls.h:108
gnutls_gen_certificate
static int gnutls_gen_certificate(gnutls_x509_privkey_t key, gnutls_x509_crt_t *crt, char **fingerprint)
Definition: tls_gnutls.c:218
ffurl_get_short_seek
int ffurl_get_short_seek(void *urlcontext)
Return the current short seek threshold value for this URL.
Definition: avio.c:844
gnutls_mutex
static AVMutex gnutls_mutex
Definition: tls_gnutls.c:346
ff_check_interrupt
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrupt a blocking function associated with cb.
Definition: avio.c:860
crt_to_pem_string
static int crt_to_pem_string(gnutls_x509_crt_t crt, char *out, size_t out_sz)
Definition: tls_gnutls.c:72
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
tls_open
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: tls_gnutls.c:532
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
AVMutex
#define AVMutex
Definition: thread.h:184
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
URLContext::flags
int flags
Definition: url.h:40
key
const char * key
Definition: hwcontext_opencl.c:189
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
dtls_class
static const AVClass dtls_class
Definition: tls_gnutls.c:784
tls_close
static int tls_close(URLContext *h)
Definition: tls_gnutls.c:419
fail
#define fail
Definition: test.h:478
ff_udp_set_remote_addr
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
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
NULL
#define NULL
Definition: coverity.c:32
ff_tls_parse_host
int ff_tls_parse_host(TLSShared *s, char *hostname, int hostname_size, int *port_ptr, const char *uri)
Definition: tls.c:35
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:242
ff_udp_get_last_recv_addr
void ff_udp_get_last_recv_addr(URLContext *h, struct sockaddr_storage *addr, socklen_t *addr_len)
Definition: udp.c:510
options
Definition: swscale.c:50
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
pkey_to_pem_string
static int pkey_to_pem_string(gnutls_x509_privkey_t key, char *out, size_t out_sz)
Definition: tls_gnutls.c:52
ff_url_read_all
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
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
AV_MUTEX_INITIALIZER
#define AV_MUTEX_INITIALIZER
Definition: thread.h:185
size
int size
Definition: twinvq_data.h:10344
TLSContext::tls_shared
TLSShared tls_shared
Definition: tls_gnutls.c:337
URLProtocol::name
const char * name
Definition: url.h:52
gnutls_gen_private_key
static int gnutls_gen_private_key(gnutls_x509_privkey_t *key)
Definition: tls_gnutls.c:192
TLSContext::io_err
int io_err
Definition: tls_gnutls.c:341
tls_get_file_handle
static int tls_get_file_handle(URLContext *h)
Definition: tls_gnutls.c:747
gnutls_url_push
static ssize_t gnutls_url_push(gnutls_transport_ptr_t transport, const void *buf, size_t len)
Definition: tls_gnutls.c:469
ff_mutex_lock
static int ff_mutex_lock(AVMutex *mutex)
Definition: thread.h:188
TLSContext::dest_addr
struct sockaddr_storage dest_addr
Definition: tls_gnutls.c:342
tls_handshake
static int tls_handshake(URLContext *h)
Definition: tls_gnutls.c:506
tls_get_short_seek
static int tls_get_short_seek(URLContext *h)
Definition: tls_gnutls.c:753
URLContext
Definition: url.h:35
dtls_open
static int dtls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: tls_gnutls.c:699
TLSContext::dest_addr_len
socklen_t dest_addr_len
Definition: tls_gnutls.c:343
ff_tls_protocol
const URLProtocol ff_tls_protocol
Definition: tls_gnutls.c:771
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
url.h
len
int len
Definition: vorbis_enc_data.h:426
ffurl_closep
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:594
ff_tls_open_underlying
int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AVDictionary **options)
Definition: tls.c:54
ret
ret
Definition: filter_design.txt:187
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:81
avformat.h
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
network.h
tls.h
status
ov_status_e status
Definition: dnn_backend_openvino.c:100
random_seed.h
ff_dtls_protocol
const URLProtocol ff_dtls_protocol
Definition: tls_gnutls.c:791
TLSContext::need_shutdown
int need_shutdown
Definition: tls_gnutls.c:340
options
static const AVOption options[]
Definition: tls_gnutls.c:759
gnutls_pull_timeout
static int gnutls_pull_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
Definition: tls_gnutls.c:489
mem.h
MAX_CERTIFICATE_SIZE
#define MAX_CERTIFICATE_SIZE
Maximum size limit of a certificate and private key size.
Definition: tls.h:35
tls_read
static int tls_read(URLContext *h, uint8_t *buf, int size)
Definition: tls_gnutls.c:707
TLSContext::session
gnutls_session_t session
Definition: tls_gnutls.c:338
TLSShared
Definition: tls.h:57
AVIO_FLAG_NONBLOCK
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:636
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2070
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:58
MAX_MD_SIZE
#define MAX_MD_SIZE
Definition: tls_gnutls.c:50
ff_gnutls_deinit
void ff_gnutls_deinit(void)
Definition: tls_gnutls.c:359
ffurl_get_file_handle
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:820
ffurl_read
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:181