• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ustream-ssl/ustream-mbedtls.c

  1 /*
  2  * ustream-ssl - library for SSL over ustream
  3  *
  4  * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
  5  *
  6  * Permission to use, copy, modify, and/or distribute this software for any
  7  * purpose with or without fee is hereby granted, provided that the above
  8  * copyright notice and this permission notice appear in all copies.
  9  *
 10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 17  */
 18 
 19 #include <sys/types.h>
 20 #include <sys/random.h>
 21 #include <fcntl.h>
 22 #include <unistd.h>
 23 #include <stdlib.h>
 24 #include <string.h>
 25 
 26 #include "ustream-ssl.h"
 27 #include "ustream-internal.h"
 28 #include <psa/crypto.h>
 29 #include <mbedtls/debug.h>
 30 
 31 static void debug_cb(void *ctx_p, int level,
 32                      const char *file, int line,
 33                      const char *str)
 34 {
 35         struct ustream_ssl_ctx *ctx = ctx_p;
 36         const char *fstr;
 37         char buf[512];
 38         int len;
 39 
 40         if (!ctx->debug_cb)
 41                 return;
 42 
 43         while ((fstr = strstr(file + 1, "library/")) != NULL)
 44                 file = fstr;
 45 
 46         len = snprintf(buf, sizeof(buf), "%s:%04d: %s", file, line, str);
 47         if (len >= (int)sizeof(buf))
 48                 len = (int)sizeof(buf) - 1;
 49         if (buf[len - 1] == '\n')
 50                 buf[len - 1] = 0;
 51         ctx->debug_cb(ctx->debug_cb_priv, level, buf);
 52 }
 53 
 54 static int s_ustream_read(void *ctx, unsigned char *buf, size_t len)
 55 {
 56         struct ustream *s = ctx;
 57         char *sbuf;
 58         int slen;
 59 
 60         if (s->eof)
 61                 return 0;
 62 
 63         sbuf = ustream_get_read_buf(s, &slen);
 64         if ((size_t) slen > len)
 65                 slen = len;
 66 
 67         if (!slen)
 68                 return MBEDTLS_ERR_SSL_WANT_READ;
 69 
 70         memcpy(buf, sbuf, slen);
 71         ustream_consume(s, slen);
 72 
 73         return slen;
 74 }
 75 
 76 static int s_ustream_write(void *ctx, const unsigned char *buf, size_t len)
 77 {
 78         struct ustream *s = ctx;
 79         int ret;
 80 
 81         ret = ustream_write(s, (const char *) buf, len, false);
 82         if (ret < 0 || s->write_error)
 83                 return MBEDTLS_ERR_NET_SEND_FAILED;
 84 
 85         return ret;
 86 }
 87 
 88 static int s_fd_read(void *ctx, unsigned char *buf, size_t len)
 89 {
 90         struct uloop_fd *ufd = ctx;
 91         mbedtls_net_context net = {
 92                 .fd = ufd->fd
 93         };
 94 
 95         return mbedtls_net_recv(&net, buf, len);
 96 }
 97 
 98 static int s_fd_write(void *ctx, const unsigned char *buf, size_t len)
 99 {
100         struct uloop_fd *ufd = ctx;
101         mbedtls_net_context net = {
102                 .fd = ufd->fd
103         };
104 
105         return mbedtls_net_send(&net, buf, len);
106 }
107 
108 __hidden void ustream_set_io(struct ustream_ssl *us)
109 {
110         if (us->conn)
111                 mbedtls_ssl_set_bio(us->ssl, us->conn, s_ustream_write, s_ustream_read, NULL);
112         else
113                 mbedtls_ssl_set_bio(us->ssl, &us->fd, s_fd_write, s_fd_read, NULL);
114 }
115 
116 static int _random(void *ctx, unsigned char *out, size_t len)
117 {
118 #ifdef linux
119         if (getrandom(out, len, 0) != (ssize_t) len)
120                 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
121 #else
122         static FILE *f;
123 
124         if (!f)
125                 f = fopen("/dev/urandom", "r");
126         if (fread(out, len, 1, f) != 1)
127                 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
128 #endif
129 
130         return 0;
131 }
132 
133 #define AES_GCM_CIPHERS(v)                              \
134         MBEDTLS_TLS_##v##_WITH_AES_128_GCM_SHA256,      \
135         MBEDTLS_TLS_##v##_WITH_AES_256_GCM_SHA384
136 
137 #define AES_CBC_CIPHERS(v)                              \
138         MBEDTLS_TLS_##v##_WITH_AES_128_CBC_SHA,         \
139         MBEDTLS_TLS_##v##_WITH_AES_256_CBC_SHA
140 
141 #define AES_CIPHERS(v)                                  \
142         AES_GCM_CIPHERS(v),                             \
143         AES_CBC_CIPHERS(v)
144 
145 static const int default_ciphersuites_server[] =
146 {
147 #ifdef MBEDTLS_SSL_PROTO_TLS1_3
148         MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256,
149         MBEDTLS_TLS1_3_AES_256_GCM_SHA384,
150         MBEDTLS_TLS1_3_AES_128_GCM_SHA256,
151         MBEDTLS_TLS1_3_AES_128_CCM_SHA256,
152         MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256,
153 #endif
154 
155         MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
156         AES_GCM_CIPHERS(ECDHE_ECDSA),
157         MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
158         AES_GCM_CIPHERS(ECDHE_RSA),
159         AES_CBC_CIPHERS(ECDHE_RSA),
160         AES_CIPHERS(RSA),
161         0
162 };
163 
164 static const int default_ciphersuites_client[] =
165 {
166 #ifdef MBEDTLS_SSL_PROTO_TLS1_3
167         MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256,
168         MBEDTLS_TLS1_3_AES_256_GCM_SHA384,
169         MBEDTLS_TLS1_3_AES_128_GCM_SHA256,
170         MBEDTLS_TLS1_3_AES_128_CCM_SHA256,
171         MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256,
172 #endif
173 
174         MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
175         AES_GCM_CIPHERS(ECDHE_ECDSA),
176         MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
177         AES_GCM_CIPHERS(ECDHE_RSA),
178         MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
179         AES_GCM_CIPHERS(DHE_RSA),
180         AES_CBC_CIPHERS(ECDHE_ECDSA),
181         AES_CBC_CIPHERS(ECDHE_RSA),
182         AES_CBC_CIPHERS(DHE_RSA),
183 /* Removed in Mbed TLS 3.0.0 */
184 #ifdef MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
185         MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
186 #endif
187         AES_CIPHERS(RSA),
188 /* Removed in Mbed TLS 3.0.0 */
189 #ifdef MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA
190         MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
191 #endif
192         0
193 };
194 
195 
196 __hidden struct ustream_ssl_ctx *
197 __ustream_ssl_context_new(bool server)
198 {
199         struct ustream_ssl_ctx *ctx;
200         mbedtls_ssl_config *conf;
201         int ep;
202 
203 #ifdef MBEDTLS_PSA_CRYPTO_C
204         static bool psa_init;
205 
206         if (!psa_init && !psa_crypto_init())
207                 psa_init = true;
208 #endif
209 
210         ctx = calloc(1, sizeof(*ctx));
211         if (!ctx)
212                 return NULL;
213 
214         ctx->server = server;
215         mbedtls_pk_init(&ctx->key);
216         mbedtls_x509_crt_init(&ctx->cert);
217         mbedtls_x509_crt_init(&ctx->ca_cert);
218 
219 #if defined(MBEDTLS_SSL_CACHE_C)
220         mbedtls_ssl_cache_init(&ctx->cache);
221         mbedtls_ssl_cache_set_timeout(&ctx->cache, 30 * 60);
222         mbedtls_ssl_cache_set_max_entries(&ctx->cache, 5);
223 #endif
224 
225         conf = &ctx->conf;
226         mbedtls_ssl_config_init(conf);
227 
228         ep = server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT;
229 
230         mbedtls_ssl_config_defaults(conf, ep, MBEDTLS_SSL_TRANSPORT_STREAM,
231                                     MBEDTLS_SSL_PRESET_DEFAULT);
232         mbedtls_ssl_conf_rng(conf, _random, NULL);
233 
234         if (server) {
235                 mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
236                 mbedtls_ssl_conf_ciphersuites(conf, default_ciphersuites_server);
237                 mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3,
238                                              MBEDTLS_SSL_MINOR_VERSION_3);
239         } else {
240                 mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
241                 mbedtls_ssl_conf_ciphersuites(conf, default_ciphersuites_client);
242         }
243 
244 #if defined(MBEDTLS_SSL_CACHE_C)
245         mbedtls_ssl_conf_session_cache(conf, &ctx->cache,
246                                        mbedtls_ssl_cache_get,
247                                        mbedtls_ssl_cache_set);
248 #endif
249         return ctx;
250 }
251 
252 static void ustream_ssl_update_own_cert(struct ustream_ssl_ctx *ctx)
253 {
254         if (!ctx->cert.version)
255                 return;
256 
257         if (mbedtls_pk_get_type(&ctx->key) == MBEDTLS_PK_NONE)
258                 return;
259 
260         mbedtls_ssl_conf_own_cert(&ctx->conf, &ctx->cert, &ctx->key);
261 }
262 
263 __hidden int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx *ctx, const char *file)
264 {
265         int ret;
266 
267         ret = mbedtls_x509_crt_parse_file(&ctx->ca_cert, file);
268         if (ret)
269                 return -1;
270 
271         mbedtls_ssl_conf_ca_chain(&ctx->conf, &ctx->ca_cert, NULL);
272         mbedtls_ssl_conf_authmode(&ctx->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
273         return 0;
274 }
275 
276 __hidden int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file)
277 {
278         int ret;
279 
280         ret = mbedtls_x509_crt_parse_file(&ctx->cert, file);
281         if (ret)
282                 return -1;
283 
284         ustream_ssl_update_own_cert(ctx);
285         return 0;
286 }
287 
288 __hidden int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file)
289 {
290         int ret;
291 
292 #if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
293         ret = mbedtls_pk_parse_keyfile(&ctx->key, file, NULL, _random, NULL);
294 #else
295         ret = mbedtls_pk_parse_keyfile(&ctx->key, file, NULL);
296 #endif
297         if (ret)
298                 return -1;
299 
300         ustream_ssl_update_own_cert(ctx);
301         return 0;
302 }
303 
304 __hidden int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers)
305 {
306         int *ciphersuites = NULL, *tmp, id;
307         char *cipherstr, *p, *last, c;
308         size_t len = 0;
309 
310         if (ciphers == NULL)
311                 return -1;
312 
313         cipherstr = strdup(ciphers);
314 
315         if (cipherstr == NULL)
316                 return -1;
317 
318         for (p = cipherstr, last = p;; p++) {
319                 if (*p == ':' || *p == 0) {
320                         c = *p;
321                         *p = 0;
322 
323                         id = mbedtls_ssl_get_ciphersuite_id(last);
324 
325                         if (id != 0) {
326                                 tmp = realloc(ciphersuites, (len + 2) * sizeof(int));
327 
328                                 if (tmp == NULL) {
329                                         free(ciphersuites);
330                                         free(cipherstr);
331 
332                                         return -1;
333                                 }
334 
335                                 ciphersuites = tmp;
336                                 ciphersuites[len++] = id;
337                                 ciphersuites[len] = 0;
338                         }
339 
340                         if (c == 0)
341                                 break;
342 
343                         last = p + 1;
344                 }
345 
346                 /*
347                  * mbedTLS expects cipher names with dashes while many sources elsewhere
348                  * like the Firefox wiki or Wireshark specify ciphers with underscores,
349                  * so simply convert all underscores to dashes to accept both notations.
350                  */
351                 else if (*p == '_') {
352                         *p = '-';
353                 }
354         }
355 
356         free(cipherstr);
357 
358         if (len == 0)
359                 return -1;
360 
361         mbedtls_ssl_conf_ciphersuites(&ctx->conf, ciphersuites);
362         free(ctx->ciphersuites);
363 
364         ctx->ciphersuites = ciphersuites;
365 
366         return 0;
367 }
368 
369 __hidden int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx *ctx, bool require)
370 {
371         int mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
372 
373         if (!require)
374                 mode = MBEDTLS_SSL_VERIFY_NONE;
375 
376         /* force TLS 1.2 when not requiring validation for now */
377         if (!require && !ctx->server)
378                 mbedtls_ssl_conf_max_version(&ctx->conf, MBEDTLS_SSL_MAJOR_VERSION_3,
379                                              MBEDTLS_SSL_MINOR_VERSION_3);
380         mbedtls_ssl_conf_authmode(&ctx->conf, mode);
381 
382         return 0;
383 }
384 
385 __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx)
386 {
387         free(ctx->session_data);
388 #if defined(MBEDTLS_SSL_CACHE_C)
389         mbedtls_ssl_cache_free(&ctx->cache);
390 #endif
391         mbedtls_pk_free(&ctx->key);
392         mbedtls_x509_crt_free(&ctx->ca_cert);
393         mbedtls_x509_crt_free(&ctx->cert);
394         mbedtls_ssl_config_free(&ctx->conf);
395         free(ctx->ciphersuites);
396         free(ctx);
397 }
398 
399 static void ustream_ssl_error(struct ustream_ssl *us, int ret)
400 {
401         us->error = ret;
402         uloop_timeout_set(&us->error_timer, 0);
403 }
404 
405 #ifdef MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET
406 static void
407 __ustream_ssl_save_session(struct ustream_ssl *us)
408 {
409         struct ustream_ssl_ctx *ctx = us->ctx;
410         mbedtls_ssl_session sess;
411 
412         if (ctx->server)
413                 return;
414 
415         free(ctx->session_data);
416         ctx->session_data = NULL;
417 
418         mbedtls_ssl_session_init(&sess);
419         if (mbedtls_ssl_get_session(us->ssl, &sess) != 0)
420                 return;
421 
422         mbedtls_ssl_session_save(&sess, NULL, 0, &ctx->session_data_len);
423         ctx->session_data = malloc(ctx->session_data_len);
424         if (mbedtls_ssl_session_save(&sess, ctx->session_data, ctx->session_data_len,
425                                      &ctx->session_data_len))
426                 ctx->session_data_len = 0;
427         mbedtls_ssl_session_free(&sess);
428 }
429 #endif
430 
431 static int ssl_check_return(struct ustream_ssl *us, int ret)
432 {
433         switch(ret) {
434         case MBEDTLS_ERR_SSL_WANT_READ:
435         case MBEDTLS_ERR_SSL_WANT_WRITE:
436                 return U_SSL_PENDING;
437 #ifdef MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET
438         case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
439                 __ustream_ssl_save_session(us);
440                 return U_SSL_RETRY;
441 #endif
442 #ifdef MBEDTLS_ECP_RESTARTABLE
443         case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
444                 return U_SSL_RETRY;
445 #endif
446         case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
447         case MBEDTLS_ERR_NET_CONN_RESET:
448                 return 0;
449         default:
450                 ustream_ssl_error(us, ret);
451                 return U_SSL_ERROR;
452         }
453 }
454 
455 static void ustream_ssl_verify_cert(struct ustream_ssl *us)
456 {
457         void *ssl = us->ssl;
458         const char *msg = NULL;
459         bool cn_mismatch;
460         int r;
461 
462         r = mbedtls_ssl_get_verify_result(ssl);
463         cn_mismatch = r & MBEDTLS_X509_BADCERT_CN_MISMATCH;
464         r &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
465 
466         if (r & MBEDTLS_X509_BADCERT_EXPIRED)
467                 msg = "certificate has expired";
468         else if (r & MBEDTLS_X509_BADCERT_REVOKED)
469                 msg = "certificate has been revoked";
470         else if (r & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
471                 msg = "certificate is self-signed or not signed by a trusted CA";
472         else
473                 msg = "unknown error";
474 
475         if (r) {
476                 if (us->notify_verify_error)
477                         us->notify_verify_error(us, r, msg);
478                 return;
479         }
480 
481         if (!cn_mismatch)
482                 us->valid_cn = true;
483 }
484 
485 __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us)
486 {
487         void *ssl = us->ssl;
488         int r;
489 
490         do {
491                 r = mbedtls_ssl_handshake(ssl);
492                 if (r == 0) {
493                         ustream_ssl_verify_cert(us);
494                         return U_SSL_OK;
495                 }
496 
497                 r = ssl_check_return(us, r);
498         } while (r == U_SSL_RETRY);
499 
500         return r;
501 }
502 
503 __hidden int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int len)
504 {
505         void *ssl = us->ssl;
506         int done = 0, ret = 0;
507 
508         while (done != len) {
509                 ret = mbedtls_ssl_write(ssl, (const unsigned char *) buf + done, len - done);
510                 if (ret < 0) {
511                         ret = ssl_check_return(us, ret);
512                         if (ret == U_SSL_RETRY)
513                                 continue;
514 
515                         if (ret == U_SSL_PENDING)
516                                 return done;
517 
518                         return -1;
519                 }
520 
521                 done += ret;
522         }
523 
524         return done;
525 }
526 
527 __hidden int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len)
528 {
529         int ret;
530 
531         do {
532                 ret = mbedtls_ssl_read(us->ssl, (unsigned char *) buf, len);
533                 if (ret >= 0)
534                         return ret;
535 
536                 ret = ssl_check_return(us, ret);
537         } while (ret == U_SSL_RETRY);
538 
539         return ret;
540 }
541 
542 __hidden void __ustream_ssl_set_debug(struct ustream_ssl_ctx *ctx, int level,
543                                       ustream_ssl_debug_cb cb, void *cb_priv)
544 {
545         ctx->debug_cb = cb;
546         ctx->debug_cb_priv = cb_priv;
547         mbedtls_ssl_conf_dbg(&ctx->conf, debug_cb, ctx);
548 #ifdef MBEDTLS_DEBUG_C
549         mbedtls_debug_set_threshold(level);
550 #endif
551 }
552 
553 __hidden void *__ustream_ssl_session_new(struct ustream_ssl_ctx *ctx)
554 {
555         mbedtls_ssl_context *ssl;
556         mbedtls_ssl_session sess;
557 
558         ssl = calloc(1, sizeof(*ssl));
559         if (!ssl)
560                 return NULL;
561 
562         mbedtls_ssl_init(ssl);
563 
564         if (mbedtls_ssl_setup(ssl, &ctx->conf)) {
565                 free(ssl);
566                 return NULL;
567         }
568 
569         if (!ctx->session_data_len)
570                 return ssl;
571 
572         mbedtls_ssl_session_init(&sess);
573         if (mbedtls_ssl_session_load(&sess, ctx->session_data, ctx->session_data_len) == 0)
574                 mbedtls_ssl_set_session(ssl, &sess);
575 
576         return ssl;
577 }
578 
579 __hidden void __ustream_ssl_session_free(struct ustream_ssl *us)
580 {
581         mbedtls_ssl_free(us->ssl);
582         free(us->ssl);
583 }
584 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt