From add9c19ae46263e9c2ca85c0baad22cd758f6c63 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Jan 2016 20:42:25 +0100 Subject: [PATCH] add mbedtls variant Signed-off-by: Felix Fietkau --- CMakeLists.txt | 6 +- ustream-internal.h | 4 +- ustream-mbedtls.c | 351 +++++++++++++++++++++++++++++++++++++++++++++ ustream-mbedtls.h | 58 ++++++++ 4 files changed, 417 insertions(+), 2 deletions(-) create mode 100644 ustream-mbedtls.c create mode 100644 ustream-mbedtls.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c09fe51..c1c2b32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,11 @@ ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations) SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") -IF(POLARSSL) +IF(MBEDTLS) + ADD_DEFINITIONS(-DHAVE_MBEDTLS) + SET(SSL_SRC ustream-mbedtls.c) + SET(SSL_LIB mbedtls mbedcrypto mbedx509 m) +ELSEIF(POLARSSL) ADD_DEFINITIONS(-DHAVE_POLARSSL) SET(SSL_SRC ustream-polarssl.c) SET(SSL_LIB polarssl m) diff --git a/ustream-internal.h b/ustream-internal.h index e0e1f50..020e1c6 100644 --- a/ustream-internal.h +++ b/ustream-internal.h @@ -21,7 +21,9 @@ #define __hidden __attribute__((visibility("hidden"))) -#ifdef HAVE_POLARSSL +#if defined(HAVE_MBEDTLS) +#include "ustream-mbedtls.h" +#elif defined(HAVE_POLARSSL) #include "ustream-polarssl.h" #else #include "ustream-openssl.h" diff --git a/ustream-mbedtls.c b/ustream-mbedtls.c new file mode 100644 index 0000000..eeabe42 --- /dev/null +++ b/ustream-mbedtls.c @@ -0,0 +1,351 @@ +/* + * ustream-ssl - library for SSL over ustream + * + * Copyright (C) 2012 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "ustream-ssl.h" +#include "ustream-internal.h" + +static int urandom_fd = -1; + +static int s_ustream_read(void *ctx, unsigned char *buf, size_t len) +{ + struct ustream *s = ctx; + char *sbuf; + int slen; + + if (s->eof) + return 0; + + sbuf = ustream_get_read_buf(s, &slen); + if (slen > len) + slen = len; + + if (!slen) + return MBEDTLS_ERR_SSL_WANT_READ; + + memcpy(buf, sbuf, slen); + ustream_consume(s, slen); + + return slen; +} + +static int s_ustream_write(void *ctx, const unsigned char *buf, size_t len) +{ + struct ustream *s = ctx; + int ret; + + ret = ustream_write(s, (const char *) buf, len, false); + if (ret < 0 || s->write_error) + return MBEDTLS_ERR_NET_SEND_FAILED; + + return ret; +} + +__hidden void ustream_set_io(struct ustream_ssl_ctx *ctx, void *ssl, struct ustream *conn) +{ + mbedtls_ssl_set_bio(ssl, conn, s_ustream_write, s_ustream_read, NULL); +} + +static bool urandom_init(void) +{ + if (urandom_fd > -1) + return true; + + urandom_fd = open("/dev/urandom", O_RDONLY); + if (urandom_fd < 0) + return false; + + return true; +} + +static int _urandom(void *ctx, unsigned char *out, size_t len) +{ + if (read(urandom_fd, out, len) < 0) + return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + + return 0; +} + +static const int default_ciphersuites[] = +{ +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA2_C) + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, +#endif /* MBEDTLS_SHA2_C */ +#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA4_C) + MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, +#endif /* MBEDTLS_SHA2_C */ + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, +#endif +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_SHA2_C) + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, +#endif /* MBEDTLS_SHA2_C */ + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, +#endif +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA2_C) + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, +#endif /* MBEDTLS_SHA2_C */ +#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA2_C) + MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, +#endif /* MBEDTLS_SHA2_C */ + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, +#endif +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_SHA2_C) + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, +#endif /* MBEDTLS_SHA2_C */ + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, +#endif +#if defined(MBEDTLS_DES_C) + MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, +#endif + 0 +}; + +__hidden struct ustream_ssl_ctx * +__ustream_ssl_context_new(bool server) +{ + struct ustream_ssl_ctx *ctx; + mbedtls_ssl_config *conf; + int ep; + + if (!urandom_init()) + return NULL; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) + return NULL; + + ctx->server = server; + mbedtls_pk_init(&ctx->key); + mbedtls_x509_crt_init(&ctx->cert); + mbedtls_x509_crt_init(&ctx->ca_cert); + + conf = &ctx->conf; + mbedtls_ssl_config_init(conf); + mbedtls_ssl_conf_ciphersuites(conf, default_ciphersuites); + + if (server) + ep = MBEDTLS_SSL_IS_SERVER; + else + ep = MBEDTLS_SSL_IS_CLIENT; + + mbedtls_ssl_config_defaults(conf, ep, MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE); + mbedtls_ssl_conf_rng(conf, _urandom, NULL); + + return ctx; +} + +static void ustream_ssl_update_own_cert(struct ustream_ssl_ctx *ctx) +{ + if (!ctx->cert.version) + return; + + if (!ctx->server) { + mbedtls_ssl_conf_ca_chain(&ctx->conf, &ctx->cert, NULL); + return; + } + + if (!ctx->key.pk_info) + return; + + if (ctx->cert.next) + mbedtls_ssl_conf_ca_chain(&ctx->conf, ctx->cert.next, NULL); + mbedtls_ssl_conf_own_cert(&ctx->conf, &ctx->cert, &ctx->key); +} + +__hidden int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx *ctx, const char *file) +{ + int ret; + + ret = mbedtls_x509_crt_parse_file(&ctx->ca_cert, file); + if (ret) + return -1; + + mbedtls_ssl_conf_ca_chain(&ctx->conf, &ctx->ca_cert, NULL); + mbedtls_ssl_conf_authmode(&ctx->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + return 0; +} + +__hidden int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file) +{ + int ret; + + ret = mbedtls_x509_crt_parse_file(&ctx->cert, file); + if (ret) + return -1; + + ustream_ssl_update_own_cert(ctx); + return 0; +} + +__hidden int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file) +{ + int ret; + + ret = mbedtls_pk_parse_keyfile(&ctx->key, file, NULL); + if (ret) + return -1; + + ustream_ssl_update_own_cert(ctx); + return 0; +} + +__hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx) +{ + mbedtls_pk_free(&ctx->key); + mbedtls_x509_crt_free(&ctx->ca_cert); + mbedtls_x509_crt_free(&ctx->cert); + mbedtls_ssl_config_free(&ctx->conf); + free(ctx); +} + +static void ustream_ssl_error(struct ustream_ssl *us, int ret) +{ + us->error = ret; + uloop_timeout_set(&us->error_timer, 0); +} + +static bool ssl_do_wait(int ret) +{ + switch(ret) { + case MBEDTLS_ERR_SSL_WANT_READ: + case MBEDTLS_ERR_SSL_WANT_WRITE: + return true; + default: + return false; + } +} + +static void ustream_ssl_verify_cert(struct ustream_ssl *us) +{ + void *ssl = us->ssl; + const char *msg = NULL; + bool cn_mismatch; + int r; + + r = mbedtls_ssl_get_verify_result(ssl); + cn_mismatch = r & MBEDTLS_X509_BADCERT_CN_MISMATCH; + r &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; + + if (r & MBEDTLS_X509_BADCERT_EXPIRED) + msg = "certificate has expired"; + else if (r & MBEDTLS_X509_BADCERT_REVOKED) + msg = "certificate has been revoked"; + else if (r & MBEDTLS_X509_BADCERT_NOT_TRUSTED) + msg = "certificate is self-signed or not signed by a trusted CA"; + else + msg = "unknown error"; + + if (r) { + if (us->notify_verify_error) + us->notify_verify_error(us, r, msg); + return; + } + + if (!cn_mismatch) + us->valid_cn = true; +} + +__hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us) +{ + void *ssl = us->ssl; + int r; + + r = mbedtls_ssl_handshake(ssl); + if (r == 0) { + ustream_ssl_verify_cert(us); + return U_SSL_OK; + } + + if (ssl_do_wait(r)) + return U_SSL_PENDING; + + ustream_ssl_error(us, r); + return U_SSL_ERROR; +} + +__hidden int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int len) +{ + void *ssl = us->ssl; + int done = 0, ret = 0; + + while (done != len) { + ret = mbedtls_ssl_write(ssl, (const unsigned char *) buf + done, len - done); + + if (ret < 0) { + if (ssl_do_wait(ret)) + return done; + + ustream_ssl_error(us, ret); + return -1; + } + + done += ret; + } + + return done; +} + +__hidden int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len) +{ + int ret = mbedtls_ssl_read(us->ssl, (unsigned char *) buf, len); + + if (ret < 0) { + if (ssl_do_wait(ret)) + return U_SSL_PENDING; + + ustream_ssl_error(us, ret); + return U_SSL_ERROR; + } + + return ret; +} + +__hidden void *__ustream_ssl_session_new(struct ustream_ssl_ctx *ctx) +{ + mbedtls_ssl_context *ssl; + + ssl = calloc(1, sizeof(*ssl)); + if (!ssl) + return NULL; + + mbedtls_ssl_init(ssl); + + if (mbedtls_ssl_setup(ssl, &ctx->conf)) { + free(ssl); + return NULL; + } + + return ssl; +} + +__hidden void __ustream_ssl_session_free(void *ssl) +{ + mbedtls_ssl_free(ssl); + free(ssl); +} diff --git a/ustream-mbedtls.h b/ustream-mbedtls.h new file mode 100644 index 0000000..a489867 --- /dev/null +++ b/ustream-mbedtls.h @@ -0,0 +1,58 @@ +/* + * ustream-ssl - library for SSL over ustream + * + * Copyright (C) 2012 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __USTREAM_POLARSSL_H +#define __USTREAM_POLARSSL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +struct ustream_ssl_ctx { + mbedtls_ssl_config conf; + mbedtls_pk_context key; + mbedtls_x509_crt ca_cert; + mbedtls_x509_crt cert; + bool server; +}; + +static inline char *__ustream_ssl_strerror(int error, char *buffer, int len) +{ + mbedtls_strerror(error, buffer, len); + return buffer; +} + +static inline void __ustream_ssl_set_server_name(struct ustream_ssl *us) +{ + mbedtls_ssl_set_hostname(us->ssl, us->server_name); +} + +static inline void __ustream_ssl_update_peer_cn(struct ustream_ssl *us) +{ + mbedtls_ssl_set_hostname(us->ssl, us->peer_cn); +} + +void __ustream_ssl_session_free(void *ssl); +void *__ustream_ssl_session_new(struct ustream_ssl_ctx *ctx); + +#endif -- 2.25.1