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"
29 static int s_ustream_read(void *ctx
, unsigned char *buf
, size_t len
)
31 struct ustream
*s
= ctx
;
38 sbuf
= ustream_get_read_buf(s
, &slen
);
39 if ((size_t) slen
> len
)
43 return MBEDTLS_ERR_SSL_WANT_READ
;
45 memcpy(buf
, sbuf
, slen
);
46 ustream_consume(s
, slen
);
51 static int s_ustream_write(void *ctx
, const unsigned char *buf
, size_t len
)
53 struct ustream
*s
= ctx
;
56 ret
= ustream_write(s
, (const char *) buf
, len
, false);
57 if (ret
< 0 || s
->write_error
)
58 return MBEDTLS_ERR_NET_SEND_FAILED
;
63 __hidden
void ustream_set_io(struct ustream_ssl_ctx
*ctx
, void *ssl
, struct ustream
*conn
)
65 mbedtls_ssl_set_bio(ssl
, conn
, s_ustream_write
, s_ustream_read
, NULL
);
68 static int _random(void *ctx
, unsigned char *out
, size_t len
)
71 if (getrandom(out
, len
, 0) != (ssize_t
) len
)
72 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
;
77 f
= fopen("/dev/urandom", "r");
78 if (fread(out
, len
, 1, f
) != 1)
79 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
;
85 #define AES_GCM_CIPHERS(v) \
86 MBEDTLS_TLS_##v##_WITH_AES_128_GCM_SHA256, \
87 MBEDTLS_TLS_##v##_WITH_AES_256_GCM_SHA384
89 #define AES_CBC_CIPHERS(v) \
90 MBEDTLS_TLS_##v##_WITH_AES_128_CBC_SHA, \
91 MBEDTLS_TLS_##v##_WITH_AES_256_CBC_SHA
93 #define AES_CIPHERS(v) \
97 static const int default_ciphersuites_server
[] =
99 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
,
100 AES_GCM_CIPHERS(ECDHE_ECDSA
),
101 MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
,
102 AES_GCM_CIPHERS(ECDHE_RSA
),
103 AES_CBC_CIPHERS(ECDHE_RSA
),
108 static const int default_ciphersuites_client
[] =
110 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
,
111 AES_GCM_CIPHERS(ECDHE_ECDSA
),
112 MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
,
113 AES_GCM_CIPHERS(ECDHE_RSA
),
114 MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
,
115 AES_GCM_CIPHERS(DHE_RSA
),
116 AES_CBC_CIPHERS(ECDHE_ECDSA
),
117 AES_CBC_CIPHERS(ECDHE_RSA
),
118 AES_CBC_CIPHERS(DHE_RSA
),
119 /* Removed in Mbed TLS 3.0.0 */
120 #ifdef MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
121 MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
,
124 /* Removed in Mbed TLS 3.0.0 */
125 #ifdef MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA
126 MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA
,
132 __hidden
struct ustream_ssl_ctx
*
133 __ustream_ssl_context_new(bool server
)
135 struct ustream_ssl_ctx
*ctx
;
136 mbedtls_ssl_config
*conf
;
139 ctx
= calloc(1, sizeof(*ctx
));
143 ctx
->server
= server
;
144 mbedtls_pk_init(&ctx
->key
);
145 mbedtls_x509_crt_init(&ctx
->cert
);
146 mbedtls_x509_crt_init(&ctx
->ca_cert
);
148 #if defined(MBEDTLS_SSL_CACHE_C)
149 mbedtls_ssl_cache_init(&ctx
->cache
);
150 mbedtls_ssl_cache_set_timeout(&ctx
->cache
, 30 * 60);
151 mbedtls_ssl_cache_set_max_entries(&ctx
->cache
, 5);
155 mbedtls_ssl_config_init(conf
);
157 ep
= server
? MBEDTLS_SSL_IS_SERVER
: MBEDTLS_SSL_IS_CLIENT
;
159 mbedtls_ssl_config_defaults(conf
, ep
, MBEDTLS_SSL_TRANSPORT_STREAM
,
160 MBEDTLS_SSL_PRESET_DEFAULT
);
161 mbedtls_ssl_conf_rng(conf
, _random
, NULL
);
164 mbedtls_ssl_conf_authmode(conf
, MBEDTLS_SSL_VERIFY_NONE
);
165 mbedtls_ssl_conf_ciphersuites(conf
, default_ciphersuites_server
);
166 mbedtls_ssl_conf_min_version(conf
, MBEDTLS_SSL_MAJOR_VERSION_3
,
167 MBEDTLS_SSL_MINOR_VERSION_3
);
169 mbedtls_ssl_conf_authmode(conf
, MBEDTLS_SSL_VERIFY_OPTIONAL
);
170 mbedtls_ssl_conf_ciphersuites(conf
, default_ciphersuites_client
);
173 #if defined(MBEDTLS_SSL_CACHE_C)
174 mbedtls_ssl_conf_session_cache(conf
, &ctx
->cache
,
175 mbedtls_ssl_cache_get
,
176 mbedtls_ssl_cache_set
);
181 static void ustream_ssl_update_own_cert(struct ustream_ssl_ctx
*ctx
)
183 if (!ctx
->cert
.version
)
186 if (mbedtls_pk_get_type(&ctx
->key
) == MBEDTLS_PK_NONE
)
189 mbedtls_ssl_conf_own_cert(&ctx
->conf
, &ctx
->cert
, &ctx
->key
);
192 __hidden
int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx
*ctx
, const char *file
)
196 ret
= mbedtls_x509_crt_parse_file(&ctx
->ca_cert
, file
);
200 mbedtls_ssl_conf_ca_chain(&ctx
->conf
, &ctx
->ca_cert
, NULL
);
201 mbedtls_ssl_conf_authmode(&ctx
->conf
, MBEDTLS_SSL_VERIFY_OPTIONAL
);
205 __hidden
int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx
*ctx
, const char *file
)
209 ret
= mbedtls_x509_crt_parse_file(&ctx
->cert
, file
);
213 ustream_ssl_update_own_cert(ctx
);
217 __hidden
int __ustream_ssl_set_key_file(struct ustream_ssl_ctx
*ctx
, const char *file
)
221 #if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
222 ret
= mbedtls_pk_parse_keyfile(&ctx
->key
, file
, NULL
, _random
, NULL
);
224 ret
= mbedtls_pk_parse_keyfile(&ctx
->key
, file
, NULL
);
229 ustream_ssl_update_own_cert(ctx
);
233 __hidden
int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx
*ctx
, const char *ciphers
)
235 int *ciphersuites
= NULL
, *tmp
, id
;
236 char *cipherstr
, *p
, *last
, c
;
242 cipherstr
= strdup(ciphers
);
244 if (cipherstr
== NULL
)
247 for (p
= cipherstr
, last
= p
;; p
++) {
248 if (*p
== ':' || *p
== 0) {
252 id
= mbedtls_ssl_get_ciphersuite_id(last
);
255 tmp
= realloc(ciphersuites
, (len
+ 2) * sizeof(int));
265 ciphersuites
[len
++] = id
;
266 ciphersuites
[len
] = 0;
276 * mbedTLS expects cipher names with dashes while many sources elsewhere
277 * like the Firefox wiki or Wireshark specify ciphers with underscores,
278 * so simply convert all underscores to dashes to accept both notations.
280 else if (*p
== '_') {
290 mbedtls_ssl_conf_ciphersuites(&ctx
->conf
, ciphersuites
);
291 free(ctx
->ciphersuites
);
293 ctx
->ciphersuites
= ciphersuites
;
298 __hidden
int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx
*ctx
, bool require
)
300 int mode
= MBEDTLS_SSL_VERIFY_OPTIONAL
;
303 mode
= MBEDTLS_SSL_VERIFY_NONE
;
305 mbedtls_ssl_conf_authmode(&ctx
->conf
, mode
);
310 __hidden
void __ustream_ssl_context_free(struct ustream_ssl_ctx
*ctx
)
312 #if defined(MBEDTLS_SSL_CACHE_C)
313 mbedtls_ssl_cache_free(&ctx
->cache
);
315 mbedtls_pk_free(&ctx
->key
);
316 mbedtls_x509_crt_free(&ctx
->ca_cert
);
317 mbedtls_x509_crt_free(&ctx
->cert
);
318 mbedtls_ssl_config_free(&ctx
->conf
);
319 free(ctx
->ciphersuites
);
323 static void ustream_ssl_error(struct ustream_ssl
*us
, int ret
)
326 uloop_timeout_set(&us
->error_timer
, 0);
329 static bool ssl_do_wait(int ret
)
332 case MBEDTLS_ERR_SSL_WANT_READ
:
333 case MBEDTLS_ERR_SSL_WANT_WRITE
:
340 static void ustream_ssl_verify_cert(struct ustream_ssl
*us
)
343 const char *msg
= NULL
;
347 r
= mbedtls_ssl_get_verify_result(ssl
);
348 cn_mismatch
= r
& MBEDTLS_X509_BADCERT_CN_MISMATCH
;
349 r
&= ~MBEDTLS_X509_BADCERT_CN_MISMATCH
;
351 if (r
& MBEDTLS_X509_BADCERT_EXPIRED
)
352 msg
= "certificate has expired";
353 else if (r
& MBEDTLS_X509_BADCERT_REVOKED
)
354 msg
= "certificate has been revoked";
355 else if (r
& MBEDTLS_X509_BADCERT_NOT_TRUSTED
)
356 msg
= "certificate is self-signed or not signed by a trusted CA";
358 msg
= "unknown error";
361 if (us
->notify_verify_error
)
362 us
->notify_verify_error(us
, r
, msg
);
370 __hidden
enum ssl_conn_status
__ustream_ssl_connect(struct ustream_ssl
*us
)
375 r
= mbedtls_ssl_handshake(ssl
);
377 ustream_ssl_verify_cert(us
);
382 return U_SSL_PENDING
;
384 ustream_ssl_error(us
, r
);
388 __hidden
int __ustream_ssl_write(struct ustream_ssl
*us
, const char *buf
, int len
)
391 int done
= 0, ret
= 0;
393 while (done
!= len
) {
394 ret
= mbedtls_ssl_write(ssl
, (const unsigned char *) buf
+ done
, len
- done
);
397 if (ssl_do_wait(ret
))
400 ustream_ssl_error(us
, ret
);
410 __hidden
int __ustream_ssl_read(struct ustream_ssl
*us
, char *buf
, int len
)
412 int ret
= mbedtls_ssl_read(us
->ssl
, (unsigned char *) buf
, len
);
415 if (ssl_do_wait(ret
))
416 return U_SSL_PENDING
;
418 if (ret
== MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY
)
421 ustream_ssl_error(us
, ret
);
428 __hidden
void *__ustream_ssl_session_new(struct ustream_ssl_ctx
*ctx
)
430 mbedtls_ssl_context
*ssl
;
432 ssl
= calloc(1, sizeof(*ssl
));
436 mbedtls_ssl_init(ssl
);
438 if (mbedtls_ssl_setup(ssl
, &ctx
->conf
)) {
446 __hidden
void __ustream_ssl_session_free(void *ssl
)
448 mbedtls_ssl_free(ssl
);