Basically complete SSL support: Optional OpenSSL and CyaSSl(wolfssl)

Signed-off-by: Jianhui Zhao <jianhuizhao329@gmail.com>
main
Jianhui Zhao 2017-11-10 18:51:49 +08:00
parent a0618b0c07
commit fbbea9df30
9 changed files with 280 additions and 33 deletions

View File

@ -5,7 +5,7 @@ project(libuhttp C)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules/") list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules/")
#set(CMAKE_VERBOSE_MAKEFILE ON) #set(CMAKE_VERBOSE_MAKEFILE ON)
#add_definitions(--DUH_DEBUG) #add_definitions(-DUH_DEBUG)
add_definitions(-O -Wall -Werror --std=gnu99 -D_GNU_SOURCE) add_definitions(-O -Wall -Werror --std=gnu99 -D_GNU_SOURCE)

View File

@ -32,7 +32,7 @@ int main(int argc, char **argv)
{ {
struct ev_loop *loop = EV_DEFAULT; struct ev_loop *loop = EV_DEFAULT;
ev_signal *sig_watcher = NULL; ev_signal *sig_watcher = NULL;
struct uh_server *srv; struct uh_server *srv = NULL;
uh_log_info("libuhttp version: %s\n", uh_version()); uh_log_info("libuhttp version: %s\n", uh_version());
@ -46,15 +46,19 @@ int main(int argc, char **argv)
srv = uh_server_new(loop, "0.0.0.0", 8000); srv = uh_server_new(loop, "0.0.0.0", 8000);
if (!srv) { if (!srv) {
uh_log_err("uh_server_new failed\n"); uh_log_err("uh_server_new failed\n");
return -1; goto err;
} }
if (uh_ssl_init(srv, "server.pem", "server.key") < 0)
goto err;
uh_register_route(srv, "/test", route_test); uh_register_route(srv, "/test", route_test);
uh_log_info("Listen on 8000...\n"); uh_log_info("Listen on 8000...\n");
ev_run(loop, 0); ev_run(loop, 0);
err:
free(sig_watcher); free(sig_watcher);
uh_server_free(srv); uh_server_free(srv);

View File

@ -12,26 +12,59 @@ find_package(CyaSSL)
include_directories(${LIBEV_INCLUDE_DIRS} ${HTTPPARSER_INCLUDE_DIRS}) include_directories(${LIBEV_INCLUDE_DIRS} ${HTTPPARSER_INCLUDE_DIRS})
set(EXTRA_LIBS ${LIBEV_LIBRARIES} ${HTTPPARSER_LIBRARIES}) set(EXTRA_LIBS ${LIBEV_LIBRARIES} ${HTTPPARSER_LIBRARIES})
set(SOURCE_FILES uhttp.c uhttp_log.c uhttp_buf.c) set(SOURCE_FILES uhttp.c uhttp_log.c uhttp_buf.c uhttp_ssl.c)
set(UHTTP_FOUND_SSL OFF)
option(UHTTP_DISABLE_SSL "Disable ssl support" OFF) option(UHTTP_DISABLE_SSL "Disable ssl support" OFF)
option(UHTTP_USE_OPENSSL "Force use OpenSSL as SSL backend" OFF)
option(UHTTP_USE_CYASSL "Force use CyaSSL as SSL backend" OFF)
set(UHTTP_SSL_ENABLED OFF)
set(UHTTP_SSL_ENABLED_CONFIG 0)
set(UHTTP_USE_OPENSSL_CONFIG 0)
set(UHTTP_USE_CYASSL_CONFIG 0)
if(NOT UHTTP_DISABLE_SSL) if(NOT UHTTP_DISABLE_SSL)
if(OPENSSL_FOUND) if(UHTTP_USE_OPENSSL)
set(UHTTP_FOUND_SSL ON) if(NOT OPENSSL_FOUND)
message(FATAL_ERROR "Could NOT find OpenSSL")
endif()
set(UHTTP_SSL_ENABLED ON)
set(UHTTP_SSL_ENABLED_CONFIG 1)
set(UHTTP_USE_OPENSSL_CONFIG 1)
list(APPEND EXTRA_LIBS ${OPENSSL_LIBRARIES}) list(APPEND EXTRA_LIBS ${OPENSSL_LIBRARIES})
include_directories(${OPENSSL_INCLUDE_DIR}) include_directories(${OPENSSL_INCLUDE_DIR})
elseif(CYASSL_FOUND) elseif(UHTTP_USE_CYASSL)
set(UHTTP_FOUND_SSL ON) if (NOT CYASSL_FOUND)
message(FATAL_ERROR "Could NOT find CyaSSL")
endif()
set(UHTTP_SSL_ENABLED ON)
set(UHTTP_SSL_ENABLED_CONFIG 1)
set(UHTTP_USE_CYASSL_CONFIG 1)
list(APPEND EXTRA_LIBS ${CYASSL_LIBRARIES}) list(APPEND EXTRA_LIBS ${CYASSL_LIBRARIES})
include_directories(${CYASSL_INCLUDE_DIR}) include_directories(${CYASSL_INCLUDE_DIR})
endif() endif()
endif()
if(UHTTP_FOUND_SSL) if(NOT UHTTP_SSL_ENABLED)
list(APPEND SOURCE_FILES uhttp_ssl.c) if(OPENSSL_FOUND)
set(UHTTP_SSL_ENABLED ON)
set(UHTTP_SSL_ENABLED_CONFIG 1)
set(UHTTP_USE_OPENSSL_CONFIG 1)
list(APPEND EXTRA_LIBS ${OPENSSL_LIBRARIES})
include_directories(${OPENSSL_INCLUDE_DIR})
elseif(CYASSL_FOUND)
set(UHTTP_SSL_ENABLED ON)
set(UHTTP_SSL_ENABLED_CONFIG 1)
set(UHTTP_USE_CYASSL_CONFIG 1)
list(APPEND EXTRA_LIBS ${CYASSL_LIBRARIES})
include_directories(${CYASSL_INCLUDE_DIR})
endif()
endif()
endif() endif()
add_library(uhttp SHARED ${SOURCE_FILES}) add_library(uhttp SHARED ${SOURCE_FILES})
@ -52,7 +85,10 @@ install(
) )
message("") message("")
message(STATUS "UHTTP_VERSION = ${UHTTP_VERSION_MAJOR}.${UHTTP_VERSION_MINOR}") message(STATUS "UHTTP_VERSION: ${UHTTP_VERSION_MAJOR}.${UHTTP_VERSION_MINOR}")
message(STATUS "UHTTP_DISABLE_SSL = ${UHTTP_DISABLE_SSL}") if(UHTTP_USE_OPENSSL_CONFIG)
message(STATUS "UHTTP_FOUND_SSL = ${UHTTP_FOUND_SSL}") message(STATUS "UHTTP_SSL_ENABLED: OpenSSL")
message("") elseif(UHTTP_USE_CYASSL_CONFIG)
message(STATUS "UHTTP_SSL_ENABLED: CyaSSL")
endif()
message("")

View File

@ -1,14 +1,13 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <unistd.h>
#include <assert.h> #include <assert.h>
#include <sys/socket.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <http_parser.h>
#include "uhttp.h" #include "uhttp.h"
#include "uhttp_internal.h" #include "uhttp_internal.h"
#include "uhttp_ssl.h"
static struct { static struct {
int code; int code;
@ -61,6 +60,8 @@ static void uh_connection_destroy(struct uh_connection *con)
ev_timer_stop(loop, &con->timer_watcher); ev_timer_stop(loop, &con->timer_watcher);
list_del(&con->list); list_del(&con->list);
uh_ssl_free(con);
free(con); free(con);
} }
} }
@ -201,9 +202,9 @@ static void connection_read_cb(struct ev_loop *loop, ev_io *w, int revents)
base = buf->base + buf->len; base = buf->base + buf->len;
len = read(w->fd, base, UH_BUFFER_SIZE); len = uh_ssl_read(con, base, UH_BUFFER_SIZE);
if (unlikely(len < 0)) { if (unlikely(len < 0)) {
if (errno == EINTR) if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
return; return;
uh_log_err("read"); uh_log_err("read");
uh_send_error(con, 500, NULL); uh_send_error(con, 500, NULL);
@ -234,7 +235,7 @@ static void connection_write_cb(struct ev_loop *loop, ev_io *w, int revents)
struct uh_buf *buf = &con->write_buf; struct uh_buf *buf = &con->write_buf;
if (buf->len > 0) { if (buf->len > 0) {
int len = write(w->fd, buf->base, buf->len); int len = uh_ssl_write(con, buf->base, buf->len);
uh_buf_remove(buf, len); uh_buf_remove(buf, len);
} }
@ -252,8 +253,6 @@ static void connection_write_cb(struct ev_loop *loop, ev_io *w, int revents)
static void uh_accept_cb(struct ev_loop *loop, ev_io *w, int revents) static void uh_accept_cb(struct ev_loop *loop, ev_io *w, int revents)
{ {
int sock = -1; int sock = -1;
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
struct uh_server *srv = container_of(w, struct uh_server, read_watcher); struct uh_server *srv = container_of(w, struct uh_server, read_watcher);
struct uh_connection *con = NULL; struct uh_connection *con = NULL;
ev_io *read_watcher, *write_watcher; ev_io *read_watcher, *write_watcher;
@ -268,15 +267,13 @@ static void uh_accept_cb(struct ev_loop *loop, ev_io *w, int revents)
con->srv = srv; con->srv = srv;
list_add(&con->list, &srv->connections); list_add(&con->list, &srv->connections);
sock = accept4(w->fd, (struct sockaddr *)&addr, &addr_len, SOCK_NONBLOCK | SOCK_CLOEXEC); sock = uh_ssl_accept(srv, con);
if (unlikely(sock < 0)) { if (unlikely(sock < 0)) {
if (errno != EINTR) if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
uh_log_err("accept"); uh_log_err("accept");
goto err; goto err;
} }
con->sock = sock;
read_watcher = &con->read_watcher; read_watcher = &con->read_watcher;
ev_io_init(read_watcher, connection_read_cb, sock, EV_READ); ev_io_init(read_watcher, connection_read_cb, sock, EV_READ);
ev_io_start(loop,read_watcher); ev_io_start(loop,read_watcher);
@ -372,6 +369,8 @@ void uh_server_free(struct uh_server *srv)
free(r->path); free(r->path);
free(r); free(r);
} }
uh_ssl_ctx_free(srv);
free(srv); free(srv);
} }

View File

@ -86,4 +86,6 @@ int uh_register_route(struct uh_server *srv, const char *path, uh_route_handler_
struct uh_value *uh_get_url(struct uh_connection *con); struct uh_value *uh_get_url(struct uh_connection *con);
struct uh_value *uh_get_header(struct uh_connection *con, const char *name); struct uh_value *uh_get_header(struct uh_connection *con, const char *name);
int uh_ssl_init(struct uh_server *srv, const char *cert, const char *key);
#endif #endif

View File

@ -5,8 +5,8 @@
#define UHTTP_VERSION_MINOR @UHTTP_VERSION_MINOR@ #define UHTTP_VERSION_MINOR @UHTTP_VERSION_MINOR@
#define UHTTP_VERSION_STRING "@UHTTP_VERSION_MAJOR@.@UHTTP_VERSION_MINOR@" #define UHTTP_VERSION_STRING "@UHTTP_VERSION_MAJOR@.@UHTTP_VERSION_MINOR@"
#define UHTTP_SSL_ENABLED @SSL_ENABLED@ #define UHTTP_SSL_ENABLED @UHTTP_SSL_ENABLED_CONFIG@
#define UHTTP_USE_OPENSSL @USE_OPENSSL@ #define UHTTP_USE_OPENSSL @UHTTP_USE_OPENSSL_CONFIG@
#define UHTTP_USE_CYASSL @USE_CYASSL@ #define UHTTP_USE_CYASSL @UHTTP_USE_CYASSL_CONFIG@
#endif #endif

View File

@ -1,6 +1,8 @@
#ifndef _UHTTP_INTERNAL_H #ifndef _UHTTP_INTERNAL_H
#define _UHTTP_INTERNAL_H #define _UHTTP_INTERNAL_H
#include <http_parser.h>
#include "list.h" #include "list.h"
#include "uhttp.h" #include "uhttp.h"
@ -21,6 +23,9 @@ struct uh_route {
struct uh_server { struct uh_server {
int sock; int sock;
#if (UHTTP_SSL_ENABLED)
void *ssl_ctx;
#endif
ev_io read_watcher; ev_io read_watcher;
struct ev_loop *loop; struct ev_loop *loop;
struct list_head routes; struct list_head routes;
@ -41,6 +46,9 @@ struct uh_request {
struct uh_connection { struct uh_connection {
int sock; int sock;
#if (UHTTP_SSL_ENABLED)
void *ssl;
#endif
unsigned char flags; unsigned char flags;
struct uh_buf read_buf; struct uh_buf read_buf;
struct uh_buf write_buf; struct uh_buf write_buf;

186
src/uhttp_ssl.c 100644 → 100755
View File

@ -0,0 +1,186 @@
#include "uhttp_ssl.h"
#include <unistd.h>
#include <sys/socket.h>
#if (UHTTP_USE_OPENSSL)
#include <openssl/ssl.h>
#include <openssl/err.h>
#elif (UHTTP_USE_CYASSL)
#include <wolfssl/ssl.h>
#endif
int uh_ssl_init(struct uh_server *srv, const char *cert, const char *key)
{
#if (UHTTP_USE_OPENSSL)
SSL_CTX *ctx = NULL;
#elif (UHTTP_USE_CYASSL)
WOLFSSL_CTX *ctx = NULL;
#endif
#if (UHTTP_USE_OPENSSL)
SSL_library_init();
/* creates a new SSL_CTX object */
ctx = SSL_CTX_new(SSLv23_server_method());
if (!ctx) {
uh_log_err("Failed to create SSL context");
return -1;
}
/* loads the first certificate stored in file into ctx */
if (!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) {
uh_log_err("OpenSSL Error: loading certificate file failed");
goto err;
}
/*
* adds the first private RSA key found in file to ctx.
*
* checks the consistency of a private key with the corresponding
* certificate loaded into ctx. If more than one key/certificate
* pair (RSA/DSA) is installed, the last item installed will be checked.
*/
if (!SSL_CTX_use_RSAPrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
uh_log_err("OpenSSL Error: loading key failed");
goto err;
}
#elif (UHTTP_USE_CYASSL)
/* Initialize wolfSSL */
wolfSSL_Init();
/* Create the WOLFSSL_CTX */
ctx = wolfSSL_CTX_new(wolfSSLv23_server_method());
if (!ctx) {
uh_log_err("Failed to create wolfSSL context");
return -1;
}
/* Load server certificates into WOLFSSL_CTX */
if (wolfSSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) != SSL_SUCCESS) {
uh_log_err("wolfSSL Error: loading certificate file failed");
goto err;
}
/* Load keys */
if (wolfSSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) != SSL_SUCCESS){
uh_log_err("wolfSSL Error: loading key failed");
goto err;
}
#endif
#if (UHTTP_SSL_ENABLED)
srv->ssl_ctx = ctx;
#endif
return 0;
#if (UHTTP_SSL_ENABLED)
err:
#if (UHTTP_USE_OPENSSL)
SSL_CTX_free(ctx);
#elif (UHTTP_USE_CYASSL)
wolfSSL_CTX_free(ctx);
wolfSSL_Cleanup();
#endif
#endif
return -1;
}
void uh_ssl_ctx_free(struct uh_server *srv)
{
#if (UHTTP_SSL_ENABLED)
if (!srv->ssl_ctx)
return;
#endif
#if (UHTTP_USE_OPENSSL)
SSL_CTX_free(srv->ssl_ctx);
#elif (UHTTP_USE_CYASSL)
wolfSSL_CTX_free(srv->ssl_ctx);
#endif
}
void uh_ssl_free(struct uh_connection *con)
{
#if (UHTTP_SSL_ENABLED)
if (!con->ssl)
return;
#endif
#if (UHTTP_USE_OPENSSL)
SSL_free(con->ssl);
#elif (UHTTP_USE_CYASSL)
wolfSSL_free(con->ssl);
#endif
}
int uh_ssl_read(struct uh_connection *con, void *buf, int count)
{
#if (UHTTP_SSL_ENABLED)
if (!con->ssl)
return read(con->sock, buf, count);
#endif
#if (UHTTP_USE_OPENSSL)
return SSL_read(con->ssl, buf, count);
#elif (UHTTP_USE_CYASSL)
return wolfSSL_read(con->ssl, buf, count);
#endif
return read(con->sock, buf, count);
}
int uh_ssl_write(struct uh_connection *con, void *buf, int count)
{
#if (UHTTP_SSL_ENABLED)
if (!con->ssl)
return write(con->sock, buf, count);
#endif
#if (UHTTP_USE_OPENSSL)
return SSL_write(con->ssl, buf, count);
#elif (UHTTP_USE_CYASSL)
return wolfSSL_write(con->ssl, buf, count);
#endif
return write(con->sock, buf, count);
}
int uh_ssl_accept(struct uh_server *srv, struct uh_connection *con)
{
int sock = -1;
sock = accept4(srv->sock, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (sock < 0)
return sock;
con->sock = sock;
#if (UHTTP_SSL_ENABLED)
if (!srv->ssl_ctx)
return sock;
#endif
#if (UHTTP_USE_OPENSSL)
con->ssl = SSL_new(srv->ssl_ctx);
if (!con->ssl)
return -1;
SSL_set_fd(con->ssl, sock);
if (!SSL_accept(con->ssl)) {
uh_log_err("SSL_accept Error: %s", ERR_reason_error_string(ERR_get_error()));
return -1;
}
#elif (UHTTP_USE_CYASSL)
con->ssl = wolfSSL_new(srv->ssl_ctx);
if (!con->ssl)
return -1;
wolfSSL_set_fd(con->ssl, sock);
#endif
return sock;
}

12
src/uhttp_ssl.h 100755
View File

@ -0,0 +1,12 @@
#ifndef _UHTTP_SSL_H
#define _UHTTP_SSL_H
#include "uhttp_internal.h"
void uh_ssl_ctx_free(struct uh_server *srv);
void uh_ssl_free(struct uh_connection *con);
int uh_ssl_read(struct uh_connection *con, void *buf, int count);
int uh_ssl_write(struct uh_connection *con, void *buf, int count);
int uh_ssl_accept(struct uh_server *srv, struct uh_connection *con);
#endif