13785ce6e587dd1be9d400ad7ab37bfc4299cf41
[project/ustream-ssl.git] / 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
30 static int s_ustream_read(void *ctx, unsigned char *buf, size_t len)
31 {
32 struct ustream *s = ctx;
33 char *sbuf;
34 int slen;
35
36 if (s->eof)
37 return 0;
38
39 sbuf = ustream_get_read_buf(s, &slen);
40 if ((size_t) slen > len)
41 slen = len;
42
43 if (!slen)
44 return MBEDTLS_ERR_SSL_WANT_READ;
45
46 memcpy(buf, sbuf, slen);
47 ustream_consume(s, slen);
48
49 return slen;
50 }
51
52 static int s_ustream_write(void *ctx, const unsigned char *buf, size_t len)
53 {
54 struct ustream *s = ctx;
55 int ret;
56
57 ret = ustream_write(s, (const char *) buf, len, false);
58 if (ret < 0 || s->write_error)
59 return MBEDTLS_ERR_NET_SEND_FAILED;
60
61 return ret;
62 }
63
64 __hidden void ustream_set_io(struct ustream_ssl_ctx *ctx, void *ssl, struct ustream *conn)
65 {
66 mbedtls_ssl_set_bio(ssl, conn, s_ustream_write, s_ustream_read, NULL);
67 }
68
69 static int _random(void *ctx, unsigned char *out, size_t len)
70 {
71 #ifdef linux
72 if (getrandom(out, len, 0) != (ssize_t) len)
73 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
74 #else
75 static FILE *f;
76
77 if (!f)
78 f = fopen("/dev/urandom", "r");
79 if (fread(out, len, 1, f) != 1)
80 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
81 #endif
82
83 return 0;
84 }
85
86 #define AES_GCM_CIPHERS(v) \
87 MBEDTLS_TLS_##v##_WITH_AES_128_GCM_SHA256, \
88 MBEDTLS_TLS_##v##_WITH_AES_256_GCM_SHA384
89
90 #define AES_CBC_CIPHERS(v) \
91 MBEDTLS_TLS_##v##_WITH_AES_128_CBC_SHA, \
92 MBEDTLS_TLS_##v##_WITH_AES_256_CBC_SHA
93
94 #define AES_CIPHERS(v) \
95 AES_GCM_CIPHERS(v), \
96 AES_CBC_CIPHERS(v)
97
98 static const int default_ciphersuites_server[] =
99 {
100 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
101 AES_GCM_CIPHERS(ECDHE_ECDSA),
102 MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
103 AES_GCM_CIPHERS(ECDHE_RSA),
104 AES_CBC_CIPHERS(ECDHE_RSA),
105 AES_CIPHERS(RSA),
106 0
107 };
108
109 static const int default_ciphersuites_client[] =
110 {
111 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
112 AES_GCM_CIPHERS(ECDHE_ECDSA),
113 MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
114 AES_GCM_CIPHERS(ECDHE_RSA),
115 MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
116 AES_GCM_CIPHERS(DHE_RSA),
117 AES_CBC_CIPHERS(ECDHE_ECDSA),
118 AES_CBC_CIPHERS(ECDHE_RSA),
119 AES_CBC_CIPHERS(DHE_RSA),
120 /* Removed in Mbed TLS 3.0.0 */
121 #ifdef MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
122 MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
123 #endif
124 AES_CIPHERS(RSA),
125 /* Removed in Mbed TLS 3.0.0 */
126 #ifdef MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA
127 MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
128 #endif
129 0
130 };
131
132
133 __hidden struct ustream_ssl_ctx *
134 __ustream_ssl_context_new(bool server)
135 {
136 struct ustream_ssl_ctx *ctx;
137 mbedtls_ssl_config *conf;
138 int ep;
139
140 #ifdef MBEDTLS_PSA_CRYPTO_C
141 static bool psa_init;
142
143 if (!psa_init && !psa_crypto_init())
144 psa_init = true;
145 #endif
146
147 ctx = calloc(1, sizeof(*ctx));
148 if (!ctx)
149 return NULL;
150
151 ctx->server = server;
152 mbedtls_pk_init(&ctx->key);
153 mbedtls_x509_crt_init(&ctx->cert);
154 mbedtls_x509_crt_init(&ctx->ca_cert);
155
156 #if defined(MBEDTLS_SSL_CACHE_C)
157 mbedtls_ssl_cache_init(&ctx->cache);
158 mbedtls_ssl_cache_set_timeout(&ctx->cache, 30 * 60);
159 mbedtls_ssl_cache_set_max_entries(&ctx->cache, 5);
160 #endif
161
162 conf = &ctx->conf;
163 mbedtls_ssl_config_init(conf);
164
165 ep = server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT;
166
167 mbedtls_ssl_config_defaults(conf, ep, MBEDTLS_SSL_TRANSPORT_STREAM,
168 MBEDTLS_SSL_PRESET_DEFAULT);
169 mbedtls_ssl_conf_rng(conf, _random, NULL);
170
171 if (server) {
172 mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
173 mbedtls_ssl_conf_ciphersuites(conf, default_ciphersuites_server);
174 mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3,
175 MBEDTLS_SSL_MINOR_VERSION_3);
176 } else {
177 mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
178 mbedtls_ssl_conf_ciphersuites(conf, default_ciphersuites_client);
179 }
180
181 #if defined(MBEDTLS_SSL_CACHE_C)
182 mbedtls_ssl_conf_session_cache(conf, &ctx->cache,
183 mbedtls_ssl_cache_get,
184 mbedtls_ssl_cache_set);
185 #endif
186 return ctx;
187 }
188
189 static void ustream_ssl_update_own_cert(struct ustream_ssl_ctx *ctx)
190 {
191 if (!ctx->cert.version)
192 return;
193
194 if (mbedtls_pk_get_type(&ctx->key) == MBEDTLS_PK_NONE)
195 return;
196
197 mbedtls_ssl_conf_own_cert(&ctx->conf, &ctx->cert, &ctx->key);
198 }
199
200 __hidden int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx *ctx, const char *file)
201 {
202 int ret;
203
204 ret = mbedtls_x509_crt_parse_file(&ctx->ca_cert, file);
205 if (ret)
206 return -1;
207
208 mbedtls_ssl_conf_ca_chain(&ctx->conf, &ctx->ca_cert, NULL);
209 mbedtls_ssl_conf_authmode(&ctx->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
210 return 0;
211 }
212
213 __hidden int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file)
214 {
215 int ret;
216
217 ret = mbedtls_x509_crt_parse_file(&ctx->cert, file);
218 if (ret)
219 return -1;
220
221 ustream_ssl_update_own_cert(ctx);
222 return 0;
223 }
224
225 __hidden int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file)
226 {
227 int ret;
228
229 #if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
230 ret = mbedtls_pk_parse_keyfile(&ctx->key, file, NULL, _random, NULL);
231 #else
232 ret = mbedtls_pk_parse_keyfile(&ctx->key, file, NULL);
233 #endif
234 if (ret)
235 return -1;
236
237 ustream_ssl_update_own_cert(ctx);
238 return 0;
239 }
240
241 __hidden int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers)
242 {
243 int *ciphersuites = NULL, *tmp, id;
244 char *cipherstr, *p, *last, c;
245 size_t len = 0;
246
247 if (ciphers == NULL)
248 return -1;
249
250 cipherstr = strdup(ciphers);
251
252 if (cipherstr == NULL)
253 return -1;
254
255 for (p = cipherstr, last = p;; p++) {
256 if (*p == ':' || *p == 0) {
257 c = *p;
258 *p = 0;
259
260 id = mbedtls_ssl_get_ciphersuite_id(last);
261
262 if (id != 0) {
263 tmp = realloc(ciphersuites, (len + 2) * sizeof(int));
264
265 if (tmp == NULL) {
266 free(ciphersuites);
267 free(cipherstr);
268
269 return -1;
270 }
271
272 ciphersuites = tmp;
273 ciphersuites[len++] = id;
274 ciphersuites[len] = 0;
275 }
276
277 if (c == 0)
278 break;
279
280 last = p + 1;
281 }
282
283 /*
284 * mbedTLS expects cipher names with dashes while many sources elsewhere
285 * like the Firefox wiki or Wireshark specify ciphers with underscores,
286 * so simply convert all underscores to dashes to accept both notations.
287 */
288 else if (*p == '_') {
289 *p = '-';
290 }
291 }
292
293 free(cipherstr);
294
295 if (len == 0)
296 return -1;
297
298 mbedtls_ssl_conf_ciphersuites(&ctx->conf, ciphersuites);
299 free(ctx->ciphersuites);
300
301 ctx->ciphersuites = ciphersuites;
302
303 return 0;
304 }
305
306 __hidden int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx *ctx, bool require)
307 {
308 int mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
309
310 if (!require)
311 mode = MBEDTLS_SSL_VERIFY_NONE;
312
313 mbedtls_ssl_conf_authmode(&ctx->conf, mode);
314
315 return 0;
316 }
317
318 __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx)
319 {
320 #if defined(MBEDTLS_SSL_CACHE_C)
321 mbedtls_ssl_cache_free(&ctx->cache);
322 #endif
323 mbedtls_pk_free(&ctx->key);
324 mbedtls_x509_crt_free(&ctx->ca_cert);
325 mbedtls_x509_crt_free(&ctx->cert);
326 mbedtls_ssl_config_free(&ctx->conf);
327 free(ctx->ciphersuites);
328 free(ctx);
329 }
330
331 static void ustream_ssl_error(struct ustream_ssl *us, int ret)
332 {
333 us->error = ret;
334 uloop_timeout_set(&us->error_timer, 0);
335 }
336
337 static bool ssl_do_wait(int ret)
338 {
339 switch(ret) {
340 case MBEDTLS_ERR_SSL_WANT_READ:
341 case MBEDTLS_ERR_SSL_WANT_WRITE:
342 return true;
343 default:
344 return false;
345 }
346 }
347
348 static void ustream_ssl_verify_cert(struct ustream_ssl *us)
349 {
350 void *ssl = us->ssl;
351 const char *msg = NULL;
352 bool cn_mismatch;
353 int r;
354
355 r = mbedtls_ssl_get_verify_result(ssl);
356 cn_mismatch = r & MBEDTLS_X509_BADCERT_CN_MISMATCH;
357 r &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
358
359 if (r & MBEDTLS_X509_BADCERT_EXPIRED)
360 msg = "certificate has expired";
361 else if (r & MBEDTLS_X509_BADCERT_REVOKED)
362 msg = "certificate has been revoked";
363 else if (r & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
364 msg = "certificate is self-signed or not signed by a trusted CA";
365 else
366 msg = "unknown error";
367
368 if (r) {
369 if (us->notify_verify_error)
370 us->notify_verify_error(us, r, msg);
371 return;
372 }
373
374 if (!cn_mismatch)
375 us->valid_cn = true;
376 }
377
378 __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us)
379 {
380 void *ssl = us->ssl;
381 int r;
382
383 r = mbedtls_ssl_handshake(ssl);
384 if (r == 0) {
385 ustream_ssl_verify_cert(us);
386 return U_SSL_OK;
387 }
388
389 if (ssl_do_wait(r))
390 return U_SSL_PENDING;
391
392 ustream_ssl_error(us, r);
393 return U_SSL_ERROR;
394 }
395
396 __hidden int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int len)
397 {
398 void *ssl = us->ssl;
399 int done = 0, ret = 0;
400
401 while (done != len) {
402 ret = mbedtls_ssl_write(ssl, (const unsigned char *) buf + done, len - done);
403
404 if (ret < 0) {
405 if (ssl_do_wait(ret))
406 return done;
407
408 ustream_ssl_error(us, ret);
409 return -1;
410 }
411
412 done += ret;
413 }
414
415 return done;
416 }
417
418 __hidden int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len)
419 {
420 int ret = mbedtls_ssl_read(us->ssl, (unsigned char *) buf, len);
421
422 if (ret < 0) {
423 if (ssl_do_wait(ret))
424 return U_SSL_PENDING;
425
426 if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
427 return 0;
428
429 ustream_ssl_error(us, ret);
430 return U_SSL_ERROR;
431 }
432
433 return ret;
434 }
435
436 __hidden void *__ustream_ssl_session_new(struct ustream_ssl_ctx *ctx)
437 {
438 mbedtls_ssl_context *ssl;
439
440 ssl = calloc(1, sizeof(*ssl));
441 if (!ssl)
442 return NULL;
443
444 mbedtls_ssl_init(ssl);
445
446 if (mbedtls_ssl_setup(ssl, &ctx->conf)) {
447 free(ssl);
448 return NULL;
449 }
450
451 return ssl;
452 }
453
454 __hidden void __ustream_ssl_session_free(void *ssl)
455 {
456 mbedtls_ssl_free(ssl);
457 free(ssl);
458 }