FFmpeg
tls_mbedtls.c
Go to the documentation of this file.
1 /*
2  * TLS/SSL Protocol
3  * Copyright (c) 2018 Thomas Volkert
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 <mbedtls/version.h>
23 #include <mbedtls/ctr_drbg.h>
24 #include <mbedtls/entropy.h>
25 #include <mbedtls/net_sockets.h>
26 #include <mbedtls/platform.h>
27 #include <mbedtls/ssl.h>
28 #include <mbedtls/x509_crt.h>
29 
30 #include "avformat.h"
31 #include "internal.h"
32 #include "url.h"
33 #include "tls.h"
34 #include "libavutil/parseutils.h"
35 
36 typedef struct TLSContext {
37  const AVClass *class;
39  mbedtls_ssl_context ssl_context;
40  mbedtls_ssl_config ssl_config;
41  mbedtls_entropy_context entropy_context;
42  mbedtls_ctr_drbg_context ctr_drbg_context;
43  mbedtls_x509_crt ca_cert;
44  mbedtls_x509_crt own_cert;
45  mbedtls_pk_context priv_key;
46  char *priv_key_pw;
47 } TLSContext;
48 
49 #define OFFSET(x) offsetof(TLSContext, x)
50 
51 static int tls_close(URLContext *h)
52 {
53  TLSContext *tls_ctx = h->priv_data;
54 
55  mbedtls_ssl_close_notify(&tls_ctx->ssl_context);
56  mbedtls_pk_free(&tls_ctx->priv_key);
57  mbedtls_x509_crt_free(&tls_ctx->ca_cert);
58  mbedtls_x509_crt_free(&tls_ctx->own_cert);
59  mbedtls_ssl_free(&tls_ctx->ssl_context);
60  mbedtls_ssl_config_free(&tls_ctx->ssl_config);
61  mbedtls_ctr_drbg_free(&tls_ctx->ctr_drbg_context);
62  mbedtls_entropy_free(&tls_ctx->entropy_context);
63 
64  ffurl_closep(&tls_ctx->tls_shared.tcp);
65  return 0;
66 }
67 
68 static int handle_transport_error(URLContext *h, const char* func_name, int react_on_eagain, int ret)
69 {
70  switch (ret) {
71  case AVERROR(EAGAIN):
72  return react_on_eagain;
73  case AVERROR_EXIT:
74  return 0;
75  case AVERROR(EPIPE):
76  case AVERROR(ECONNRESET):
77  return MBEDTLS_ERR_NET_CONN_RESET;
78  default:
79  av_log(h, AV_LOG_ERROR, "%s returned 0x%x\n", func_name, ret);
80  errno = EIO;
81  return MBEDTLS_ERR_NET_SEND_FAILED;
82  }
83 }
84 
85 static int mbedtls_send(void *ctx, const unsigned char *buf, size_t len)
86 {
87  URLContext *h = (URLContext*) ctx;
88  int ret = ffurl_write(h, buf, len);
89  if (ret >= 0)
90  return ret;
91 
92  if (h->max_packet_size && len > h->max_packet_size)
93  return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
94 
95  return handle_transport_error(h, "ffurl_write", MBEDTLS_ERR_SSL_WANT_WRITE, ret);
96 }
97 
98 static int mbedtls_recv(void *ctx, unsigned char *buf, size_t len)
99 {
100  URLContext *h = (URLContext*) ctx;
101  int ret = ffurl_read(h, buf, len);
102  if (ret >= 0)
103  return ret;
104 
105  if (h->max_packet_size && len > h->max_packet_size)
106  return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
107 
108  return handle_transport_error(h, "ffurl_read", MBEDTLS_ERR_SSL_WANT_READ, ret);
109 }
110 
112 {
113  switch (ret) {
114  case MBEDTLS_ERR_PK_FILE_IO_ERROR:
115  av_log(h, AV_LOG_ERROR, "Read of key file failed. Is it actually there, are the access permissions correct?\n");
116  break;
117  case MBEDTLS_ERR_PK_PASSWORD_REQUIRED:
118  av_log(h, AV_LOG_ERROR, "A password for the private key is missing.\n");
119  break;
120  case MBEDTLS_ERR_PK_PASSWORD_MISMATCH:
121  av_log(h, AV_LOG_ERROR, "The given password for the private key is wrong.\n");
122  break;
123  default:
124  av_log(h, AV_LOG_ERROR, "mbedtls_pk_parse_key returned -0x%x\n", -ret);
125  break;
126  }
127 }
128 
130 {
131  switch (ret) {
132 #if MBEDTLS_VERSION_MAJOR < 3
133  case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE:
134  av_log(h, AV_LOG_ERROR, "None of the common ciphersuites is usable. Was the local certificate correctly set?\n");
135  break;
136 #else
137  case MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:
138  av_log(h, AV_LOG_ERROR, "TLS handshake failed.\n");
139  break;
140 #endif
141  case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE:
142  av_log(h, AV_LOG_ERROR, "A fatal alert message was received from the peer, has the peer a correct certificate?\n");
143  break;
144  case MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED:
145  av_log(h, AV_LOG_ERROR, "No CA chain is set, but required to operate. Was the CA correctly set?\n");
146  break;
147  case MBEDTLS_ERR_NET_CONN_RESET:
148  av_log(h, AV_LOG_ERROR, "TLS handshake was aborted by peer.\n");
149  break;
150  default:
151  av_log(h, AV_LOG_ERROR, "mbedtls_ssl_handshake returned -0x%x\n", -ret);
152  break;
153  }
154 }
155 
156 static void parse_options(TLSContext *tls_ctxc, const char *uri)
157 {
158  char buf[1024];
159  const char *p = strchr(uri, '?');
160  if (!p)
161  return;
162 
163  if (!tls_ctxc->priv_key_pw && av_find_info_tag(buf, sizeof(buf), "key_password", p))
164  tls_ctxc->priv_key_pw = av_strdup(buf);
165 }
166 
167 static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
168 {
169  TLSContext *tls_ctx = h->priv_data;
170  TLSShared *shr = &tls_ctx->tls_shared;
171  uint32_t verify_res_flags;
172  int ret;
173 
174  // parse additional options
175  parse_options(tls_ctx, uri);
176 
177  if ((ret = ff_tls_open_underlying(shr, h, uri, options)) < 0)
178  goto fail;
179 
180  mbedtls_ssl_init(&tls_ctx->ssl_context);
181  mbedtls_ssl_config_init(&tls_ctx->ssl_config);
182  mbedtls_entropy_init(&tls_ctx->entropy_context);
183  mbedtls_ctr_drbg_init(&tls_ctx->ctr_drbg_context);
184  mbedtls_x509_crt_init(&tls_ctx->ca_cert);
185  mbedtls_pk_init(&tls_ctx->priv_key);
186 
187  // load trusted CA
188  if (shr->ca_file) {
189  if ((ret = mbedtls_x509_crt_parse_file(&tls_ctx->ca_cert, shr->ca_file)) != 0) {
190  av_log(h, AV_LOG_ERROR, "mbedtls_x509_crt_parse_file for CA cert returned %d\n", ret);
191  goto fail;
192  }
193  }
194 
195  // load own certificate
196  if (shr->cert_file) {
197  if ((ret = mbedtls_x509_crt_parse_file(&tls_ctx->own_cert, shr->cert_file)) != 0) {
198  av_log(h, AV_LOG_ERROR, "mbedtls_x509_crt_parse_file for own cert returned %d\n", ret);
199  goto fail;
200  }
201  }
202 
203  // seed the random number generator
204  if ((ret = mbedtls_ctr_drbg_seed(&tls_ctx->ctr_drbg_context,
205  mbedtls_entropy_func,
206  &tls_ctx->entropy_context,
207  NULL, 0)) != 0) {
208  av_log(h, AV_LOG_ERROR, "mbedtls_ctr_drbg_seed returned %d\n", ret);
209  goto fail;
210  }
211 
212  // load key file
213  if (shr->key_file) {
214  if ((ret = mbedtls_pk_parse_keyfile(&tls_ctx->priv_key,
215  shr->key_file,
216  tls_ctx->priv_key_pw
217 #if MBEDTLS_VERSION_MAJOR >= 3
218  , mbedtls_ctr_drbg_random,
219  &tls_ctx->ctr_drbg_context
220 #endif
221  )) != 0) {
223  goto fail;
224  }
225  }
226 
227  if ((ret = mbedtls_ssl_config_defaults(&tls_ctx->ssl_config,
228  shr->listen ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
229  MBEDTLS_SSL_TRANSPORT_STREAM,
230  MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
231  av_log(h, AV_LOG_ERROR, "mbedtls_ssl_config_defaults returned %d\n", ret);
232  goto fail;
233  }
234 
235  mbedtls_ssl_conf_authmode(&tls_ctx->ssl_config,
236  shr->ca_file ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE);
237  mbedtls_ssl_conf_rng(&tls_ctx->ssl_config, mbedtls_ctr_drbg_random, &tls_ctx->ctr_drbg_context);
238  mbedtls_ssl_conf_ca_chain(&tls_ctx->ssl_config, &tls_ctx->ca_cert, NULL);
239 
240  // set own certificate and private key
241  if ((ret = mbedtls_ssl_conf_own_cert(&tls_ctx->ssl_config, &tls_ctx->own_cert, &tls_ctx->priv_key)) != 0) {
242  av_log(h, AV_LOG_ERROR, "mbedtls_ssl_conf_own_cert returned %d\n", ret);
243  goto fail;
244  }
245 
246  if ((ret = mbedtls_ssl_setup(&tls_ctx->ssl_context, &tls_ctx->ssl_config)) != 0) {
247  av_log(h, AV_LOG_ERROR, "mbedtls_ssl_setup returned %d\n", ret);
248  goto fail;
249  }
250 
251  if (!shr->listen && !shr->numerichost) {
252  if ((ret = mbedtls_ssl_set_hostname(&tls_ctx->ssl_context, shr->host)) != 0) {
253  av_log(h, AV_LOG_ERROR, "mbedtls_ssl_set_hostname returned %d\n", ret);
254  goto fail;
255  }
256  }
257 
258  // set I/O functions to use FFmpeg internal code for transport layer
259  mbedtls_ssl_set_bio(&tls_ctx->ssl_context, shr->tcp, mbedtls_send, mbedtls_recv, NULL);
260 
261  // ssl handshake
262  while ((ret = mbedtls_ssl_handshake(&tls_ctx->ssl_context)) != 0) {
263  if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
265  goto fail;
266  }
267  }
268 
269  if (shr->verify) {
270  // check the result of the certificate verification
271  if ((verify_res_flags = mbedtls_ssl_get_verify_result(&tls_ctx->ssl_context)) != 0) {
272  av_log(h, AV_LOG_ERROR, "mbedtls_ssl_get_verify_result reported problems "\
273  "with the certificate verification, returned flags: %u\n",
274  verify_res_flags);
275  if (verify_res_flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
276  av_log(h, AV_LOG_ERROR, "The certificate is not correctly signed by the trusted CA.\n");
277  goto fail;
278  }
279  }
280 
281  return 0;
282 
283 fail:
284  tls_close(h);
285  return AVERROR(EIO);
286 }
287 
288 static int handle_tls_error(URLContext *h, const char* func_name, int ret)
289 {
290  switch (ret) {
291  case MBEDTLS_ERR_SSL_WANT_READ:
292  case MBEDTLS_ERR_SSL_WANT_WRITE:
293  return AVERROR(EAGAIN);
294  case MBEDTLS_ERR_NET_SEND_FAILED:
295  case MBEDTLS_ERR_NET_RECV_FAILED:
296  return AVERROR(EIO);
297  case MBEDTLS_ERR_NET_CONN_RESET:
298  case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
299  av_log(h, AV_LOG_WARNING, "%s reported connection reset by peer\n", func_name);
300  return AVERROR_EOF;
301  default:
302  av_log(h, AV_LOG_ERROR, "%s returned -0x%x\n", func_name, -ret);
303  return AVERROR(EIO);
304  }
305 }
306 
307 static int tls_read(URLContext *h, uint8_t *buf, int size)
308 {
309  TLSContext *tls_ctx = h->priv_data;
310  int ret;
311 
312  if ((ret = mbedtls_ssl_read(&tls_ctx->ssl_context, buf, size)) > 0) {
313  // return read length
314  return ret;
315  }
316 
317  return handle_tls_error(h, "mbedtls_ssl_read", ret);
318 }
319 
320 static int tls_write(URLContext *h, const uint8_t *buf, int size)
321 {
322  TLSContext *tls_ctx = h->priv_data;
323  int ret;
324 
325  if ((ret = mbedtls_ssl_write(&tls_ctx->ssl_context, buf, size)) > 0) {
326  // return written length
327  return ret;
328  }
329 
330  return handle_tls_error(h, "mbedtls_ssl_write", ret);
331 }
332 
334 {
335  TLSContext *c = h->priv_data;
336  return ffurl_get_file_handle(c->tls_shared.tcp);
337 }
338 
339 static const AVOption options[] = {
340  TLS_COMMON_OPTIONS(TLSContext, tls_shared), \
341  {"key_password", "Password for the private key file", OFFSET(priv_key_pw), AV_OPT_TYPE_STRING, .flags = TLS_OPTFL }, \
342  { NULL }
343 };
344 
345 static const AVClass tls_class = {
346  .class_name = "tls",
347  .item_name = av_default_item_name,
348  .option = options,
349  .version = LIBAVUTIL_VERSION_INT,
350 };
351 
353  .name = "tls",
354  .url_open2 = tls_open,
355  .url_read = tls_read,
356  .url_write = tls_write,
357  .url_close = tls_close,
358  .url_get_file_handle = tls_get_file_handle,
359  .priv_data_size = sizeof(TLSContext),
361  .priv_data_class = &tls_class,
362 };
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
TLSContext
Definition: tls_gnutls.c:48
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
av_find_info_tag
int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
Attempt to find a specific tag in a URL.
Definition: parseutils.c:751
URL_PROTOCOL_FLAG_NETWORK
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:34
TLSContext::entropy_context
mbedtls_entropy_context entropy_context
Definition: tls_mbedtls.c:41
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:55
handle_pk_parse_error
static void handle_pk_parse_error(URLContext *h, int ret)
Definition: tls_mbedtls.c:111
AVOption
AVOption.
Definition: opt.h:246
AVDictionary
Definition: dict.c:30
URLProtocol
Definition: url.h:54
TLSShared::verify
int verify
Definition: tls.h:31
TLSShared::listen
int listen
Definition: tls.h:34
TLSContext::ctr_drbg_context
mbedtls_ctr_drbg_context ctr_drbg_context
Definition: tls_mbedtls.c:42
TLS_COMMON_OPTIONS
#define TLS_COMMON_OPTIONS(pstruct, options_field)
Definition: tls.h:45
fail
#define fail()
Definition: checkasm.h:123
TLSContext::ca_cert
mbedtls_x509_crt ca_cert
Definition: tls_mbedtls.c:43
tls_close
static int tls_close(URLContext *h)
Definition: tls_mbedtls.c:51
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
mbedtls_recv
static int mbedtls_recv(void *ctx, unsigned char *buf, size_t len)
Definition: tls_mbedtls.c:98
TLS_OPTFL
#define TLS_OPTFL
Definition: tls.h:44
TLSContext::priv_key
mbedtls_pk_context priv_key
Definition: tls_mbedtls.c:45
ctx
AVFormatContext * ctx
Definition: movenc.c:48
TLSContext::ssl_context
mbedtls_ssl_context ssl_context
Definition: tls_mbedtls.c:39
internal.h
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
parse_options
static void parse_options(TLSContext *tls_ctxc, const char *uri)
Definition: tls_mbedtls.c:156
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
NULL
#define NULL
Definition: coverity.c:32
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
parseutils.h
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
TLSShared::host
char * host
Definition: tls.h:36
OFFSET
#define OFFSET(x)
Definition: tls_mbedtls.c:49
ff_tls_protocol
const URLProtocol ff_tls_protocol
Definition: tls_mbedtls.c:352
TLSContext::ssl_config
mbedtls_ssl_config ssl_config
Definition: tls_mbedtls.c:40
mbedtls_send
static int mbedtls_send(void *ctx, const unsigned char *buf, size_t len)
Definition: tls_mbedtls.c:85
size
int size
Definition: twinvq_data.h:11134
handle_handshake_error
static void handle_handshake_error(URLContext *h, int ret)
Definition: tls_mbedtls.c:129
TLSContext::tls_shared
TLSShared tls_shared
Definition: tls_gnutls.c:50
URLProtocol::name
const char * name
Definition: url.h:55
tls_read
static int tls_read(URLContext *h, uint8_t *buf, int size)
Definition: tls_mbedtls.c:307
handle_transport_error
static int handle_transport_error(URLContext *h, const char *func_name, int react_on_eagain, int ret)
Definition: tls_mbedtls.c:68
options
static const AVOption options[]
Definition: tls_mbedtls.c:339
URLContext
Definition: url.h:38
url.h
uint8_t
uint8_t
Definition: audio_convert.c:194
len
int len
Definition: vorbis_enc_data.h:452
TLSShared::cert_file
char * cert_file
Definition: tls.h:32
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:446
ff_tls_open_underlying
int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AVDictionary **options)
Definition: tls.c:56
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:72
TLSShared::ca_file
char * ca_file
Definition: tls.h:30
avformat.h
tls_class
static const AVClass tls_class
Definition: tls_mbedtls.c:345
tls.h
TLSContext::own_cert
mbedtls_x509_crt own_cert
Definition: tls_mbedtls.c:44
TLSShared::key_file
char * key_file
Definition: tls.h:33
ffurl_read
int ffurl_read(URLContext *h, unsigned char *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition: avio.c:409
ffurl_write
int ffurl_write(URLContext *h, const unsigned char *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: avio.c:423
tls_open
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: tls_mbedtls.c:167
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
tls_write
static int tls_write(URLContext *h, const uint8_t *buf, int size)
Definition: tls_mbedtls.c:320
TLSShared
Definition: tls.h:29
handle_tls_error
static int handle_tls_error(URLContext *h, const char *func_name, int ret)
Definition: tls_mbedtls.c:288
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:565
tls_get_file_handle
static int tls_get_file_handle(URLContext *h)
Definition: tls_mbedtls.c:333
TLSContext::priv_key_pw
char * priv_key_pw
Definition: tls_mbedtls.c:46
TLSShared::numerichost
int numerichost
Definition: tls.h:39
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
h
h
Definition: vp9dsp_template.c:2038
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:56
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:227
ffurl_get_file_handle
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:628
TLSShared::tcp
URLContext * tcp
Definition: tls.h:41