]>
Commit | Line | Data |
---|---|---|
cd492e44 | 1 | /* |
fe037171 | 2 | * librb: a library used by ircd-ratbox and other things |
1e7342d0 | 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 | #include <commio-int.h> |
30 | #include <commio-ssl.h> | |
cf430c1a | 31 | #include <stdbool.h> |
cd492e44 AC |
32 | |
33 | #ifdef HAVE_MBEDTLS | |
34 | ||
35 | #include "mbedtls/entropy.h" | |
36 | #include "mbedtls/ctr_drbg.h" | |
37 | #include "mbedtls/certs.h" | |
38 | #include "mbedtls/x509.h" | |
39 | #include "mbedtls/ssl.h" | |
40 | #include "mbedtls/net.h" | |
41 | #include "mbedtls/error.h" | |
42 | #include "mbedtls/debug.h" | |
43 | #include "mbedtls/dhm.h" | |
44 | #include "mbedtls/version.h" | |
45 | ||
1e7342d0 | 46 | #include "mbedtls_embedded_data.h" |
cd492e44 | 47 | |
1e7342d0 AJ |
48 | typedef struct |
49 | { | |
50 | mbedtls_x509_crt crt; | |
51 | mbedtls_pk_context key; | |
52 | mbedtls_dhm_context dhp; | |
53 | mbedtls_ssl_config server_cfg; | |
54 | mbedtls_ssl_config client_cfg; | |
55 | size_t refcount; | |
56 | } rb_mbedtls_cfg_context; | |
57 | ||
58 | typedef struct | |
59 | { | |
60 | rb_mbedtls_cfg_context *cfg; | |
61 | mbedtls_ssl_context ssl; | |
62 | } rb_mbedtls_ssl_context; | |
63 | ||
64 | #define SSL_C(x) ((rb_mbedtls_ssl_context *) (x)->ssl)->cfg | |
65 | #define SSL_P(x) &((rb_mbedtls_ssl_context *) (x)->ssl)->ssl | |
66 | ||
67 | static mbedtls_ctr_drbg_context ctr_drbg_ctx; | |
68 | static mbedtls_entropy_context entropy_ctx; | |
69 | ||
70 | static mbedtls_x509_crt dummy_ca_ctx; | |
71 | static rb_mbedtls_cfg_context *rb_mbedtls_cfg = NULL; | |
72 | ||
73 | static const char * | |
74 | rb_get_ssl_strerror_internal(int err) | |
75 | { | |
76 | static char errbuf[512]; | |
77 | ||
78 | #ifdef MBEDTLS_ERROR_C | |
79 | char mbed_errbuf[512]; | |
80 | mbedtls_strerror(err, mbed_errbuf, sizeof mbed_errbuf); | |
81 | snprintf(errbuf, sizeof errbuf, "(-0x%x) %s", -err, mbed_errbuf); | |
82 | #else | |
83 | snprintf(errbuf, sizeof errbuf, "-0x%x", -err); | |
84 | #endif | |
85 | ||
86 | return errbuf; | |
87 | } | |
88 | ||
89 | const char * | |
90 | rb_get_ssl_strerror(rb_fde_t *F) | |
91 | { | |
92 | return rb_get_ssl_strerror_internal(F->ssl_errno); | |
93 | } | |
94 | ||
95 | static void rb_mbedtls_cfg_incref(rb_mbedtls_cfg_context *cfg) | |
96 | { | |
97 | lrb_assert(cfg->refcount > 0); | |
98 | ||
99 | cfg->refcount++; | |
100 | } | |
101 | ||
102 | static void rb_mbedtls_cfg_decref(rb_mbedtls_cfg_context *cfg) | |
103 | { | |
104 | if(cfg == NULL) | |
105 | return; | |
106 | ||
107 | lrb_assert(cfg->refcount > 0); | |
108 | ||
109 | if((--cfg->refcount) > 0) | |
110 | return; | |
111 | ||
112 | mbedtls_ssl_config_free(&cfg->client_cfg); | |
113 | mbedtls_ssl_config_free(&cfg->server_cfg); | |
114 | mbedtls_dhm_free(&cfg->dhp); | |
115 | mbedtls_pk_free(&cfg->key); | |
116 | mbedtls_x509_crt_free(&cfg->crt); | |
117 | ||
118 | rb_free(cfg); | |
119 | } | |
120 | ||
121 | static rb_mbedtls_cfg_context *rb_mbedtls_cfg_new(void) | |
122 | { | |
123 | rb_mbedtls_cfg_context *cfg; | |
124 | int ret; | |
125 | ||
126 | if((cfg = rb_malloc(sizeof(rb_mbedtls_cfg_context))) == NULL) | |
127 | return NULL; | |
128 | ||
129 | mbedtls_x509_crt_init(&cfg->crt); | |
130 | mbedtls_pk_init(&cfg->key); | |
131 | mbedtls_dhm_init(&cfg->dhp); | |
132 | mbedtls_ssl_config_init(&cfg->server_cfg); | |
133 | mbedtls_ssl_config_init(&cfg->client_cfg); | |
134 | ||
135 | cfg->refcount = 1; | |
136 | ||
137 | if((ret = mbedtls_ssl_config_defaults(&cfg->server_cfg, | |
138 | MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, | |
139 | MBEDTLS_SSL_PRESET_DEFAULT)) != 0) | |
140 | { | |
141 | rb_lib_log("rb_mbedtls_cfg_new: ssl_config_defaults (server): %s", | |
142 | rb_get_ssl_strerror_internal(ret)); | |
143 | rb_mbedtls_cfg_decref(cfg); | |
144 | return NULL; | |
145 | } | |
146 | ||
147 | if((ret = mbedtls_ssl_config_defaults(&cfg->client_cfg, | |
148 | MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, | |
149 | MBEDTLS_SSL_PRESET_DEFAULT)) != 0) | |
150 | { | |
151 | rb_lib_log("rb_mbedtls_cfg_new: ssl_config_defaults (client): %s", | |
152 | rb_get_ssl_strerror_internal(ret)); | |
153 | rb_mbedtls_cfg_decref(cfg); | |
154 | return NULL; | |
155 | } | |
156 | ||
157 | mbedtls_ssl_conf_rng(&cfg->server_cfg, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); | |
158 | mbedtls_ssl_conf_rng(&cfg->client_cfg, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); | |
159 | ||
160 | mbedtls_ssl_conf_ca_chain(&cfg->server_cfg, &dummy_ca_ctx, NULL); | |
161 | mbedtls_ssl_conf_ca_chain(&cfg->client_cfg, &dummy_ca_ctx, NULL); | |
162 | ||
163 | mbedtls_ssl_conf_authmode(&cfg->server_cfg, MBEDTLS_SSL_VERIFY_OPTIONAL); | |
164 | mbedtls_ssl_conf_authmode(&cfg->client_cfg, MBEDTLS_SSL_VERIFY_NONE); | |
165 | ||
166 | return cfg; | |
167 | } | |
cd492e44 AC |
168 | |
169 | void | |
170 | rb_ssl_shutdown(rb_fde_t *F) | |
171 | { | |
cd492e44 AC |
172 | if(F == NULL || F->ssl == NULL) |
173 | return; | |
1e7342d0 AJ |
174 | |
175 | if(SSL_P(F) != NULL) | |
cd492e44 | 176 | { |
1e7342d0 AJ |
177 | for(int i = 0; i < 4; i++) |
178 | { | |
179 | int r = mbedtls_ssl_close_notify(SSL_P(F)); | |
180 | if(r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE) | |
181 | break; | |
182 | } | |
183 | mbedtls_ssl_free(SSL_P(F)); | |
cd492e44 | 184 | } |
1e7342d0 AJ |
185 | |
186 | if(SSL_C(F) != NULL) | |
187 | rb_mbedtls_cfg_decref(SSL_C(F)); | |
188 | ||
cd492e44 AC |
189 | rb_free(F->ssl); |
190 | } | |
191 | ||
192 | unsigned int | |
193 | rb_ssl_handshake_count(rb_fde_t *F) | |
194 | { | |
195 | return F->handshake_count; | |
196 | } | |
197 | ||
198 | void | |
199 | rb_ssl_clear_handshake_count(rb_fde_t *F) | |
200 | { | |
201 | F->handshake_count = 0; | |
202 | } | |
203 | ||
204 | static void | |
205 | rb_ssl_timeout(rb_fde_t *F, void *notused) | |
206 | { | |
207 | lrb_assert(F->accept != NULL); | |
208 | F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data); | |
209 | } | |
210 | ||
cd492e44 AC |
211 | static int |
212 | do_ssl_handshake(rb_fde_t *F, PF * callback, void *data) | |
213 | { | |
1e7342d0 | 214 | int ret = mbedtls_ssl_handshake(SSL_P(F)); |
cd492e44 | 215 | |
1e7342d0 | 216 | if(ret == 0) |
cd492e44 | 217 | { |
1e7342d0 AJ |
218 | F->handshake_count++; |
219 | return 1; | |
220 | } | |
539d912b | 221 | |
1e7342d0 AJ |
222 | if(ret == -1 && rb_ignore_errno(errno)) |
223 | ret = MBEDTLS_ERR_SSL_WANT_READ; | |
539d912b | 224 | |
1e7342d0 AJ |
225 | switch(ret) |
226 | { | |
227 | case MBEDTLS_ERR_SSL_WANT_READ: | |
228 | rb_setselect(F, RB_SELECT_READ, callback, data); | |
229 | return 0; | |
230 | case MBEDTLS_ERR_SSL_WANT_WRITE: | |
231 | rb_setselect(F, RB_SELECT_WRITE, callback, data); | |
232 | return 0; | |
233 | default: | |
cd492e44 AC |
234 | F->ssl_errno = ret; |
235 | return -1; | |
236 | } | |
cd492e44 AC |
237 | } |
238 | ||
239 | static void | |
240 | rb_ssl_tryaccept(rb_fde_t *F, void *data) | |
241 | { | |
cd492e44 AC |
242 | lrb_assert(F->accept != NULL); |
243 | ||
1e7342d0 | 244 | int ret = do_ssl_handshake(F, rb_ssl_tryaccept, NULL); |
cd492e44 AC |
245 | |
246 | /* do_ssl_handshake does the rb_setselect */ | |
247 | if(ret == 0) | |
248 | return; | |
249 | ||
1e7342d0 | 250 | struct acceptdata *ad = F->accept; |
cd492e44 AC |
251 | F->accept = NULL; |
252 | rb_settimeout(F, 0, NULL, NULL); | |
253 | rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); | |
254 | ||
255 | if(ret > 0) | |
256 | ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); | |
257 | else | |
258 | ad->callback(F, RB_ERROR_SSL, NULL, 0, ad->data); | |
259 | ||
260 | rb_free(ad); | |
261 | } | |
262 | ||
263 | static int | |
264 | rb_ssl_read_cb(void *opaque, unsigned char *buf, size_t size) | |
265 | { | |
266 | rb_fde_t *F = opaque; | |
267 | ||
1e7342d0 AJ |
268 | int ret = (int) read(F->fd, buf, size); |
269 | if(ret < 0 && rb_ignore_errno(errno)) | |
539d912b AC |
270 | return MBEDTLS_ERR_SSL_WANT_READ; |
271 | ||
272 | return ret; | |
cd492e44 AC |
273 | } |
274 | ||
275 | static int | |
276 | rb_ssl_write_cb(void *opaque, const unsigned char *buf, size_t size) | |
277 | { | |
278 | rb_fde_t *F = opaque; | |
279 | ||
1e7342d0 AJ |
280 | int ret = (int) write(F->fd, buf, size); |
281 | if(ret < 0 && rb_ignore_errno(errno)) | |
539d912b AC |
282 | return MBEDTLS_ERR_SSL_WANT_WRITE; |
283 | ||
284 | return ret; | |
cd492e44 AC |
285 | } |
286 | ||
287 | static void | |
1e7342d0 | 288 | rb_ssl_setup_mbed_context(rb_fde_t *F, bool is_server) |
cd492e44 | 289 | { |
1e7342d0 AJ |
290 | rb_mbedtls_ssl_context *mbed_ssl_ctx; |
291 | mbedtls_ssl_config *mbed_config; | |
cd492e44 AC |
292 | int ret; |
293 | ||
1e7342d0 AJ |
294 | if((mbed_ssl_ctx = rb_malloc(sizeof(rb_mbedtls_ssl_context))) == NULL) |
295 | { | |
296 | rb_lib_log("rb_ssl_setup_mbed_context: rb_malloc: allocation failure"); | |
297 | rb_close(F); | |
298 | return; | |
299 | } | |
300 | ||
301 | if(is_server) | |
302 | mbed_config = &rb_mbedtls_cfg->server_cfg; | |
303 | else | |
304 | mbed_config = &rb_mbedtls_cfg->client_cfg; | |
305 | ||
306 | mbedtls_ssl_init(&mbed_ssl_ctx->ssl); | |
307 | mbedtls_ssl_set_bio(&mbed_ssl_ctx->ssl, F, rb_ssl_write_cb, rb_ssl_read_cb, NULL); | |
308 | ||
309 | if((ret = mbedtls_ssl_setup(&mbed_ssl_ctx->ssl, mbed_config)) != 0) | |
cd492e44 | 310 | { |
1e7342d0 AJ |
311 | rb_lib_log("rb_ssl_setup_mbed_context: ssl_setup: %s", |
312 | rb_get_ssl_strerror_internal(ret)); | |
313 | mbedtls_ssl_free(&mbed_ssl_ctx->ssl); | |
314 | rb_free(mbed_ssl_ctx); | |
cd492e44 AC |
315 | rb_close(F); |
316 | return; | |
317 | } | |
318 | ||
1e7342d0 AJ |
319 | mbed_ssl_ctx->cfg = rb_mbedtls_cfg; |
320 | rb_mbedtls_cfg_incref(mbed_ssl_ctx->cfg); | |
321 | F->ssl = mbed_ssl_ctx; | |
cd492e44 AC |
322 | } |
323 | ||
324 | void | |
1e7342d0 | 325 | rb_ssl_start_accepted(rb_fde_t *F, ACCB * cb, void *data, int timeout) |
cd492e44 | 326 | { |
1e7342d0 AJ |
327 | F->type |= RB_FD_SSL; |
328 | F->accept = rb_malloc(sizeof(struct acceptdata)); | |
cd492e44 | 329 | |
1e7342d0 AJ |
330 | F->accept->callback = cb; |
331 | F->accept->data = data; | |
332 | rb_settimeout(F, timeout, rb_ssl_timeout, NULL); | |
cd492e44 | 333 | |
1e7342d0 | 334 | F->accept->addrlen = 0; |
cd492e44 | 335 | |
1e7342d0 AJ |
336 | rb_ssl_setup_mbed_context(F, true); |
337 | if(do_ssl_handshake(F, rb_ssl_tryaccept, NULL)) | |
cd492e44 | 338 | { |
1e7342d0 AJ |
339 | struct acceptdata *ad = F->accept; |
340 | F->accept = NULL; | |
341 | ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); | |
cd492e44 AC |
342 | rb_free(ad); |
343 | } | |
344 | } | |
345 | ||
346 | void | |
347 | rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen) | |
348 | { | |
349 | new_F->type |= RB_FD_SSL; | |
cd492e44 AC |
350 | new_F->accept = rb_malloc(sizeof(struct acceptdata)); |
351 | ||
352 | new_F->accept->callback = F->accept->callback; | |
353 | new_F->accept->data = F->accept->data; | |
354 | rb_settimeout(new_F, 10, rb_ssl_timeout, NULL); | |
1e7342d0 | 355 | |
cd492e44 AC |
356 | memcpy(&new_F->accept->S, st, addrlen); |
357 | new_F->accept->addrlen = addrlen; | |
358 | ||
1e7342d0 | 359 | rb_ssl_setup_mbed_context(new_F, true); |
cd492e44 AC |
360 | if(do_ssl_handshake(F, rb_ssl_tryaccept, NULL)) |
361 | { | |
362 | struct acceptdata *ad = F->accept; | |
363 | F->accept = NULL; | |
364 | ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); | |
365 | rb_free(ad); | |
366 | } | |
367 | } | |
368 | ||
369 | static ssize_t | |
1e7342d0 | 370 | rb_ssl_read_or_write(bool do_read, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count) |
cd492e44 AC |
371 | { |
372 | ssize_t ret; | |
373 | ||
1e7342d0 AJ |
374 | if(do_read) |
375 | ret = mbedtls_ssl_read(SSL_P(F), rbuf, count); | |
cd492e44 | 376 | else |
1e7342d0 | 377 | ret = mbedtls_ssl_write(SSL_P(F), wbuf, count); |
cd492e44 AC |
378 | |
379 | if(ret < 0) | |
380 | { | |
1e7342d0 | 381 | switch(ret) |
cd492e44 AC |
382 | { |
383 | case MBEDTLS_ERR_SSL_WANT_READ: | |
384 | return RB_RW_SSL_NEED_READ; | |
385 | case MBEDTLS_ERR_SSL_WANT_WRITE: | |
386 | return RB_RW_SSL_NEED_WRITE; | |
387 | default: | |
388 | F->ssl_errno = ret; | |
389 | errno = EIO; | |
499612f1 | 390 | return RB_RW_SSL_ERROR; |
cd492e44 AC |
391 | } |
392 | } | |
393 | ||
394 | return ret; | |
395 | } | |
396 | ||
397 | ssize_t | |
398 | rb_ssl_read(rb_fde_t *F, void *buf, size_t count) | |
399 | { | |
1e7342d0 | 400 | return rb_ssl_read_or_write(true, F, buf, NULL, count); |
cd492e44 AC |
401 | } |
402 | ||
403 | ssize_t | |
404 | rb_ssl_write(rb_fde_t *F, const void *buf, size_t count) | |
405 | { | |
1e7342d0 | 406 | return rb_ssl_read_or_write(false, F, NULL, buf, count); |
cd492e44 AC |
407 | } |
408 | ||
409 | int | |
410 | rb_init_ssl(void) | |
411 | { | |
412 | int ret; | |
413 | ||
1e7342d0 AJ |
414 | mbedtls_ctr_drbg_init(&ctr_drbg_ctx); |
415 | mbedtls_entropy_init(&entropy_ctx); | |
cd492e44 | 416 | |
1e7342d0 AJ |
417 | if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, |
418 | (const unsigned char *)rb_mbedtls_personal_str, sizeof(rb_mbedtls_personal_str))) != 0) | |
cd492e44 | 419 | { |
1e7342d0 AJ |
420 | rb_lib_log("rb_init_ssl: ctr_drbg_seed: %s", |
421 | rb_get_ssl_strerror_internal(ret)); | |
cd492e44 AC |
422 | return 0; |
423 | } | |
424 | ||
1e7342d0 AJ |
425 | if((ret = mbedtls_x509_crt_parse_der(&dummy_ca_ctx, rb_mbedtls_dummy_ca_certificate, |
426 | sizeof(rb_mbedtls_dummy_ca_certificate))) != 0) | |
cd492e44 | 427 | { |
1e7342d0 AJ |
428 | rb_lib_log("rb_init_ssl: x509_crt_parse_der (Dummy CA): %s", |
429 | rb_get_ssl_strerror_internal(ret)); | |
cd492e44 AC |
430 | return 0; |
431 | } | |
432 | ||
cd492e44 AC |
433 | return 1; |
434 | } | |
435 | ||
436 | int | |
1e7342d0 | 437 | rb_setup_ssl_server(const char *certfile, const char *keyfile, const char *dhfile, const char *cipher_list) |
cd492e44 | 438 | { |
1e7342d0 | 439 | rb_mbedtls_cfg_context *newcfg; |
cd492e44 AC |
440 | int ret; |
441 | ||
1e7342d0 | 442 | if(certfile == NULL) |
cd492e44 | 443 | { |
1e7342d0 | 444 | rb_lib_log("rb_setup_ssl_server: no certificate file specified"); |
cd492e44 AC |
445 | return 0; |
446 | } | |
447 | ||
1e7342d0 AJ |
448 | if(keyfile == NULL) |
449 | keyfile = certfile; | |
450 | ||
451 | if((newcfg = rb_mbedtls_cfg_new()) == NULL) | |
cd492e44 | 452 | { |
1e7342d0 | 453 | rb_lib_log("rb_setup_ssl_server: rb_mbedtls_cfg_new: allocation failed"); |
cd492e44 AC |
454 | return 0; |
455 | } | |
456 | ||
1e7342d0 | 457 | if((ret = mbedtls_x509_crt_parse_file(&newcfg->crt, certfile)) != 0) |
cd492e44 | 458 | { |
1e7342d0 AJ |
459 | rb_lib_log("rb_setup_ssl_server: x509_crt_parse_file ('%s'): %s", |
460 | certfile, rb_get_ssl_strerror_internal(ret)); | |
461 | rb_mbedtls_cfg_decref(newcfg); | |
cd492e44 AC |
462 | return 0; |
463 | } | |
1e7342d0 | 464 | if((ret = mbedtls_pk_parse_keyfile(&newcfg->key, keyfile, NULL)) != 0) |
cd492e44 | 465 | { |
1e7342d0 AJ |
466 | rb_lib_log("rb_setup_ssl_server: pk_parse_keyfile ('%s'): %s", |
467 | keyfile, rb_get_ssl_strerror_internal(ret)); | |
468 | rb_mbedtls_cfg_decref(newcfg); | |
cd492e44 AC |
469 | return 0; |
470 | } | |
471 | ||
1e7342d0 AJ |
472 | /* Absense of DH parameters does not matter with mbedTLS, as it comes with its own defaults |
473 | Thus, clients can still use DHE- ciphersuites, just over a weaker, common DH group | |
474 | So, we do not consider failure to parse DH parameters as fatal */ | |
475 | if(dhfile == NULL) | |
476 | { | |
477 | rb_lib_log("rb_setup_ssl_server: no DH parameters file specified"); | |
478 | } | |
479 | else | |
493897d6 | 480 | { |
1e7342d0 AJ |
481 | if((ret = mbedtls_dhm_parse_dhmfile(&newcfg->dhp, dhfile)) != 0) |
482 | { | |
483 | rb_lib_log("rb_setup_ssl_server: dhm_parse_dhmfile ('%s'): %s", | |
484 | dhfile, rb_get_ssl_strerror_internal(ret)); | |
485 | } | |
486 | else if((ret = mbedtls_ssl_conf_dh_param_ctx(&newcfg->server_cfg, &newcfg->dhp)) != 0) | |
487 | { | |
488 | rb_lib_log("rb_setup_ssl_server: ssl_conf_dh_param_ctx: %s", | |
489 | rb_get_ssl_strerror_internal(ret)); | |
490 | } | |
493897d6 | 491 | } |
cd492e44 | 492 | |
1e7342d0 | 493 | if((ret = mbedtls_ssl_conf_own_cert(&newcfg->server_cfg, &newcfg->crt, &newcfg->key)) != 0) |
cd492e44 | 494 | { |
1e7342d0 AJ |
495 | rb_lib_log("rb_setup_ssl_server: ssl_conf_own_cert (server): %s", |
496 | rb_get_ssl_strerror_internal(ret)); | |
497 | rb_mbedtls_cfg_decref(newcfg); | |
cd492e44 AC |
498 | return 0; |
499 | } | |
1e7342d0 | 500 | if((ret = mbedtls_ssl_conf_own_cert(&newcfg->client_cfg, &newcfg->crt, &newcfg->key)) != 0) |
493897d6 | 501 | { |
1e7342d0 AJ |
502 | rb_lib_log("rb_setup_ssl_server: ssl_conf_own_cert (client): %s", |
503 | rb_get_ssl_strerror_internal(ret)); | |
504 | rb_mbedtls_cfg_decref(newcfg); | |
493897d6 AC |
505 | return 0; |
506 | } | |
507 | ||
c1725bda AC |
508 | /* XXX support cipher lists when added to mbedtls */ |
509 | ||
1e7342d0 AJ |
510 | rb_mbedtls_cfg_decref(rb_mbedtls_cfg); |
511 | rb_mbedtls_cfg = newcfg; | |
512 | ||
cd492e44 AC |
513 | return 1; |
514 | } | |
515 | ||
516 | int | |
517 | rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept) | |
518 | { | |
1e7342d0 | 519 | int result = rb_listen(F, backlog, defer_accept); |
cd492e44 AC |
520 | F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL; |
521 | ||
522 | return result; | |
523 | } | |
524 | ||
525 | struct ssl_connect | |
526 | { | |
527 | CNCB *callback; | |
528 | void *data; | |
529 | int timeout; | |
530 | }; | |
531 | ||
532 | static void | |
533 | rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn) | |
534 | { | |
535 | F->connect->callback = sconn->callback; | |
536 | F->connect->data = sconn->data; | |
537 | rb_free(sconn); | |
538 | rb_connect_callback(F, status); | |
539 | } | |
540 | ||
541 | static void | |
542 | rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data) | |
543 | { | |
544 | rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data); | |
545 | } | |
546 | ||
547 | static void | |
548 | rb_ssl_tryconn_cb(rb_fde_t *F, void *data) | |
549 | { | |
1e7342d0 | 550 | int ret = do_ssl_handshake(F, rb_ssl_tryconn_cb, data); |
cd492e44 | 551 | |
1e7342d0 | 552 | switch(ret) |
cd492e44 AC |
553 | { |
554 | case -1: | |
1e7342d0 | 555 | rb_ssl_connect_realcb(F, RB_ERROR_SSL, data); |
cd492e44 AC |
556 | break; |
557 | case 0: | |
558 | /* do_ssl_handshake does the rb_setselect stuff */ | |
559 | return; | |
560 | default: | |
561 | break; | |
cd492e44 | 562 | } |
1e7342d0 | 563 | rb_ssl_connect_realcb(F, RB_OK, data); |
cd492e44 AC |
564 | } |
565 | ||
566 | static void | |
567 | rb_ssl_tryconn(rb_fde_t *F, int status, void *data) | |
568 | { | |
cd492e44 AC |
569 | if(status != RB_OK) |
570 | { | |
1e7342d0 | 571 | rb_ssl_connect_realcb(F, status, data); |
cd492e44 AC |
572 | return; |
573 | } | |
574 | ||
575 | F->type |= RB_FD_SSL; | |
576 | ||
1e7342d0 AJ |
577 | rb_ssl_setup_mbed_context(F, false); |
578 | rb_settimeout(F, ((struct ssl_connect *)data)->timeout, rb_ssl_tryconn_timeout_cb, data); | |
579 | do_ssl_handshake(F, rb_ssl_tryconn_cb, data); | |
cd492e44 AC |
580 | } |
581 | ||
582 | void | |
583 | rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest, | |
5ad62c80 | 584 | struct sockaddr *clocal, CNCB * callback, void *data, int timeout) |
cd492e44 | 585 | { |
cd492e44 AC |
586 | if(F == NULL) |
587 | return; | |
588 | ||
1e7342d0 | 589 | struct ssl_connect *sconn = rb_malloc(sizeof(struct ssl_connect)); |
cd492e44 AC |
590 | sconn->data = data; |
591 | sconn->callback = callback; | |
592 | sconn->timeout = timeout; | |
1e7342d0 | 593 | |
5ad62c80 | 594 | rb_connect_tcp(F, dest, clocal, rb_ssl_tryconn, sconn, timeout); |
cd492e44 AC |
595 | } |
596 | ||
597 | void | |
598 | rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout) | |
599 | { | |
cd492e44 AC |
600 | if(F == NULL) |
601 | return; | |
602 | ||
1e7342d0 | 603 | struct ssl_connect *sconn = rb_malloc(sizeof(struct ssl_connect)); |
cd492e44 AC |
604 | sconn->data = data; |
605 | sconn->callback = callback; | |
606 | sconn->timeout = timeout; | |
1e7342d0 | 607 | |
cd492e44 AC |
608 | F->connect = rb_malloc(sizeof(struct conndata)); |
609 | F->connect->callback = callback; | |
610 | F->connect->data = data; | |
611 | F->type |= RB_FD_SSL; | |
cd492e44 | 612 | |
1e7342d0 | 613 | rb_ssl_setup_mbed_context(F, false); |
cd492e44 | 614 | rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); |
1e7342d0 | 615 | do_ssl_handshake(F, rb_ssl_tryconn_cb, sconn); |
cd492e44 AC |
616 | } |
617 | ||
618 | int | |
619 | rb_init_prng(const char *path, prng_seed_t seed_type) | |
620 | { | |
621 | return 1; | |
622 | } | |
623 | ||
624 | int | |
625 | rb_get_random(void *buf, size_t length) | |
626 | { | |
1e7342d0 | 627 | if(mbedtls_ctr_drbg_random(&ctr_drbg_ctx, buf, length)) |
cd492e44 AC |
628 | return 0; |
629 | ||
630 | return 1; | |
631 | } | |
632 | ||
03469187 | 633 | static size_t |
1e7342d0 | 634 | rb_make_certfp(const mbedtls_x509_crt *peer_cert, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) |
cd492e44 | 635 | { |
677d3cb1 | 636 | const mbedtls_md_info_t *md_info; |
e6bbb410 | 637 | mbedtls_md_type_t md_type; |
cf430c1a | 638 | bool spki = false; |
1e7342d0 | 639 | size_t hashlen; |
03469187 | 640 | int ret; |
cd492e44 | 641 | |
1e7342d0 AJ |
642 | uint8_t der_pubkey[8192]; |
643 | void* data = peer_cert->raw.p; | |
644 | size_t datalen = peer_cert->raw.len; | |
645 | ||
646 | switch(method) | |
e6bbb410 | 647 | { |
cf430c1a | 648 | case RB_SSL_CERTFP_METH_CERT_SHA1: |
e6bbb410 | 649 | md_type = MBEDTLS_MD_SHA1; |
1e7342d0 | 650 | hashlen = RB_SSL_CERTFP_LEN_SHA1; |
7da82465 | 651 | break; |
1e7342d0 | 652 | |
cf430c1a SA |
653 | case RB_SSL_CERTFP_METH_SPKI_SHA256: |
654 | spki = true; | |
655 | case RB_SSL_CERTFP_METH_CERT_SHA256: | |
e6bbb410 | 656 | md_type = MBEDTLS_MD_SHA256; |
1e7342d0 | 657 | hashlen = RB_SSL_CERTFP_LEN_SHA256; |
7da82465 | 658 | break; |
1e7342d0 | 659 | |
cf430c1a SA |
660 | case RB_SSL_CERTFP_METH_SPKI_SHA512: |
661 | spki = true; | |
662 | case RB_SSL_CERTFP_METH_CERT_SHA512: | |
e6bbb410 | 663 | md_type = MBEDTLS_MD_SHA512; |
1e7342d0 | 664 | hashlen = RB_SSL_CERTFP_LEN_SHA512; |
7da82465 | 665 | break; |
1e7342d0 | 666 | |
e6bbb410 EM |
667 | default: |
668 | return 0; | |
669 | } | |
670 | ||
1e7342d0 | 671 | if((md_info = mbedtls_md_info_from_type(md_type)) == NULL) |
cd492e44 | 672 | return 0; |
cd492e44 | 673 | |
1e7342d0 | 674 | if(spki) |
cd492e44 | 675 | { |
1e7342d0 AJ |
676 | if ((ret = mbedtls_pk_write_pubkey_der((mbedtls_pk_context *)&peer_cert->pk, |
677 | der_pubkey, sizeof(der_pubkey))) < 0) | |
cf430c1a | 678 | { |
1e7342d0 AJ |
679 | rb_lib_log("rb_get_ssl_certfp: pk_write_pubkey_der: %s", |
680 | rb_get_ssl_strerror_internal(ret)); | |
681 | return 0; | |
cf430c1a | 682 | } |
1e7342d0 AJ |
683 | data = der_pubkey + (sizeof(der_pubkey) - ret); |
684 | datalen = ret; | |
cf430c1a | 685 | } |
cf430c1a | 686 | |
1e7342d0 AJ |
687 | if((ret = mbedtls_md(md_info, data, datalen, certfp)) != 0) |
688 | { | |
689 | rb_lib_log("rb_get_ssl_certfp: mbedtls_md: %s", | |
690 | rb_get_ssl_strerror_internal(ret)); | |
691 | return 0; | |
cd492e44 AC |
692 | } |
693 | ||
1e7342d0 | 694 | return hashlen; |
03469187 SA |
695 | } |
696 | ||
697 | int | |
698 | rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) | |
699 | { | |
700 | const mbedtls_x509_crt *peer_cert; | |
701 | ||
1e7342d0 | 702 | if ((peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F))) == NULL) |
03469187 SA |
703 | return 0; |
704 | ||
1e7342d0 | 705 | return (int) rb_make_certfp(peer_cert, certfp, method); |
03469187 SA |
706 | } |
707 | ||
708 | int | |
709 | rb_get_ssl_certfp_file(const char *filename, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) | |
710 | { | |
711 | mbedtls_x509_crt cert; | |
712 | int ret; | |
713 | ||
714 | mbedtls_x509_crt_init(&cert); | |
715 | ||
1e7342d0 | 716 | if ((ret = mbedtls_x509_crt_parse_file(&cert, filename)) != 0) |
03469187 | 717 | return -1; |
cd492e44 | 718 | |
1e7342d0 AJ |
719 | size_t len = rb_make_certfp(&cert, certfp, method); |
720 | ||
721 | mbedtls_x509_crt_free(&cert); | |
722 | ||
723 | return (int) len; | |
cd492e44 AC |
724 | } |
725 | ||
726 | int | |
727 | rb_supports_ssl(void) | |
728 | { | |
729 | return 1; | |
730 | } | |
731 | ||
732 | void | |
733 | rb_get_ssl_info(char *buf, size_t len) | |
734 | { | |
735 | char version_str[512]; | |
736 | mbedtls_version_get_string(version_str); | |
737 | ||
c40eede1 AJ |
738 | snprintf(buf, len, "ARM mbedTLS: compiled (v%s), library (v%s)", |
739 | MBEDTLS_VERSION_STRING, version_str); | |
cd492e44 AC |
740 | } |
741 | ||
833b2f9c AC |
742 | const char * |
743 | rb_ssl_get_cipher(rb_fde_t *F) | |
744 | { | |
1e7342d0 | 745 | if(F == NULL || F->ssl == NULL || SSL_P(F) == NULL) |
833b2f9c AC |
746 | return NULL; |
747 | return mbedtls_ssl_get_ciphersuite(SSL_P(F)); | |
748 | } | |
cd492e44 | 749 | |
1e7342d0 | 750 | #endif /* HAVE_MBEDTLS */ |