2 * librb: a library used by ircd-ratbox and other things
3 * mbedtls.c: mbedtls related code
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>
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.
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.
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
26 #include <librb_config.h>
28 #include <commio-int.h>
29 #include <commio-ssl.h>
33 #include "mbedtls/entropy.h"
34 #include "mbedtls/ctr_drbg.h"
35 #include "mbedtls/certs.h"
36 #include "mbedtls/x509.h"
37 #include "mbedtls/ssl.h"
38 #include "mbedtls/net.h"
39 #include "mbedtls/error.h"
40 #include "mbedtls/debug.h"
41 #include "mbedtls/dhm.h"
42 #include "mbedtls/version.h"
44 static mbedtls_x509_crt x509
;
45 static mbedtls_pk_context serv_pk
;
46 static mbedtls_dhm_context dh_params
;
47 static mbedtls_ctr_drbg_context ctr_drbg
;
48 static mbedtls_entropy_context entropy
;
49 static mbedtls_ssl_config serv_config
;
50 static mbedtls_ssl_config client_config
;
52 #define SSL_P(x) ((mbedtls_ssl_context *)F->ssl)
55 rb_ssl_shutdown(rb_fde_t
*F
)
58 if(F
== NULL
|| F
->ssl
== NULL
)
60 for(i
= 0; i
< 4; i
++)
62 int r
= mbedtls_ssl_close_notify(SSL_P(F
));
63 if(r
!= MBEDTLS_ERR_SSL_WANT_READ
&& r
!= MBEDTLS_ERR_SSL_WANT_WRITE
)
66 mbedtls_ssl_free(SSL_P(F
));
71 rb_ssl_handshake_count(rb_fde_t
*F
)
73 return F
->handshake_count
;
77 rb_ssl_clear_handshake_count(rb_fde_t
*F
)
79 F
->handshake_count
= 0;
83 rb_ssl_timeout(rb_fde_t
*F
, void *notused
)
85 lrb_assert(F
->accept
!= NULL
);
86 F
->accept
->callback(F
, RB_ERR_TIMEOUT
, NULL
, 0, F
->accept
->data
);
91 do_ssl_handshake(rb_fde_t
*F
, PF
* callback
, void *data
)
96 ret
= mbedtls_ssl_handshake(SSL_P(F
));
99 if (ret
== -1 && rb_ignore_errno(errno
))
100 ret
= MBEDTLS_ERR_SSL_WANT_READ
;
102 if((ret
== MBEDTLS_ERR_SSL_WANT_READ
|| ret
== MBEDTLS_ERR_SSL_WANT_WRITE
))
104 if(ret
== MBEDTLS_ERR_SSL_WANT_READ
)
105 flags
= RB_SELECT_READ
;
107 flags
= RB_SELECT_WRITE
;
108 rb_setselect(F
, flags
, callback
, data
);
115 return 1; /* handshake is finished..go about life */
119 rb_ssl_tryaccept(rb_fde_t
*F
, void *data
)
122 struct acceptdata
*ad
;
124 lrb_assert(F
->accept
!= NULL
);
126 ret
= do_ssl_handshake(F
, rb_ssl_tryaccept
, NULL
);
128 /* do_ssl_handshake does the rb_setselect */
134 rb_settimeout(F
, 0, NULL
, NULL
);
135 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
, NULL
, NULL
);
138 ad
->callback(F
, RB_OK
, (struct sockaddr
*)&ad
->S
, ad
->addrlen
, ad
->data
);
140 ad
->callback(F
, RB_ERROR_SSL
, NULL
, 0, ad
->data
);
146 rb_ssl_read_cb(void *opaque
, unsigned char *buf
, size_t size
)
149 rb_fde_t
*F
= opaque
;
151 ret
= read(F
->fd
, buf
, size
);
152 if (ret
< 0 && rb_ignore_errno(errno
))
153 return MBEDTLS_ERR_SSL_WANT_READ
;
159 rb_ssl_write_cb(void *opaque
, const unsigned char *buf
, size_t size
)
161 rb_fde_t
*F
= opaque
;
164 ret
= write(F
->fd
, buf
, size
);
165 if (ret
< 0 && rb_ignore_errno(errno
))
166 return MBEDTLS_ERR_SSL_WANT_WRITE
;
172 rb_ssl_setup_srv_context(rb_fde_t
*F
, mbedtls_ssl_context
*ssl
)
176 mbedtls_ssl_init(ssl
);
177 if ((ret
= mbedtls_ssl_setup(ssl
, &serv_config
)) != 0)
179 rb_lib_log("rb_ssl_setup_srv_context: failed to set up ssl context: -0x%x", -ret
);
184 mbedtls_ssl_set_bio(ssl
, F
, rb_ssl_write_cb
, rb_ssl_read_cb
, NULL
);
188 rb_ssl_start_accepted(rb_fde_t
*new_F
, ACCB
* cb
, void *data
, int timeout
)
190 mbedtls_ssl_context
*ssl
;
191 new_F
->type
|= RB_FD_SSL
;
192 ssl
= new_F
->ssl
= rb_malloc(sizeof(mbedtls_ssl_context
));
193 new_F
->accept
= rb_malloc(sizeof(struct acceptdata
));
195 new_F
->accept
->callback
= cb
;
196 new_F
->accept
->data
= data
;
197 rb_settimeout(new_F
, timeout
, rb_ssl_timeout
, NULL
);
199 new_F
->accept
->addrlen
= 0;
201 rb_ssl_setup_srv_context(new_F
, ssl
);
202 if(do_ssl_handshake(new_F
, rb_ssl_tryaccept
, NULL
))
204 struct acceptdata
*ad
= new_F
->accept
;
205 new_F
->accept
= NULL
;
207 ad
->callback(new_F
, RB_OK
, (struct sockaddr
*)&ad
->S
, ad
->addrlen
, ad
->data
);
213 rb_ssl_accept_setup(rb_fde_t
*F
, rb_fde_t
*new_F
, struct sockaddr
*st
, int addrlen
)
215 new_F
->type
|= RB_FD_SSL
;
216 new_F
->ssl
= rb_malloc(sizeof(mbedtls_ssl_context
));
217 new_F
->accept
= rb_malloc(sizeof(struct acceptdata
));
219 new_F
->accept
->callback
= F
->accept
->callback
;
220 new_F
->accept
->data
= F
->accept
->data
;
221 rb_settimeout(new_F
, 10, rb_ssl_timeout
, NULL
);
222 memcpy(&new_F
->accept
->S
, st
, addrlen
);
223 new_F
->accept
->addrlen
= addrlen
;
225 rb_ssl_setup_srv_context(new_F
, new_F
->ssl
);
226 if(do_ssl_handshake(F
, rb_ssl_tryaccept
, NULL
))
228 struct acceptdata
*ad
= F
->accept
;
231 ad
->callback(F
, RB_OK
, (struct sockaddr
*)&ad
->S
, ad
->addrlen
, ad
->data
);
237 rb_ssl_read_or_write(int r_or_w
, rb_fde_t
*F
, void *rbuf
, const void *wbuf
, size_t count
)
242 ret
= mbedtls_ssl_read(F
->ssl
, rbuf
, count
);
244 ret
= mbedtls_ssl_write(F
->ssl
, wbuf
, count
);
250 case MBEDTLS_ERR_SSL_WANT_READ
:
251 return RB_RW_SSL_NEED_READ
;
252 case MBEDTLS_ERR_SSL_WANT_WRITE
:
253 return RB_RW_SSL_NEED_WRITE
;
257 return RB_RW_IO_ERROR
;
265 rb_ssl_read(rb_fde_t
*F
, void *buf
, size_t count
)
267 return rb_ssl_read_or_write(0, F
, buf
, NULL
, count
);
271 rb_ssl_write(rb_fde_t
*F
, const void *buf
, size_t count
)
273 return rb_ssl_read_or_write(1, F
, NULL
, buf
, count
);
281 mbedtls_entropy_init(&entropy
);
282 mbedtls_ctr_drbg_init(&ctr_drbg
);
284 if((ret
= mbedtls_ctr_drbg_seed(&ctr_drbg
, mbedtls_entropy_func
, &entropy
, NULL
, 0)) != 0)
286 rb_lib_log("rb_init_prng: unable to initialize PRNG, mbedtls_ctr_drbg_seed() returned -0x%x", -ret
);
290 mbedtls_ssl_config_init(&serv_config
);
292 if ((ret
= mbedtls_ssl_config_defaults(&serv_config
,
293 MBEDTLS_SSL_IS_SERVER
,
294 MBEDTLS_SSL_TRANSPORT_STREAM
,
295 MBEDTLS_SSL_PRESET_DEFAULT
)) != 0)
297 rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for server context: -0x%x", -ret
);
301 mbedtls_ssl_conf_rng(&serv_config
, mbedtls_ctr_drbg_random
, &ctr_drbg
);
303 /***************************************************************************************************************/
305 mbedtls_ssl_config_init(&client_config
);
307 if ((ret
= mbedtls_ssl_config_defaults(&client_config
,
308 MBEDTLS_SSL_IS_CLIENT
,
309 MBEDTLS_SSL_TRANSPORT_STREAM
,
310 MBEDTLS_SSL_PRESET_DEFAULT
)) != 0)
312 rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for client context: -0x%x", -ret
);
316 mbedtls_ssl_conf_rng(&client_config
, mbedtls_ctr_drbg_random
, &ctr_drbg
);
317 mbedtls_ssl_conf_authmode(&client_config
, MBEDTLS_SSL_VERIFY_NONE
);
323 rb_setup_ssl_server(const char *cert
, const char *keyfile
, const char *dhfile
, const char *cipher_list
)
327 mbedtls_x509_crt_init(&x509
);
328 ret
= mbedtls_x509_crt_parse_file(&x509
, cert
);
331 rb_lib_log("rb_setup_ssl_server: failed to parse certificate '%s': -0x%x", cert
, -ret
);
335 mbedtls_pk_init(&serv_pk
);
336 ret
= mbedtls_pk_parse_keyfile(&serv_pk
, keyfile
, NULL
);
339 rb_lib_log("rb_setup_ssl_server: failed to parse private key '%s': -0x%x", keyfile
, -ret
);
343 mbedtls_dhm_init(&dh_params
);
344 ret
= mbedtls_dhm_parse_dhmfile(&dh_params
, dhfile
);
347 rb_lib_log("rb_setup_ssl_server: failed to parse DH parameters '%s': -0x%x", dhfile
, -ret
);
351 ret
= mbedtls_ssl_conf_dh_param_ctx(&serv_config
, &dh_params
);
354 rb_lib_log("rb_setup_ssl_server: failed to set DH parameters on SSL config context: -0x%x", -ret
);
360 mbedtls_ssl_conf_ca_chain(&serv_config
, x509
.next
, NULL
);
361 mbedtls_ssl_conf_ca_chain(&client_config
, x509
.next
, NULL
);
364 if ((ret
= mbedtls_ssl_conf_own_cert(&serv_config
, &x509
, &serv_pk
)) != 0)
366 rb_lib_log("rb_setup_ssl_server: failed to set up own certificate: -0x%x", -ret
);
370 if ((ret
= mbedtls_ssl_conf_own_cert(&client_config
, &x509
, &serv_pk
)) != 0)
372 rb_lib_log("rb_setup_ssl_server: failed to set up own certificate: -0x%x", -ret
);
376 /* XXX support cipher lists when added to mbedtls */
382 rb_ssl_listen(rb_fde_t
*F
, int backlog
, int defer_accept
)
386 result
= rb_listen(F
, backlog
, defer_accept
);
387 F
->type
= RB_FD_SOCKET
| RB_FD_LISTEN
| RB_FD_SSL
;
400 rb_ssl_connect_realcb(rb_fde_t
*F
, int status
, struct ssl_connect
*sconn
)
402 F
->connect
->callback
= sconn
->callback
;
403 F
->connect
->data
= sconn
->data
;
405 rb_connect_callback(F
, status
);
409 rb_ssl_tryconn_timeout_cb(rb_fde_t
*F
, void *data
)
411 rb_ssl_connect_realcb(F
, RB_ERR_TIMEOUT
, data
);
415 rb_ssl_tryconn_cb(rb_fde_t
*F
, void *data
)
417 struct ssl_connect
*sconn
= data
;
420 ret
= do_ssl_handshake(F
, rb_ssl_tryconn_cb
, (void *)sconn
);
425 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
428 /* do_ssl_handshake does the rb_setselect stuff */
435 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
439 rb_ssl_setup_client_context(rb_fde_t
*F
, mbedtls_ssl_context
*ssl
)
443 mbedtls_ssl_init(ssl
);
444 if ((ret
= mbedtls_ssl_setup(ssl
, &client_config
)) != 0)
446 rb_lib_log("rb_ssl_setup_client_context: failed to set up ssl context: -0x%x", -ret
);
451 mbedtls_ssl_set_bio(ssl
, F
, rb_ssl_write_cb
, rb_ssl_read_cb
, NULL
);
455 rb_ssl_tryconn(rb_fde_t
*F
, int status
, void *data
)
457 struct ssl_connect
*sconn
= data
;
460 rb_ssl_connect_realcb(F
, status
, sconn
);
464 F
->type
|= RB_FD_SSL
;
467 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
468 F
->ssl
= rb_malloc(sizeof(mbedtls_ssl_context
));
469 rb_ssl_setup_client_context(F
, F
->ssl
);
471 do_ssl_handshake(F
, rb_ssl_tryconn_cb
, (void *)sconn
);
475 rb_connect_tcp_ssl(rb_fde_t
*F
, struct sockaddr
*dest
,
476 struct sockaddr
*clocal
, int socklen
, CNCB
* callback
, void *data
, int timeout
)
478 struct ssl_connect
*sconn
;
482 sconn
= rb_malloc(sizeof(struct ssl_connect
));
484 sconn
->callback
= callback
;
485 sconn
->timeout
= timeout
;
486 rb_connect_tcp(F
, dest
, clocal
, socklen
, rb_ssl_tryconn
, sconn
, timeout
);
490 rb_ssl_start_connected(rb_fde_t
*F
, CNCB
* callback
, void *data
, int timeout
)
492 struct ssl_connect
*sconn
;
496 sconn
= rb_malloc(sizeof(struct ssl_connect
));
498 sconn
->callback
= callback
;
499 sconn
->timeout
= timeout
;
500 F
->connect
= rb_malloc(sizeof(struct conndata
));
501 F
->connect
->callback
= callback
;
502 F
->connect
->data
= data
;
503 F
->type
|= RB_FD_SSL
;
504 F
->ssl
= rb_malloc(sizeof(mbedtls_ssl_context
));
506 rb_ssl_setup_client_context(F
, F
->ssl
);
507 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
509 do_ssl_handshake(F
, rb_ssl_tryconn_cb
, (void *)sconn
);
513 rb_init_prng(const char *path
, prng_seed_t seed_type
)
519 rb_get_random(void *buf
, size_t length
)
521 if (mbedtls_ctr_drbg_random(&ctr_drbg
, buf
, length
))
528 rb_get_ssl_strerror(rb_fde_t
*F
)
530 #ifdef MBEDTLS_ERROR_C
531 static char errbuf
[512];
532 mbedtls_strerror(F
->ssl_errno
, errbuf
, sizeof errbuf
);
540 rb_get_ssl_certfp(rb_fde_t
*F
, uint8_t certfp
[RB_SSL_CERTFP_LEN
], int method
)
542 const mbedtls_x509_crt
*peer_cert
;
543 uint8_t hash
[RB_SSL_CERTFP_LEN
];
545 const mbedtls_md_info_t
*md_info
;
546 mbedtls_md_type_t md_type
;
551 case RB_SSL_CERTFP_METH_SHA1
:
552 md_type
= MBEDTLS_MD_SHA1
;
553 hashlen
= RB_SSL_CERTFP_LEN_SHA1
;
554 case RB_SSL_CERTFP_METH_SHA256
:
555 md_type
= MBEDTLS_MD_SHA256
;
556 hashlen
= RB_SSL_CERTFP_LEN_SHA256
;
557 case RB_SSL_CERTFP_METH_SHA512
:
558 md_type
= MBEDTLS_MD_SHA512
;
559 hashlen
= RB_SSL_CERTFP_LEN_SHA512
;
564 peer_cert
= mbedtls_ssl_get_peer_cert(SSL_P(F
));
565 if (peer_cert
== NULL
)
568 md_info
= mbedtls_md_info_from_type(md_type
);
572 if ((ret
= mbedtls_md(md_info
, peer_cert
->raw
.p
, peer_cert
->raw
.len
, hash
)) != 0)
574 rb_lib_log("rb_get_ssl_certfp: unable to get certfp for F: %p, -0x%x", -ret
);
578 memcpy(certfp
, hash
, hashlen
);
584 rb_supports_ssl(void)
590 rb_get_ssl_info(char *buf
, size_t len
)
592 char version_str
[512];
593 mbedtls_version_get_string(version_str
);
595 snprintf(buf
, len
, "MBEDTLS: compiled (%s), library(%s)",
596 MBEDTLS_VERSION_STRING
, version_str
);
600 rb_ssl_get_cipher(rb_fde_t
*F
)
602 if(F
== NULL
|| F
->ssl
== NULL
)
604 return mbedtls_ssl_get_ciphersuite(SSL_P(F
));
607 #endif /* HAVE_GNUTLS */