]>
Commit | Line | Data |
---|---|---|
cd492e44 | 1 | /* |
fe037171 | 2 | * librb: a library used by ircd-ratbox and other things |
72725187 | 3 | * mbedtls.c: ARM MbedTLS backend |
cd492e44 AC |
4 | * |
5 | * Copyright (C) 2007-2008 ircd-ratbox development team | |
6 | * Copyright (C) 2007-2008 Aaron Sethman <androsyn@ratbox.org> | |
7 | * Copyright (C) 2015 William Pitcock <nenolod@dereferenced.org> | |
1e7342d0 | 8 | * Copyright (C) 2016 Aaron Jones <aaronmdjones@gmail.com> |
cd492e44 AC |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or | |
13 | * (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |
23 | * USA | |
24 | * | |
cd492e44 AC |
25 | */ |
26 | ||
fe037171 EM |
27 | #include <librb_config.h> |
28 | #include <rb_lib.h> | |
cd492e44 AC |
29 | |
30 | #ifdef HAVE_MBEDTLS | |
31 | ||
dd066596 AJ |
32 | #include <commio-int.h> |
33 | #include <commio-ssl.h> | |
34 | #include <stdbool.h> | |
cd492e44 | 35 | |
dd066596 | 36 | #include "mbedtls_ratbox.h" |
cd492e44 | 37 | |
c4acd427 AJ |
38 | typedef enum |
39 | { | |
40 | RB_FD_TLS_DIRECTION_IN = 0, | |
41 | RB_FD_TLS_DIRECTION_OUT = 1 | |
42 | } rb_fd_tls_direction; | |
43 | ||
72725187 AJ |
44 | #define RB_MAX_CIPHERSUITES 512 |
45 | ||
1e7342d0 AJ |
46 | typedef struct |
47 | { | |
48 | mbedtls_x509_crt crt; | |
49 | mbedtls_pk_context key; | |
50 | mbedtls_dhm_context dhp; | |
51 | mbedtls_ssl_config server_cfg; | |
52 | mbedtls_ssl_config client_cfg; | |
53 | size_t refcount; | |
515467e5 | 54 | int suites[RB_MAX_CIPHERSUITES + 1]; |
1e7342d0 AJ |
55 | } rb_mbedtls_cfg_context; |
56 | ||
57 | typedef struct | |
58 | { | |
59 | rb_mbedtls_cfg_context *cfg; | |
60 | mbedtls_ssl_context ssl; | |
61 | } rb_mbedtls_ssl_context; | |
62 | ||
63 | #define SSL_C(x) ((rb_mbedtls_ssl_context *) (x)->ssl)->cfg | |
64 | #define SSL_P(x) &((rb_mbedtls_ssl_context *) (x)->ssl)->ssl | |
65 | ||
66 | static mbedtls_ctr_drbg_context ctr_drbg_ctx; | |
67 | static mbedtls_entropy_context entropy_ctx; | |
68 | ||
69 | static mbedtls_x509_crt dummy_ca_ctx; | |
70 | static rb_mbedtls_cfg_context *rb_mbedtls_cfg = NULL; | |
71 | ||
72725187 AJ |
72 | |
73 | ||
74 | struct ssl_connect | |
75 | { | |
76 | CNCB *callback; | |
77 | void *data; | |
78 | int timeout; | |
79 | }; | |
80 | ||
dd066596 | 81 | static const char *rb_ssl_strerror(int); |
72725187 AJ |
82 | static void rb_ssl_connect_realcb(rb_fde_t *, int, struct ssl_connect *); |
83 | ||
72725187 AJ |
84 | |
85 | ||
86 | /* | |
87 | * Internal MbedTLS-specific code | |
88 | */ | |
89 | ||
72725187 AJ |
90 | static void |
91 | rb_mbedtls_cfg_incref(rb_mbedtls_cfg_context *const cfg) | |
1e7342d0 AJ |
92 | { |
93 | lrb_assert(cfg->refcount > 0); | |
94 | ||
95 | cfg->refcount++; | |
96 | } | |
97 | ||
72725187 AJ |
98 | static void |
99 | rb_mbedtls_cfg_decref(rb_mbedtls_cfg_context *const cfg) | |
1e7342d0 AJ |
100 | { |
101 | if(cfg == NULL) | |
102 | return; | |
103 | ||
104 | lrb_assert(cfg->refcount > 0); | |
105 | ||
106 | if((--cfg->refcount) > 0) | |
107 | return; | |
108 | ||
109 | mbedtls_ssl_config_free(&cfg->client_cfg); | |
110 | mbedtls_ssl_config_free(&cfg->server_cfg); | |
111 | mbedtls_dhm_free(&cfg->dhp); | |
112 | mbedtls_pk_free(&cfg->key); | |
113 | mbedtls_x509_crt_free(&cfg->crt); | |
114 | ||
c4acd427 AJ |
115 | rb_free(cfg); |
116 | } | |
117 | ||
05281d7a AJ |
118 | static int |
119 | rb_sock_net_recv(void *const context_ptr, unsigned char *const buf, const size_t count) | |
120 | { | |
121 | const int fd = rb_get_fd((rb_fde_t *)context_ptr); | |
122 | ||
123 | const int ret = (int) read(fd, buf, count); | |
124 | ||
125 | if(ret < 0 && rb_ignore_errno(errno)) | |
126 | return MBEDTLS_ERR_SSL_WANT_READ; | |
127 | ||
128 | return ret; | |
129 | } | |
130 | ||
131 | static int | |
132 | rb_sock_net_xmit(void *const context_ptr, const unsigned char *const buf, const size_t count) | |
133 | { | |
134 | const int fd = rb_get_fd((rb_fde_t *)context_ptr); | |
135 | ||
136 | const int ret = (int) write(fd, buf, count); | |
137 | ||
138 | if(ret < 0 && rb_ignore_errno(errno)) | |
139 | return MBEDTLS_ERR_SSL_WANT_WRITE; | |
140 | ||
141 | return ret; | |
142 | } | |
143 | ||
c4acd427 | 144 | static void |
dd066596 | 145 | rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir) |
c4acd427 | 146 | { |
dd066596 AJ |
147 | rb_mbedtls_ssl_context *const mbed_ssl_ctx = rb_malloc(sizeof *mbed_ssl_ctx); |
148 | ||
149 | if(mbed_ssl_ctx == NULL) | |
150 | { | |
151 | rb_lib_log("%s: rb_malloc: allocation failure", __func__); | |
152 | rb_close(F); | |
153 | return; | |
154 | } | |
155 | ||
c3abf982 | 156 | mbedtls_ssl_config *mbed_config = NULL; |
c4acd427 AJ |
157 | |
158 | switch(dir) | |
159 | { | |
160 | case RB_FD_TLS_DIRECTION_IN: | |
161 | mbed_config = &rb_mbedtls_cfg->server_cfg; | |
162 | break; | |
163 | case RB_FD_TLS_DIRECTION_OUT: | |
164 | mbed_config = &rb_mbedtls_cfg->client_cfg; | |
165 | break; | |
c4acd427 AJ |
166 | } |
167 | ||
168 | mbedtls_ssl_init(&mbed_ssl_ctx->ssl); | |
c4acd427 AJ |
169 | |
170 | int ret; | |
171 | ||
172 | if((ret = mbedtls_ssl_setup(&mbed_ssl_ctx->ssl, mbed_config)) != 0) | |
173 | { | |
dd066596 | 174 | rb_lib_log("%s: ssl_setup: %s", __func__, rb_ssl_strerror(ret)); |
c4acd427 AJ |
175 | mbedtls_ssl_free(&mbed_ssl_ctx->ssl); |
176 | rb_free(mbed_ssl_ctx); | |
177 | rb_close(F); | |
178 | return; | |
179 | } | |
180 | ||
dd066596 AJ |
181 | mbedtls_ssl_set_bio(&mbed_ssl_ctx->ssl, F, rb_sock_net_xmit, rb_sock_net_recv, NULL); |
182 | ||
c4acd427 AJ |
183 | rb_mbedtls_cfg_incref(rb_mbedtls_cfg); |
184 | mbed_ssl_ctx->cfg = rb_mbedtls_cfg; | |
185 | ||
186 | F->ssl = mbed_ssl_ctx; | |
1e7342d0 AJ |
187 | } |
188 | ||
72725187 AJ |
189 | static rb_mbedtls_cfg_context * |
190 | rb_mbedtls_cfg_new(void) | |
1e7342d0 | 191 | { |
c4acd427 | 192 | rb_mbedtls_cfg_context *const cfg = rb_malloc(sizeof *cfg); |
1e7342d0 | 193 | |
72725187 | 194 | if(cfg == NULL) |
1e7342d0 AJ |
195 | return NULL; |
196 | ||
197 | mbedtls_x509_crt_init(&cfg->crt); | |
198 | mbedtls_pk_init(&cfg->key); | |
199 | mbedtls_dhm_init(&cfg->dhp); | |
200 | mbedtls_ssl_config_init(&cfg->server_cfg); | |
201 | mbedtls_ssl_config_init(&cfg->client_cfg); | |
202 | ||
72725187 AJ |
203 | (void) memset(cfg->suites, 0x00, sizeof cfg->suites); |
204 | ||
1e7342d0 AJ |
205 | cfg->refcount = 1; |
206 | ||
72725187 AJ |
207 | int ret; |
208 | ||
1e7342d0 AJ |
209 | if((ret = mbedtls_ssl_config_defaults(&cfg->server_cfg, |
210 | MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, | |
211 | MBEDTLS_SSL_PRESET_DEFAULT)) != 0) | |
212 | { | |
dd066596 | 213 | rb_lib_log("%s: ssl_config_defaults (server): %s", __func__, rb_ssl_strerror(ret)); |
1e7342d0 AJ |
214 | rb_mbedtls_cfg_decref(cfg); |
215 | return NULL; | |
216 | } | |
217 | ||
218 | if((ret = mbedtls_ssl_config_defaults(&cfg->client_cfg, | |
219 | MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, | |
220 | MBEDTLS_SSL_PRESET_DEFAULT)) != 0) | |
221 | { | |
dd066596 | 222 | rb_lib_log("%s: ssl_config_defaults (client): %s", __func__, rb_ssl_strerror(ret)); |
1e7342d0 AJ |
223 | rb_mbedtls_cfg_decref(cfg); |
224 | return NULL; | |
225 | } | |
226 | ||
227 | mbedtls_ssl_conf_rng(&cfg->server_cfg, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); | |
228 | mbedtls_ssl_conf_rng(&cfg->client_cfg, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); | |
229 | ||
230 | mbedtls_ssl_conf_ca_chain(&cfg->server_cfg, &dummy_ca_ctx, NULL); | |
231 | mbedtls_ssl_conf_ca_chain(&cfg->client_cfg, &dummy_ca_ctx, NULL); | |
232 | ||
233 | mbedtls_ssl_conf_authmode(&cfg->server_cfg, MBEDTLS_SSL_VERIFY_OPTIONAL); | |
234 | mbedtls_ssl_conf_authmode(&cfg->client_cfg, MBEDTLS_SSL_VERIFY_NONE); | |
235 | ||
c3abf982 AJ |
236 | mbedtls_ssl_conf_min_version(&cfg->server_cfg, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2); |
237 | mbedtls_ssl_conf_min_version(&cfg->client_cfg, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2); | |
238 | ||
72725187 AJ |
239 | #ifdef MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE |
240 | mbedtls_ssl_conf_legacy_renegotiation(&cfg->client_cfg, MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE); | |
241 | #endif | |
242 | ||
243 | #ifdef MBEDTLS_SSL_SESSION_TICKETS_DISABLED | |
244 | mbedtls_ssl_conf_session_tickets(&cfg->client_cfg, MBEDTLS_SSL_SESSION_TICKETS_DISABLED); | |
245 | #endif | |
246 | ||
1e7342d0 AJ |
247 | return cfg; |
248 | } | |
cd492e44 | 249 | |
cd492e44 | 250 | static void |
72725187 | 251 | rb_ssl_accept_common(rb_fde_t *const F, void *const data) |
cd492e44 | 252 | { |
72725187 | 253 | lrb_assert(F != NULL); |
cd492e44 | 254 | lrb_assert(F->accept != NULL); |
72725187 AJ |
255 | lrb_assert(F->accept->callback != NULL); |
256 | lrb_assert(F->ssl != NULL); | |
cd492e44 | 257 | |
515467e5 AJ |
258 | (void) data; |
259 | ||
dd066596 | 260 | const int ret = mbedtls_ssl_handshake(SSL_P(F)); |
cd492e44 | 261 | |
c4acd427 | 262 | switch(ret) |
cd492e44 | 263 | { |
c4acd427 AJ |
264 | case 0: |
265 | F->handshake_count++; | |
266 | break; | |
267 | case MBEDTLS_ERR_SSL_WANT_READ: | |
268 | rb_setselect(F, RB_SELECT_READ, rb_ssl_accept_common, NULL); | |
269 | return; | |
270 | case MBEDTLS_ERR_SSL_WANT_WRITE: | |
271 | rb_setselect(F, RB_SELECT_WRITE, rb_ssl_accept_common, NULL); | |
272 | return; | |
273 | default: | |
274 | errno = EIO; | |
dd066596 | 275 | F->ssl_errno = (unsigned long) -ret; |
c4acd427 AJ |
276 | F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data); |
277 | return; | |
1e7342d0 | 278 | } |
539d912b | 279 | |
72725187 AJ |
280 | rb_settimeout(F, 0, NULL, NULL); |
281 | rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); | |
539d912b | 282 | |
72725187 AJ |
283 | struct acceptdata *const ad = F->accept; |
284 | F->accept = NULL; | |
285 | ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); | |
c4acd427 | 286 | rb_free(ad); |
cd492e44 AC |
287 | } |
288 | ||
289 | static void | |
dd066596 | 290 | rb_ssl_connect_common(rb_fde_t *const F, void *const data) |
cd492e44 | 291 | { |
72725187 AJ |
292 | lrb_assert(F != NULL); |
293 | lrb_assert(F->ssl != NULL); | |
cd492e44 | 294 | |
dd066596 | 295 | const int ret = mbedtls_ssl_handshake(SSL_P(F)); |
cd492e44 | 296 | |
c4acd427 | 297 | switch(ret) |
72725187 | 298 | { |
c4acd427 AJ |
299 | case 0: |
300 | F->handshake_count++; | |
301 | break; | |
302 | case MBEDTLS_ERR_SSL_WANT_READ: | |
dd066596 | 303 | rb_setselect(F, RB_SELECT_READ, rb_ssl_connect_common, data); |
c4acd427 AJ |
304 | return; |
305 | case MBEDTLS_ERR_SSL_WANT_WRITE: | |
dd066596 | 306 | rb_setselect(F, RB_SELECT_WRITE, rb_ssl_connect_common, data); |
c4acd427 AJ |
307 | return; |
308 | default: | |
309 | errno = EIO; | |
dd066596 | 310 | F->ssl_errno = (unsigned long) -ret; |
c4acd427 AJ |
311 | rb_ssl_connect_realcb(F, RB_ERROR_SSL, data); |
312 | return; | |
72725187 | 313 | } |
cd492e44 | 314 | |
72725187 | 315 | rb_ssl_connect_realcb(F, RB_OK, data); |
cd492e44 AC |
316 | } |
317 | ||
c4acd427 | 318 | static const char * |
515467e5 | 319 | rb_ssl_strerror(int err) |
c4acd427 AJ |
320 | { |
321 | static char errbuf[512]; | |
322 | ||
515467e5 AJ |
323 | if (err < 0) |
324 | err = -err; | |
325 | ||
c4acd427 AJ |
326 | #ifdef MBEDTLS_ERROR_C |
327 | char mbed_errbuf[512]; | |
328 | mbedtls_strerror(err, mbed_errbuf, sizeof mbed_errbuf); | |
515467e5 | 329 | (void) snprintf(errbuf, sizeof errbuf, "-0x%X: %s", (unsigned int) err, mbed_errbuf); |
c4acd427 | 330 | #else |
515467e5 | 331 | (void) snprintf(errbuf, sizeof errbuf, "-0x%X", (unsigned int) err); |
c4acd427 AJ |
332 | #endif |
333 | ||
334 | return errbuf; | |
335 | } | |
336 | ||
dd066596 AJ |
337 | static int |
338 | rb_make_certfp(const mbedtls_x509_crt *const peer_cert, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method) | |
cd492e44 | 339 | { |
72725187 | 340 | size_t hashlen = 0; |
dd066596 | 341 | mbedtls_md_type_t md_type; |
72725187 | 342 | bool spki = false; |
cd492e44 | 343 | |
72725187 AJ |
344 | switch(method) |
345 | { | |
346 | case RB_SSL_CERTFP_METH_CERT_SHA1: | |
347 | md_type = MBEDTLS_MD_SHA1; | |
348 | hashlen = RB_SSL_CERTFP_LEN_SHA1; | |
349 | break; | |
72725187 AJ |
350 | case RB_SSL_CERTFP_METH_SPKI_SHA256: |
351 | spki = true; | |
352 | case RB_SSL_CERTFP_METH_CERT_SHA256: | |
353 | md_type = MBEDTLS_MD_SHA256; | |
354 | hashlen = RB_SSL_CERTFP_LEN_SHA256; | |
355 | break; | |
72725187 AJ |
356 | case RB_SSL_CERTFP_METH_SPKI_SHA512: |
357 | spki = true; | |
358 | case RB_SSL_CERTFP_METH_CERT_SHA512: | |
359 | md_type = MBEDTLS_MD_SHA512; | |
360 | hashlen = RB_SSL_CERTFP_LEN_SHA512; | |
361 | break; | |
72725187 AJ |
362 | default: |
363 | return 0; | |
364 | } | |
365 | ||
366 | const mbedtls_md_info_t *const md_info = mbedtls_md_info_from_type(md_type); | |
367 | if(md_info == NULL) | |
368 | return 0; | |
cd492e44 | 369 | |
cd492e44 | 370 | int ret; |
72725187 AJ |
371 | void* data = peer_cert->raw.p; |
372 | size_t datalen = peer_cert->raw.len; | |
cd492e44 | 373 | |
72725187 | 374 | if(spki) |
1e7342d0 | 375 | { |
515467e5 AJ |
376 | // Compiler may complain about dropping const qualifier on the cast below |
377 | // See <https://github.com/ARMmbed/mbedtls/issues/396> -- this is okay | |
378 | ||
72725187 AJ |
379 | unsigned char der_pubkey[8192]; |
380 | if((ret = mbedtls_pk_write_pubkey_der((mbedtls_pk_context *)&peer_cert->pk, | |
381 | der_pubkey, sizeof der_pubkey)) < 0) | |
382 | { | |
dd066596 | 383 | rb_lib_log("rb_get_ssl_certfp: pk_write_pubkey_der: %s", rb_ssl_strerror(ret)); |
72725187 AJ |
384 | return 0; |
385 | } | |
386 | data = der_pubkey + (sizeof(der_pubkey) - (size_t)ret); | |
387 | datalen = (size_t)ret; | |
1e7342d0 AJ |
388 | } |
389 | ||
72725187 | 390 | if((ret = mbedtls_md(md_info, data, datalen, certfp)) != 0) |
cd492e44 | 391 | { |
dd066596 | 392 | rb_lib_log("rb_get_ssl_certfp: mbedtls_md: %s", rb_ssl_strerror(ret)); |
72725187 | 393 | return 0; |
cd492e44 AC |
394 | } |
395 | ||
dd066596 | 396 | return (int) hashlen; |
cd492e44 AC |
397 | } |
398 | ||
cd492e44 | 399 | |
cd492e44 | 400 | |
72725187 AJ |
401 | /* |
402 | * External MbedTLS-specific code | |
403 | */ | |
cd492e44 AC |
404 | |
405 | void | |
72725187 | 406 | rb_ssl_shutdown(rb_fde_t *const F) |
cd492e44 | 407 | { |
72725187 AJ |
408 | if(F == NULL || F->ssl == NULL) |
409 | return; | |
cd492e44 | 410 | |
c4acd427 | 411 | for(int i = 0; i < 4; i++) |
cd492e44 | 412 | { |
c4acd427 | 413 | int ret = mbedtls_ssl_close_notify(SSL_P(F)); |
72725187 | 414 | |
c4acd427 AJ |
415 | if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) |
416 | break; | |
cd492e44 AC |
417 | } |
418 | ||
c4acd427 AJ |
419 | mbedtls_ssl_free(SSL_P(F)); |
420 | rb_mbedtls_cfg_decref(SSL_C(F)); | |
cd492e44 | 421 | |
c4acd427 | 422 | rb_free(F->ssl); |
72725187 | 423 | F->ssl = NULL; |
cd492e44 AC |
424 | } |
425 | ||
426 | int | |
427 | rb_init_ssl(void) | |
428 | { | |
1e7342d0 AJ |
429 | mbedtls_ctr_drbg_init(&ctr_drbg_ctx); |
430 | mbedtls_entropy_init(&entropy_ctx); | |
cd492e44 | 431 | |
72725187 AJ |
432 | int ret; |
433 | ||
1e7342d0 | 434 | if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, |
72725187 | 435 | (const unsigned char *)rb_mbedtls_personal_str, sizeof(rb_mbedtls_personal_str))) != 0) |
cd492e44 | 436 | { |
dd066596 | 437 | rb_lib_log("%s: ctr_drbg_seed: %s", __func__, rb_ssl_strerror(ret)); |
cd492e44 AC |
438 | return 0; |
439 | } | |
440 | ||
1e7342d0 AJ |
441 | if((ret = mbedtls_x509_crt_parse_der(&dummy_ca_ctx, rb_mbedtls_dummy_ca_certificate, |
442 | sizeof(rb_mbedtls_dummy_ca_certificate))) != 0) | |
cd492e44 | 443 | { |
dd066596 | 444 | rb_lib_log("%s: x509_crt_parse_der (Dummy CA): %s", __func__, rb_ssl_strerror(ret)); |
cd492e44 AC |
445 | return 0; |
446 | } | |
447 | ||
dd066596 | 448 | rb_lib_log("%s: MbedTLS backend initialised", __func__); |
cd492e44 AC |
449 | return 1; |
450 | } | |
451 | ||
452 | int | |
72725187 AJ |
453 | rb_setup_ssl_server(const char *const certfile, const char *keyfile, |
454 | const char *const dhfile, const char *const cipherlist) | |
cd492e44 | 455 | { |
1e7342d0 | 456 | if(certfile == NULL) |
cd492e44 | 457 | { |
dd066596 | 458 | rb_lib_log("%s: no certificate file specified", __func__); |
cd492e44 AC |
459 | return 0; |
460 | } | |
461 | ||
1e7342d0 AJ |
462 | if(keyfile == NULL) |
463 | keyfile = certfile; | |
464 | ||
72725187 AJ |
465 | rb_mbedtls_cfg_context *const newcfg = rb_mbedtls_cfg_new(); |
466 | ||
467 | if(newcfg == NULL) | |
cd492e44 | 468 | { |
dd066596 | 469 | rb_lib_log("%s: rb_mbedtls_cfg_new: allocation failed", __func__); |
cd492e44 AC |
470 | return 0; |
471 | } | |
472 | ||
72725187 AJ |
473 | int ret; |
474 | ||
1e7342d0 | 475 | if((ret = mbedtls_x509_crt_parse_file(&newcfg->crt, certfile)) != 0) |
cd492e44 | 476 | { |
dd066596 | 477 | rb_lib_log("%s: x509_crt_parse_file ('%s'): %s", __func__, certfile, rb_ssl_strerror(ret)); |
1e7342d0 | 478 | rb_mbedtls_cfg_decref(newcfg); |
cd492e44 AC |
479 | return 0; |
480 | } | |
1e7342d0 | 481 | if((ret = mbedtls_pk_parse_keyfile(&newcfg->key, keyfile, NULL)) != 0) |
cd492e44 | 482 | { |
dd066596 AJ |
483 | rb_lib_log("%s: pk_parse_keyfile ('%s'): %s", __func__, keyfile, rb_ssl_strerror(ret)); |
484 | rb_mbedtls_cfg_decref(newcfg); | |
485 | return 0; | |
486 | } | |
e081bf29 AJ |
487 | if((ret = mbedtls_pk_check_pair(&newcfg->crt.pk, &newcfg->key)) != 0) |
488 | { | |
489 | rb_lib_log("%s: pk_check_pair: public/private key mismatch", __func__); | |
490 | rb_mbedtls_cfg_decref(newcfg); | |
491 | return 0; | |
492 | } | |
dd066596 AJ |
493 | if((ret = mbedtls_ssl_conf_own_cert(&newcfg->server_cfg, &newcfg->crt, &newcfg->key)) != 0) |
494 | { | |
495 | rb_lib_log("%s: ssl_conf_own_cert (server): %s", __func__, rb_ssl_strerror(ret)); | |
496 | rb_mbedtls_cfg_decref(newcfg); | |
497 | return 0; | |
498 | } | |
499 | if((ret = mbedtls_ssl_conf_own_cert(&newcfg->client_cfg, &newcfg->crt, &newcfg->key)) != 0) | |
500 | { | |
501 | rb_lib_log("%s: ssl_conf_own_cert (client): %s", __func__, rb_ssl_strerror(ret)); | |
1e7342d0 | 502 | rb_mbedtls_cfg_decref(newcfg); |
cd492e44 AC |
503 | return 0; |
504 | } | |
505 | ||
dd066596 | 506 | |
1e7342d0 AJ |
507 | /* Absense of DH parameters does not matter with mbedTLS, as it comes with its own defaults |
508 | Thus, clients can still use DHE- ciphersuites, just over a weaker, common DH group | |
509 | So, we do not consider failure to parse DH parameters as fatal */ | |
510 | if(dhfile == NULL) | |
511 | { | |
dd066596 | 512 | rb_lib_log("%s: no DH parameters file specified", __func__); |
1e7342d0 AJ |
513 | } |
514 | else | |
493897d6 | 515 | { |
1e7342d0 AJ |
516 | if((ret = mbedtls_dhm_parse_dhmfile(&newcfg->dhp, dhfile)) != 0) |
517 | { | |
dd066596 | 518 | rb_lib_log("%s: dhm_parse_dhmfile ('%s'): %s", __func__, dhfile, rb_ssl_strerror(ret)); |
1e7342d0 AJ |
519 | } |
520 | else if((ret = mbedtls_ssl_conf_dh_param_ctx(&newcfg->server_cfg, &newcfg->dhp)) != 0) | |
521 | { | |
dd066596 | 522 | rb_lib_log("%s: ssl_conf_dh_param_ctx: %s", __func__, rb_ssl_strerror(ret)); |
1e7342d0 | 523 | } |
493897d6 | 524 | } |
cd492e44 | 525 | |
1e7342d0 | 526 | |
72725187 AJ |
527 | const int *rb_ciphersuites = newcfg->suites; |
528 | size_t suites_count = 0; | |
cd492e44 | 529 | |
72725187 AJ |
530 | if(cipherlist != NULL) |
531 | { | |
532 | // The cipherlist is (const char *) -- we should not modify it | |
533 | char *const cipherlist_dup = strdup(cipherlist); | |
cd492e44 | 534 | |
72725187 AJ |
535 | if(cipherlist_dup != NULL) |
536 | { | |
537 | char *cipher_str = cipherlist_dup; | |
538 | char *cipher_idx; | |
cd492e44 | 539 | |
72725187 AJ |
540 | do |
541 | { | |
542 | // Arbitrary, but the same separator as OpenSSL uses | |
543 | cipher_idx = strchr(cipher_str, ':'); | |
cd492e44 | 544 | |
72725187 AJ |
545 | // This could legitimately be NULL (last ciphersuite in the list) |
546 | if(cipher_idx != NULL) | |
547 | *cipher_idx = '\0'; | |
548 | ||
549 | size_t cipher_len = strlen(cipher_str); | |
550 | int cipher_idn = 0; | |
551 | ||
552 | // All MbedTLS ciphersuite names begin with these 4 characters | |
553 | if(cipher_len > 4 && strncmp(cipher_str, "TLS-", 4) == 0) | |
554 | cipher_idn = mbedtls_ssl_get_ciphersuite_id(cipher_str); | |
555 | ||
556 | // Prevent the same ciphersuite being added multiple times | |
557 | for(size_t x = 0; cipher_idn != 0 && newcfg->suites[x] != 0; x++) | |
558 | if(newcfg->suites[x] == cipher_idn) | |
559 | cipher_idn = 0; | |
560 | ||
561 | // Add the suite to the list | |
562 | if(cipher_idn != 0) | |
563 | newcfg->suites[suites_count++] = cipher_idn; | |
564 | ||
565 | // Advance the string to the next entry | |
566 | if(cipher_idx) | |
567 | cipher_str = cipher_idx + 1; | |
568 | ||
569 | } while(cipher_idx && suites_count < RB_MAX_CIPHERSUITES); | |
570 | ||
571 | if(suites_count == 0) | |
dd066596 | 572 | rb_lib_log("%s: Ciphersuites provided, but could not parse any", __func__); |
72725187 AJ |
573 | |
574 | free(cipherlist_dup); | |
575 | } | |
576 | else | |
577 | { | |
dd066596 | 578 | rb_lib_log("%s: strdup: %s", __func__, strerror(errno)); |
72725187 AJ |
579 | } |
580 | } | |
581 | else | |
582 | { | |
dd066596 | 583 | rb_lib_log("%s: No ciphersuite list provided", __func__); |
72725187 AJ |
584 | } |
585 | ||
586 | if(suites_count == 0) | |
587 | { | |
dd066596 | 588 | rb_lib_log("%s: Using default ciphersuites", __func__); |
72725187 AJ |
589 | |
590 | rb_ciphersuites = rb_mbedtls_ciphersuites; | |
591 | suites_count = (sizeof(rb_mbedtls_ciphersuites) / sizeof(rb_mbedtls_ciphersuites[0])) - 1; | |
592 | } | |
593 | ||
594 | mbedtls_ssl_conf_ciphersuites(&newcfg->server_cfg, rb_ciphersuites); | |
595 | mbedtls_ssl_conf_ciphersuites(&newcfg->client_cfg, rb_ciphersuites); | |
dd066596 | 596 | rb_lib_log("%s: Configured %zu ciphersuites", __func__, suites_count); |
72725187 AJ |
597 | |
598 | ||
599 | rb_mbedtls_cfg_decref(rb_mbedtls_cfg); | |
600 | rb_mbedtls_cfg = newcfg; | |
601 | ||
dd066596 | 602 | rb_lib_log("%s: TLS configuration successful", __func__); |
72725187 | 603 | return 1; |
cd492e44 AC |
604 | } |
605 | ||
72725187 AJ |
606 | int |
607 | rb_init_prng(const char *const path, prng_seed_t seed_type) | |
cd492e44 | 608 | { |
515467e5 AJ |
609 | (void) path; |
610 | (void) seed_type; | |
611 | ||
dd066596 | 612 | rb_lib_log("%s: Skipping PRNG initialisation; not required by MbedTLS backend", __func__); |
72725187 | 613 | return 1; |
cd492e44 AC |
614 | } |
615 | ||
72725187 | 616 | int |
dd066596 | 617 | rb_get_random(void *const buf, const size_t length) |
cd492e44 | 618 | { |
72725187 | 619 | int ret; |
cd492e44 | 620 | |
72725187 | 621 | if((ret = mbedtls_ctr_drbg_random(&ctr_drbg_ctx, buf, length)) != 0) |
cd492e44 | 622 | { |
dd066596 | 623 | rb_lib_log("%s: ctr_drbg_random: %s", __func__, rb_ssl_strerror(ret)); |
72725187 | 624 | return 0; |
cd492e44 | 625 | } |
72725187 AJ |
626 | |
627 | return 1; | |
cd492e44 AC |
628 | } |
629 | ||
72725187 AJ |
630 | const char * |
631 | rb_get_ssl_strerror(rb_fde_t *const F) | |
cd492e44 | 632 | { |
dd066596 | 633 | const int err = (int) F->ssl_errno; |
515467e5 | 634 | return rb_ssl_strerror(err); |
72725187 | 635 | } |
cd492e44 | 636 | |
72725187 | 637 | int |
dd066596 | 638 | rb_get_ssl_certfp(rb_fde_t *const F, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method) |
72725187 AJ |
639 | { |
640 | const mbedtls_x509_crt *const peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F)); | |
cd492e44 | 641 | |
dd066596 AJ |
642 | if(peer_cert == NULL) |
643 | return 0; | |
644 | ||
645 | return rb_make_certfp(peer_cert, certfp, method); | |
cd492e44 AC |
646 | } |
647 | ||
72725187 | 648 | int |
dd066596 | 649 | rb_get_ssl_certfp_file(const char *const filename, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method) |
cd492e44 | 650 | { |
72725187 | 651 | mbedtls_x509_crt cert; |
dd066596 | 652 | |
72725187 | 653 | mbedtls_x509_crt_init(&cert); |
cd492e44 | 654 | |
dd066596 AJ |
655 | const int ret = mbedtls_x509_crt_parse_file(&cert, filename); |
656 | ||
657 | if(ret != 0) | |
72725187 | 658 | return -1; |
1e7342d0 | 659 | |
dd066596 | 660 | const int len = rb_make_certfp(&cert, certfp, method); |
72725187 AJ |
661 | |
662 | mbedtls_x509_crt_free(&cert); | |
663 | ||
dd066596 | 664 | return len; |
cd492e44 | 665 | } |
cd492e44 | 666 | void |
dd066596 | 667 | rb_get_ssl_info(char *const buf, const size_t len) |
cd492e44 | 668 | { |
72725187 | 669 | char version_str[512]; |
1e7342d0 | 670 | |
72725187 | 671 | mbedtls_version_get_string(version_str); |
cd492e44 | 672 | |
72725187 AJ |
673 | (void) snprintf(buf, len, "ARM mbedTLS: compiled (v%s), library (v%s)", |
674 | MBEDTLS_VERSION_STRING, version_str); | |
cd492e44 AC |
675 | } |
676 | ||
72725187 AJ |
677 | const char * |
678 | rb_ssl_get_cipher(rb_fde_t *const F) | |
cd492e44 | 679 | { |
dd066596 | 680 | if(F == NULL || F->ssl == NULL) |
72725187 | 681 | return NULL; |
cd492e44 | 682 | |
72725187 | 683 | static char buf[512]; |
cd492e44 | 684 | |
72725187 AJ |
685 | const char *const version = mbedtls_ssl_get_version(SSL_P(F)); |
686 | const char *const cipher = mbedtls_ssl_get_ciphersuite(SSL_P(F)); | |
687 | ||
688 | (void) snprintf(buf, sizeof buf, "%s, %s", version, cipher); | |
689 | ||
690 | return buf; | |
cd492e44 AC |
691 | } |
692 | ||
72725187 | 693 | ssize_t |
dd066596 | 694 | rb_ssl_read(rb_fde_t *const F, void *const buf, const size_t count) |
cd492e44 | 695 | { |
72725187 AJ |
696 | lrb_assert(F != NULL); |
697 | lrb_assert(F->ssl != NULL); | |
cd492e44 | 698 | |
dd066596 | 699 | const int ret = mbedtls_ssl_read(SSL_P(F), buf, count); |
1e7342d0 | 700 | |
73c486c7 | 701 | if(ret >= 0) |
dd066596 | 702 | return (ssize_t) ret; |
72725187 AJ |
703 | |
704 | switch(ret) | |
e6bbb410 | 705 | { |
72725187 AJ |
706 | case MBEDTLS_ERR_SSL_WANT_READ: |
707 | errno = EAGAIN; | |
708 | return RB_RW_SSL_NEED_READ; | |
709 | case MBEDTLS_ERR_SSL_WANT_WRITE: | |
710 | errno = EAGAIN; | |
711 | return RB_RW_SSL_NEED_WRITE; | |
712 | default: | |
713 | errno = EIO; | |
dd066596 | 714 | F->ssl_errno = (unsigned long) -ret; |
72725187 AJ |
715 | return RB_RW_SSL_ERROR; |
716 | } | |
717 | } | |
1e7342d0 | 718 | |
72725187 | 719 | ssize_t |
dd066596 | 720 | rb_ssl_write(rb_fde_t *const F, const void *const buf, const size_t count) |
72725187 AJ |
721 | { |
722 | lrb_assert(F != NULL); | |
723 | lrb_assert(F->ssl != NULL); | |
1e7342d0 | 724 | |
dd066596 | 725 | const int ret = mbedtls_ssl_write(SSL_P(F), buf, count); |
1e7342d0 | 726 | |
73c486c7 | 727 | if(ret >= 0) |
dd066596 | 728 | return (ssize_t) ret; |
72725187 AJ |
729 | |
730 | switch(ret) | |
731 | { | |
732 | case MBEDTLS_ERR_SSL_WANT_READ: | |
733 | errno = EAGAIN; | |
734 | return RB_RW_SSL_NEED_READ; | |
735 | case MBEDTLS_ERR_SSL_WANT_WRITE: | |
736 | errno = EAGAIN; | |
737 | return RB_RW_SSL_NEED_WRITE; | |
e6bbb410 | 738 | default: |
72725187 | 739 | errno = EIO; |
dd066596 | 740 | F->ssl_errno = (unsigned long) -ret; |
72725187 | 741 | return RB_RW_SSL_ERROR; |
e6bbb410 | 742 | } |
72725187 | 743 | } |
e6bbb410 | 744 | |
cd492e44 | 745 | |
cf430c1a | 746 | |
72725187 AJ |
747 | /* |
748 | * Internal library-agnostic code | |
72725187 AJ |
749 | */ |
750 | ||
751 | static void | |
dd066596 | 752 | rb_ssl_connect_realcb(rb_fde_t *const F, const int status, struct ssl_connect *const sconn) |
72725187 | 753 | { |
dd066596 | 754 | lrb_assert(F != NULL); |
72725187 AJ |
755 | lrb_assert(F->connect != NULL); |
756 | ||
757 | F->connect->callback = sconn->callback; | |
758 | F->connect->data = sconn->data; | |
dd066596 | 759 | |
72725187 | 760 | rb_connect_callback(F, status); |
c4acd427 | 761 | rb_free(sconn); |
72725187 AJ |
762 | } |
763 | ||
764 | static void | |
765 | rb_ssl_timeout_cb(rb_fde_t *const F, void *const data) | |
766 | { | |
515467e5 AJ |
767 | (void) data; |
768 | ||
72725187 AJ |
769 | lrb_assert(F->accept != NULL); |
770 | lrb_assert(F->accept->callback != NULL); | |
771 | ||
772 | F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data); | |
773 | } | |
774 | ||
775 | static void | |
776 | rb_ssl_tryconn_timeout_cb(rb_fde_t *const F, void *const data) | |
777 | { | |
778 | rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data); | |
779 | } | |
780 | ||
781 | static void | |
dd066596 | 782 | rb_ssl_tryconn(rb_fde_t *const F, const int status, void *const data) |
72725187 AJ |
783 | { |
784 | lrb_assert(F != NULL); | |
785 | ||
dd066596 AJ |
786 | struct ssl_connect *const sconn = data; |
787 | ||
72725187 | 788 | if(status != RB_OK) |
1e7342d0 | 789 | { |
dd066596 | 790 | rb_ssl_connect_realcb(F, status, sconn); |
72725187 | 791 | return; |
cd492e44 AC |
792 | } |
793 | ||
72725187 AJ |
794 | F->type |= RB_FD_SSL; |
795 | ||
c4acd427 AJ |
796 | rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); |
797 | rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT); | |
dd066596 | 798 | rb_ssl_connect_common(F, sconn); |
03469187 SA |
799 | } |
800 | ||
1e7342d0 | 801 | |
72725187 AJ |
802 | |
803 | /* | |
804 | * External library-agnostic code | |
72725187 | 805 | */ |
cd492e44 AC |
806 | |
807 | int | |
808 | rb_supports_ssl(void) | |
809 | { | |
810 | return 1; | |
811 | } | |
812 | ||
72725187 AJ |
813 | unsigned int |
814 | rb_ssl_handshake_count(rb_fde_t *const F) | |
815 | { | |
816 | return F->handshake_count; | |
817 | } | |
818 | ||
cd492e44 | 819 | void |
72725187 | 820 | rb_ssl_clear_handshake_count(rb_fde_t *const F) |
cd492e44 | 821 | { |
72725187 AJ |
822 | F->handshake_count = 0; |
823 | } | |
cd492e44 | 824 | |
72725187 | 825 | void |
dd066596 | 826 | rb_ssl_start_accepted(rb_fde_t *const F, ACCB *const cb, void *const data, const int timeout) |
72725187 AJ |
827 | { |
828 | F->type |= RB_FD_SSL; | |
72725187 | 829 | |
c4acd427 | 830 | F->accept = rb_malloc(sizeof(struct acceptdata)); |
72725187 AJ |
831 | F->accept->callback = cb; |
832 | F->accept->data = data; | |
72725187 AJ |
833 | F->accept->addrlen = 0; |
834 | (void) memset(&F->accept->S, 0x00, sizeof F->accept->S); | |
835 | ||
c4acd427 AJ |
836 | rb_settimeout(F, timeout, rb_ssl_timeout_cb, NULL); |
837 | rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_IN); | |
72725187 | 838 | rb_ssl_accept_common(F, NULL); |
cd492e44 AC |
839 | } |
840 | ||
72725187 | 841 | void |
dd066596 | 842 | rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockaddr *const st, const int addrlen) |
833b2f9c | 843 | { |
72725187 | 844 | cli_F->type |= RB_FD_SSL; |
31145ea0 | 845 | |
c4acd427 | 846 | cli_F->accept = rb_malloc(sizeof(struct acceptdata)); |
72725187 AJ |
847 | cli_F->accept->callback = srv_F->accept->callback; |
848 | cli_F->accept->data = srv_F->accept->data; | |
dd066596 | 849 | cli_F->accept->addrlen = (rb_socklen_t) addrlen; |
72725187 | 850 | (void) memset(&cli_F->accept->S, 0x00, sizeof cli_F->accept->S); |
dd066596 | 851 | (void) memcpy(&cli_F->accept->S, st, (size_t) addrlen); |
31145ea0 | 852 | |
c4acd427 AJ |
853 | rb_settimeout(cli_F, 10, rb_ssl_timeout_cb, NULL); |
854 | rb_ssl_init_fd(cli_F, RB_FD_TLS_DIRECTION_IN); | |
72725187 AJ |
855 | rb_ssl_accept_common(cli_F, NULL); |
856 | } | |
31145ea0 | 857 | |
72725187 | 858 | int |
dd066596 | 859 | rb_ssl_listen(rb_fde_t *const F, const int backlog, const int defer_accept) |
72725187 AJ |
860 | { |
861 | int result = rb_listen(F, backlog, defer_accept); | |
dd066596 | 862 | |
72725187 AJ |
863 | F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL; |
864 | ||
865 | return result; | |
866 | } | |
867 | ||
868 | void | |
869 | rb_connect_tcp_ssl(rb_fde_t *const F, struct sockaddr *const dest, struct sockaddr *const clocal, | |
dd066596 | 870 | CNCB *const callback, void *const data, const int timeout) |
72725187 AJ |
871 | { |
872 | if(F == NULL) | |
873 | return; | |
874 | ||
875 | struct ssl_connect *const sconn = rb_malloc(sizeof *sconn); | |
876 | sconn->data = data; | |
877 | sconn->callback = callback; | |
878 | sconn->timeout = timeout; | |
879 | ||
880 | rb_connect_tcp(F, dest, clocal, rb_ssl_tryconn, sconn, timeout); | |
881 | } | |
882 | ||
883 | void | |
dd066596 | 884 | rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data, const int timeout) |
72725187 AJ |
885 | { |
886 | if(F == NULL) | |
887 | return; | |
888 | ||
72725187 AJ |
889 | struct ssl_connect *const sconn = rb_malloc(sizeof *sconn); |
890 | sconn->data = data; | |
891 | sconn->callback = callback; | |
892 | sconn->timeout = timeout; | |
893 | ||
dd066596 AJ |
894 | F->connect = rb_malloc(sizeof(struct conndata)); |
895 | F->connect->callback = callback; | |
896 | F->connect->data = data; | |
897 | ||
898 | F->type |= RB_FD_SSL; | |
899 | ||
72725187 | 900 | rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); |
c4acd427 | 901 | rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT); |
dd066596 | 902 | rb_ssl_connect_common(F, sconn); |
833b2f9c | 903 | } |
cd492e44 | 904 | |
1e7342d0 | 905 | #endif /* HAVE_MBEDTLS */ |