]> jfr.im git - solanum.git/blame - libratbox/src/mbedtls.c
mbedtls: use server certificate for client mode too
[solanum.git] / libratbox / src / mbedtls.c
CommitLineData
cd492e44
AC
1/*
2 * libratbox: a library used by ircd-ratbox and other things
3 * mbedtls.c: mbedtls related code
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>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 * USA
23 *
24 * $Id$
25 */
26
27#include <libratbox_config.h>
28#include <ratbox_lib.h>
29#include <commio-int.h>
30#include <commio-ssl.h>
31
32#ifdef HAVE_MBEDTLS
33
34#include "mbedtls/entropy.h"
35#include "mbedtls/ctr_drbg.h"
36#include "mbedtls/certs.h"
37#include "mbedtls/x509.h"
38#include "mbedtls/ssl.h"
39#include "mbedtls/net.h"
40#include "mbedtls/error.h"
41#include "mbedtls/debug.h"
42#include "mbedtls/dhm.h"
43#include "mbedtls/version.h"
44
45static mbedtls_x509_crt x509;
46static mbedtls_pk_context serv_pk;
47static mbedtls_dhm_context dh_params;
48static mbedtls_ctr_drbg_context ctr_drbg;
49static mbedtls_entropy_context entropy;
50static mbedtls_ssl_config serv_config;
51static mbedtls_ssl_config client_config;
52
53#define SSL_P(x) ((mbedtls_ssl_context *)F->ssl)
54
55void
56rb_ssl_shutdown(rb_fde_t *F)
57{
58 int i;
59 if(F == NULL || F->ssl == NULL)
60 return;
61 for(i = 0; i < 4; i++)
62 {
63 int r = mbedtls_ssl_close_notify(SSL_P(F));
64 if(r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE)
65 break;
66 }
67 mbedtls_ssl_free(SSL_P(F));
68 rb_free(F->ssl);
69}
70
71unsigned int
72rb_ssl_handshake_count(rb_fde_t *F)
73{
74 return F->handshake_count;
75}
76
77void
78rb_ssl_clear_handshake_count(rb_fde_t *F)
79{
80 F->handshake_count = 0;
81}
82
83static void
84rb_ssl_timeout(rb_fde_t *F, void *notused)
85{
86 lrb_assert(F->accept != NULL);
87 F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data);
88}
89
90
91static int
92do_ssl_handshake(rb_fde_t *F, PF * callback, void *data)
93{
94 int ret;
95 int flags;
96
97 ret = mbedtls_ssl_handshake(SSL_P(F));
98 if(ret < 0)
99 {
539d912b
AC
100 if (ret == -1 && rb_ignore_errno(errno))
101 ret = MBEDTLS_ERR_SSL_WANT_READ;
102
cd492e44
AC
103 if((ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE))
104 {
105 if(ret == MBEDTLS_ERR_SSL_WANT_READ)
106 flags = RB_SELECT_READ;
107 else
108 flags = RB_SELECT_WRITE;
109 rb_setselect(F, flags, callback, data);
110 return 0;
111 }
539d912b 112
cd492e44
AC
113 F->ssl_errno = ret;
114 return -1;
115 }
116 return 1; /* handshake is finished..go about life */
117}
118
119static void
120rb_ssl_tryaccept(rb_fde_t *F, void *data)
121{
122 int ret;
123 struct acceptdata *ad;
124
125 lrb_assert(F->accept != NULL);
126
127 ret = do_ssl_handshake(F, rb_ssl_tryaccept, NULL);
128
129 /* do_ssl_handshake does the rb_setselect */
130 if(ret == 0)
131 return;
132
133 ad = F->accept;
134 F->accept = NULL;
135 rb_settimeout(F, 0, NULL, NULL);
136 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
137
138 if(ret > 0)
139 ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
140 else
141 ad->callback(F, RB_ERROR_SSL, NULL, 0, ad->data);
142
143 rb_free(ad);
144}
145
146static int
147rb_ssl_read_cb(void *opaque, unsigned char *buf, size_t size)
148{
539d912b 149 int ret;
cd492e44
AC
150 rb_fde_t *F = opaque;
151
539d912b
AC
152 ret = read(F->fd, buf, size);
153 if (ret < 0 && rb_ignore_errno(errno))
154 return MBEDTLS_ERR_SSL_WANT_READ;
155
156 return ret;
cd492e44
AC
157}
158
159static int
160rb_ssl_write_cb(void *opaque, const unsigned char *buf, size_t size)
161{
162 rb_fde_t *F = opaque;
539d912b 163 int ret;
cd492e44 164
539d912b
AC
165 ret = write(F->fd, buf, size);
166 if (ret < 0 && rb_ignore_errno(errno))
167 return MBEDTLS_ERR_SSL_WANT_WRITE;
168
169 return ret;
cd492e44
AC
170}
171
172static void
173rb_ssl_setup_srv_context(rb_fde_t *F, mbedtls_ssl_context *ssl)
174{
175 int ret;
176
177 mbedtls_ssl_init(ssl);
178 if ((ret = mbedtls_ssl_setup(ssl, &serv_config)) != 0)
179 {
180 rb_lib_log("rb_ssl_setup_srv_context: failed to set up ssl context: -0x%x", -ret);
181 rb_close(F);
182 return;
183 }
184
185 mbedtls_ssl_set_bio(ssl, F, rb_ssl_write_cb, rb_ssl_read_cb, NULL);
186}
187
188void
189rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout)
190{
191 mbedtls_ssl_context *ssl;
192 new_F->type |= RB_FD_SSL;
193 ssl = new_F->ssl = rb_malloc(sizeof(mbedtls_ssl_context));
194 new_F->accept = rb_malloc(sizeof(struct acceptdata));
195
196 new_F->accept->callback = cb;
197 new_F->accept->data = data;
198 rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL);
199
200 new_F->accept->addrlen = 0;
201
202 rb_ssl_setup_srv_context(new_F, ssl);
203 if(do_ssl_handshake(new_F, rb_ssl_tryaccept, NULL))
204 {
205 struct acceptdata *ad = new_F->accept;
206 new_F->accept = NULL;
539d912b 207
cd492e44
AC
208 ad->callback(new_F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
209 rb_free(ad);
210 }
211}
212
213void
214rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen)
215{
216 new_F->type |= RB_FD_SSL;
217 new_F->ssl = rb_malloc(sizeof(mbedtls_ssl_context));
218 new_F->accept = rb_malloc(sizeof(struct acceptdata));
219
220 new_F->accept->callback = F->accept->callback;
221 new_F->accept->data = F->accept->data;
222 rb_settimeout(new_F, 10, rb_ssl_timeout, NULL);
223 memcpy(&new_F->accept->S, st, addrlen);
224 new_F->accept->addrlen = addrlen;
225
226 rb_ssl_setup_srv_context(new_F, new_F->ssl);
227 if(do_ssl_handshake(F, rb_ssl_tryaccept, NULL))
228 {
229 struct acceptdata *ad = F->accept;
230 F->accept = NULL;
539d912b 231
cd492e44
AC
232 ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
233 rb_free(ad);
234 }
235}
236
237static ssize_t
238rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count)
239{
240 ssize_t ret;
241
242 if(r_or_w == 0)
243 ret = mbedtls_ssl_read(F->ssl, rbuf, count);
244 else
245 ret = mbedtls_ssl_write(F->ssl, wbuf, count);
246
247 if(ret < 0)
248 {
249 switch (ret)
250 {
251 case MBEDTLS_ERR_SSL_WANT_READ:
252 return RB_RW_SSL_NEED_READ;
253 case MBEDTLS_ERR_SSL_WANT_WRITE:
254 return RB_RW_SSL_NEED_WRITE;
255 default:
256 F->ssl_errno = ret;
257 errno = EIO;
258 return RB_RW_IO_ERROR;
259 }
260 }
261
262 return ret;
263}
264
265ssize_t
266rb_ssl_read(rb_fde_t *F, void *buf, size_t count)
267{
268 return rb_ssl_read_or_write(0, F, buf, NULL, count);
269}
270
271ssize_t
272rb_ssl_write(rb_fde_t *F, const void *buf, size_t count)
273{
274 return rb_ssl_read_or_write(1, F, NULL, buf, count);
275}
276
277int
278rb_init_ssl(void)
279{
280 int ret;
281
282 mbedtls_entropy_init(&entropy);
283 mbedtls_ctr_drbg_init(&ctr_drbg);
284
285 if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)) != 0)
286 {
287 rb_lib_log("rb_init_prng: unable to initialize PRNG, mbedtls_ctr_drbg_seed() returned -0x%x", -ret);
288 return 0;
289 }
290
291 mbedtls_ssl_config_init(&serv_config);
292
293 if ((ret = mbedtls_ssl_config_defaults(&serv_config,
294 MBEDTLS_SSL_IS_SERVER,
295 MBEDTLS_SSL_TRANSPORT_STREAM,
296 MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
297 {
298 rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for server context: -0x%x", -ret);
299 return 0;
300 }
301
302 mbedtls_ssl_conf_rng(&serv_config, mbedtls_ctr_drbg_random, &ctr_drbg);
303
304 /***************************************************************************************************************/
305
306 mbedtls_ssl_config_init(&client_config);
307
308 if ((ret = mbedtls_ssl_config_defaults(&client_config,
309 MBEDTLS_SSL_IS_CLIENT,
310 MBEDTLS_SSL_TRANSPORT_STREAM,
311 MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
312 {
313 rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for client context: -0x%x", -ret);
314 return 0;
315 }
316
539d912b 317 mbedtls_ssl_conf_rng(&client_config, mbedtls_ctr_drbg_random, &ctr_drbg);
162a91d6 318 mbedtls_ssl_conf_authmode(&client_config, MBEDTLS_SSL_VERIFY_NONE);
cd492e44
AC
319
320 return 1;
321}
322
323int
324rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile)
325{
326 int ret;
327
328 mbedtls_x509_crt_init(&x509);
329 ret = mbedtls_x509_crt_parse_file(&x509, cert);
330 if (ret != 0)
331 {
539d912b 332 rb_lib_log("rb_setup_ssl_server: failed to parse certificate '%s': -0x%x", cert, -ret);
cd492e44
AC
333 return 0;
334 }
335
336 mbedtls_pk_init(&serv_pk);
337 ret = mbedtls_pk_parse_keyfile(&serv_pk, keyfile, NULL);
338 if (ret != 0)
339 {
539d912b 340 rb_lib_log("rb_setup_ssl_server: failed to parse private key '%s': -0x%x", keyfile, -ret);
cd492e44
AC
341 return 0;
342 }
343
344 mbedtls_dhm_init(&dh_params);
345 ret = mbedtls_dhm_parse_dhmfile(&dh_params, dhfile);
346 if (ret != 0)
347 {
539d912b 348 rb_lib_log("rb_setup_ssl_server: failed to parse DH parameters '%s': -0x%x", dhfile, -ret);
cd492e44
AC
349 return 0;
350 }
351
352 ret = mbedtls_ssl_conf_dh_param_ctx(&serv_config, &dh_params);
353 if (ret != 0)
354 {
355 rb_lib_log("rb_setup_ssl_server: failed to set DH parameters on SSL config context: -0x%x", -ret);
356 return 0;
357 }
358
359 if (x509.next)
493897d6 360 {
cd492e44 361 mbedtls_ssl_conf_ca_chain(&serv_config, x509.next, NULL);
493897d6
AC
362 mbedtls_ssl_conf_ca_chain(&client_config, x509.next, NULL);
363 }
cd492e44
AC
364
365 if ((ret = mbedtls_ssl_conf_own_cert(&serv_config, &x509, &serv_pk)) != 0)
366 {
367 rb_lib_log("rb_setup_ssl_server: failed to set up own certificate: -0x%x", -ret);
368 return 0;
369 }
370
493897d6
AC
371 if ((ret = mbedtls_ssl_conf_own_cert(&client_config, &x509, &serv_pk)) != 0)
372 {
373 rb_lib_log("rb_setup_ssl_server: failed to set up own certificate: -0x%x", -ret);
374 return 0;
375 }
376
cd492e44
AC
377 return 1;
378}
379
380int
381rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept)
382{
383 int result;
384
385 result = rb_listen(F, backlog, defer_accept);
386 F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
387
388 return result;
389}
390
391struct ssl_connect
392{
393 CNCB *callback;
394 void *data;
395 int timeout;
396};
397
398static void
399rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn)
400{
401 F->connect->callback = sconn->callback;
402 F->connect->data = sconn->data;
403 rb_free(sconn);
404 rb_connect_callback(F, status);
405}
406
407static void
408rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data)
409{
410 rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
411}
412
413static void
414rb_ssl_tryconn_cb(rb_fde_t *F, void *data)
415{
416 struct ssl_connect *sconn = data;
417 int ret;
418
419 ret = do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn);
420
421 switch (ret)
422 {
423 case -1:
424 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
425 break;
426 case 0:
427 /* do_ssl_handshake does the rb_setselect stuff */
428 return;
429 default:
430 break;
431
432
433 }
434 rb_ssl_connect_realcb(F, RB_OK, sconn);
435}
436
437static void
438rb_ssl_setup_client_context(rb_fde_t *F, mbedtls_ssl_context *ssl)
439{
440 int ret;
441
442 mbedtls_ssl_init(ssl);
443 if ((ret = mbedtls_ssl_setup(ssl, &client_config)) != 0)
444 {
445 rb_lib_log("rb_ssl_setup_client_context: failed to set up ssl context: -0x%x", -ret);
446 rb_close(F);
447 return;
448 }
449
450 mbedtls_ssl_set_bio(ssl, F, rb_ssl_write_cb, rb_ssl_read_cb, NULL);
451}
452
453static void
454rb_ssl_tryconn(rb_fde_t *F, int status, void *data)
455{
456 struct ssl_connect *sconn = data;
457 if(status != RB_OK)
458 {
459 rb_ssl_connect_realcb(F, status, sconn);
460 return;
461 }
462
463 F->type |= RB_FD_SSL;
464
465
466 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
467 F->ssl = rb_malloc(sizeof(mbedtls_ssl_context));
468 rb_ssl_setup_client_context(F, F->ssl);
469
470 do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn);
471}
472
473void
474rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest,
475 struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
476{
477 struct ssl_connect *sconn;
478 if(F == NULL)
479 return;
480
481 sconn = rb_malloc(sizeof(struct ssl_connect));
482 sconn->data = data;
483 sconn->callback = callback;
484 sconn->timeout = timeout;
485 rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout);
486}
487
488void
489rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout)
490{
491 struct ssl_connect *sconn;
492 if(F == NULL)
493 return;
494
495 sconn = rb_malloc(sizeof(struct ssl_connect));
496 sconn->data = data;
497 sconn->callback = callback;
498 sconn->timeout = timeout;
499 F->connect = rb_malloc(sizeof(struct conndata));
500 F->connect->callback = callback;
501 F->connect->data = data;
502 F->type |= RB_FD_SSL;
503 F->ssl = rb_malloc(sizeof(mbedtls_ssl_context));
504
505 rb_ssl_setup_client_context(F, F->ssl);
506 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
507
508 do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn);
509}
510
511int
512rb_init_prng(const char *path, prng_seed_t seed_type)
513{
514 return 1;
515}
516
517int
518rb_get_random(void *buf, size_t length)
519{
520 if (mbedtls_ctr_drbg_random(&ctr_drbg, buf, length))
521 return 0;
522
523 return 1;
524}
525
526const char *
527rb_get_ssl_strerror(rb_fde_t *F)
528{
529#ifdef MBEDTLS_ERROR_C
530 static char errbuf[512];
531 mbedtls_strerror(F->ssl_errno, errbuf, sizeof errbuf);
532 return errbuf;
533#else
534 return "???";
535#endif
536}
537
538int
539rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN])
540{
541 const mbedtls_x509_crt *peer_cert;
542
543 peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F));
544 if (peer_cert == NULL)
545 return 0;
546
547 return 0;
548#if 0
549 gnutls_x509_crt_t cert;
550 unsigned int cert_list_size;
551 const gnutls_datum_t *cert_list;
552 uint8_t digest[RB_SSL_CERTFP_LEN * 2];
553 size_t digest_size;
554
555 if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509)
556 return 0;
557
558 if (gnutls_x509_crt_init(&cert) < 0)
559 return 0;
560
561 cert_list_size = 0;
562 cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size);
563 if (cert_list == NULL)
564 {
565 gnutls_x509_crt_deinit(cert);
566 return 0;
567 }
568
569 if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
570 {
571 gnutls_x509_crt_deinit(cert);
572 return 0;
573 }
574
575 if (gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, digest, &digest_size) < 0)
576 {
577 gnutls_x509_crt_deinit(cert);
578 return 0;
579 }
580
581 memcpy(certfp, digest, RB_SSL_CERTFP_LEN);
582
583 gnutls_x509_crt_deinit(cert);
584 return 1;
585#endif
586
587}
588
589int
590rb_supports_ssl(void)
591{
592 return 1;
593}
594
595void
596rb_get_ssl_info(char *buf, size_t len)
597{
598 char version_str[512];
599 mbedtls_version_get_string(version_str);
600
601 rb_snprintf(buf, len, "MBEDTLS: compiled (%s), library(%s)",
602 MBEDTLS_VERSION_STRING, version_str);
603}
604
605
606#endif /* HAVE_GNUTLS */