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