Merge branch 'mbedtls'

This patch set provides mbed TLS support.

The interface part (include/event2/bufferevent_ssl.h) LGTM, so this can
be safely merged (although there are some bits left).

Includes:
- bufferevent_mbedtls_*
- regress_mbedtls tests

Left:
- regress_http https_mbedtls support
- ChangeLog entry

* mbedtls:
  test: rename ssl/* -> openssl/*
  Join le_ssl_ops.post_init with le_ssl_ops.init
  Update LICENSE for ssl-client-mbedtls.c
  Merge ssl implementations (openssl and mbedtls)
  add mbedtls to CI
  fix build system and add test and cleanup code
  mbed TLS cmake support
  simple https client example using mbedtls
  mbedtls based SSL implementation
This commit is contained in:
Azat Khuzhin 2020-07-23 00:14:34 +03:00
commit 0e339b04b5
29 changed files with 3174 additions and 1467 deletions

View File

@ -53,6 +53,11 @@ jobs:
path: dist
key: ${{ matrix.os }}-cmake-dist-${{ matrix.EVENT_MATRIX }}-v2
- name: Install Depends
run: |
sudo apt-get update
sudo apt-get install -y libmbedtls-dev
- name: Build And Test
shell: bash
run: |
@ -153,6 +158,11 @@ jobs:
path: dist
key: ${{ matrix.os }}-autotools-dist-${{ matrix.EVENT_MATRIX }}-v2
- name: Install Depends
run: |
sudo apt-get update
sudo apt-get install -y libmbedtls-dev
- name: Build And Test
shell: bash
run: |

View File

@ -45,6 +45,9 @@ jobs:
path: build
key: macos-10.15-cmake-${{ matrix.EVENT_MATRIX }}-v2
- name: Install Depends
run: brew install mbedtls
- name: Build And Test
shell: bash
run: |
@ -124,7 +127,7 @@ jobs:
key: ${{ matrix.os }}-autotools-${{ matrix.EVENT_MATRIX }}-v2
- name: Install Depends
run: brew install autoconf automake libtool pkg-config
run: brew install autoconf automake libtool pkg-config mbedtls
- name: Build And Test
shell: bash

View File

@ -46,7 +46,7 @@ jobs:
uses: actions/cache@v1.1.2
with:
path: build
key: mingw-autotools-${{ matrix.EVENT_MATRIX }}-v2
key: mingw-autotools-${{ matrix.EVENT_MATRIX }}-v3
- uses: numworks/setup-msys2@v1
if: steps.cache-mingw.outputs.cache-hit != 'true'
@ -56,7 +56,7 @@ jobs:
- name: Install Dependes
if: steps.cache-mingw.outputs.cache-hit != 'true'
run: |
msys2do pacman -S --noconfirm mingw-w64-x86_64-gcc autoconf automake libtool mingw-w64-x86_64-openssl
msys2do pacman -S --noconfirm mingw-w64-x86_64-gcc autoconf automake libtool mingw-w64-x86_64-openssl mingw-w64-x86_64-mbedtls
- name: Build And Test
shell: powershell
@ -115,7 +115,7 @@ jobs:
uses: actions/cache@v1.1.2
with:
path: build
key: mingw-cmake-${{ matrix.EVENT_MATRIX }}-v2
key: mingw-cmake-${{ matrix.EVENT_MATRIX }}-v3
- uses: numworks/setup-msys2@v1
if: steps.cache-mingw-cmake.outputs.cache-hit != 'true'
@ -125,7 +125,7 @@ jobs:
- name: Install Dependes
if: steps.cache-mingw-cmake.outputs.cache-hit != 'true'
run: |
msys2do pacman -S --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-openssl
msys2do pacman -S --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-openssl mingw-w64-x86_64-mbedtls
- name: Build And Test
shell: powershell

View File

@ -36,7 +36,7 @@ jobs:
uses: actions/cache@v1.0.3
with:
path: C:\vcpkg\installed
key: ${{ matrix.os }}-vcpkg
key: ${{ matrix.os }}-vcpkg-v2
- name: Cache Build
uses: actions/cache@v1.0.3
@ -50,19 +50,18 @@ jobs:
run: |
vcpkg install openssl:x64-windows
vcpkg install zlib:x64-windows
vcpkg install mbedtls:x64-windows
- name: Build And Test
shell: powershell
run: |
$OPENSSL_ROOT_DIR="C:\vcpkg\installed\x64-windows"
$EVENT_BUILD_PARALLEL=10
$EVENT_TESTS_PARALLEL=1
$env:PATH="$OPENSSL_ROOT_DIR/bin;$env:PATH"
mkdir build -ea 0
cd build
$CMAKE_CMD="cmake -G 'Visual Studio 15 2017 Win64' .."
$CMAKE_CMD="cmake -G 'Visual Studio 15 2017 Win64' -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake .."
function cmake_configure($retry)
{
$errcode=0
@ -142,7 +141,7 @@ jobs:
uses: actions/cache@v1.1.0
with:
path: C:\vcpkg\installed
key: ${{ matrix.os }}-vcpkg
key: ${{ matrix.os }}-vcpkg-v2
- name: Cache Build
uses: actions/cache@v1.1.0
@ -156,17 +155,16 @@ jobs:
run: |
vcpkg install openssl:x64-windows
vcpkg install zlib:x64-windows
vcpkg install mbedtls:x64-windows
- name: Build And Test
shell: powershell
run: |
$OPENSSL_ROOT_DIR="C:\vcpkg\installed\x64-windows"
$EVENT_BUILD_PARALLEL=10
$EVENT_TESTS_PARALLEL=1
$env:PATH="$OPENSSL_ROOT_DIR/bin;$env:PATH"
if ( "${{ matrix.EVENT_MATRIX }}" -eq "LIBRARY_TYPE_STATIC" ) {
$EVENT_CMAKE_OPTIONS="-DEVENT__LIBRARY_TYPE=STATIC"
$EVENT_CMAKE_OPTIONS="-DEVENT__LIBRARY_TYPE=STATIC -DEVENT__MSVC_STATIC_RUNTIME=OFF"
}
elseif ( "${{ matrix.EVENT_MATRIX }}" -eq "DISABLE_OPENSSL" ) {
$EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_OPENSSL=ON"
@ -187,7 +185,7 @@ jobs:
$EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_TESTS=ON -DEVENT__DISABLE_SAMPLES=ON"
}
elseif ( "${{ matrix.EVENT_MATRIX }}" -eq "TEST_EXPORT_STATIC" ) {
$EVENT_CMAKE_OPTIONS="-DEVENT__LIBRARY_TYPE=STATIC -DEVENT__DISABLE_TESTS=ON -DEVENT__DISABLE_SAMPLES=ON"
$EVENT_CMAKE_OPTIONS="-DEVENT__LIBRARY_TYPE=STATIC -DEVENT__MSVC_STATIC_RUNTIME=OFF -DEVENT__DISABLE_TESTS=ON -DEVENT__DISABLE_SAMPLES=ON"
}
else {
$EVENT_CMAKE_OPTIONS=""
@ -197,10 +195,10 @@ jobs:
cd build
if ("${{ matrix.os }}" -eq "windows-2016") {
$CMAKE_CMD="cmake -G 'Visual Studio 15 2017 Win64' .."
$CMAKE_CMD="cmake -G 'Visual Studio 15 2017 Win64' -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake .."
}
else { # windows-2019
$CMAKE_CMD="cmake -G 'Visual Studio 16 2019' -A x64 .. $EVENT_CMAKE_OPTIONS"
$CMAKE_CMD="cmake -G 'Visual Studio 16 2019' -A x64 -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake .. $EVENT_CMAKE_OPTIONS"
}
function cmake_configure($retry)
{

View File

@ -132,6 +132,9 @@ option(EVENT__DISABLE_THREAD_SUPPORT
option(EVENT__DISABLE_OPENSSL
"Define if libevent should build without support for OpenSSL encryption" OFF)
option(EVENT__DISABLE_MBEDTLS
"Define if libevent should build without support for mbed TLS encryption" OFF)
option(EVENT__DISABLE_BENCHMARK
"Defines if libevent should build without the benchmark executables" OFF)
@ -861,11 +864,26 @@ if (NOT EVENT__DISABLE_OPENSSL)
include_directories(${OPENSSL_INCLUDE_DIR})
list(APPEND SRC_OPENSSL bufferevent_openssl.c)
list(APPEND SRC_OPENSSL bufferevent_openssl.c bufferevent_ssl.c)
list(APPEND HDR_PUBLIC include/event2/bufferevent_ssl.h)
list(APPEND LIB_APPS ${OPENSSL_LIBRARIES})
endif()
if (NOT EVENT__DISABLE_MBEDTLS)
find_package(MbedTLS REQUIRED)
set(EVENT__HAVE_MBEDTLS 1)
message(STATUS "mbed TLS include: ${MBEDTLS_INCLUDE_DIR}")
message(STATUS "mbed TLS lib: ${MBEDTLS_LIBRARIES}")
include_directories(${MBEDTLS_INCLUDE_DIR})
list(APPEND SRC_MBEDTLS bufferevent_mbedtls.c bufferevent_ssl.c)
list(APPEND HDR_PUBLIC include/event2/bufferevent_ssl.h)
list(APPEND LIB_APPS ${MBEDTLS_LIBRARIES})
endif()
if (NOT EVENT__DISABLE_THREAD_SUPPORT)
if (WIN32)
list(APPEND SRC_CORE evthread_win32.c)
@ -971,6 +989,14 @@ if (NOT EVENT__DISABLE_OPENSSL)
SOURCES ${SRC_OPENSSL})
endif()
if (NOT EVENT__DISABLE_MBEDTLS)
add_event_library(event_mbedtls
INNER_LIBRARIES event_core
OUTER_INCLUDES ${MBEDTLS_INCLUDE_DIR}
LIBRARIES ${MBEDTLS_LIBRARIES}
SOURCES ${SRC_MBEDTLS})
endif()
if (EVENT__HAVE_PTHREADS)
set(SRC_PTHREADS evthread_pthread.c)
add_event_library(event_pthreads
@ -1014,8 +1040,8 @@ macro(add_sample_prog ssl name)
${LIB_APPS}
${LIB_PLATFORM})
if (${ssl})
target_link_libraries(${name} event_openssl)
if (TARGET ${ssl})
target_link_libraries(${name} ${ssl})
if(WIN32)
target_link_libraries(${name} crypt32)
endif()
@ -1038,13 +1064,18 @@ if (NOT EVENT__DISABLE_SAMPLES)
endif()
if (NOT EVENT__DISABLE_OPENSSL)
add_sample_prog(ON https-client
add_sample_prog(event_openssl https-client
sample/https-client.c
sample/openssl_hostname_validation.c
sample/hostcheck.c)
add_sample_prog(ON le-proxy
add_sample_prog(event_openssl le-proxy
sample/le-proxy.c)
add_sample_prog(ON becat sample/becat.c ${WIN32_GETOPT})
add_sample_prog(event_openssl becat sample/becat.c ${WIN32_GETOPT})
endif()
if (NOT EVENT__DISABLE_MBEDTLS)
add_sample_prog(event_mbedtls ssl-client-mbedtls
sample/ssl-client-mbedtls.c)
endif()
set(SAMPLES_WOPT
@ -1156,7 +1187,11 @@ if (NOT EVENT__DISABLE_TESTS)
endif()
if (NOT EVENT__DISABLE_OPENSSL)
list(APPEND SRC_REGRESS test/regress_ssl.c)
list(APPEND SRC_REGRESS test/regress_openssl.c)
endif()
if (NOT EVENT__DISABLE_MBEDTLS)
list(APPEND SRC_REGRESS test/regress_mbedtls.c)
endif()
add_executable(regress ${SRC_REGRESS})
@ -1169,6 +1204,9 @@ if (NOT EVENT__DISABLE_TESTS)
if (NOT EVENT__DISABLE_OPENSSL)
target_link_libraries(regress event_openssl)
endif()
if (NOT EVENT__DISABLE_MBEDTLS)
target_link_libraries(regress event_mbedtls)
endif()
if (CMAKE_USE_PTHREADS_INIT)
target_link_libraries(regress event_pthreads)
endif()

21
LICENSE
View File

@ -128,3 +128,24 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==============================
The ssl-client-mbedtls.c is available under the following license:
Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
SPDX-License-Identifier: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This file is part of mbed TLS (https://tls.mbed.org)

View File

@ -101,7 +101,9 @@ LIBEVENT_PKGCONFIG=libevent.pc libevent_core.pc libevent_extra.pc
# included from other files.
PLATFORM_DEPENDENT_SRC = \
arc4random.c \
epoll_sub.c
epoll_sub.c \
bufferevent_ssl.c \
test/regress_ssl.c
CMAKE_FILES = \
cmake/AddCompilerFlags.cmake \
@ -116,6 +118,7 @@ CMAKE_FILES = \
cmake/CodeCoverage.cmake \
cmake/COPYING-CMAKE-SCRIPTS \
cmake/Copyright.txt \
cmake/FindMbedTLS.cmake \
cmake/LibeventConfig.cmake.in \
cmake/LibeventConfigVersion.cmake.in \
cmake/Macros.cmake \
@ -154,6 +157,10 @@ if OPENSSL
LIBEVENT_LIBS_LA += libevent_openssl.la
LIBEVENT_PKGCONFIG += libevent_openssl.pc
endif
if MBEDTLS
LIBEVENT_LIBS_LA += libevent_mbedtls.la
LIBEVENT_PKGCONFIG += libevent_mbedtls.pc
endif
if INSTALL_LIBEVENT
lib_LTLIBRARIES = $(LIBEVENT_LIBS_LA)
@ -287,12 +294,19 @@ libevent_extra_la_LIBADD = $(MAYBE_CORE) $(SYS_LIBS)
libevent_extra_la_LDFLAGS = $(GENERIC_LDFLAGS)
if OPENSSL
libevent_openssl_la_SOURCES = bufferevent_openssl.c
libevent_openssl_la_SOURCES = bufferevent_openssl.c bufferevent_ssl.c
libevent_openssl_la_LIBADD = $(MAYBE_CORE) $(OPENSSL_LIBS)
libevent_openssl_la_LDFLAGS = $(GENERIC_LDFLAGS)
libevent_openssl_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS)
endif
if MBEDTLS
libevent_mbedtls_la_SOURCES = bufferevent_mbedtls.c bufferevent_ssl.c
libevent_mbedtls_la_LIBADD = $(MAYBE_CORE) $(MBEDTLS_LIBS)
libevent_mbedtls_la_LDFLAGS = $(GENERIC_LDFLAGS)
libevent_mbedtls_la_CPPFLAGS = $(AM_CPPFLAGS) $(MBEDTLS_INCS)
endif
noinst_HEADERS += \
WIN32-Code/getopt.h \
WIN32-Code/getopt.c \
@ -323,6 +337,7 @@ noinst_HEADERS += \
time-internal.h \
util-internal.h \
openssl-compat.h \
ssl-compat.h \
wepoll.h
EVENT1_HDRS = \

View File

@ -306,11 +306,18 @@ extern const struct bufferevent_ops bufferevent_ops_pair;
#define BEV_IS_FILTER(bevp) ((bevp)->be_ops == &bufferevent_ops_filter)
#define BEV_IS_PAIR(bevp) ((bevp)->be_ops == &bufferevent_ops_pair)
#if defined(EVENT__HAVE_OPENSSL)
extern const struct bufferevent_ops bufferevent_ops_openssl;
#define BEV_IS_OPENSSL(bevp) ((bevp)->be_ops == &bufferevent_ops_openssl)
#if defined(EVENT__HAVE_OPENSSL) | defined(EVENT__HAVE_MBEDTLS)
extern const struct bufferevent_ops bufferevent_ops_ssl;
#define BEV_IS_SSL(bevp) ((bevp)->be_ops == &bufferevent_ops_ssl)
#else
#define BEV_IS_OPENSSL(bevp) 0
#define BEV_IS_SSL(bevp) 0
#endif
#if defined(EVENT__HAVE_MBEDTLS)
extern const struct bufferevent_ops bufferevent_ops_mbedtls;
#define BEV_IS_MBEDTLS(bevp) ((bevp)->be_ops == &bufferevent_ops_mbedtls)
#else
#define BEV_IS_MBEDTLS(bevp) 0
#endif
#ifdef _WIN32

397
bufferevent_mbedtls.c Normal file
View File

@ -0,0 +1,397 @@
/*
* Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <mbedtls/ssl.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/error.h>
#include "event2/util.h"
#include "util-internal.h"
#include "event2/buffer.h"
#include "event2/bufferevent.h"
#include "event2/bufferevent_struct.h"
#include "event2/bufferevent_ssl.h"
#include "ssl-compat.h"
#include "mm-internal.h"
struct mbedtls_context {
mbedtls_ssl_context *ssl;
mbedtls_net_context net;
};
static void *
mbedtls_context_init(void *ssl)
{
struct mbedtls_context *ctx = mm_malloc(sizeof(*ctx));
if (ctx) {
ctx->ssl = ssl;
ctx->net.fd = -1;
}
return ctx;
}
static void
mbedtls_context_free(void *ssl, int flags)
{
struct mbedtls_context *ctx = ssl;
if (flags & BEV_OPT_CLOSE_ON_FREE)
mbedtls_ssl_free(ctx->ssl);
mm_free(ctx);
}
static int
mbedtls_context_renegotiate(void *ssl)
{
struct mbedtls_context *ctx = ssl;
return mbedtls_ssl_renegotiate(ctx->ssl);
}
static int
mbedtls_context_write(void *ssl, const unsigned char *buf, size_t len)
{
struct mbedtls_context *ctx = ssl;
return mbedtls_ssl_write(ctx->ssl, buf, len);
}
static int
mbedtls_context_read(void *ssl, unsigned char *buf, size_t len)
{
struct mbedtls_context *ctx = ssl;
return mbedtls_ssl_read(ctx->ssl, buf, len);
}
static size_t
mbedtls_context_pending(void *ssl)
{
struct mbedtls_context *ctx = ssl;
return mbedtls_ssl_get_bytes_avail(ctx->ssl);
}
static int
mbedtls_context_handshake(void *ssl)
{
struct mbedtls_context *ctx = ssl;
return mbedtls_ssl_handshake(ctx->ssl);
}
static int
mbedtls_get_error(void *ssl, int ret)
{
return ret;
}
static void
mbedtls_clear_error(void)
{
}
static int
mbedtls_clear(void *ssl)
{
return 1;
}
static void
mbedtls_set_ssl_noops(void *ssl)
{
}
static int
mbedtls_is_ok(int err)
{
return err == 0;
}
static int
mbedtls_is_want_read(int err)
{
return err == MBEDTLS_ERR_SSL_WANT_READ;
}
static int
mbedtls_is_want_write(int err)
{
return err == MBEDTLS_ERR_SSL_WANT_WRITE;
}
static evutil_socket_t
be_mbedtls_get_fd(void *ssl)
{
struct bufferevent_ssl *bev = ssl;
struct mbedtls_context *ctx = bev->ssl;
return ctx->net.fd;
}
static int be_mbedtls_bio_set_fd(
struct bufferevent_ssl *bev_ssl, evutil_socket_t fd);
#if 0
static void
print_err(int val)
{
char buf[1024];
mbedtls_strerror(val, buf, sizeof(buf));
printf("Error was %d:%s\n", val, buf);
}
#else
static void
print_err(int val)
{
}
#endif
/* Called to extract data from the BIO. */
static int
bio_bufferevent_read(void *ctx, unsigned char *out, size_t outlen)
{
struct bufferevent *bufev = (struct bufferevent *)ctx;
int r = 0;
struct evbuffer *input;
if (!out)
return 0;
if (!bufev)
return MBEDTLS_ERR_NET_INVALID_CONTEXT;
input = bufferevent_get_input(bufev);
if (evbuffer_get_length(input) == 0) {
/* If there's no data to read, say so. */
return MBEDTLS_ERR_SSL_WANT_READ;
} else {
r = evbuffer_remove(input, out, outlen);
}
return r;
}
/* Called to write data into the BIO */
static int
bio_bufferevent_write(void *ctx, const unsigned char *in, size_t inlen)
{
struct bufferevent *bufev = (struct bufferevent *)ctx;
struct evbuffer *output;
size_t outlen;
if (!bufev)
return MBEDTLS_ERR_NET_INVALID_CONTEXT;
output = bufferevent_get_output(bufev);
outlen = evbuffer_get_length(output);
/* Copy only as much data onto the output buffer as can fit under the
* high-water mark. */
if (bufev->wm_write.high && bufev->wm_write.high <= (outlen + inlen)) {
if (bufev->wm_write.high <= outlen) {
/* If no data can fit, we'll need to retry later. */
return MBEDTLS_ERR_SSL_WANT_WRITE;
}
inlen = bufev->wm_write.high - outlen;
}
EVUTIL_ASSERT(inlen > 0);
evbuffer_add(output, in, inlen);
return inlen;
}
static void
conn_closed(struct bufferevent_ssl *bev_ssl, int when, int errcode, int ret)
{
int event = BEV_EVENT_ERROR;
char buf[100];
if (when & BEV_EVENT_READING && ret == 0) {
if (bev_ssl->allow_dirty_shutdown)
event = BEV_EVENT_EOF;
} else {
mbedtls_strerror(errcode, buf, sizeof(buf));
switch (errcode) {
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
event = BEV_EVENT_EOF;
break;
case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
event_warnx("BUG: Unsupported feature %d: %s", errcode, buf);
break;
default:
/* should be impossible; treat as normal error. */
event_warnx(
"BUG: Unexpected mbedtls error code %d: %s", errcode, buf);
break;
}
bufferevent_ssl_put_error(bev_ssl, errcode);
}
bufferevent_ssl_stop_reading(bev_ssl);
bufferevent_ssl_stop_writing(bev_ssl);
bufferevent_run_eventcb_(&bev_ssl->bev.bev, when | event, 0);
}
static int
be_mbedtls_bio_set_fd(struct bufferevent_ssl *bev_ssl, evutil_socket_t fd)
{
struct mbedtls_context *ctx = bev_ssl->ssl;
if (!bev_ssl->underlying) {
ctx->net.fd = fd;
mbedtls_ssl_set_bio(
ctx->ssl, &ctx->net, mbedtls_net_send, mbedtls_net_recv, NULL);
} else {
mbedtls_ssl_set_bio(ctx->ssl, bev_ssl->underlying,
bio_bufferevent_write, bio_bufferevent_read, NULL);
}
return 0;
}
int
bufferevent_mbedtls_get_allow_dirty_shutdown(struct bufferevent *bev)
{
return bufferevent_ssl_get_allow_dirty_shutdown(bev);
}
void
bufferevent_mbedtls_set_allow_dirty_shutdown(
struct bufferevent *bev, int allow_dirty_shutdown)
{
bufferevent_ssl_set_allow_dirty_shutdown(bev, allow_dirty_shutdown);
}
mbedtls_ssl_context *
bufferevent_mbedtls_get_ssl(struct bufferevent *bufev)
{
struct mbedtls_context *ctx = NULL;
struct bufferevent_ssl *bev_ssl = bufferevent_ssl_upcast(bufev);
if (!bev_ssl)
return NULL;
ctx = bev_ssl->ssl;
return ctx->ssl;
}
int
bufferevent_mbedtls_renegotiate(struct bufferevent *bufev)
{
struct bufferevent_ssl *bev_ssl = bufferevent_ssl_upcast(bufev);
if (!bev_ssl)
return -1;
return bufferevent_ssl_renegotiate_impl(bufev);
}
unsigned long
bufferevent_get_mbedtls_error(struct bufferevent *bufev)
{
struct bufferevent_ssl *bev_ssl = bufferevent_ssl_upcast(bufev);
if (!bev_ssl)
return -1;
return bufferevent_get_ssl_error(bufev);
}
static struct le_ssl_ops le_mbedtls_ops = {
mbedtls_context_init,
mbedtls_context_free,
(void (*)(void *))mbedtls_ssl_free,
mbedtls_context_renegotiate,
mbedtls_context_write,
mbedtls_context_read,
mbedtls_context_pending,
mbedtls_context_handshake,
mbedtls_get_error,
mbedtls_clear_error,
mbedtls_clear,
mbedtls_set_ssl_noops,
mbedtls_set_ssl_noops,
mbedtls_is_ok,
mbedtls_is_want_read,
mbedtls_is_want_write,
be_mbedtls_get_fd,
be_mbedtls_bio_set_fd,
(void (*)(struct bufferevent_ssl *))mbedtls_set_ssl_noops,
(void (*)(struct bufferevent_ssl *))mbedtls_set_ssl_noops,
conn_closed,
print_err,
};
struct bufferevent *
bufferevent_mbedtls_filter_new(struct event_base *base,
struct bufferevent *underlying, mbedtls_ssl_context *ssl,
enum bufferevent_ssl_state state, int options)
{
struct bufferevent *bev;
if (!underlying)
goto err;
bev = bufferevent_ssl_new_impl(
base, underlying, -1, ssl, state, options, &le_mbedtls_ops);
if (bev) {
be_mbedtls_bio_set_fd(bufferevent_ssl_upcast(bev), -1);
}
return bev;
err:
if (options & BEV_OPT_CLOSE_ON_FREE)
mbedtls_ssl_free(ssl);
return NULL;
}
struct bufferevent *
bufferevent_mbedtls_socket_new(struct event_base *base, evutil_socket_t fd,
mbedtls_ssl_context *ssl, enum bufferevent_ssl_state state, int options)
{
long have_fd = -1;
struct bufferevent *bev;
if (ssl->p_bio) {
/* The SSL is already configured with bio. */
if (ssl->f_send == mbedtls_net_send &&
ssl->f_recv == mbedtls_net_recv) {
have_fd = ((mbedtls_net_context *)ssl->p_bio)->fd;
} else if (ssl->f_send == bio_bufferevent_write &&
ssl->f_recv == bio_bufferevent_read) {
have_fd = bufferevent_getfd(ssl->p_bio);
} else {
/* We don't known the fd. */
have_fd = LONG_MAX;
}
}
if (have_fd >= 0) {
if (fd < 0) {
/* We should learn the fd from the SSL. */
fd = (evutil_socket_t)have_fd;
} else if (have_fd == (long)fd) {
/* We already know the fd from the SSL; do nothing */
} else {
/* We specified an fd different from that of the SSL.
This is probably an error on our part. Fail. */
goto err;
}
} else {
if (fd >= 0) {
/* ... and we have an fd we want to use. */
} else {
/* Leave the fd unset. */
}
}
bev = bufferevent_ssl_new_impl(
base, NULL, fd, ssl, state, options, &le_mbedtls_ops);
if (bev) {
be_mbedtls_bio_set_fd(bufferevent_ssl_upcast(bev), fd);
}
return bev;
err:
return NULL;
}

File diff suppressed because it is too large Load Diff

1092
bufferevent_ssl.c Normal file

File diff suppressed because it is too large Load Diff

159
cmake/FindMbedTLS.cmake Normal file
View File

@ -0,0 +1,159 @@
# Copyright 2017-2019 AVSystem <avsystem@avsystem.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#.rst:
# FindMbedTLS
# -----------
#
# Find the mbedTLS encryption library.
#
# Imported Targets
# ^^^^^^^^^^^^^^^^
#
# This module defines the following :prop_tgt:`IMPORTED` targets:
#
# ``mbedtls``
# The mbedTLS ``mbedtls`` library, if found.
# ``mbedcrypto``
# The mbedtls ``crypto`` library, if found.
# ``mbedx509``
# The mbedtls ``x509`` library, if found.
#
# Result Variables
# ^^^^^^^^^^^^^^^^
#
# This module will set the following variables in your project:
#
# ``MBEDTLS_FOUND``
# System has the mbedTLS library.
# ``MBEDTLS_INCLUDE_DIR``
# The mbedTLS include directory.
# ``MBEDTLS_LIBRARY``
# The mbedTLS SSL library.
# ``MBEDTLS_CRYPTO_LIBRARY``
# The mbedTLS crypto library.
# ``MBEDTLS_X509_LIBRARY``
# The mbedTLS x509 library.
# ``MBEDTLS_LIBRARIES``
# All mbedTLS libraries.
# ``MBEDTLS_VERSION``
# This is set to ``$major.$minor.$patch``.
# ``MBEDTLS_VERSION_MAJOR``
# Set to major mbedTLS version number.
# ``MBEDTLS_VERSION_MINOR``
# Set to minor mbedTLS version number.
# ``MBEDTLS_VERSION_PATCH``
# Set to patch mbedTLS version number.
#
# Hints
# ^^^^^
#
# Set ``MBEDTLS_ROOT_DIR`` to the root directory of an mbedTLS installation.
# Set ``MBEDTLS_USE_STATIC_LIBS`` to ``TRUE`` to look for static libraries.
if(MBEDTLS_ROOT_DIR)
# Disable re-rooting paths in find_path/find_library.
# This assumes MBEDTLS_ROOT_DIR is an absolute path.
set(_EXTRA_FIND_ARGS "NO_CMAKE_FIND_ROOT_PATH")
endif()
find_path(MBEDTLS_INCLUDE_DIR
NAMES mbedtls/ssl.h
PATH_SUFFIXES include
HINTS ${MBEDTLS_ROOT_DIR}
${_EXTRA_FIND_ARGS})
# based on https://github.com/ARMmbed/mbedtls/issues/298
if(MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" VERSION_STRING_LINE REGEX "^#define MBEDTLS_VERSION_STRING[ \\t\\n\\r]+\"[^\"]*\"$")
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" VERSION_MAJOR_LINE REGEX "^#define MBEDTLS_VERSION_MAJOR[ \\t\\n\\r]+[0-9]+$")
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" VERSION_MINOR_LINE REGEX "^#define MBEDTLS_VERSION_MINOR[ \\t\\n\\r]+[0-9]+$")
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" VERSION_PATCH_LINE REGEX "^#define MBEDTLS_VERSION_PATCH[ \\t\\n\\r]+[0-9]+$")
string(REGEX REPLACE "^#define MBEDTLS_VERSION_STRING[ \\t\\n\\r]+\"([^\"]*)\"$" "\\1" MBEDTLS_VERSION "${VERSION_STRING_LINE}")
string(REGEX REPLACE "^#define MBEDTLS_VERSION_MAJOR[ \\t\\n\\r]+([0-9]+)$" "\\1" MBEDTLS_VERSION_MAJOR "${VERSION_MAJOR_LINE}")
string(REGEX REPLACE "^#define MBEDTLS_VERSION_MINOR[ \\t\\n\\r]+([0-9]+)$" "\\1" MBEDTLS_VERSION_MINOR "${VERSION_MINOR_LINE}")
string(REGEX REPLACE "^#define MBEDTLS_VERSION_PATCH[ \\t\\n\\r]+([0-9]+)$" "\\1" MBEDTLS_VERSION_PATCH "${VERSION_PATCH_LINE}")
endif()
if(MBEDTLS_USE_STATIC_LIBS)
set(_MBEDTLS_LIB_NAME libmbedtls.a)
set(_MBEDTLS_CRYPTO_LIB_NAME libmbedcrypto.a)
set(_MBEDTLS_X509_LIB_NAME libmbedx509.a)
else()
set(_MBEDTLS_LIB_NAME mbedtls)
set(_MBEDTLS_CRYPTO_LIB_NAME mbedcrypto)
set(_MBEDTLS_X509_LIB_NAME mbedx509)
endif()
find_library(MBEDTLS_LIBRARY
NAMES ${_MBEDTLS_LIB_NAME}
PATH_SUFFIXES lib
HINTS ${MBEDTLS_ROOT_DIR}
${_EXTRA_FIND_ARGS})
find_library(MBEDTLS_CRYPTO_LIBRARY
NAMES ${_MBEDTLS_CRYPTO_LIB_NAME}
PATH_SUFFIXES lib
HINTS ${MBEDTLS_ROOT_DIR}
${_EXTRA_FIND_ARGS})
find_library(MBEDTLS_X509_LIBRARY
NAMES ${_MBEDTLS_X509_LIB_NAME}
PATH_SUFFIXES lib
HINTS ${MBEDTLS_ROOT_DIR}
${_EXTRA_FIND_ARGS})
set(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY} ${MBEDTLS_X509_LIBRARY})
if(MBEDTLS_INCLUDE_DIR)
set(MBEDTLS_FOUND TRUE)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MbedTLS
FOUND_VAR MBEDTLS_FOUND
REQUIRED_VARS
MBEDTLS_INCLUDE_DIR
MBEDTLS_LIBRARY
MBEDTLS_CRYPTO_LIBRARY
MBEDTLS_X509_LIBRARY
MBEDTLS_LIBRARIES
MBEDTLS_VERSION
VERSION_VAR MBEDTLS_VERSION)
if(NOT TARGET mbedtls)
add_library(mbedtls UNKNOWN IMPORTED)
set_target_properties(mbedtls PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${MBEDTLS_LIBRARY}")
endif()
if(NOT TARGET mbedcrypto)
add_library(mbedcrypto UNKNOWN IMPORTED)
set_target_properties(mbedcrypto PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${MBEDTLS_CRYPTO_LIBRARY}")
endif()
if(NOT TARGET mbedx509)
add_library(mbedx509 UNKNOWN IMPORTED)
set_target_properties(mbedx509 PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${MBEDTLS_X509_LIBRARY}")
endif()

View File

@ -60,6 +60,9 @@ AC_ARG_ENABLE(malloc-replacement,
AC_ARG_ENABLE(openssl,
AS_HELP_STRING(--disable-openssl, disable support for openssl encryption),
[], [enable_openssl=yes])
AC_ARG_ENABLE(mbedtls,
AS_HELP_STRING(--disable-mbedtls, disable support for mbedtls encryption),
[], [enable_mbedtls=yes])
AC_ARG_ENABLE(debug-mode,
AS_HELP_STRING(--disable-debug-mode, disable support for running in debug mode),
[], [enable_debug_mode=yes])
@ -179,6 +182,7 @@ AC_SUBST(OPENSSL_LIBADD)
AC_SYS_LARGEFILE
LIBEVENT_OPENSSL
LIBEVENT_MBEDTLS
dnl Checks for header files.
AC_CHECK_HEADERS([ \
@ -804,7 +808,7 @@ if test x$enable_debug_mode = xno; then
[Define if libevent should build without support for a debug mode])
fi
dnl check if we should enable verbose debugging
dnl check if we should enable verbose debugging
if test x$enable_verbose_debug = xyes; then
CFLAGS="$CFLAGS -DUSE_DEBUG"
fi
@ -812,6 +816,9 @@ fi
dnl check if we have and should use OpenSSL
AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"])
# check if we have and should use mbedtls
AM_CONDITIONAL(MBEDTLS, [test "$enable_mbedtls" != "no" && test "$have_mbedtls" = "yes"])
dnl enable some warnings by default
AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"],[],[-Werror])
@ -961,5 +968,5 @@ DX_INIT_DOXYGEN([libevent], [${top_srcdir}/Doxyfile], [doxygen])
AM_CONDITIONAL([ENABLE_DOXYGEN], [test "$DX_FLAG_doc" = "1"])
AM_CONDITIONAL([ENABLE_DOXYGEN_MAN], [test "$DX_FLAG_man" = "1"])
AC_CONFIG_FILES( [libevent.pc libevent_openssl.pc libevent_pthreads.pc libevent_core.pc libevent_extra.pc] )
AC_CONFIG_FILES( [libevent.pc libevent_mbedtls.pc libevent_openssl.pc libevent_pthreads.pc libevent_core.pc libevent_extra.pc] )
AC_OUTPUT(Makefile)

View File

@ -214,6 +214,9 @@
/* Define if the system has openssl */
#cmakedefine EVENT__HAVE_OPENSSL 1
/* Define if the system has mbedtls */
#cmakedefine EVENT__HAVE_MBEDTLS 1
/* Define to 1 if you have the `pipe' function. */
#cmakedefine EVENT__HAVE_PIPE 1

View File

@ -39,9 +39,6 @@
extern "C" {
#endif
/* This is what openssl's SSL objects are underneath. */
struct ssl_st;
/**
The state of an SSL object to be used when creating a new
SSL bufferevent.
@ -53,6 +50,9 @@ enum bufferevent_ssl_state {
};
#if defined(EVENT__HAVE_OPENSSL) || defined(EVENT_IN_DOXYGEN_)
/* This is what openssl's SSL objects are underneath. */
struct ssl_st;
/**
Create a new SSL bufferevent to send its data over another bufferevent.
@ -125,6 +125,81 @@ int bufferevent_ssl_renegotiate(struct bufferevent *bev);
EVENT2_EXPORT_SYMBOL
unsigned long bufferevent_get_openssl_error(struct bufferevent *bev);
#endif
#if defined(EVENT__HAVE_MBEDTLS) || defined(EVENT_IN_DOXYGEN_)
struct mbedtls_ssl_context;
/**
Create a new SSL bufferevent to send its data over another bufferevent.
@param base An event_base to use to detect reading and writing. It
must also be the base for the underlying bufferevent.
@param underlying A socket to use for this SSL
@param ssl A SSL* object from openssl.
@param state The current state of the SSL connection
@param options One or more bufferevent_options
@return A new bufferevent on success, or NULL on failure
*/
EVENT2_EXPORT_SYMBOL
struct bufferevent *
bufferevent_mbedtls_filter_new(struct event_base *base,
struct bufferevent *underlying,
struct mbedtls_ssl_context *ssl,
enum bufferevent_ssl_state state,
int options);
/**
Create a new SSL bufferevent to send its data over an SSL * on a socket.
@param base An event_base to use to detect reading and writing
@param fd A socket to use for this SSL
@param ssl A SSL* object from mbedtls.
@param state The current state of the SSL connection
@param options One or more bufferevent_options
@return A new bufferevent on success, or NULL on failure.
*/
EVENT2_EXPORT_SYMBOL
struct bufferevent *
bufferevent_mbedtls_socket_new(struct event_base *base,
evutil_socket_t fd,
struct mbedtls_ssl_context *ssl,
enum bufferevent_ssl_state state,
int options);
/** Control how to report dirty SSL shutdowns.
If the peer (or the network, or an attacker) closes the TCP
connection before closing the SSL channel, and the protocol is SSL >= v3,
this is a "dirty" shutdown. If allow_dirty_shutdown is 0 (default),
this is reported as BEV_EVENT_ERROR.
If instead allow_dirty_shutdown=1, a dirty shutdown is reported as
BEV_EVENT_EOF.
(Note that if the protocol is < SSLv3, you will always receive
BEV_EVENT_EOF, since SSL 2 and earlier cannot distinguish a secure
connection close from a dirty one. This is one reason (among many)
not to use SSL 2.)
*/
EVENT2_EXPORT_SYMBOL
int bufferevent_mbedtls_get_allow_dirty_shutdown(struct bufferevent *bev);
EVENT2_EXPORT_SYMBOL
void bufferevent_mbedtls_set_allow_dirty_shutdown(struct bufferevent *bev,
int allow_dirty_shutdown);
/** Return the underlying mbedtls SSL * object for an SSL bufferevent. */
EVENT2_EXPORT_SYMBOL
struct mbedtls_ssl_context *
bufferevent_mbedtls_get_ssl(struct bufferevent *bufev);
/** Tells a bufferevent to begin SSL renegotiation. */
EVENT2_EXPORT_SYMBOL
int bufferevent_mbedtls_renegotiate(struct bufferevent *bev);
/** Return the most recent OpenSSL error reported on an SSL bufferevent. */
EVENT2_EXPORT_SYMBOL
unsigned long bufferevent_get_mbedtls_error(struct bufferevent *bev);
#endif
#ifdef __cplusplus

View File

@ -33,7 +33,8 @@
defined(event_extra_shared_EXPORTS) || \
defined(event_core_shared_EXPORTS) || \
defined(event_pthreads_shared_EXPORTS) || \
defined(event_openssl_shared_EXPORTS)
defined(event_openssl_shared_EXPORTS) || \
defined(event_mbedtls_shared_EXPORTS)
# if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
# define EVENT2_EXPORT_SYMBOL __global

16
libevent_mbedtls.pc.in Normal file
View File

@ -0,0 +1,16 @@
#libevent pkg-config source file
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libevent_mbedtls
Description: libevent_mbedtls adds mbedtls-based TLS support to libevent
Version: @VERSION@
Requires: libevent
Conflicts:
Libs: -L${libdir} -levent_mbedtls
Libs.private: @LIBS@ @MBEDTLS_LIBS@
Cflags: -I${includedir} @MBEDTLS_INCS@

38
m4/libevent_mbedtls.m4 Normal file
View File

@ -0,0 +1,38 @@
dnl ######################################################################
dnl mbedtls support
AC_DEFUN([LIBEVENT_MBEDTLS], [
AC_REQUIRE([NTP_PKG_CONFIG])dnl
case "$enable_mbedtls" in
yes)
case "$have_mbedtls" in
yes) ;;
*)
save_LIBS="$LIBS"
LIBS=""
MBEDTLS_LIBS=""
# clear cache
unset ac_cv_search_mbedtls_ssl_init
AC_SEARCH_LIBS([mbedtls_ssl_init], [mbedtls],
[have_mbedtls=yes
MBEDTLS_LIBS="$LIBS -lmbedtls -lmbedcrypto -lmbedx509 $EV_LIB_GDI $EV_LIB_WS32"],
[have_mbedtls=no],
[-lmbedtls -lmbedcrypto -lmbedx509 $EV_LIB_GDI $EV_LIB_WS32])
LIBS="$save_LIBS"
test "$have_mbedtls" = "yes" && break
esac
CPPFLAGS_SAVE=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $MBEDTLS_INCS"
AC_CHECK_HEADERS([mbedtls/ssl.h], [], [have_mbedtls=no])
CPPFLAGS=$CPPFLAGS_SAVE
AC_SUBST(MBEDTLS_INCS)
AC_SUBST(MBEDTLS_LIBS)
case "$have_mbedtls" in
yes) AC_DEFINE(HAVE_MBEDTLS, 1, [Define if the system has mbedtls]) ;;
esac
;;
esac
# check if we have and should use mbedtls
AM_CONDITIONAL(MBEDTLS, [test "$enable_mbedtls" != "no" && test "$have_mbedtls" = "yes"])
])

View File

@ -40,6 +40,13 @@ noinst_HEADERS += \
sample/openssl_hostname_validation.h
endif
if MBEDTLS
SAMPLES += sample/ssl-client-mbedtls
sample_ssl_client_mbedtls_SOURCES = sample/ssl-client-mbedtls.c
sample_ssl_client_mbedtls_LDADD = libevent.la libevent_mbedtls.la $(MBEDTLS_LIBS) $(MBEDTLS_LIBADD)
sample_ssl_client_mbedtls_CPPFLAGS = $(AM_CPPFLAGS) $(MBEDTLS_INCS)
endif
if BUILD_SAMPLES
noinst_PROGRAMS += $(SAMPLES)
endif

264
sample/ssl-client-mbedtls.c Normal file
View File

@ -0,0 +1,264 @@
/*
* SSL client demonstration program
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#include "mbedtls/config.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"
#include <string.h>
#include <event2/event.h>
#include <event2/dns.h>
#include <event2/bufferevent.h>
#include <event2/bufferevent_ssl.h>
#include <event2/util.h>
#define SERVER_PORT "443"
#define SERVER_NAME "amazon.com"
#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
#define DEBUG_LEVEL 1
static void
my_debug(void *ctx, int level, const char *file, int line, const char *str)
{
((void)level);
mbedtls_fprintf((FILE *)ctx, "%s:%04d: %s", file, line, str);
fflush((FILE *)ctx);
}
static void
writecb(struct bufferevent *bev, void *arg)
{
fprintf(stderr, "writecb\n");
}
static void
readcb(struct bufferevent *bev, void *arg)
{
char buf[1000];
size_t r = 0;
int i;
for (i = 0; i < 10; ++i) {
r = bufferevent_read(bev, buf, 800);
fprintf(stderr, "readcb %zu\n\n", r);
if (r > 1) {
fwrite(buf, 1, r, stdout);
fwrite("\n", 1, r, stdout);
fflush(stdout);
}
}
}
static void
eventcb(struct bufferevent *bev, short what, void *arg)
{
fprintf(stderr, "\n---------------eventcb %d\n", what);
if (what & BEV_EVENT_CONNECTED) {
const char headers[] = "GET / HTTP/1.1\r\n"
"HOST: " SERVER_NAME "\r\n"
"User-Agent: curl/7.65.1\r\n"
"Connection: Keep-Alive\r\n"
"\r\n";
bufferevent_write(
bev, headers, sizeof(headers) - 1); // without ending '\0'
// bufferevent_disable(bev, EV_WRITE);
fprintf(stderr, "write request completely\n");
} else if (what & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
fprintf(stderr, "closed\n");
bufferevent_free(bev);
}
}
int
main(void)
{
int ret;
mbedtls_net_context server_fd;
const char *pers = "ssl_client1";
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;
struct event_base *evbase;
struct evdns_base *evdns;
struct bufferevent *bev;
struct bufferevent *bevf;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
#if defined(MBEDTLS_DEBUG_C)
mbedtls_debug_set_threshold(DEBUG_LEVEL);
#endif
/*
* 0. Initialize the RNG and the session data
*/
mbedtls_net_init(&server_fd);
mbedtls_ssl_init(&ssl);
mbedtls_ssl_config_init(&conf);
mbedtls_x509_crt_init(&cacert);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_printf("\n . Seeding the random number generator...");
fflush(stdout);
mbedtls_entropy_init(&entropy);
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *)pers, strlen(pers))) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
goto exit;
}
mbedtls_printf(" ok\n");
/*
* 0. Initialize certificates
*/
mbedtls_printf(" . Loading the CA root certificate ...");
fflush(stdout);
ret = mbedtls_x509_crt_parse(&cacert,
(const unsigned char *)mbedtls_test_cas_pem, mbedtls_test_cas_pem_len);
if (ret < 0) {
mbedtls_printf(
" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
goto exit;
}
mbedtls_printf(" ok (%d skipped)\n", ret);
/*
* 1. Start the connection
*/
mbedtls_printf(" . Connecting to tcp/%s/%s...", SERVER_NAME, SERVER_PORT);
fflush(stdout);
if ((ret = mbedtls_net_connect(&server_fd, SERVER_NAME, SERVER_PORT,
MBEDTLS_NET_PROTO_TCP)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_net_connect returned %d\n\n", ret);
goto exit;
}
mbedtls_printf(" ok\n");
/*
* 2. Setup stuff
*/
mbedtls_printf(" . Setting up the SSL/TLS structure...");
fflush(stdout);
if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
mbedtls_printf(
" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
goto exit;
}
mbedtls_printf(" ok\n");
/* OPTIONAL is not optimal for security,
* but makes interop easier in this simplified example */
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE);
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret);
goto exit;
}
if ((ret = mbedtls_ssl_set_hostname(&ssl, SERVER_NAME)) != 0) {
mbedtls_printf(
" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
goto exit;
}
fflush(stdout);
event_enable_debug_mode();
evbase = event_base_new();
evdns = evdns_base_new(evbase, 1);
evdns_base_set_option(evdns, "randomize-case:", "0");
evutil_make_socket_nonblocking(server_fd.fd);
bev = bufferevent_socket_new(evbase, server_fd.fd, BEV_OPT_CLOSE_ON_FREE);
bevf = bufferevent_mbedtls_filter_new(
evbase, bev, &ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
bev = bevf;
bufferevent_setcb(bev, readcb, writecb, eventcb, NULL);
bufferevent_enable(bev, EV_READ);
event_base_loop(evbase, 0);
event_base_free(evbase);
exit:
#ifdef MBEDTLS_ERROR_C
if (ret != 0) {
char error_buf[100];
mbedtls_strerror(ret, error_buf, 100);
mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf);
}
#endif
mbedtls_net_free(&server_fd);
mbedtls_x509_crt_free(&cacert);
mbedtls_ssl_free(&ssl);
mbedtls_ssl_config_free(&conf);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
#if defined(_WIN32)
mbedtls_printf(" + Press Enter to exit this program.\n");
fflush(stdout);
getchar();
#endif
return (ret);
}

101
ssl-compat.h Normal file
View File

@ -0,0 +1,101 @@
#ifndef SSL_COMPACT_H
#define SSL_COMPACT_H
#include "event.h"
#include "bufferevent-internal.h"
#include "event2/bufferevent_ssl.h"
struct bufferevent_ssl;
struct le_ssl_ops {
void *(*init)(void *ssl);
void (*free)(void *ssl, int flags);
void (*free_raw)(void *ssl);
int (*renegotiate)(void *ssl);
int (*write)(void *ssl, const unsigned char *buf, size_t len);
int (*read)(void *ssl, unsigned char *buf, size_t len);
size_t (*pending)(void *ssl);
int (*handshake)(void *ssl);
int (*get_error)(void *ssl, int ret);
void (*clear_error)(void);
int (*clear)(void *ssl);
void (*set_connect_state)(void *ssl);
void (*set_accept_state)(void *ssl);
int (*err_is_ok)(int err);
int (*err_is_want_read)(int err);
int (*err_is_want_write)(int err);
evutil_socket_t (*get_fd)(void *ssl);
int (*bio_set_fd)(struct bufferevent_ssl *ssl, evutil_socket_t fd);
void (*init_bio_counts)(struct bufferevent_ssl *bev);
void (*decrement_buckets)(struct bufferevent_ssl *bev);
void (*conn_closed)(
struct bufferevent_ssl *bev, int when, int errcode, int ret);
void (*print_err)(int err);
};
struct bio_data_counts {
unsigned long n_written;
unsigned long n_read;
};
struct bufferevent_ssl {
/* Shared fields with common bufferevent implementation code.
If we were set up with an underlying bufferevent, we use the
events here as timers only. If we have an SSL, then we use
the events as socket events.
*/
struct bufferevent_private bev;
/* An underlying bufferevent that we're directing our output to.
If it's NULL, then we're connected to an fd, not an evbuffer. */
struct bufferevent *underlying;
/* The SSL context doing our encryption. */
void *ssl;
/* The SSL operations doing on ssl. */
struct le_ssl_ops *ssl_ops;
/* A callback that's invoked when data arrives on our outbuf so we
know to write data to the SSL. */
struct evbuffer_cb_entry *outbuf_cb;
/* A count of how much data the bios have read/written total. Used
for rate-limiting. */
struct bio_data_counts counts;
/* If this value is greater than 0, then the last SSL_write blocked,
* and we need to try it again with this many bytes. */
ev_ssize_t last_write;
#define NUM_ERRORS 3
ev_uint32_t errors[NUM_ERRORS];
/* When we next get available space, we should say "read" instead of
"write". This can happen if there's a renegotiation during a read
operation. */
unsigned read_blocked_on_write : 1;
/* When we next get data, we should say "write" instead of "read". */
unsigned write_blocked_on_read : 1;
/* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */
unsigned allow_dirty_shutdown : 1;
/* XXX */
unsigned n_errors : 2;
/* Are we currently connecting, accepting, or doing IO? */
unsigned state : 2;
/* If we reset fd, we sould reset state too */
unsigned old_state : 2;
};
struct bufferevent *bufferevent_ssl_new_impl(struct event_base *base,
struct bufferevent *underlying, evutil_socket_t fd, void *ssl,
enum bufferevent_ssl_state state, int options, struct le_ssl_ops *ssl_ops);
struct bufferevent_ssl *bufferevent_ssl_upcast(struct bufferevent *bev);
void bufferevent_ssl_put_error(
struct bufferevent_ssl *bev_ssl, unsigned long err);
void bufferevent_ssl_stop_reading(struct bufferevent_ssl *bev_ssl);
void bufferevent_ssl_stop_writing(struct bufferevent_ssl *bev_ssl);
int bufferevent_ssl_renegotiate_impl(struct bufferevent *bev);
unsigned long bufferevent_get_ssl_error(struct bufferevent *bev);
int bufferevent_ssl_get_allow_dirty_shutdown(struct bufferevent *bev);
void bufferevent_ssl_set_allow_dirty_shutdown(
struct bufferevent *bev, int allow_dirty_shutdown);
#endif /* SSL_COMPACT_H */

View File

@ -9,6 +9,9 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <event2/bufferevent_ssl.h>
#elif defined(EVENT_EXPORT_TEST_COMPONENT_MBEDTLS)
#include <mbedtls/ssl.h>
#include <event2/bufferevent_ssl.h>
#endif
#if defined(EVENT_EXPORT_TEST_COMPONENT_EXTRA)
@ -90,6 +93,54 @@ error:
SSL_free(ssl);
return r;
}
#elif defined(EVENT_EXPORT_TEST_COMPONENT_MBEDTLS)
static int
test()
{
struct event_base *base = NULL;
mbedtls_ssl_config *conf = NULL;
mbedtls_ssl_context *ssl = NULL;
struct bufferevent *bev;
int r = 1;
base = event_base_new();
if (!base) {
goto error;
}
conf = malloc(sizeof(*conf));
if (!conf) {
goto error;
}
mbedtls_ssl_config_init(conf);
ssl = malloc(sizeof(*ssl));
if (!ssl) {
goto error;
}
mbedtls_ssl_init(ssl);
mbedtls_ssl_setup(ssl, conf);
bev = bufferevent_mbedtls_socket_new(base, -1, ssl,
BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
if (bev == NULL) {
goto error;
}
r = 0;
error:
if (base)
event_base_free(base);
if (ssl) {
mbedtls_ssl_free(ssl);
free(ssl);
}
if (conf) {
mbedtls_ssl_config_free(conf);
free(conf);
}
return r;
}
#else
static int
test()

View File

@ -88,13 +88,18 @@ def test_group():
testcase("core", "core", 0)
testcase("extra", "extra", 0)
testcase("openssl", "openssl", 0)
testcase("mbedtls", "mbedtls", 0)
testcase("", "", 0)
testcase("extra", "core", 0)
testcase("openssl", "core", 0)
testcase("mbedtls", "core", 0)
testcase("core", "extra", 1)
testcase("core", "openssl", 1)
testcase("extra", "openssl", 1)
testcase("openssl", "extra", 1)
testcase("core", "mbedtls", 1)
testcase("extra", "mbedtls", 1)
testcase("mbedtls", "extra", 1)
if platform.system() != "Windows":
testcase("pthreads", "pthreads", 0)
testcase("pthreads", "core", 0)
@ -103,6 +108,8 @@ def test_group():
testcase("pthreads", "extra", 1)
testcase("pthreads", "openssl", 1)
testcase("openssl", "pthreads", 1)
testcase("pthreads", "mbedtls", 1)
testcase("mbedtls", "pthreads", 1)
def config_restore():

View File

@ -149,11 +149,17 @@ test_regress_CPPFLAGS = $(AM_CPPFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) -Itest
test_regress_LDFLAGS = $(PTHREAD_CFLAGS)
if OPENSSL
test_regress_SOURCES += test/regress_ssl.c
test_regress_SOURCES += test/regress_openssl.c
test_regress_CPPFLAGS += $(OPENSSL_INCS)
test_regress_LDADD += libevent_openssl.la $(OPENSSL_LIBS) ${OPENSSL_LIBADD}
endif
if MBEDTLS
test_regress_SOURCES += test/regress_mbedtls.c
test_regress_CPPFLAGS += $(MBEDTLS_INCS)
test_regress_LDADD += libevent_mbedtls.la $(MBEDTLS_LIBS)
endif
test_bench_SOURCES = test/bench.c
test_bench_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
test_bench_cascade_SOURCES = test/bench_cascade.c

View File

@ -49,7 +49,8 @@ extern struct testcase_t rpc_testcases[];
extern struct testcase_t edgetriggered_testcases[];
extern struct testcase_t minheap_testcases[];
extern struct testcase_t iocp_testcases[];
extern struct testcase_t ssl_testcases[];
extern struct testcase_t openssl_testcases[];
extern struct testcase_t mbedtls_testcases[];
extern struct testcase_t listener_testcases[];
extern struct testcase_t listener_iocp_testcases[];
extern struct testcase_t thread_testcases[];

View File

@ -451,7 +451,10 @@ struct testgroup_t testgroups[] = {
{ "iocp/http/", http_iocp_testcases },
#endif
#ifdef EVENT__HAVE_OPENSSL
{ "ssl/", ssl_testcases },
{ "openssl/", openssl_testcases },
#endif
#ifdef EVENT__HAVE_MBEDTLS
{ "mbedtls/", mbedtls_testcases },
#endif
END_OF_GROUPS
};

335
test/regress_mbedtls.c Normal file
View File

@ -0,0 +1,335 @@
/*
* Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** For event_debug() usage/coverage */
#define EVENT_VISIBILITY_WANT_DLLIMPORT
#include "event2/util.h"
#include <mbedtls/ssl.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/debug.h>
#include "regress.h"
#include "tinytest.h"
#define TESTCASES_NAME mbedtls_testcases
#ifdef OPENSSL_VERSION_NUMBER
#undef OPENSSL_VERSION_NUMBER
#endif
#define OPENSSL_VERSION_NUMBER 0
#define SSL_IS_CLIENT MBEDTLS_SSL_IS_CLIENT
#define SSL_IS_SERVER MBEDTLS_SSL_IS_SERVER
#define get_ssl_ctx get_mbedtls_config
#define SSL_renegotiate mbedtls_ssl_renegotiate
#define SSL_get_peer_certificate mbedtls_ssl_get_peer_cert
#define SSL_new mbedtls_ssl_new
#define SSL_use_certificate(a, b) \
do { \
} while (0);
#define SSL_use_PrivateKey(a, b) \
do { \
} while (0);
#define X509_free(x) \
do { \
} while (0);
#define X509 const mbedtls_x509_crt
#define SSL mbedtls_ssl_context
#define bufferevent_ssl_get_ssl bufferevent_mbedtls_get_ssl
#define bufferevent_ssl_set_allow_dirty_shutdown \
bufferevent_mbedtls_set_allow_dirty_shutdown
#define bufferevent_ssl_socket_new bufferevent_mbedtls_socket_new
#define bufferevent_ssl_filter_new bufferevent_mbedtls_filter_new
struct rwcount;
static void BIO_setup(SSL *ssl, struct rwcount *rw);
static mbedtls_ssl_config *get_mbedtls_config(int endpoint);
static mbedtls_ssl_context *mbedtls_ssl_new(mbedtls_ssl_config *config);
static void *mbedtls_test_setup(const struct testcase_t *testcase);
static int mbedtls_test_cleanup(const struct testcase_t *testcase, void *ptr);
static const struct testcase_setup_t ssl_setup = {
mbedtls_test_setup, mbedtls_test_cleanup};
#include "regress_ssl.c"
static mbedtls_ssl_config *the_mbedtls_conf[2] = {NULL, NULL};
static mbedtls_ssl_context *the_mbedtls_ctx[1024] = {NULL};
static int the_mbedtls_ctx_count = 0;
static mbedtls_entropy_context entropy;
static mbedtls_ctr_drbg_context ctr_drbg;
static mbedtls_x509_crt *the_cert;
static mbedtls_pk_context *the_key;
static void
mbedtls_debug(
void *userdata, int level, const char *file, int line, const char *str)
{
int loglen = strlen(str);
if (str[loglen - 1] == '\n')
loglen--;
event_debug(("[mbedtls][%s][%d][%s][%d]%.*s", (char *)userdata, level, file,
line, loglen, str));
}
static mbedtls_pk_context *
mbedtls_getkey(void)
{
int ret = 0;
mbedtls_pk_context *pk = malloc(sizeof(mbedtls_pk_context));
tt_assert(pk);
mbedtls_pk_init(pk);
ret = mbedtls_pk_parse_key(
pk, (const unsigned char *)KEY, sizeof(KEY), NULL, 0);
tt_assert(ret == 0);
return pk;
end:
if (pk) {
mbedtls_pk_free(pk);
free(pk);
}
return NULL;
}
static void
create_tm_from_unix_epoch(struct tm *cur_p, const time_t t)
{
#ifdef _WIN32
struct tm *tmp = gmtime(&t);
if (!tmp) {
fprintf(stderr, "gmtime: %s (%i)", strerror(errno), (int)t);
exit(1);
}
*cur_p = *tmp;
#else
gmtime_r(&t, cur_p);
#endif
}
static mbedtls_x509_crt *
mbedtls_getcert(mbedtls_pk_context *pk)
{
const char *name = "commonName=example.com";
time_t now = time(NULL);
char now_string[32] = "";
char not_before[32] = "";
char not_after[32] = "";
unsigned char certbuf[8192];
struct tm tm;
mbedtls_x509_crt *crt = NULL;
int ret = 0;
mbedtls_mpi serial;
mbedtls_x509write_cert write_cert;
snprintf(now_string, sizeof(now_string), "%lld", (long long)now);
create_tm_from_unix_epoch(&tm, now);
strftime(not_before, sizeof(not_before), "%Y%m%d%H%M%S", &tm);
now += 3600;
create_tm_from_unix_epoch(&tm, now);
strftime(not_after, sizeof(not_after), "%Y%m%d%H%M%S", &tm);
mbedtls_x509write_crt_init(&write_cert);
mbedtls_x509write_crt_set_version(&write_cert, 2);
mbedtls_mpi_init(&serial);
ret = mbedtls_mpi_read_string(&serial, 10, now_string);
tt_assert(ret == 0);
ret = mbedtls_x509write_crt_set_serial(&write_cert, &serial);
tt_assert(ret == 0);
mbedtls_mpi_free(&serial);
ret = mbedtls_x509write_crt_set_subject_name(&write_cert, name);
tt_assert(ret == 0);
ret = mbedtls_x509write_crt_set_issuer_name(&write_cert, name);
tt_assert(ret == 0);
mbedtls_x509write_crt_set_md_alg(&write_cert, MBEDTLS_MD_SHA256);
ret =
mbedtls_x509write_crt_set_validity(&write_cert, not_before, not_after);
tt_assert(ret == 0);
mbedtls_x509write_crt_set_issuer_key(&write_cert, pk);
mbedtls_x509write_crt_set_subject_key(&write_cert, pk);
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *)name, strlen(name));
tt_assert(ret == 0);
ret = mbedtls_x509write_crt_pem(&write_cert, certbuf, sizeof(certbuf),
mbedtls_ctr_drbg_random, &ctr_drbg);
tt_assert(ret == 0);
mbedtls_x509write_crt_free(&write_cert);
crt = malloc(sizeof(mbedtls_x509_crt));
tt_assert(crt);
mbedtls_x509_crt_init(crt);
ret = mbedtls_x509_crt_parse(crt, certbuf, strlen((char *)certbuf) + 1);
tt_assert(ret == 0);
return crt;
end:
if (crt) {
mbedtls_x509_crt_free(crt);
free(crt);
}
return NULL;
}
static mbedtls_ssl_config *
get_mbedtls_config(int endpoint)
{
if (the_mbedtls_conf[endpoint])
return the_mbedtls_conf[endpoint];
the_mbedtls_conf[endpoint] = malloc(sizeof(mbedtls_ssl_config));
if (!the_mbedtls_conf[endpoint])
return NULL;
mbedtls_ssl_config_init(the_mbedtls_conf[endpoint]);
mbedtls_ssl_conf_renegotiation(
the_mbedtls_conf[endpoint], MBEDTLS_SSL_RENEGOTIATION_ENABLED);
mbedtls_ssl_conf_dbg(the_mbedtls_conf[endpoint], mbedtls_debug,
(void *)(endpoint == MBEDTLS_SSL_IS_SERVER ? "server" : "client"));
mbedtls_ssl_config_defaults(the_mbedtls_conf[endpoint], endpoint,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
mbedtls_ssl_conf_rng(
the_mbedtls_conf[endpoint], mbedtls_ctr_drbg_random, &ctr_drbg);
if (disable_tls_11_and_12) {
mbedtls_ssl_conf_max_version(the_mbedtls_conf[endpoint],
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1);
}
if (endpoint == MBEDTLS_SSL_IS_SERVER) {
mbedtls_ssl_conf_own_cert(
the_mbedtls_conf[endpoint], the_cert, the_key);
} else { /* MBEDTLS_SSL_IS_CLIENT */
mbedtls_ssl_conf_ca_chain(the_mbedtls_conf[endpoint], the_cert, NULL);
}
return the_mbedtls_conf[endpoint];
}
static void
init_mbedtls(void)
{
mbedtls_debug_set_threshold(5);
}
static void *
mbedtls_test_setup(const struct testcase_t *testcase)
{
init_mbedtls();
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *)"libevent", sizeof("libevent"));
the_key = mbedtls_getkey();
EVUTIL_ASSERT(the_key);
the_cert = mbedtls_getcert(the_key);
EVUTIL_ASSERT(the_cert);
disable_tls_11_and_12 = 0;
return basic_test_setup(testcase);
}
static int
mbedtls_test_cleanup(const struct testcase_t *testcase, void *ptr)
{
int i;
int ret = basic_test_cleanup(testcase, ptr);
if (!ret) {
return ret;
}
test_is_done = 0;
n_connected = 0;
got_close = 0;
got_error = 0;
got_timeout = 0;
renegotiate_at = -1;
stop_when_connected = 0;
pending_connect_events = 0;
exit_base = NULL;
mbedtls_x509_crt_free(the_cert);
free(the_cert);
mbedtls_pk_free(the_key);
free(the_key);
for (i = 0; i < the_mbedtls_ctx_count; i++) {
mbedtls_ssl_free(the_mbedtls_ctx[i]);
}
if (the_mbedtls_conf[0]) {
mbedtls_ssl_config_free(the_mbedtls_conf[0]);
free(the_mbedtls_conf[0]);
the_mbedtls_conf[0] = NULL;
}
if (the_mbedtls_conf[1]) {
mbedtls_ssl_config_free(the_mbedtls_conf[1]);
free(the_mbedtls_conf[1]);
the_mbedtls_conf[1] = NULL;
}
return 1;
}
static mbedtls_ssl_context *
mbedtls_ssl_new(mbedtls_ssl_config *config)
{
mbedtls_ssl_context *ssl = malloc(sizeof(*ssl));
mbedtls_ssl_init(ssl);
mbedtls_ssl_setup(ssl, config);
the_mbedtls_ctx[the_mbedtls_ctx_count++] = ssl;
return ssl;
}
static int
bio_rwcount_read(void *ctx, unsigned char *out, size_t outlen)
{
struct rwcount *rw = ctx;
ev_ssize_t ret = recv(rw->fd, out, outlen, 0);
++rw->read;
if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
return MBEDTLS_ERR_SSL_WANT_READ;
}
return ret;
}
static int
bio_rwcount_write(void *ctx, const unsigned char *in, size_t inlen)
{
struct rwcount *rw = ctx;
ev_ssize_t ret = send(rw->fd, in, inlen, 0);
++rw->write;
if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
return MBEDTLS_ERR_SSL_WANT_WRITE;
}
return ret;
}
static void
BIO_setup(SSL *ssl, struct rwcount *rw)
{
mbedtls_ssl_set_bio(ssl, rw, bio_rwcount_write, bio_rwcount_read,
NULL);
}

311
test/regress_openssl.c Normal file
View File

@ -0,0 +1,311 @@
/*
* Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/util.h"
#include <openssl/err.h>
#include <openssl/pem.h>
#include "openssl-compat.h"
#include "regress.h"
#include "tinytest.h"
#define TESTCASES_NAME openssl_testcases
static void *ssl_test_setup(const struct testcase_t *testcase);
static int ssl_test_cleanup(const struct testcase_t *testcase, void *ptr);
static const struct testcase_setup_t ssl_setup = {
ssl_test_setup, ssl_test_cleanup};
static X509 *the_cert;
EVP_PKEY *the_key;
#define SSL_IS_CLIENT
#define SSL_IS_SERVER
#define bufferevent_ssl_get_ssl bufferevent_openssl_get_ssl
#define bufferevent_ssl_set_allow_dirty_shutdown \
bufferevent_openssl_set_allow_dirty_shutdown
#define bufferevent_ssl_socket_new bufferevent_openssl_socket_new
#define bufferevent_ssl_filter_new bufferevent_openssl_filter_new
struct rwcount;
static void BIO_setup(SSL *ssl, struct rwcount *rw);
#include "regress_ssl.c"
EVP_PKEY *
ssl_getkey(void)
{
EVP_PKEY *key;
BIO *bio;
/* new read-only BIO backed by KEY. */
bio = BIO_new_mem_buf((char *)KEY, -1);
tt_assert(bio);
key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
BIO_free(bio);
tt_assert(key);
return key;
end:
return NULL;
}
X509 *
ssl_getcert(EVP_PKEY *key)
{
/* Dummy code to make a quick-and-dirty valid certificate with
OpenSSL. Don't copy this code into your own program! It does a
number of things in a stupid and insecure way. */
X509 *x509 = NULL;
X509_NAME *name = NULL;
int nid;
time_t now = time(NULL);
tt_assert(key);
x509 = X509_new();
tt_assert(x509);
tt_assert(0 != X509_set_version(x509, 2));
tt_assert(0 != ASN1_INTEGER_set(X509_get_serialNumber(x509), (long)now));
name = X509_NAME_new();
tt_assert(name);
nid = OBJ_txt2nid("commonName");
tt_assert(NID_undef != nid);
tt_assert(0 != X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,
(unsigned char *)"example.com", -1, -1, 0));
X509_set_subject_name(x509, name);
X509_set_issuer_name(x509, name);
X509_NAME_free(name);
X509_time_adj(X509_getm_notBefore(x509), 0, &now);
now += 3600;
X509_time_adj(X509_getm_notAfter(x509), 0, &now);
X509_set_pubkey(x509, key);
tt_assert(0 != X509_sign(x509, key, EVP_sha1()));
return x509;
end:
X509_free(x509);
X509_NAME_free(name);
return NULL;
}
static SSL_CTX *the_ssl_ctx = NULL;
SSL_CTX *
get_ssl_ctx(void)
{
if (the_ssl_ctx)
return the_ssl_ctx;
the_ssl_ctx = SSL_CTX_new(SSLv23_method());
if (!the_ssl_ctx)
return NULL;
if (disable_tls_11_and_12) {
#ifdef SSL_OP_NO_TLSv1_2
SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_2);
#endif
#ifdef SSL_OP_NO_TLSv1_1
SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_1);
#endif
}
return the_ssl_ctx;
}
void
init_ssl(void)
{
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER < 0x20700000L)
SSL_library_init();
ERR_load_crypto_strings();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
if (SSLeay() != OPENSSL_VERSION_NUMBER) {
TT_DECLARE("WARN", ("Version mismatch for openssl: compiled with %lx "
"but running with %lx",
(unsigned long)OPENSSL_VERSION_NUMBER,
(unsigned long)SSLeay()));
}
#endif
}
static void *
ssl_test_setup(const struct testcase_t *testcase)
{
init_ssl();
the_key = ssl_getkey();
EVUTIL_ASSERT(the_key);
the_cert = ssl_getcert(the_key);
EVUTIL_ASSERT(the_cert);
disable_tls_11_and_12 = 0;
return basic_test_setup(testcase);
}
static int
ssl_test_cleanup(const struct testcase_t *testcase, void *ptr)
{
int ret = basic_test_cleanup(testcase, ptr);
if (!ret) {
return ret;
}
test_is_done = 0;
n_connected = 0;
got_close = 0;
got_error = 0;
got_timeout = 0;
renegotiate_at = -1;
stop_when_connected = 0;
pending_connect_events = 0;
exit_base = NULL;
X509_free(the_cert);
EVP_PKEY_free(the_key);
SSL_CTX_free(the_ssl_ctx);
the_ssl_ctx = NULL;
return 1;
}
static int
bio_rwcount_new(BIO *b)
{
BIO_set_init(b, 0);
BIO_set_data(b, NULL);
return 1;
}
static int
bio_rwcount_free(BIO *b)
{
TT_BLATHER(("bio_rwcount_free: %p", b));
if (!b)
return 0;
if (BIO_get_shutdown(b)) {
BIO_set_init(b, 0);
BIO_set_data(b, NULL);
}
return 1;
}
static int
bio_rwcount_read(BIO *b, char *out, int outlen)
{
struct rwcount *rw = BIO_get_data(b);
ev_ssize_t ret = recv(rw->fd, out, outlen, 0);
++rw->read;
if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
BIO_set_retry_read(b);
}
return ret;
}
static int
bio_rwcount_write(BIO *b, const char *in, int inlen)
{
struct rwcount *rw = BIO_get_data(b);
ev_ssize_t ret = send(rw->fd, in, inlen, 0);
++rw->write;
if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
BIO_set_retry_write(b);
}
return ret;
}
static long
bio_rwcount_ctrl(BIO *b, int cmd, long num, void *ptr)
{
struct rwcount *rw = BIO_get_data(b);
long ret = 0;
switch (cmd) {
case BIO_C_GET_FD:
ret = rw->fd;
break;
case BIO_CTRL_GET_CLOSE:
ret = BIO_get_shutdown(b);
break;
case BIO_CTRL_SET_CLOSE:
BIO_set_shutdown(b, (int)num);
break;
case BIO_CTRL_PENDING:
ret = 0;
break;
case BIO_CTRL_WPENDING:
ret = 0;
break;
case BIO_CTRL_DUP:
case BIO_CTRL_FLUSH:
ret = 1;
break;
}
return ret;
}
static int
bio_rwcount_puts(BIO *b, const char *s)
{
return bio_rwcount_write(b, s, strlen(s));
}
#define BIO_TYPE_LIBEVENT_RWCOUNT 0xff1
static BIO_METHOD *methods_rwcount;
static BIO_METHOD *
BIO_s_rwcount(void)
{
if (methods_rwcount == NULL) {
methods_rwcount = BIO_meth_new(BIO_TYPE_LIBEVENT_RWCOUNT, "rwcount");
if (methods_rwcount == NULL)
return NULL;
BIO_meth_set_write(methods_rwcount, bio_rwcount_write);
BIO_meth_set_read(methods_rwcount, bio_rwcount_read);
BIO_meth_set_puts(methods_rwcount, bio_rwcount_puts);
BIO_meth_set_ctrl(methods_rwcount, bio_rwcount_ctrl);
BIO_meth_set_create(methods_rwcount, bio_rwcount_new);
BIO_meth_set_destroy(methods_rwcount, bio_rwcount_free);
}
return methods_rwcount;
}
static BIO *
BIO_new_rwcount(int close_flag)
{
BIO *result;
if (!(result = BIO_new(BIO_s_rwcount())))
return NULL;
BIO_set_init(result, 1);
BIO_set_data(result, NULL);
BIO_set_shutdown(result, !!close_flag);
return result;
}
static void
BIO_setup(SSL *ssl, struct rwcount *rw)
{
BIO *bio;
bio = BIO_new_rwcount(0);
tt_assert(bio);
BIO_set_data(bio, rw);
SSL_set_bio(ssl, bio, bio);
end:
return;
}

View File

@ -42,21 +42,15 @@
#include <netinet/in.h>
#endif
#include "event2/util.h"
#include "event2/event.h"
#include "event2/bufferevent_ssl.h"
#include "event2/bufferevent_struct.h"
#include "event2/buffer.h"
#include "event2/listener.h"
#include "regress.h"
#include "tinytest.h"
#include "tinytest_macros.h"
#include <openssl/err.h>
#include <openssl/pem.h>
#include "openssl-compat.h"
#include <string.h>
#ifdef _WIN32
#include <io.h>
@ -98,91 +92,7 @@ static const char KEY[] =
"lhdEOj7mAgHwGwwVZWOgs9Lq6vfztnSuhqjha1daESY6kDscPIQ=\n"
"-----END RSA PRIVATE KEY-----\n";
EVP_PKEY *
ssl_getkey(void)
{
EVP_PKEY *key;
BIO *bio;
/* new read-only BIO backed by KEY. */
bio = BIO_new_mem_buf((char*)KEY, -1);
tt_assert(bio);
key = PEM_read_bio_PrivateKey(bio,NULL,NULL,NULL);
BIO_free(bio);
tt_assert(key);
return key;
end:
return NULL;
}
X509 *
ssl_getcert(EVP_PKEY *key)
{
/* Dummy code to make a quick-and-dirty valid certificate with
OpenSSL. Don't copy this code into your own program! It does a
number of things in a stupid and insecure way. */
X509 *x509 = NULL;
X509_NAME *name = NULL;
int nid;
time_t now = time(NULL);
tt_assert(key);
x509 = X509_new();
tt_assert(x509);
tt_assert(0 != X509_set_version(x509, 2));
tt_assert(0 != ASN1_INTEGER_set(X509_get_serialNumber(x509),
(long)now));
name = X509_NAME_new();
tt_assert(name);
nid = OBJ_txt2nid("commonName");
tt_assert(NID_undef != nid);
tt_assert(0 != X509_NAME_add_entry_by_NID(
name, nid, MBSTRING_ASC, (unsigned char*)"example.com",
-1, -1, 0));
X509_set_subject_name(x509, name);
X509_set_issuer_name(x509, name);
X509_NAME_free(name);
X509_time_adj(X509_getm_notBefore(x509), 0, &now);
now += 3600;
X509_time_adj(X509_getm_notAfter(x509), 0, &now);
X509_set_pubkey(x509, key);
tt_assert(0 != X509_sign(x509, key, EVP_sha1()));
return x509;
end:
X509_free(x509);
X509_NAME_free(name);
return NULL;
}
static int disable_tls_11_and_12 = 0;
static SSL_CTX *the_ssl_ctx = NULL;
SSL_CTX *
get_ssl_ctx(void)
{
if (the_ssl_ctx)
return the_ssl_ctx;
the_ssl_ctx = SSL_CTX_new(SSLv23_method());
if (!the_ssl_ctx)
return NULL;
if (disable_tls_11_and_12) {
#ifdef SSL_OP_NO_TLSv1_2
SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_2);
#endif
#ifdef SSL_OP_NO_TLSv1_1
SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_1);
#endif
}
return the_ssl_ctx;
}
static int test_is_done;
static int n_connected;
static int got_close;
@ -192,70 +102,6 @@ static int renegotiate_at = -1;
static int stop_when_connected;
static int pending_connect_events;
static struct event_base *exit_base;
static X509 *the_cert;
EVP_PKEY *the_key;
void
init_ssl(void)
{
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
SSL_library_init();
ERR_load_crypto_strings();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
if (SSLeay() != OPENSSL_VERSION_NUMBER) {
TT_DECLARE("WARN",
("Version mismatch for openssl: compiled with %lx but running with %lx",
(unsigned long)OPENSSL_VERSION_NUMBER, (unsigned long)SSLeay()));
}
#endif
}
static void *
ssl_test_setup(const struct testcase_t *testcase)
{
init_ssl();
the_key = ssl_getkey();
EVUTIL_ASSERT(the_key);
the_cert = ssl_getcert(the_key);
EVUTIL_ASSERT(the_cert);
disable_tls_11_and_12 = 0;
return basic_test_setup(testcase);
}
static int
ssl_test_cleanup(const struct testcase_t *testcase, void *ptr)
{
int ret = basic_test_cleanup(testcase, ptr);
if (!ret) {
return ret;
}
test_is_done = 0;
n_connected = 0;
got_close = 0;
got_error = 0;
got_timeout = 0;
renegotiate_at = -1;
stop_when_connected = 0;
pending_connect_events = 0;
exit_base = NULL;
X509_free(the_cert);
EVP_PKEY_free(the_key);
SSL_CTX_free(the_ssl_ctx);
the_ssl_ctx = NULL;
return 1;
}
const struct testcase_setup_t ssl_setup = {
ssl_test_setup, ssl_test_cleanup
};
/* ====================
@ -285,7 +131,7 @@ enum regress_openssl_type
};
static void
bufferevent_openssl_check_fd(struct bufferevent *bev, int filter)
bufferevent_ssl_check_fd(struct bufferevent *bev, int filter)
{
tt_fd_op(bufferevent_getfd(bev), !=, EVUTIL_INVALID_SOCKET);
tt_fd_op(bufferevent_setfd(bev, EVUTIL_INVALID_SOCKET), ==, 0);
@ -299,7 +145,7 @@ end:
;
}
static void
bufferevent_openssl_check_freed(struct bufferevent *bev)
bufferevent_ssl_check_freed(struct bufferevent *bev)
{
tt_int_op(event_pending(&bev->ev_read, EVLIST_ALL, NULL), ==, 0);
tt_int_op(event_pending(&bev->ev_write, EVLIST_ALL, NULL), ==, 0);
@ -339,14 +185,15 @@ respond_to_number(struct bufferevent *bev, void *ctx)
return;
}
if ((type & REGRESS_OPENSSL_CLIENT) && n == renegotiate_at) {
SSL_renegotiate(bufferevent_openssl_get_ssl(bev));
SSL_renegotiate(bufferevent_ssl_get_ssl(bev));
}
++n;
evbuffer_add_printf(bufferevent_get_output(bev),
"%d\n", n);
TT_BLATHER(("Done reading; now writing."));
bufferevent_enable(bev, EV_WRITE);
bufferevent_disable(bev, EV_READ);
// we shouldn't disable EV_READ here, otherwise we wouldn't got close cb
// bufferevent_disable(bev, EV_READ);
}
static void
@ -372,7 +219,7 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
if (what & BEV_EVENT_CONNECTED) {
SSL *ssl;
++n_connected;
ssl = bufferevent_openssl_get_ssl(bev);
ssl = bufferevent_ssl_get_ssl(bev);
tt_assert(ssl);
peer_cert = SSL_get_peer_certificate(ssl);
if (type & REGRESS_OPENSSL_SERVER) {
@ -391,30 +238,30 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
TT_BLATHER(("Got a good EOF"));
++got_close;
if (type & REGRESS_OPENSSL_FD) {
bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
bufferevent_ssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
}
if (type & REGRESS_OPENSSL_FREED) {
bufferevent_openssl_check_freed(bev);
bufferevent_ssl_check_freed(bev);
}
bufferevent_free(bev);
} else if (what & BEV_EVENT_ERROR) {
TT_BLATHER(("Got an error."));
++got_error;
if (type & REGRESS_OPENSSL_FD) {
bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
bufferevent_ssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
}
if (type & REGRESS_OPENSSL_FREED) {
bufferevent_openssl_check_freed(bev);
bufferevent_ssl_check_freed(bev);
}
bufferevent_free(bev);
} else if (what & BEV_EVENT_TIMEOUT) {
TT_BLATHER(("Got timeout."));
++got_timeout;
if (type & REGRESS_OPENSSL_FD) {
bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
bufferevent_ssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
}
if (type & REGRESS_OPENSSL_FREED) {
bufferevent_openssl_check_freed(bev);
bufferevent_ssl_check_freed(bev);
}
bufferevent_free(bev);
}
@ -434,14 +281,14 @@ open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out,
int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING;
int dirty_shutdown = type & REGRESS_OPENSSL_DIRTY_SHUTDOWN;
if (fd_pair) {
*bev1_out = bufferevent_openssl_socket_new(
*bev1_out = bufferevent_ssl_socket_new(
base, fd_pair[0], ssl1, state1, flags);
*bev2_out = bufferevent_openssl_socket_new(
*bev2_out = bufferevent_ssl_socket_new(
base, fd_pair[1], ssl2, state2, flags);
} else {
*bev1_out = bufferevent_openssl_filter_new(
*bev1_out = bufferevent_ssl_filter_new(
base, underlying_pair[0], ssl1, state1, flags);
*bev2_out = bufferevent_openssl_filter_new(
*bev2_out = bufferevent_ssl_filter_new(
base, underlying_pair[1], ssl2, state2, flags);
}
@ -450,8 +297,8 @@ open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out,
bufferevent_setcb(*bev2_out, respond_to_number, done_writing_cb,
eventcb, (void*)(REGRESS_OPENSSL_SERVER | (long)type));
bufferevent_openssl_set_allow_dirty_shutdown(*bev1_out, dirty_shutdown);
bufferevent_openssl_set_allow_dirty_shutdown(*bev2_out, dirty_shutdown);
bufferevent_ssl_set_allow_dirty_shutdown(*bev1_out, dirty_shutdown);
bufferevent_ssl_set_allow_dirty_shutdown(*bev2_out, dirty_shutdown);
}
static void
@ -478,8 +325,8 @@ regress_bufferevent_openssl(void *arg)
renegotiate_at = 600;
}
ssl1 = SSL_new(get_ssl_ctx());
ssl2 = SSL_new(get_ssl_ctx());
ssl1 = SSL_new(get_ssl_ctx(SSL_IS_CLIENT));
ssl2 = SSL_new(get_ssl_ctx(SSL_IS_SERVER));
SSL_use_certificate(ssl2, the_cert);
SSL_use_PrivateKey(ssl2, the_key);
@ -581,14 +428,14 @@ acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
struct basic_test_data *data = arg;
struct bufferevent *bev;
enum regress_openssl_type type;
SSL *ssl = SSL_new(get_ssl_ctx());
SSL *ssl = SSL_new(get_ssl_ctx(SSL_IS_SERVER));
type = (enum regress_openssl_type)data->setup_data;
SSL_use_certificate(ssl, the_cert);
SSL_use_PrivateKey(ssl, the_key);
bev = bufferevent_openssl_socket_new(
bev = bufferevent_ssl_socket_new(
data->base, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
tt_assert(bev);
@ -618,110 +465,6 @@ struct rwcount
size_t read;
size_t write;
};
static int
bio_rwcount_new(BIO *b)
{
BIO_set_init(b, 0);
BIO_set_data(b, NULL);
return 1;
}
static int
bio_rwcount_free(BIO *b)
{
TT_BLATHER(("bio_rwcount_free: %p", b));
if (!b)
return 0;
if (BIO_get_shutdown(b)) {
BIO_set_init(b, 0);
BIO_set_data(b, NULL);
}
return 1;
}
static int
bio_rwcount_read(BIO *b, char *out, int outlen)
{
struct rwcount *rw = BIO_get_data(b);
ev_ssize_t ret = recv(rw->fd, out, outlen, 0);
++rw->read;
if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
BIO_set_retry_read(b);
}
return ret;
}
static int
bio_rwcount_write(BIO *b, const char *in, int inlen)
{
struct rwcount *rw = BIO_get_data(b);
ev_ssize_t ret = send(rw->fd, in, inlen, 0);
++rw->write;
if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
BIO_set_retry_write(b);
}
return ret;
}
static long
bio_rwcount_ctrl(BIO *b, int cmd, long num, void *ptr)
{
struct rwcount *rw = BIO_get_data(b);
long ret = 0;
switch (cmd) {
case BIO_C_GET_FD:
ret = rw->fd;
break;
case BIO_CTRL_GET_CLOSE:
ret = BIO_get_shutdown(b);
break;
case BIO_CTRL_SET_CLOSE:
BIO_set_shutdown(b, (int)num);
break;
case BIO_CTRL_PENDING:
ret = 0;
break;
case BIO_CTRL_WPENDING:
ret = 0;
break;
case BIO_CTRL_DUP:
case BIO_CTRL_FLUSH:
ret = 1;
break;
}
return ret;
}
static int
bio_rwcount_puts(BIO *b, const char *s)
{
return bio_rwcount_write(b, s, strlen(s));
}
#define BIO_TYPE_LIBEVENT_RWCOUNT 0xff1
static BIO_METHOD *methods_rwcount;
static BIO_METHOD *
BIO_s_rwcount(void)
{
if (methods_rwcount == NULL) {
methods_rwcount = BIO_meth_new(BIO_TYPE_LIBEVENT_RWCOUNT, "rwcount");
if (methods_rwcount == NULL)
return NULL;
BIO_meth_set_write(methods_rwcount, bio_rwcount_write);
BIO_meth_set_read(methods_rwcount, bio_rwcount_read);
BIO_meth_set_puts(methods_rwcount, bio_rwcount_puts);
BIO_meth_set_ctrl(methods_rwcount, bio_rwcount_ctrl);
BIO_meth_set_create(methods_rwcount, bio_rwcount_new);
BIO_meth_set_destroy(methods_rwcount, bio_rwcount_free);
}
return methods_rwcount;
}
static BIO *
BIO_new_rwcount(int close_flag)
{
BIO *result;
if (!(result = BIO_new(BIO_s_rwcount())))
return NULL;
BIO_set_init(result, 1);
BIO_set_data(result, NULL);
BIO_set_shutdown(result, !!close_flag);
return result;
}
static void
regress_bufferevent_openssl_connect(void *arg)
@ -755,10 +498,10 @@ regress_bufferevent_openssl_connect(void *arg)
tt_assert(listener);
tt_assert(evconnlistener_get_fd(listener) >= 0);
ssl = SSL_new(get_ssl_ctx());
ssl = SSL_new(get_ssl_ctx(SSL_IS_CLIENT));
tt_assert(ssl);
bev = bufferevent_openssl_socket_new(
bev = bufferevent_ssl_socket_new(
data->base, -1, ssl,
BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
@ -777,13 +520,8 @@ regress_bufferevent_openssl_connect(void *arg)
/* Possible only when we have fd, since be_openssl can and will overwrite
* bio otherwise before */
if (type & REGRESS_OPENSSL_SLEEP) {
BIO *bio;
rw.fd = bufferevent_getfd(bev);
bio = BIO_new_rwcount(0);
tt_assert(bio);
BIO_set_data(bio, &rw);
SSL_set_bio(ssl, bio, bio);
BIO_setup(ssl, &rw);
}
evbuffer_add_printf(bufferevent_get_output(bev), "1\n");
bufferevent_enable(bev, EV_READ|EV_WRITE);
@ -859,12 +597,12 @@ wm_acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
struct wm_context *ctx = arg;
struct bufferevent *bev;
struct event_base *base = evconnlistener_get_base(listener);
SSL *ssl = SSL_new(get_ssl_ctx());
SSL *ssl = SSL_new(get_ssl_ctx(SSL_IS_SERVER));
SSL_use_certificate(ssl, the_cert);
SSL_use_PrivateKey(ssl, the_key);
bev = bufferevent_openssl_socket_new(
bev = bufferevent_ssl_socket_new(
base, fd, ssl, BUFFEREVENT_SSL_ACCEPTING, ctx->flags);
TT_BLATHER(("wm_transfer-%s(%p): accept",
@ -940,16 +678,16 @@ regress_bufferevent_openssl_wm(void *arg)
tt_assert(listener);
tt_assert(evconnlistener_get_fd(listener) >= 0);
ssl = SSL_new(get_ssl_ctx());
ssl = SSL_new(get_ssl_ctx(SSL_IS_CLIENT));
tt_assert(ssl);
if (type & REGRESS_OPENSSL_FILTER) {
bev = bufferevent_socket_new(data->base, -1, client.flags);
tt_assert(bev);
bev = bufferevent_openssl_filter_new(
bev = bufferevent_ssl_filter_new(
base, bev, ssl, BUFFEREVENT_SSL_CONNECTING, client.flags);
} else {
bev = bufferevent_openssl_socket_new(
bev = bufferevent_ssl_socket_new(
data->base, -1, ssl,
BUFFEREVENT_SSL_CONNECTING,
client.flags);
@ -988,7 +726,7 @@ end:
event_base_loop(base, EVLOOP_ONCE);
}
struct testcase_t ssl_testcases[] = {
struct testcase_t TESTCASES_NAME[] = {
#define T(a) ((void *)(a))
{ "bufferevent_socketpair", regress_bufferevent_openssl,
TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR) },
@ -1057,12 +795,10 @@ struct testcase_t ssl_testcases[] = {
{ "bufferevent_socketpair_timeout_freed_fd", regress_bufferevent_openssl,
TT_ISOLATED, &ssl_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) },
{ "bufferevent_connect", regress_bufferevent_openssl_connect,
TT_FORK|TT_NEED_BASE, &ssl_setup, NULL },
{ "bufferevent_connect_sleep", regress_bufferevent_openssl_connect,
TT_FORK|TT_NEED_BASE, &ssl_setup, T(REGRESS_OPENSSL_SLEEP) },
{ "bufferevent_wm", regress_bufferevent_openssl_wm,
TT_FORK|TT_NEED_BASE, &ssl_setup, NULL },
{ "bufferevent_wm_filter", regress_bufferevent_openssl_wm,