From 1e7342d0f4ca7de1d56bdc13a546d6f15964cec4 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Thu, 5 May 2016 03:31:32 +0000 Subject: [PATCH] [mbedtls] Various fixes and improvements * Move certificate, key, DH parameters and configuration to heap (Documentation states that setting new configuration, e.g. during a rehash, is unsupported while connections using that configuration are active) This is the same approach as the fix for #186 Refcount these structures so as to not introduce a memory leak On rehash, it will use new structures only if there are no errors in constructing them * Make fingerprint generation work for TLS connections See the comments in the newly created file for an explanation * Fix memory leak when generating a fingerprint from a file * Add better error-reporting (strings in addition to numbers) where possible * Coalesce several connection memory allocations into one function * Reduce boilerplate where possible (Charybdis targets C99) * Support private key being in certificate file, and having no DH parameters file * Correct erroneous closing comment --- librb/src/mbedtls.c | 554 +++++++++++++++++------------- librb/src/mbedtls_embedded_data.h | 107 ++++++ 2 files changed, 430 insertions(+), 231 deletions(-) create mode 100644 librb/src/mbedtls_embedded_data.h diff --git a/librb/src/mbedtls.c b/librb/src/mbedtls.c index f13b74ea..629830b9 100644 --- a/librb/src/mbedtls.c +++ b/librb/src/mbedtls.c @@ -1,10 +1,11 @@ /* * librb: a library used by ircd-ratbox and other things - * mbedtls.c: mbedtls related code + * mbedtls.c: ARM mbedTLS backend * * Copyright (C) 2007-2008 ircd-ratbox development team * Copyright (C) 2007-2008 Aaron Sethman * Copyright (C) 2015 William Pitcock + * Copyright (C) 2016 Aaron Jones * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,29 +43,149 @@ #include "mbedtls/dhm.h" #include "mbedtls/version.h" -static mbedtls_x509_crt x509; -static mbedtls_pk_context serv_pk; -static mbedtls_dhm_context dh_params; -static mbedtls_ctr_drbg_context ctr_drbg; -static mbedtls_entropy_context entropy; -static mbedtls_ssl_config serv_config; -static mbedtls_ssl_config client_config; +#include "mbedtls_embedded_data.h" -#define SSL_P(x) ((mbedtls_ssl_context *)F->ssl) +typedef struct +{ + mbedtls_x509_crt crt; + mbedtls_pk_context key; + mbedtls_dhm_context dhp; + mbedtls_ssl_config server_cfg; + mbedtls_ssl_config client_cfg; + size_t refcount; +} rb_mbedtls_cfg_context; + +typedef struct +{ + rb_mbedtls_cfg_context *cfg; + mbedtls_ssl_context ssl; +} rb_mbedtls_ssl_context; + +#define SSL_C(x) ((rb_mbedtls_ssl_context *) (x)->ssl)->cfg +#define SSL_P(x) &((rb_mbedtls_ssl_context *) (x)->ssl)->ssl + +static mbedtls_ctr_drbg_context ctr_drbg_ctx; +static mbedtls_entropy_context entropy_ctx; + +static mbedtls_x509_crt dummy_ca_ctx; +static rb_mbedtls_cfg_context *rb_mbedtls_cfg = NULL; + +static const char * +rb_get_ssl_strerror_internal(int err) +{ + static char errbuf[512]; + +#ifdef MBEDTLS_ERROR_C + char mbed_errbuf[512]; + mbedtls_strerror(err, mbed_errbuf, sizeof mbed_errbuf); + snprintf(errbuf, sizeof errbuf, "(-0x%x) %s", -err, mbed_errbuf); +#else + snprintf(errbuf, sizeof errbuf, "-0x%x", -err); +#endif + + return errbuf; +} + +const char * +rb_get_ssl_strerror(rb_fde_t *F) +{ + return rb_get_ssl_strerror_internal(F->ssl_errno); +} + +static void rb_mbedtls_cfg_incref(rb_mbedtls_cfg_context *cfg) +{ + lrb_assert(cfg->refcount > 0); + + cfg->refcount++; +} + +static void rb_mbedtls_cfg_decref(rb_mbedtls_cfg_context *cfg) +{ + if(cfg == NULL) + return; + + lrb_assert(cfg->refcount > 0); + + if((--cfg->refcount) > 0) + return; + + mbedtls_ssl_config_free(&cfg->client_cfg); + mbedtls_ssl_config_free(&cfg->server_cfg); + mbedtls_dhm_free(&cfg->dhp); + mbedtls_pk_free(&cfg->key); + mbedtls_x509_crt_free(&cfg->crt); + + rb_free(cfg); +} + +static rb_mbedtls_cfg_context *rb_mbedtls_cfg_new(void) +{ + rb_mbedtls_cfg_context *cfg; + int ret; + + if((cfg = rb_malloc(sizeof(rb_mbedtls_cfg_context))) == NULL) + return NULL; + + mbedtls_x509_crt_init(&cfg->crt); + mbedtls_pk_init(&cfg->key); + mbedtls_dhm_init(&cfg->dhp); + mbedtls_ssl_config_init(&cfg->server_cfg); + mbedtls_ssl_config_init(&cfg->client_cfg); + + cfg->refcount = 1; + + if((ret = mbedtls_ssl_config_defaults(&cfg->server_cfg, + MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) + { + rb_lib_log("rb_mbedtls_cfg_new: ssl_config_defaults (server): %s", + rb_get_ssl_strerror_internal(ret)); + rb_mbedtls_cfg_decref(cfg); + return NULL; + } + + if((ret = mbedtls_ssl_config_defaults(&cfg->client_cfg, + MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) + { + rb_lib_log("rb_mbedtls_cfg_new: ssl_config_defaults (client): %s", + rb_get_ssl_strerror_internal(ret)); + rb_mbedtls_cfg_decref(cfg); + return NULL; + } + + mbedtls_ssl_conf_rng(&cfg->server_cfg, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); + mbedtls_ssl_conf_rng(&cfg->client_cfg, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); + + mbedtls_ssl_conf_ca_chain(&cfg->server_cfg, &dummy_ca_ctx, NULL); + mbedtls_ssl_conf_ca_chain(&cfg->client_cfg, &dummy_ca_ctx, NULL); + + mbedtls_ssl_conf_authmode(&cfg->server_cfg, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_authmode(&cfg->client_cfg, MBEDTLS_SSL_VERIFY_NONE); + + return cfg; +} void rb_ssl_shutdown(rb_fde_t *F) { - int i; if(F == NULL || F->ssl == NULL) return; - for(i = 0; i < 4; i++) + + if(SSL_P(F) != NULL) { - int r = mbedtls_ssl_close_notify(SSL_P(F)); - if(r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE) - break; + for(int i = 0; i < 4; i++) + { + int r = mbedtls_ssl_close_notify(SSL_P(F)); + if(r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE) + break; + } + mbedtls_ssl_free(SSL_P(F)); } - mbedtls_ssl_free(SSL_P(F)); + + if(SSL_C(F) != NULL) + rb_mbedtls_cfg_decref(SSL_C(F)); + rb_free(F->ssl); } @@ -87,50 +208,46 @@ rb_ssl_timeout(rb_fde_t *F, void *notused) F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data); } - static int do_ssl_handshake(rb_fde_t *F, PF * callback, void *data) { - int ret; - int flags; + int ret = mbedtls_ssl_handshake(SSL_P(F)); - ret = mbedtls_ssl_handshake(SSL_P(F)); - if(ret < 0) + if(ret == 0) { - if (ret == -1 && rb_ignore_errno(errno)) - ret = MBEDTLS_ERR_SSL_WANT_READ; + F->handshake_count++; + return 1; + } - if((ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)) - { - if(ret == MBEDTLS_ERR_SSL_WANT_READ) - flags = RB_SELECT_READ; - else - flags = RB_SELECT_WRITE; - rb_setselect(F, flags, callback, data); - return 0; - } + if(ret == -1 && rb_ignore_errno(errno)) + ret = MBEDTLS_ERR_SSL_WANT_READ; + switch(ret) + { + case MBEDTLS_ERR_SSL_WANT_READ: + rb_setselect(F, RB_SELECT_READ, callback, data); + return 0; + case MBEDTLS_ERR_SSL_WANT_WRITE: + rb_setselect(F, RB_SELECT_WRITE, callback, data); + return 0; + default: F->ssl_errno = ret; return -1; } - return 1; /* handshake is finished..go about life */ } static void rb_ssl_tryaccept(rb_fde_t *F, void *data) { - int ret; - struct acceptdata *ad; - lrb_assert(F->accept != NULL); - ret = do_ssl_handshake(F, rb_ssl_tryaccept, NULL); + int ret = do_ssl_handshake(F, rb_ssl_tryaccept, NULL); /* do_ssl_handshake does the rb_setselect */ if(ret == 0) return; - ad = F->accept; + struct acceptdata *ad = F->accept; F->accept = NULL; rb_settimeout(F, 0, NULL, NULL); rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); @@ -146,11 +263,10 @@ rb_ssl_tryaccept(rb_fde_t *F, void *data) static int rb_ssl_read_cb(void *opaque, unsigned char *buf, size_t size) { - int ret; rb_fde_t *F = opaque; - ret = read(F->fd, buf, size); - if (ret < 0 && rb_ignore_errno(errno)) + int ret = (int) read(F->fd, buf, size); + if(ret < 0 && rb_ignore_errno(errno)) return MBEDTLS_ERR_SSL_WANT_READ; return ret; @@ -160,52 +276,69 @@ static int rb_ssl_write_cb(void *opaque, const unsigned char *buf, size_t size) { rb_fde_t *F = opaque; - int ret; - ret = write(F->fd, buf, size); - if (ret < 0 && rb_ignore_errno(errno)) + int ret = (int) write(F->fd, buf, size); + if(ret < 0 && rb_ignore_errno(errno)) return MBEDTLS_ERR_SSL_WANT_WRITE; return ret; } static void -rb_ssl_setup_srv_context(rb_fde_t *F, mbedtls_ssl_context *ssl) +rb_ssl_setup_mbed_context(rb_fde_t *F, bool is_server) { + rb_mbedtls_ssl_context *mbed_ssl_ctx; + mbedtls_ssl_config *mbed_config; int ret; - mbedtls_ssl_init(ssl); - if ((ret = mbedtls_ssl_setup(ssl, &serv_config)) != 0) + if((mbed_ssl_ctx = rb_malloc(sizeof(rb_mbedtls_ssl_context))) == NULL) { - rb_lib_log("rb_ssl_setup_srv_context: failed to set up ssl context: -0x%x", -ret); + rb_lib_log("rb_ssl_setup_mbed_context: rb_malloc: allocation failure"); rb_close(F); return; } - mbedtls_ssl_set_bio(ssl, F, rb_ssl_write_cb, rb_ssl_read_cb, NULL); + if(is_server) + mbed_config = &rb_mbedtls_cfg->server_cfg; + else + mbed_config = &rb_mbedtls_cfg->client_cfg; + + mbedtls_ssl_init(&mbed_ssl_ctx->ssl); + mbedtls_ssl_set_bio(&mbed_ssl_ctx->ssl, F, rb_ssl_write_cb, rb_ssl_read_cb, NULL); + + if((ret = mbedtls_ssl_setup(&mbed_ssl_ctx->ssl, mbed_config)) != 0) + { + rb_lib_log("rb_ssl_setup_mbed_context: ssl_setup: %s", + rb_get_ssl_strerror_internal(ret)); + mbedtls_ssl_free(&mbed_ssl_ctx->ssl); + rb_free(mbed_ssl_ctx); + rb_close(F); + return; + } + + mbed_ssl_ctx->cfg = rb_mbedtls_cfg; + rb_mbedtls_cfg_incref(mbed_ssl_ctx->cfg); + F->ssl = mbed_ssl_ctx; } void -rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) +rb_ssl_start_accepted(rb_fde_t *F, ACCB * cb, void *data, int timeout) { - mbedtls_ssl_context *ssl; - new_F->type |= RB_FD_SSL; - ssl = new_F->ssl = rb_malloc(sizeof(mbedtls_ssl_context)); - new_F->accept = rb_malloc(sizeof(struct acceptdata)); + F->type |= RB_FD_SSL; + F->accept = rb_malloc(sizeof(struct acceptdata)); - new_F->accept->callback = cb; - new_F->accept->data = data; - rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL); + F->accept->callback = cb; + F->accept->data = data; + rb_settimeout(F, timeout, rb_ssl_timeout, NULL); - new_F->accept->addrlen = 0; + F->accept->addrlen = 0; - rb_ssl_setup_srv_context(new_F, ssl); - if(do_ssl_handshake(new_F, rb_ssl_tryaccept, NULL)) + rb_ssl_setup_mbed_context(F, true); + if(do_ssl_handshake(F, rb_ssl_tryaccept, NULL)) { - struct acceptdata *ad = new_F->accept; - new_F->accept = NULL; - - ad->callback(new_F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); + struct acceptdata *ad = F->accept; + F->accept = NULL; + ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); rb_free(ad); } } @@ -214,39 +347,38 @@ void rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen) { new_F->type |= RB_FD_SSL; - new_F->ssl = rb_malloc(sizeof(mbedtls_ssl_context)); new_F->accept = rb_malloc(sizeof(struct acceptdata)); new_F->accept->callback = F->accept->callback; new_F->accept->data = F->accept->data; rb_settimeout(new_F, 10, rb_ssl_timeout, NULL); + memcpy(&new_F->accept->S, st, addrlen); new_F->accept->addrlen = addrlen; - rb_ssl_setup_srv_context(new_F, new_F->ssl); + rb_ssl_setup_mbed_context(new_F, true); if(do_ssl_handshake(F, rb_ssl_tryaccept, NULL)) { struct acceptdata *ad = F->accept; F->accept = NULL; - ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); rb_free(ad); } } static ssize_t -rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count) +rb_ssl_read_or_write(bool do_read, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count) { ssize_t ret; - if(r_or_w == 0) - ret = mbedtls_ssl_read(F->ssl, rbuf, count); + if(do_read) + ret = mbedtls_ssl_read(SSL_P(F), rbuf, count); else - ret = mbedtls_ssl_write(F->ssl, wbuf, count); + ret = mbedtls_ssl_write(SSL_P(F), wbuf, count); if(ret < 0) { - switch (ret) + switch(ret) { case MBEDTLS_ERR_SSL_WANT_READ: return RB_RW_SSL_NEED_READ; @@ -265,13 +397,13 @@ rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size ssize_t rb_ssl_read(rb_fde_t *F, void *buf, size_t count) { - return rb_ssl_read_or_write(0, F, buf, NULL, count); + return rb_ssl_read_or_write(true, F, buf, NULL, count); } ssize_t rb_ssl_write(rb_fde_t *F, const void *buf, size_t count) { - return rb_ssl_read_or_write(1, F, NULL, buf, count); + return rb_ssl_read_or_write(false, F, NULL, buf, count); } int @@ -279,112 +411,112 @@ rb_init_ssl(void) { int ret; - mbedtls_entropy_init(&entropy); - mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_ctr_drbg_init(&ctr_drbg_ctx); + mbedtls_entropy_init(&entropy_ctx); - if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)) != 0) + if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, + (const unsigned char *)rb_mbedtls_personal_str, sizeof(rb_mbedtls_personal_str))) != 0) { - rb_lib_log("rb_init_prng: unable to initialize PRNG, mbedtls_ctr_drbg_seed() returned -0x%x", -ret); + rb_lib_log("rb_init_ssl: ctr_drbg_seed: %s", + rb_get_ssl_strerror_internal(ret)); return 0; } - mbedtls_ssl_config_init(&serv_config); - - if ((ret = mbedtls_ssl_config_defaults(&serv_config, - MBEDTLS_SSL_IS_SERVER, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT)) != 0) + if((ret = mbedtls_x509_crt_parse_der(&dummy_ca_ctx, rb_mbedtls_dummy_ca_certificate, + sizeof(rb_mbedtls_dummy_ca_certificate))) != 0) { - rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for server context: -0x%x", -ret); + rb_lib_log("rb_init_ssl: x509_crt_parse_der (Dummy CA): %s", + rb_get_ssl_strerror_internal(ret)); return 0; } - mbedtls_ssl_conf_rng(&serv_config, mbedtls_ctr_drbg_random, &ctr_drbg); - - /***************************************************************************************************************/ - - mbedtls_ssl_config_init(&client_config); - - if ((ret = mbedtls_ssl_config_defaults(&client_config, - MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT)) != 0) - { - rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for client context: -0x%x", -ret); - return 0; - } - - mbedtls_ssl_conf_rng(&client_config, mbedtls_ctr_drbg_random, &ctr_drbg); - mbedtls_ssl_conf_authmode(&client_config, MBEDTLS_SSL_VERIFY_NONE); - return 1; } int -rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list) +rb_setup_ssl_server(const char *certfile, const char *keyfile, const char *dhfile, const char *cipher_list) { + rb_mbedtls_cfg_context *newcfg; int ret; - mbedtls_x509_crt_init(&x509); - ret = mbedtls_x509_crt_parse_file(&x509, cert); - if (ret != 0) + if(certfile == NULL) { - rb_lib_log("rb_setup_ssl_server: failed to parse certificate '%s': -0x%x", cert, -ret); + rb_lib_log("rb_setup_ssl_server: no certificate file specified"); return 0; } - mbedtls_pk_init(&serv_pk); - ret = mbedtls_pk_parse_keyfile(&serv_pk, keyfile, NULL); - if (ret != 0) + if(keyfile == NULL) + keyfile = certfile; + + if((newcfg = rb_mbedtls_cfg_new()) == NULL) { - rb_lib_log("rb_setup_ssl_server: failed to parse private key '%s': -0x%x", keyfile, -ret); + rb_lib_log("rb_setup_ssl_server: rb_mbedtls_cfg_new: allocation failed"); return 0; } - mbedtls_dhm_init(&dh_params); - ret = mbedtls_dhm_parse_dhmfile(&dh_params, dhfile); - if (ret != 0) + if((ret = mbedtls_x509_crt_parse_file(&newcfg->crt, certfile)) != 0) { - rb_lib_log("rb_setup_ssl_server: failed to parse DH parameters '%s': -0x%x", dhfile, -ret); + rb_lib_log("rb_setup_ssl_server: x509_crt_parse_file ('%s'): %s", + certfile, rb_get_ssl_strerror_internal(ret)); + rb_mbedtls_cfg_decref(newcfg); + return 0; + } + if((ret = mbedtls_pk_parse_keyfile(&newcfg->key, keyfile, NULL)) != 0) + { + rb_lib_log("rb_setup_ssl_server: pk_parse_keyfile ('%s'): %s", + keyfile, rb_get_ssl_strerror_internal(ret)); + rb_mbedtls_cfg_decref(newcfg); return 0; } - ret = mbedtls_ssl_conf_dh_param_ctx(&serv_config, &dh_params); - if (ret != 0) + /* Absense of DH parameters does not matter with mbedTLS, as it comes with its own defaults + Thus, clients can still use DHE- ciphersuites, just over a weaker, common DH group + So, we do not consider failure to parse DH parameters as fatal */ + if(dhfile == NULL) { - rb_lib_log("rb_setup_ssl_server: failed to set DH parameters on SSL config context: -0x%x", -ret); + rb_lib_log("rb_setup_ssl_server: no DH parameters file specified"); + } + else + { + if((ret = mbedtls_dhm_parse_dhmfile(&newcfg->dhp, dhfile)) != 0) + { + rb_lib_log("rb_setup_ssl_server: dhm_parse_dhmfile ('%s'): %s", + dhfile, rb_get_ssl_strerror_internal(ret)); + } + else if((ret = mbedtls_ssl_conf_dh_param_ctx(&newcfg->server_cfg, &newcfg->dhp)) != 0) + { + rb_lib_log("rb_setup_ssl_server: ssl_conf_dh_param_ctx: %s", + rb_get_ssl_strerror_internal(ret)); + } + } + + if((ret = mbedtls_ssl_conf_own_cert(&newcfg->server_cfg, &newcfg->crt, &newcfg->key)) != 0) + { + rb_lib_log("rb_setup_ssl_server: ssl_conf_own_cert (server): %s", + rb_get_ssl_strerror_internal(ret)); + rb_mbedtls_cfg_decref(newcfg); return 0; } - - if (x509.next) + if((ret = mbedtls_ssl_conf_own_cert(&newcfg->client_cfg, &newcfg->crt, &newcfg->key)) != 0) { - mbedtls_ssl_conf_ca_chain(&serv_config, x509.next, NULL); - mbedtls_ssl_conf_ca_chain(&client_config, x509.next, NULL); - } - - if ((ret = mbedtls_ssl_conf_own_cert(&serv_config, &x509, &serv_pk)) != 0) - { - rb_lib_log("rb_setup_ssl_server: failed to set up own certificate: -0x%x", -ret); - return 0; - } - - if ((ret = mbedtls_ssl_conf_own_cert(&client_config, &x509, &serv_pk)) != 0) - { - rb_lib_log("rb_setup_ssl_server: failed to set up own certificate: -0x%x", -ret); + rb_lib_log("rb_setup_ssl_server: ssl_conf_own_cert (client): %s", + rb_get_ssl_strerror_internal(ret)); + rb_mbedtls_cfg_decref(newcfg); return 0; } /* XXX support cipher lists when added to mbedtls */ + rb_mbedtls_cfg_decref(rb_mbedtls_cfg); + rb_mbedtls_cfg = newcfg; + return 1; } int rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept) { - int result; - - result = rb_listen(F, backlog, defer_accept); + int result = rb_listen(F, backlog, defer_accept); F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL; return result; @@ -415,99 +547,72 @@ rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data) static void rb_ssl_tryconn_cb(rb_fde_t *F, void *data) { - struct ssl_connect *sconn = data; - int ret; + int ret = do_ssl_handshake(F, rb_ssl_tryconn_cb, data); - ret = do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn); - - switch (ret) + switch(ret) { case -1: - rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); + rb_ssl_connect_realcb(F, RB_ERROR_SSL, data); break; case 0: /* do_ssl_handshake does the rb_setselect stuff */ return; default: break; - - } - rb_ssl_connect_realcb(F, RB_OK, sconn); -} - -static void -rb_ssl_setup_client_context(rb_fde_t *F, mbedtls_ssl_context *ssl) -{ - int ret; - - mbedtls_ssl_init(ssl); - if ((ret = mbedtls_ssl_setup(ssl, &client_config)) != 0) - { - rb_lib_log("rb_ssl_setup_client_context: failed to set up ssl context: -0x%x", -ret); - rb_close(F); - return; - } - - mbedtls_ssl_set_bio(ssl, F, rb_ssl_write_cb, rb_ssl_read_cb, NULL); + rb_ssl_connect_realcb(F, RB_OK, data); } static void rb_ssl_tryconn(rb_fde_t *F, int status, void *data) { - struct ssl_connect *sconn = data; if(status != RB_OK) { - rb_ssl_connect_realcb(F, status, sconn); + rb_ssl_connect_realcb(F, status, data); return; } F->type |= RB_FD_SSL; - - rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); - F->ssl = rb_malloc(sizeof(mbedtls_ssl_context)); - rb_ssl_setup_client_context(F, F->ssl); - - do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn); + rb_ssl_setup_mbed_context(F, false); + rb_settimeout(F, ((struct ssl_connect *)data)->timeout, rb_ssl_tryconn_timeout_cb, data); + do_ssl_handshake(F, rb_ssl_tryconn_cb, data); } void rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest, struct sockaddr *clocal, CNCB * callback, void *data, int timeout) { - struct ssl_connect *sconn; if(F == NULL) return; - sconn = rb_malloc(sizeof(struct ssl_connect)); + struct ssl_connect *sconn = rb_malloc(sizeof(struct ssl_connect)); sconn->data = data; sconn->callback = callback; sconn->timeout = timeout; + rb_connect_tcp(F, dest, clocal, rb_ssl_tryconn, sconn, timeout); } void rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout) { - struct ssl_connect *sconn; if(F == NULL) return; - sconn = rb_malloc(sizeof(struct ssl_connect)); + struct ssl_connect *sconn = rb_malloc(sizeof(struct ssl_connect)); sconn->data = data; sconn->callback = callback; sconn->timeout = timeout; + F->connect = rb_malloc(sizeof(struct conndata)); F->connect->callback = callback; F->connect->data = data; F->type |= RB_FD_SSL; - F->ssl = rb_malloc(sizeof(mbedtls_ssl_context)); - rb_ssl_setup_client_context(F, F->ssl); + rb_ssl_setup_mbed_context(F, false); rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); - - do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn); + do_ssl_handshake(F, rb_ssl_tryconn_cb, sconn); } int @@ -519,89 +624,74 @@ rb_init_prng(const char *path, prng_seed_t seed_type) int rb_get_random(void *buf, size_t length) { - if (mbedtls_ctr_drbg_random(&ctr_drbg, buf, length)) + if(mbedtls_ctr_drbg_random(&ctr_drbg_ctx, buf, length)) return 0; return 1; } -const char * -rb_get_ssl_strerror(rb_fde_t *F) -{ -#ifdef MBEDTLS_ERROR_C - static char errbuf[512]; - mbedtls_strerror(F->ssl_errno, errbuf, sizeof errbuf); - return errbuf; -#else - return "???"; -#endif -} - static size_t -make_certfp(const mbedtls_x509_crt *peer_cert, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +rb_make_certfp(const mbedtls_x509_crt *peer_cert, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { const mbedtls_md_info_t *md_info; mbedtls_md_type_t md_type; bool spki = false; + size_t hashlen; int ret; - int len; - switch (method) + uint8_t der_pubkey[8192]; + void* data = peer_cert->raw.p; + size_t datalen = peer_cert->raw.len; + + switch(method) { case RB_SSL_CERTFP_METH_CERT_SHA1: md_type = MBEDTLS_MD_SHA1; - len = RB_SSL_CERTFP_LEN_SHA1; + hashlen = RB_SSL_CERTFP_LEN_SHA1; break; + case RB_SSL_CERTFP_METH_SPKI_SHA256: spki = true; case RB_SSL_CERTFP_METH_CERT_SHA256: md_type = MBEDTLS_MD_SHA256; - len = RB_SSL_CERTFP_LEN_SHA256; + hashlen = RB_SSL_CERTFP_LEN_SHA256; break; + case RB_SSL_CERTFP_METH_SPKI_SHA512: spki = true; case RB_SSL_CERTFP_METH_CERT_SHA512: md_type = MBEDTLS_MD_SHA512; - len = RB_SSL_CERTFP_LEN_SHA512; + hashlen = RB_SSL_CERTFP_LEN_SHA512; break; + default: return 0; } - md_info = mbedtls_md_info_from_type(md_type); - if (md_info == NULL) + if((md_info = mbedtls_md_info_from_type(md_type)) == NULL) return 0; - if (!spki) + if(spki) { - if ((ret = mbedtls_md(md_info, peer_cert->raw.p, peer_cert->raw.len, certfp)) != 0) + if ((ret = mbedtls_pk_write_pubkey_der((mbedtls_pk_context *)&peer_cert->pk, + der_pubkey, sizeof(der_pubkey))) < 0) { - rb_lib_log("rb_get_ssl_certfp: unable to calculate certfp: -0x%x", -ret); - len = 0; + rb_lib_log("rb_get_ssl_certfp: pk_write_pubkey_der: %s", + rb_get_ssl_strerror_internal(ret)); + return 0; } - } - else - { - const size_t der_pubkey_bufsz = 4096; - void *der_pubkey = rb_malloc(der_pubkey_bufsz); - int der_pubkey_len; - - der_pubkey_len = mbedtls_pk_write_pubkey_der((mbedtls_pk_context *)&peer_cert->pk, der_pubkey, der_pubkey_bufsz); - if (der_pubkey_len < 0) - { - rb_lib_log("rb_get_ssl_certfp: unable to retrieve pubkey: -0x%x", -der_pubkey_len); - len = 0; - } - else if ((ret = mbedtls_md(md_info, der_pubkey+(der_pubkey_bufsz-der_pubkey_len), der_pubkey_len, certfp)) != 0) - { - rb_lib_log("rb_get_ssl_certfp: unable to calculate certfp: -0x%x", -ret); - len = 0; - } - - rb_free(der_pubkey); + data = der_pubkey + (sizeof(der_pubkey) - ret); + datalen = ret; } - return len; + if((ret = mbedtls_md(md_info, data, datalen, certfp)) != 0) + { + rb_lib_log("rb_get_ssl_certfp: mbedtls_md: %s", + rb_get_ssl_strerror_internal(ret)); + return 0; + } + + return hashlen; } int @@ -609,11 +699,10 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { const mbedtls_x509_crt *peer_cert; - peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F)); - if (peer_cert == NULL) + if ((peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F))) == NULL) return 0; - return make_certfp(peer_cert, certfp, method); + return (int) rb_make_certfp(peer_cert, certfp, method); } int @@ -624,11 +713,14 @@ rb_get_ssl_certfp_file(const char *filename, uint8_t certfp[RB_SSL_CERTFP_LEN], mbedtls_x509_crt_init(&cert); - ret = mbedtls_x509_crt_parse_file(&cert, filename); - if (ret != 0) + if ((ret = mbedtls_x509_crt_parse_file(&cert, filename)) != 0) return -1; - return make_certfp(&cert, certfp, method); + size_t len = rb_make_certfp(&cert, certfp, method); + + mbedtls_x509_crt_free(&cert); + + return (int) len; } int @@ -650,9 +742,9 @@ rb_get_ssl_info(char *buf, size_t len) const char * rb_ssl_get_cipher(rb_fde_t *F) { - if(F == NULL || F->ssl == NULL) + if(F == NULL || F->ssl == NULL || SSL_P(F) == NULL) return NULL; return mbedtls_ssl_get_ciphersuite(SSL_P(F)); } -#endif /* HAVE_GNUTLS */ +#endif /* HAVE_MBEDTLS */ diff --git a/librb/src/mbedtls_embedded_data.h b/librb/src/mbedtls_embedded_data.h new file mode 100644 index 00000000..83782089 --- /dev/null +++ b/librb/src/mbedtls_embedded_data.h @@ -0,0 +1,107 @@ +/* + * libratbox: a library used by ircd-ratbox and other things + * mbedtls.h: embedded data for ARM mbedTLS backend + * + * Copyright (C) 2016 Aaron Jones + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * $Id$ + */ + +#ifndef RB_MBEDTLS_EMBEDDED_DATA_H +#define RB_MBEDTLS_EMBEDDED_DATA_H + +/* + * Personalization string for CTR-DRBG initialization + */ +static const char rb_mbedtls_personal_str[] = "charybdis/librb personalization string"; + +/* + * YES, this is a hardcoded CA certificate. + * + * BEFORE YOU THROW YOUR ARMS UP IN A PANIC ABOUT A BACKDOOR, READ THIS TEXT! + * + * ARM mbedTLS requires a CA certificate to be set in its configuration before it will + * request a client certificate from peers. Since we want to do that, and not all + * installations will have a CA certificate to hand, we have this. + * + * Its key was securely destroyed after being generated, but even if it wasn't, that + * doesn't matter; the IRCd will accept ALL certificates, whether signed by this CA + * certificate or not! + * + * After all, it only cares about certificates in as far as to generate a fingerprint + * for them. + * + * Yes, this is a massive hack, but there is no alternative. + */ + +static const unsigned char rb_mbedtls_dummy_ca_certificate[825] = { + 0x30, 0x82, 0x03, 0x35, 0x30, 0x82, 0x02, 0x1D, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, + 0x86, 0xC5, 0x1F, 0x62, 0xBE, 0xFC, 0x0B, 0xA8, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x31, 0x31, 0x2F, 0x30, 0x2D, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0C, 0x26, 0x43, 0x68, 0x61, 0x72, 0x79, 0x62, 0x64, 0x69, 0x73, 0x20, 0x6D, 0x62, + 0x65, 0x64, 0x54, 0x4C, 0x53, 0x20, 0x44, 0x75, 0x6D, 0x6D, 0x79, 0x20, 0x43, 0x41, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x36, + 0x30, 0x35, 0x30, 0x34, 0x30, 0x38, 0x35, 0x32, 0x35, 0x33, 0x5A, 0x17, 0x0D, 0x34, 0x33, 0x30, + 0x39, 0x32, 0x30, 0x30, 0x38, 0x35, 0x32, 0x35, 0x33, 0x5A, 0x30, 0x31, 0x31, 0x2F, 0x30, 0x2D, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x26, 0x43, 0x68, 0x61, 0x72, 0x79, 0x62, 0x64, 0x69, 0x73, + 0x20, 0x6D, 0x62, 0x65, 0x64, 0x54, 0x4C, 0x53, 0x20, 0x44, 0x75, 0x6D, 0x6D, 0x79, 0x20, 0x43, + 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xCA, 0x4B, + 0xA6, 0xA1, 0x82, 0x5B, 0x06, 0xC6, 0x82, 0x76, 0x8E, 0xB2, 0x22, 0x37, 0x83, 0x91, 0x4B, 0xD0, + 0xAE, 0x2F, 0xEE, 0x8E, 0x60, 0x04, 0xBA, 0x77, 0x8C, 0xD0, 0xCF, 0x5E, 0xA4, 0xFD, 0x80, 0xA1, + 0x2E, 0xDC, 0x1F, 0xD9, 0x72, 0x2C, 0x28, 0x03, 0x27, 0x48, 0x23, 0x6E, 0x41, 0x49, 0x62, 0x09, + 0x2D, 0xCF, 0x87, 0xA1, 0x45, 0x9D, 0x2B, 0x43, 0x6F, 0xBB, 0xDB, 0x23, 0xD8, 0xD9, 0x6D, 0x36, + 0x4E, 0xA3, 0x85, 0x40, 0x4D, 0x72, 0xEC, 0x7B, 0xEF, 0x2B, 0x13, 0xE4, 0x6F, 0xDA, 0x23, 0x4F, + 0x1C, 0xE7, 0xEA, 0xD9, 0x17, 0x2B, 0xD6, 0x67, 0x79, 0x42, 0xC3, 0x81, 0x9A, 0x77, 0x64, 0xC7, + 0xC5, 0x44, 0xE1, 0xA4, 0xA3, 0x50, 0x8C, 0x1F, 0xCA, 0xD3, 0x6F, 0xC7, 0xFF, 0x2C, 0xBA, 0x7B, + 0x21, 0x0C, 0xF3, 0xA9, 0x6A, 0x89, 0x74, 0x33, 0x60, 0xA1, 0xF8, 0x9F, 0xAA, 0x39, 0xA9, 0x45, + 0x7E, 0x3D, 0x41, 0x67, 0x04, 0xF5, 0x9F, 0x47, 0x62, 0xAC, 0x65, 0xE0, 0x8D, 0x46, 0x9E, 0xD9, + 0xE5, 0x77, 0xD5, 0x8C, 0x47, 0xA2, 0xFB, 0x7D, 0x94, 0x27, 0xC9, 0xB9, 0x3F, 0x4D, 0xF4, 0xFD, + 0x19, 0x3C, 0xF6, 0x24, 0xAE, 0x70, 0xD7, 0x23, 0xE4, 0x64, 0x0A, 0xFC, 0x63, 0x89, 0x8A, 0xFE, + 0xD0, 0x8E, 0x48, 0x1A, 0xD8, 0xC3, 0xA9, 0xEC, 0x9D, 0x0F, 0xC7, 0xC5, 0x22, 0xBC, 0x45, 0x4A, + 0x2F, 0x4D, 0xF5, 0x0E, 0x4F, 0xFF, 0xAC, 0xE0, 0x55, 0xF4, 0x86, 0x04, 0x1B, 0x60, 0xDF, 0x4C, + 0x25, 0xB9, 0xEC, 0x10, 0x0C, 0x54, 0x16, 0xDF, 0x42, 0xF0, 0x07, 0x00, 0x28, 0x81, 0x7C, 0x95, + 0xAA, 0xC1, 0x01, 0xA3, 0xB8, 0xDF, 0x68, 0xCB, 0x55, 0xA7, 0x80, 0xCC, 0xE5, 0x3D, 0xE1, 0x68, + 0x10, 0x27, 0x56, 0x94, 0x67, 0xEC, 0x82, 0x66, 0x3D, 0x96, 0x76, 0xC3, 0xEE, 0x23, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xA3, 0x50, 0x30, 0x4E, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, + 0x04, 0x14, 0xFF, 0xC8, 0xBA, 0x56, 0x74, 0xB1, 0x03, 0xA9, 0x79, 0x55, 0xFA, 0x58, 0x86, 0x13, + 0xDE, 0xC0, 0xFA, 0xF2, 0x94, 0x62, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0xFF, 0xC8, 0xBA, 0x56, 0x74, 0xB1, 0x03, 0xA9, 0x79, 0x55, 0xFA, 0x58, 0x86, + 0x13, 0xDE, 0xC0, 0xFA, 0xF2, 0x94, 0x62, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x05, + 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3D, 0x35, 0x69, 0x87, 0xEB, 0x41, 0xA9, + 0x2A, 0x51, 0xF3, 0x28, 0x71, 0xB4, 0x06, 0x7F, 0x15, 0x5A, 0x6D, 0x88, 0x5B, 0xC8, 0x4C, 0xE1, + 0x6C, 0xC7, 0xCB, 0x93, 0x63, 0x69, 0xFB, 0xA6, 0x6D, 0xC7, 0x44, 0x6B, 0xD6, 0x39, 0x46, 0x34, + 0xFC, 0x45, 0x23, 0xD2, 0x29, 0x1B, 0xCC, 0x1C, 0x13, 0xD7, 0x63, 0x10, 0x81, 0xF5, 0x82, 0x45, + 0xEC, 0xDC, 0x20, 0x5F, 0xBB, 0xC3, 0xE6, 0x4A, 0x07, 0xA7, 0xBD, 0x9E, 0xFC, 0x5D, 0xFE, 0xC5, + 0x43, 0x3A, 0xC6, 0xA4, 0x6C, 0x5B, 0xF9, 0x63, 0x8F, 0xF9, 0xEB, 0xC2, 0xF4, 0xA7, 0xE4, 0x1B, + 0x23, 0xFA, 0xE1, 0x5A, 0x79, 0xC5, 0x1D, 0x1D, 0xFC, 0xAA, 0x81, 0xF7, 0x21, 0x52, 0xC9, 0x46, + 0x17, 0x1B, 0x24, 0x4B, 0x14, 0x5C, 0xF9, 0xB5, 0x86, 0x04, 0x80, 0x51, 0x95, 0xCF, 0x4E, 0x47, + 0x32, 0x8A, 0x1E, 0x52, 0x2E, 0xBF, 0x08, 0x8E, 0x9E, 0xE3, 0x88, 0x45, 0xC3, 0x75, 0xD7, 0xAE, + 0xC3, 0x7E, 0x7E, 0xE9, 0xC9, 0x5B, 0xD8, 0x58, 0x3B, 0x25, 0x53, 0x0C, 0x00, 0x21, 0x1A, 0x71, + 0x12, 0x23, 0xA0, 0x35, 0x6E, 0xC9, 0x7D, 0x83, 0x5C, 0x19, 0xE4, 0x05, 0x84, 0x46, 0x4E, 0x50, + 0xE2, 0x9E, 0x70, 0x2E, 0x74, 0x05, 0xEA, 0x31, 0x04, 0x55, 0xA7, 0xF4, 0x67, 0x95, 0xDC, 0x86, + 0x1F, 0x9D, 0xA0, 0x5D, 0x7F, 0x29, 0x48, 0x84, 0xEF, 0x13, 0xB8, 0xB3, 0xBF, 0x65, 0xD4, 0x52, + 0x98, 0x06, 0xE6, 0x8A, 0xB1, 0x36, 0xEA, 0x39, 0xB3, 0x04, 0x2B, 0x6E, 0x64, 0x6E, 0xF3, 0x20, + 0x74, 0xB6, 0x6E, 0x21, 0x3B, 0x99, 0xFE, 0x6E, 0x70, 0x48, 0x78, 0xEA, 0x31, 0x95, 0xB3, 0xB0, + 0x0E, 0x48, 0x83, 0x35, 0xA9, 0x74, 0xBF, 0x45, 0x07, 0xC8, 0x5A, 0x12, 0xA2, 0x4D, 0x16, 0xDB, + 0xB3, 0x1F, 0x72, 0xDE, 0x2A, 0x28, 0xFE, 0x7C, 0x2D +}; + +#endif /* RB_MBEDTLS_EMBEDDED_DATA_H */