2 * ustream-ssl - library for SSL over ustream
4 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
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.
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.
19 #include <sys/types.h>
20 #include <sys/random.h>
26 #include "ustream-ssl.h"
27 #include "ustream-internal.h"
28 #include <psa/crypto.h>
29 #include <mbedtls/debug.h>
31 static void debug_cb(void *ctx_p
, int level
,
32 const char *file
, int line
,
35 struct ustream_ssl_ctx
*ctx
= ctx_p
;
43 while ((fstr
= strstr(file
+ 1, "library/")) != NULL
)
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')
51 ctx
->debug_cb(ctx
->debug_cb_priv
, level
, buf
);
54 static int s_ustream_read(void *ctx
, unsigned char *buf
, size_t len
)
56 struct ustream
*s
= ctx
;
63 sbuf
= ustream_get_read_buf(s
, &slen
);
64 if ((size_t) slen
> len
)
68 return MBEDTLS_ERR_SSL_WANT_READ
;
70 memcpy(buf
, sbuf
, slen
);
71 ustream_consume(s
, slen
);
76 static int s_ustream_write(void *ctx
, const unsigned char *buf
, size_t len
)
78 struct ustream
*s
= ctx
;
81 ret
= ustream_write(s
, (const char *) buf
, len
, false);
82 if (ret
< 0 || s
->write_error
)
83 return MBEDTLS_ERR_NET_SEND_FAILED
;
88 static int s_fd_read(void *ctx
, unsigned char *buf
, size_t len
)
90 struct uloop_fd
*ufd
= ctx
;
91 mbedtls_net_context net
= {
95 return mbedtls_net_recv(&net
, buf
, len
);
98 static int s_fd_write(void *ctx
, const unsigned char *buf
, size_t len
)
100 struct uloop_fd
*ufd
= ctx
;
101 mbedtls_net_context net
= {
105 return mbedtls_net_send(&net
, buf
, len
);
108 __hidden
void ustream_set_io(struct ustream_ssl
*us
)
111 mbedtls_ssl_set_bio(us
->ssl
, us
->conn
, s_ustream_write
, s_ustream_read
, NULL
);
113 mbedtls_ssl_set_bio(us
->ssl
, &us
->fd
, s_fd_write
, s_fd_read
, NULL
);
116 static int _random(void *ctx
, unsigned char *out
, size_t len
)
119 if (getrandom(out
, len
, 0) != (ssize_t
) len
)
120 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
;
125 f
= fopen("/dev/urandom", "r");
126 if (fread(out
, len
, 1, f
) != 1)
127 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
;
133 #define AES_GCM_CIPHERS(v) \
134 MBEDTLS_TLS_##v##_WITH_AES_128_GCM_SHA256, \
135 MBEDTLS_TLS_##v##_WITH_AES_256_GCM_SHA384
137 #define AES_CBC_CIPHERS(v) \
138 MBEDTLS_TLS_##v##_WITH_AES_128_CBC_SHA, \
139 MBEDTLS_TLS_##v##_WITH_AES_256_CBC_SHA
141 #define AES_CIPHERS(v) \
142 AES_GCM_CIPHERS(v), \
145 static const int default_ciphersuites_server
[] =
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
,
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
),
164 static const int default_ciphersuites_client
[] =
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
,
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
,
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
,
196 __hidden
struct ustream_ssl_ctx
*
197 __ustream_ssl_context_new(bool server
)
199 struct ustream_ssl_ctx
*ctx
;
200 mbedtls_ssl_config
*conf
;
203 #ifdef MBEDTLS_PSA_CRYPTO_C
204 static bool psa_init
;
206 if (!psa_init
&& !psa_crypto_init())
210 ctx
= calloc(1, sizeof(*ctx
));
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
);
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);
226 mbedtls_ssl_config_init(conf
);
228 ep
= server
? MBEDTLS_SSL_IS_SERVER
: MBEDTLS_SSL_IS_CLIENT
;
230 mbedtls_ssl_config_defaults(conf
, ep
, MBEDTLS_SSL_TRANSPORT_STREAM
,
231 MBEDTLS_SSL_PRESET_DEFAULT
);
232 mbedtls_ssl_conf_rng(conf
, _random
, NULL
);
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
);
240 mbedtls_ssl_conf_authmode(conf
, MBEDTLS_SSL_VERIFY_OPTIONAL
);
241 mbedtls_ssl_conf_ciphersuites(conf
, default_ciphersuites_client
);
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
);
252 static void ustream_ssl_update_own_cert(struct ustream_ssl_ctx
*ctx
)
254 if (!ctx
->cert
.version
)
257 if (mbedtls_pk_get_type(&ctx
->key
) == MBEDTLS_PK_NONE
)
260 mbedtls_ssl_conf_own_cert(&ctx
->conf
, &ctx
->cert
, &ctx
->key
);
263 __hidden
int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx
*ctx
, const char *file
)
267 ret
= mbedtls_x509_crt_parse_file(&ctx
->ca_cert
, file
);
271 mbedtls_ssl_conf_ca_chain(&ctx
->conf
, &ctx
->ca_cert
, NULL
);
272 mbedtls_ssl_conf_authmode(&ctx
->conf
, MBEDTLS_SSL_VERIFY_OPTIONAL
);
276 __hidden
int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx
*ctx
, const char *file
)
280 ret
= mbedtls_x509_crt_parse_file(&ctx
->cert
, file
);
284 ustream_ssl_update_own_cert(ctx
);
288 __hidden
int __ustream_ssl_set_key_file(struct ustream_ssl_ctx
*ctx
, const char *file
)
292 #if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
293 ret
= mbedtls_pk_parse_keyfile(&ctx
->key
, file
, NULL
, _random
, NULL
);
295 ret
= mbedtls_pk_parse_keyfile(&ctx
->key
, file
, NULL
);
300 ustream_ssl_update_own_cert(ctx
);
304 __hidden
int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx
*ctx
, const char *ciphers
)
306 int *ciphersuites
= NULL
, *tmp
, id
;
307 char *cipherstr
, *p
, *last
, c
;
313 cipherstr
= strdup(ciphers
);
315 if (cipherstr
== NULL
)
318 for (p
= cipherstr
, last
= p
;; p
++) {
319 if (*p
== ':' || *p
== 0) {
323 id
= mbedtls_ssl_get_ciphersuite_id(last
);
326 tmp
= realloc(ciphersuites
, (len
+ 2) * sizeof(int));
336 ciphersuites
[len
++] = id
;
337 ciphersuites
[len
] = 0;
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.
351 else if (*p
== '_') {
361 mbedtls_ssl_conf_ciphersuites(&ctx
->conf
, ciphersuites
);
362 free(ctx
->ciphersuites
);
364 ctx
->ciphersuites
= ciphersuites
;
369 __hidden
int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx
*ctx
, bool require
)
371 int mode
= MBEDTLS_SSL_VERIFY_OPTIONAL
;
374 mode
= MBEDTLS_SSL_VERIFY_NONE
;
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
);
385 __hidden
void __ustream_ssl_context_free(struct ustream_ssl_ctx
*ctx
)
387 free(ctx
->session_data
);
388 #if defined(MBEDTLS_SSL_CACHE_C)
389 mbedtls_ssl_cache_free(&ctx
->cache
);
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
);
399 static void ustream_ssl_error(struct ustream_ssl
*us
, int ret
)
402 uloop_timeout_set(&us
->error_timer
, 0);
405 #ifdef MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET
407 __ustream_ssl_save_session(struct ustream_ssl
*us
)
409 struct ustream_ssl_ctx
*ctx
= us
->ctx
;
410 mbedtls_ssl_session sess
;
415 free(ctx
->session_data
);
416 ctx
->session_data
= NULL
;
418 mbedtls_ssl_session_init(&sess
);
419 if (mbedtls_ssl_get_session(us
->ssl
, &sess
) != 0)
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
);
431 static int ssl_check_return(struct ustream_ssl
*us
, int 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
);
442 #ifdef MBEDTLS_ECP_RESTARTABLE
443 case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
:
446 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY
:
447 case MBEDTLS_ERR_NET_CONN_RESET
:
450 ustream_ssl_error(us
, ret
);
455 static void ustream_ssl_verify_cert(struct ustream_ssl
*us
)
458 const char *msg
= NULL
;
462 r
= mbedtls_ssl_get_verify_result(ssl
);
463 cn_mismatch
= r
& MBEDTLS_X509_BADCERT_CN_MISMATCH
;
464 r
&= ~MBEDTLS_X509_BADCERT_CN_MISMATCH
;
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";
473 msg
= "unknown error";
476 if (us
->notify_verify_error
)
477 us
->notify_verify_error(us
, r
, msg
);
485 __hidden
enum ssl_conn_status
__ustream_ssl_connect(struct ustream_ssl
*us
)
491 r
= mbedtls_ssl_handshake(ssl
);
493 ustream_ssl_verify_cert(us
);
497 r
= ssl_check_return(us
, r
);
498 } while (r
== U_SSL_RETRY
);
503 __hidden
int __ustream_ssl_write(struct ustream_ssl
*us
, const char *buf
, int len
)
506 int done
= 0, ret
= 0;
508 while (done
!= len
) {
509 ret
= mbedtls_ssl_write(ssl
, (const unsigned char *) buf
+ done
, len
- done
);
511 ret
= ssl_check_return(us
, ret
);
512 if (ret
== U_SSL_RETRY
)
515 if (ret
== U_SSL_PENDING
)
527 __hidden
int __ustream_ssl_read(struct ustream_ssl
*us
, char *buf
, int len
)
532 ret
= mbedtls_ssl_read(us
->ssl
, (unsigned char *) buf
, len
);
536 ret
= ssl_check_return(us
, ret
);
537 } while (ret
== U_SSL_RETRY
);
542 __hidden
void __ustream_ssl_set_debug(struct ustream_ssl_ctx
*ctx
, int level
,
543 ustream_ssl_debug_cb cb
, void *cb_priv
)
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
);
553 __hidden
void *__ustream_ssl_session_new(struct ustream_ssl_ctx
*ctx
)
555 mbedtls_ssl_context
*ssl
;
556 mbedtls_ssl_session sess
;
558 ssl
= calloc(1, sizeof(*ssl
));
562 mbedtls_ssl_init(ssl
);
564 if (mbedtls_ssl_setup(ssl
, &ctx
->conf
)) {
569 if (!ctx
->session_data_len
)
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
);
579 __hidden
void __ustream_ssl_session_free(struct ustream_ssl
*us
)
581 mbedtls_ssl_free(us
->ssl
);