[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
This commit is contained in:
Aaron Jones 2016-05-05 03:31:32 +00:00
parent c40eede13b
commit 1e7342d0f4
No known key found for this signature in database
GPG key ID: 6E854C0FAAD4CEA4
2 changed files with 430 additions and 231 deletions

View file

@ -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 <androsyn@ratbox.org>
* Copyright (C) 2015 William Pitcock <nenolod@dereferenced.org>
* Copyright (C) 2016 Aaron Jones <aaronmdjones@gmail.com>
*
* 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)
{
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));
}
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)
{
F->handshake_count++;
return 1;
}
if(ret == -1 && rb_ignore_errno(errno))
ret = MBEDTLS_ERR_SSL_WANT_READ;
if((ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE))
switch(ret)
{
if(ret == MBEDTLS_ERR_SSL_WANT_READ)
flags = RB_SELECT_READ;
else
flags = RB_SELECT_WRITE;
rb_setselect(F, flags, callback, data);
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,10 +263,9 @@ 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);
int ret = (int) read(F->fd, buf, size);
if(ret < 0 && rb_ignore_errno(errno))
return MBEDTLS_ERR_SSL_WANT_READ;
@ -160,9 +276,8 @@ 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);
int ret = (int) write(F->fd, buf, size);
if(ret < 0 && rb_ignore_errno(errno))
return MBEDTLS_ERR_SSL_WANT_WRITE;
@ -170,42 +285,60 @@ rb_ssl_write_cb(void *opaque, const unsigned char *buf, size_t size)
}
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,35 +347,34 @@ 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)
{
@ -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;
ret = do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn);
int ret = do_ssl_handshake(F, rb_ssl_tryconn_cb, data);
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;
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;
data = der_pubkey + (sizeof(der_pubkey) - ret);
datalen = ret;
}
rb_free(der_pubkey);
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 len;
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 */

View file

@ -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 <aaronmdjones@gmail.com>
*
* 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 */