Add mod_openssl
parent
a663088a77
commit
e7b7b1d82c
54
configure.ac
54
configure.ac
|
@ -149,6 +149,60 @@ if test x$ipv6 = xtrue; then
|
|||
fi
|
||||
fi
|
||||
|
||||
|
||||
dnl Check for openssl
|
||||
AC_MSG_CHECKING(for OpenSSL)
|
||||
AC_ARG_WITH(openssl,
|
||||
AC_HELP_STRING([--with-openssl@<:@=DIR@:>@],[Include openssl support (default no)]),
|
||||
[WITH_OPENSSL=$withval],[WITH_OPENSSL=no])
|
||||
|
||||
OPENSSL_CFLAGS=""
|
||||
OPENSSL_LIBS=""
|
||||
|
||||
if test "$WITH_OPENSSL" != "no"; then
|
||||
use_openssl=yes
|
||||
if test "$WITH_OPENSSL" != "yes"; then
|
||||
OPENSSL_CFLAGS="-I$WITH_OPENSSL/include"
|
||||
OPENSSL_LIBS="-L$WITH_OPENSSL/lib"
|
||||
fi
|
||||
else
|
||||
use_openssl=no
|
||||
fi
|
||||
AC_MSG_RESULT([$use_openssl])
|
||||
|
||||
AC_ARG_WITH(openssl-includes,
|
||||
AC_HELP_STRING([--with-openssl-includes=DIR],[OpenSSL includes]),
|
||||
[ use_openssl=yes OPENSSL_CFLAGS="-I$withval" ]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(openssl-libs,
|
||||
AC_HELP_STRING([--with-openssl-libs=DIR],[OpenSSL libraries]),
|
||||
[ use_openssl=yes OPENSSL_LIBS="-L$withval" ]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(kerberos5,
|
||||
AC_HELP_STRING([--with-kerberos5],[use Kerberos5 support with OpenSSL]),
|
||||
[ use_kerberos=yes ], [use_kerberos=no]
|
||||
)
|
||||
|
||||
if test "x$use_openssl" = "xyes"; then
|
||||
if test "x$use_kerberos" != "xyes"; then
|
||||
OPENSSL_CFLAGS="$OPENSSL_CFLAGS -DOPENSSL_NO_KRB5"
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS([openssl/ssl.h])
|
||||
OLDLIBS="$LIBS"
|
||||
AC_CHECK_LIB(crypto, BIO_f_base64, [
|
||||
AC_CHECK_LIB(ssl, SSL_new, [ OPENSSL_LIBS="$OPENSSL_LIBS -lssl -lcrypto"
|
||||
AC_DEFINE(HAVE_LIBSSL, [], [Have libssl]) ], [], [ -lcrypto "$DL_LIB" ])
|
||||
], [], [])
|
||||
LIBS="$OLDLIBS"
|
||||
|
||||
AC_SUBST(OPENSSL_CFLAGS)
|
||||
AC_SUBST(OPENSSL_LIBS)
|
||||
fi
|
||||
|
||||
|
||||
# check for extra compiler options (warning options)
|
||||
if test "${GCC}" = "yes"; then
|
||||
CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99"
|
||||
|
|
|
@ -19,6 +19,7 @@ ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES)
|
|||
|
||||
# OPTION(WITH_OPENSSL "with openssl-support [default: on]" ON)
|
||||
OPTION(WITH_LUA "with lua 5.1 for lua-configfile [default: on]" ON)
|
||||
OPTION(WITH_OPENSSL "with openssl-support [default: off]")
|
||||
OPTION(BUILD_STATIC "build a static lighttpd with all modules added")
|
||||
OPTION(BUILD_EXTRA_WARNINGS "extra warnings")
|
||||
|
||||
|
@ -71,17 +72,6 @@ CHECK_C_SOURCE_COMPILES("
|
|||
return 0;
|
||||
}" HAVE_IPV6)
|
||||
|
||||
# IF(WITH_OPENSSL)
|
||||
# CHECK_INCLUDE_FILES(openssl/ssl.h HAVE_OPENSSL_SSL_H)
|
||||
# IF(HAVE_OPENSSL_SSL_H)
|
||||
# CHECK_LIBRARY_EXISTS(crypto BIO_f_base64 "" HAVE_LIBCRYPTO)
|
||||
# IF(HAVE_LIBCRYPTO)
|
||||
# SET(OPENSSL_NO_KRB5 1)
|
||||
# CHECK_LIBRARY_EXISTS(ssl SSL_new "" HAVE_LIBSSL)
|
||||
# ENDIF(HAVE_LIBCRYPTO)
|
||||
# ENDIF(HAVE_OPENSSL_SSL_H)
|
||||
# ENDIF(WITH_OPENSSL)
|
||||
|
||||
# glib/gthread
|
||||
pkg_check_modules(GTHREAD REQUIRED gthread-2.0)
|
||||
pkg_check_modules(GMODULE REQUIRED gmodule-2.0)
|
||||
|
@ -92,6 +82,17 @@ IF(WITH_LUA)
|
|||
SET(HAVE_LUA_H 1 "Have liblua header")
|
||||
ENDIF(WITH_LUA)
|
||||
|
||||
IF(WITH_OPENSSL)
|
||||
CHECK_INCLUDE_FILES(openssl/ssl.h HAVE_OPENSSL_SSL_H)
|
||||
IF(HAVE_OPENSSL_SSL_H)
|
||||
CHECK_LIBRARY_EXISTS(crypto BIO_f_base64 "" HAVE_LIBCRYPTO)
|
||||
IF(HAVE_LIBCRYPTO)
|
||||
SET(OPENSSL_NO_KRB5 1)
|
||||
CHECK_LIBRARY_EXISTS(ssl SSL_new "" HAVE_LIBSSL)
|
||||
ENDIF(HAVE_LIBCRYPTO)
|
||||
ENDIF(HAVE_OPENSSL_SSL_H)
|
||||
ENDIF(WITH_OPENSSL)
|
||||
|
||||
IF(NOT BUILD_STATIC)
|
||||
CHECK_INCLUDE_FILES(dlfcn.h HAVE_DLFCN_H)
|
||||
ENDIF(NOT BUILD_STATIC)
|
||||
|
@ -252,6 +253,13 @@ ADD_AND_INSTALL_LIBRARY(mod_rewrite "modules/mod_rewrite.c")
|
|||
ADD_AND_INSTALL_LIBRARY(mod_status "modules/mod_status.c")
|
||||
ADD_AND_INSTALL_LIBRARY(mod_vhost "modules/mod_vhost.c")
|
||||
|
||||
IF(HAVE_LIBSSL AND HAVE_LIBCRYPTO)
|
||||
ADD_AND_INSTALL_LIBRARY(mod_openssl "modules/mod_openssl.c")
|
||||
TARGET_LINK_LIBRARIES(mod_openssl ssl)
|
||||
TARGET_LINK_LIBRARIES(mod_openssl crypto)
|
||||
ENDIF(HAVE_LIBSSL AND HAVE_LIBCRYPTO)
|
||||
|
||||
|
||||
ADD_TARGET_PROPERTIES(common LINK_FLAGS ${COMMON_LDFLAGS})
|
||||
ADD_TARGET_PROPERTIES(common COMPILE_FLAGS ${COMMON_CFLAGS})
|
||||
|
||||
|
@ -282,11 +290,6 @@ IF(WIN32)
|
|||
ENDIF(MINGW)
|
||||
ENDIF(WIN32)
|
||||
|
||||
IF(HAVE_LIBSSL AND HAVE_LIBCRYPTO)
|
||||
TARGET_LINK_LIBRARIES(lighttpd ssl)
|
||||
TARGET_LINK_LIBRARIES(lighttpd crypto)
|
||||
ENDIF(HAVE_LIBSSL AND HAVE_LIBCRYPTO)
|
||||
|
||||
IF(NOT WIN32)
|
||||
INSTALL(TARGETS ${L_INSTALL_TARGETS}
|
||||
RUNTIME DESTINATION ${SBINDIR}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
install_libs =
|
||||
|
||||
common_cflags = -I$(top_srcdir)/include -I$(top_builddir)/include
|
||||
common_cflags += $(GTHREAD_CFLAGS) $(GMODULE_CFLAGS) $(LIBEV_CFLAGS) $(LUA_CFLAGS)
|
||||
common_cflags += $(GTHREAD_CFLAGS) $(GMODULE_CFLAGS) $(LIBEV_CFLAGS) $(LUA_CFLAGS) $(OPENSSL_CFLAGS)
|
||||
common_libadd = $(GTHREAD_LIBS) $(GMODULE_LIBS) $(LIBEV_LIBS) $(LUA_LIBS)
|
||||
common_ldflags = -module -export-dynamic -avoid-version -no-undefined $(common_libadd)
|
||||
|
||||
|
@ -57,6 +57,11 @@ libmod_fortune_la_SOURCES = mod_fortune.c
|
|||
libmod_fortune_la_LDFLAGS = $(common_ldflags)
|
||||
# libmod_fortune_la_LIBADD = $(common_libadd)
|
||||
|
||||
install_libs += libmod_openssl.la
|
||||
libmod_openssl_la_SOURCES = mod_openssl.c
|
||||
libmod_openssl_la_LDFLAGS = $(common_ldflags) $(OPENSSL_LIBS)
|
||||
# libmod_openssl_la_LIBADD = $(common_libadd)
|
||||
|
||||
install_libs += libmod_redirect.la
|
||||
libmod_redirect_la_SOURCES = mod_redirect.c
|
||||
libmod_redirect_la_LDFLAGS = $(common_ldflags)
|
||||
|
|
|
@ -0,0 +1,493 @@
|
|||
/*
|
||||
* mod_openssl - ssl support
|
||||
*
|
||||
* Description:
|
||||
* mod_openssl listens on separate sockets for ssl connections (https://...)
|
||||
*
|
||||
* Setups:
|
||||
* openssl - setup a ssl socket; takes a hash of following parameters:
|
||||
* listen - (mandatory) the socket address (same as standard listen)
|
||||
* pemfile - (mandatory) contains key and direct certificate for the key (PEM format)
|
||||
* ca-file - contains certificate chain
|
||||
* ciphers - contains comma separated list of allowed ciphers
|
||||
* allow-ssl2 - boolean option to allow ssl2 (disabled by default)
|
||||
*
|
||||
* Example config:
|
||||
* setup openssl [ "listen": "0.0.0.0:8443", "pemfile": "server.pem" ];
|
||||
* setup openssl [ "listen": "[::]:8443", "pemfile": "server.pem" ];
|
||||
*
|
||||
* Author:
|
||||
* Copyright (c) 2009 Stefan Bühler
|
||||
*/
|
||||
|
||||
#include <lighttpd/base.h>
|
||||
#include <lighttpd/plugin_core.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
LI_API gboolean mod_openssl_init(liModules *mods, liModule *mod);
|
||||
LI_API gboolean mod_openssl_free(liModules *mods, liModule *mod);
|
||||
|
||||
|
||||
typedef struct openssl_connection_ctx openssl_connection_ctx;
|
||||
typedef struct openssl_context openssl_context;
|
||||
|
||||
struct openssl_connection_ctx {
|
||||
SSL *ssl;
|
||||
GByteArray *reuse_read_buffer;
|
||||
};
|
||||
|
||||
struct openssl_context {
|
||||
SSL_CTX *ssl_ctx;
|
||||
};
|
||||
|
||||
static gboolean openssl_con_new(liConnection *con) {
|
||||
liServer *srv = con->srv;
|
||||
openssl_context *ctx = con->srv_sock->data;
|
||||
openssl_connection_ctx *conctx = g_slice_new0(openssl_connection_ctx);
|
||||
|
||||
if (NULL == (conctx->ssl = SSL_new(ctx->ssl_ctx))) {
|
||||
ERROR(srv, "SSL_new: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SSL_set_accept_state(conctx->ssl);
|
||||
|
||||
if (1 != (SSL_set_fd(conctx->ssl, con->sock_watcher.fd))) {
|
||||
ERROR(srv, "SSL_set_fd: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
con->srv_sock_data = conctx;
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
if (conctx->ssl) {
|
||||
SSL_free(conctx->ssl);
|
||||
}
|
||||
|
||||
g_slice_free(openssl_connection_ctx, conctx);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void openssl_con_close(liConnection *con) {
|
||||
openssl_connection_ctx *conctx = con->srv_sock_data;
|
||||
|
||||
if (conctx->ssl) {
|
||||
SSL_shutdown(conctx->ssl); /* TODO: wait for something??? */
|
||||
SSL_free(conctx->ssl);
|
||||
conctx->ssl = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static liNetworkStatus openssl_con_write(liConnection *con, goffset write_max) {
|
||||
const ssize_t blocksize = 16*1024; /* 16k */
|
||||
char *block_data;
|
||||
off_t block_len;
|
||||
ssize_t r;
|
||||
liChunkIter ci;
|
||||
liChunkQueue *cq = con->raw_out;
|
||||
openssl_connection_ctx *conctx = con->srv_sock_data;
|
||||
|
||||
do {
|
||||
if (0 == cq->length)
|
||||
return LI_NETWORK_STATUS_SUCCESS;
|
||||
|
||||
ci = chunkqueue_iter(cq);
|
||||
switch (li_chunkiter_read(con->mainvr, ci, 0, blocksize, &block_data, &block_len)) {
|
||||
case LI_HANDLER_GO_ON:
|
||||
break;
|
||||
case LI_HANDLER_ERROR:
|
||||
default:
|
||||
return LI_NETWORK_STATUS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* SSL_write man-page
|
||||
*
|
||||
* WARNING
|
||||
* When an SSL_write() operation has to be repeated because of
|
||||
* SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
|
||||
* repeated with the same arguments.
|
||||
*
|
||||
*/
|
||||
|
||||
ERR_clear_error();
|
||||
if ((r = SSL_write(conctx->ssl, block_data, block_len)) <= 0) {
|
||||
int ssl_r;
|
||||
unsigned long err;
|
||||
|
||||
switch ((ssl_r = SSL_get_error(conctx->ssl, r))) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return LI_NETWORK_STATUS_WAIT_FOR_EVENT;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
/* perhaps we have error waiting in our error-queue */
|
||||
if (0 != (err = ERR_get_error())) {
|
||||
do {
|
||||
VR_ERROR(con->mainvr, "SSL_write: %s",
|
||||
ERR_error_string(err, NULL));
|
||||
} while (0 != (err = ERR_get_error()));
|
||||
} else if (r == -1) {
|
||||
/* no, but we have errno */
|
||||
switch(errno) {
|
||||
case EPIPE:
|
||||
case ECONNRESET:
|
||||
return LI_NETWORK_STATUS_CONNECTION_CLOSE;
|
||||
default:
|
||||
VR_ERROR(con->mainvr, "SSL_write: %s",
|
||||
g_strerror(errno));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* neither error-queue nor errno ? */
|
||||
VR_ERROR(con->mainvr, "SSL_write: %s",
|
||||
"Unexpected eof");
|
||||
return LI_NETWORK_STATUS_CONNECTION_CLOSE;
|
||||
}
|
||||
|
||||
return LI_NETWORK_STATUS_FATAL_ERROR;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
/* clean shutdown on the remote side */
|
||||
return LI_NETWORK_STATUS_CONNECTION_CLOSE;
|
||||
default:
|
||||
while (0 != (err = ERR_get_error())) {
|
||||
VR_ERROR(con->mainvr, "SSL_write: %s",
|
||||
ERR_error_string(err, NULL));
|
||||
}
|
||||
|
||||
return LI_NETWORK_STATUS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
li_chunkqueue_skip(cq, r);
|
||||
write_max -= r;
|
||||
} while (r == block_len && write_max > 0);
|
||||
|
||||
return LI_NETWORK_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static liNetworkStatus openssl_con_read(liConnection *con) {
|
||||
liChunkQueue *cq = con->raw_in;
|
||||
openssl_connection_ctx *conctx = con->srv_sock_data;
|
||||
GByteArray *buf;
|
||||
|
||||
const ssize_t blocksize = 16*1024; /* 16k */
|
||||
off_t max_read = 16 * blocksize; /* 256k */
|
||||
ssize_t r;
|
||||
off_t len = 0;
|
||||
|
||||
if (cq->limit && cq->limit->limit > 0) {
|
||||
if (max_read > cq->limit->limit - cq->limit->current) {
|
||||
max_read = cq->limit->limit - cq->limit->current;
|
||||
if (max_read <= 0) {
|
||||
max_read = 0; /* we still have to read something */
|
||||
VR_ERROR(con->mainvr, "%s", "li_network_read: fd should be disabled as chunkqueue is already full");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf = conctx->reuse_read_buffer;
|
||||
conctx->reuse_read_buffer = NULL;
|
||||
|
||||
do {
|
||||
ERR_clear_error();
|
||||
|
||||
if (!buf) {
|
||||
buf = g_byte_array_new();
|
||||
g_byte_array_set_size(buf, blocksize);
|
||||
}
|
||||
|
||||
r = SSL_read(conctx->ssl, buf->data, buf->len);
|
||||
if (r < 0) {
|
||||
int oerrno = errno, err;
|
||||
gboolean was_fatal;
|
||||
|
||||
err = SSL_get_error(conctx->ssl, r);
|
||||
|
||||
if (SSL_ERROR_WANT_READ == err || SSL_ERROR_WANT_WRITE == err) {
|
||||
conctx->reuse_read_buffer = buf;
|
||||
return LI_NETWORK_STATUS_WAIT_FOR_EVENT;
|
||||
}
|
||||
g_byte_array_free(buf, TRUE);
|
||||
buf = NULL;
|
||||
|
||||
switch (err) {
|
||||
case SSL_ERROR_SYSCALL:
|
||||
/**
|
||||
* man SSL_get_error()
|
||||
*
|
||||
* SSL_ERROR_SYSCALL
|
||||
* Some I/O error occurred. The OpenSSL error queue may contain more
|
||||
* information on the error. If the error queue is empty (i.e.
|
||||
* ERR_get_error() returns 0), ret can be used to find out more about
|
||||
* the error: If ret == 0, an EOF was observed that violates the
|
||||
* protocol. If ret == -1, the underlying BIO reported an I/O error
|
||||
* (for socket I/O on Unix systems, consult errno for details).
|
||||
*
|
||||
*/
|
||||
while (0 != (err = ERR_get_error())) {
|
||||
VR_ERROR(con->mainvr, "SSL_read: %s",
|
||||
ERR_error_string(err, NULL));
|
||||
}
|
||||
|
||||
switch (oerrno) {
|
||||
case EPIPE:
|
||||
case ECONNRESET:
|
||||
return LI_NETWORK_STATUS_CONNECTION_CLOSE;
|
||||
}
|
||||
|
||||
VR_ERROR(con->mainvr, "SSL_read: %s", g_strerror(oerrno));
|
||||
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
/* clean shutdown on the remote side */
|
||||
return LI_NETWORK_STATUS_CONNECTION_CLOSE;
|
||||
default:
|
||||
was_fatal = FALSE;
|
||||
|
||||
while((err = ERR_get_error())) {
|
||||
switch (ERR_GET_REASON(err)) {
|
||||
case SSL_R_SSL_HANDSHAKE_FAILURE:
|
||||
case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
|
||||
case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
|
||||
case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
|
||||
/* TODO: if (!con->conf.log_ssl_noise) */ continue;
|
||||
break;
|
||||
default:
|
||||
was_fatal = TRUE;
|
||||
break;
|
||||
}
|
||||
/* get all errors from the error-queue */
|
||||
VR_ERROR(con->mainvr, "SSL_read: %s",
|
||||
ERR_error_string(err, NULL));
|
||||
}
|
||||
if (!was_fatal) return LI_NETWORK_STATUS_CONNECTION_CLOSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return LI_NETWORK_STATUS_FATAL_ERROR;
|
||||
} else if (r == 0) {
|
||||
g_byte_array_free(buf, TRUE);
|
||||
return LI_NETWORK_STATUS_CONNECTION_CLOSE;
|
||||
}
|
||||
|
||||
g_byte_array_set_size(buf, r);
|
||||
li_chunkqueue_append_bytearr(cq, buf);
|
||||
buf = NULL;
|
||||
len += r;
|
||||
} while (r == blocksize && len < max_read);
|
||||
|
||||
return LI_NETWORK_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void openssl_sock_release(liServerSocket *srv_sock) {
|
||||
openssl_context *ctx = srv_sock->data;
|
||||
|
||||
if (!ctx) return;
|
||||
|
||||
SSL_CTX_free(ctx->ssl_ctx);
|
||||
g_slice_free(openssl_context, ctx);
|
||||
}
|
||||
|
||||
static void openssl_setup_listen_cb(liServer *srv, int fd, gpointer data) {
|
||||
openssl_context *ctx = data;
|
||||
liServerSocket *srv_sock;
|
||||
UNUSED(data);
|
||||
|
||||
if (-1 == fd) {
|
||||
SSL_CTX_free(ctx->ssl_ctx);
|
||||
g_slice_free(openssl_context, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
srv_sock = li_server_listen(srv, fd);
|
||||
|
||||
srv_sock->data = ctx;
|
||||
|
||||
srv_sock->write_cb = openssl_con_write;
|
||||
srv_sock->read_cb = openssl_con_read;
|
||||
srv_sock->new_cb = openssl_con_new;
|
||||
srv_sock->close_cb = openssl_con_close;
|
||||
srv_sock->release_cb = openssl_sock_release;
|
||||
}
|
||||
|
||||
static gboolean openssl_setup(liServer *srv, liPlugin* p, liValue *val) {
|
||||
openssl_context *ctx;
|
||||
GHashTableIter hti;
|
||||
gpointer hkey, hvalue;
|
||||
GString *htkey;
|
||||
liValue *htval;
|
||||
|
||||
/* options */
|
||||
const char *pemfile = NULL, *ca_file = NULL, *ciphers = NULL;
|
||||
GString *ipstr = NULL;
|
||||
gboolean allow_ssl2 = FALSE;
|
||||
|
||||
UNUSED(p);
|
||||
|
||||
if (val->type != LI_VALUE_HASH) {
|
||||
ERROR(srv, "%s", "openssl expects a hash as parameter");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_hash_table_iter_init(&hti, val->data.hash);
|
||||
while (g_hash_table_iter_next(&hti, &hkey, &hvalue)) {
|
||||
htkey = hkey; htval = hvalue;
|
||||
|
||||
if (g_str_equal(htkey->str, "listen")) {
|
||||
if (htval->type != LI_VALUE_STRING) {
|
||||
ERROR(srv, "%s", "openssl pemfile expects a string as parameter");
|
||||
return FALSE;
|
||||
}
|
||||
ipstr = htval->data.string;
|
||||
} else if (g_str_equal(htkey->str, "pemfile")) {
|
||||
if (htval->type != LI_VALUE_STRING) {
|
||||
ERROR(srv, "%s", "openssl pemfile expects a string as parameter");
|
||||
return FALSE;
|
||||
}
|
||||
pemfile = htval->data.string->str;
|
||||
} else if (g_str_equal(htkey->str, "ca-file")) {
|
||||
if (htval->type != LI_VALUE_STRING) {
|
||||
ERROR(srv, "%s", "openssl ca-file expects a string as parameter");
|
||||
return FALSE;
|
||||
}
|
||||
ca_file = htval->data.string->str;
|
||||
} else if (g_str_equal(htkey->str, "ciphers")) {
|
||||
if (htval->type != LI_VALUE_STRING) {
|
||||
ERROR(srv, "%s", "openssl ciphers expects a string as parameter");
|
||||
return FALSE;
|
||||
}
|
||||
ciphers = htval->data.string->str;
|
||||
} else if (g_str_equal(htkey->str, "allow-ssl2")) {
|
||||
if (htval->type != LI_VALUE_BOOLEAN) {
|
||||
ERROR(srv, "%s", "openssl allow-ssl2 expects a boolean as parameter");
|
||||
return FALSE;
|
||||
}
|
||||
allow_ssl2 = htval->data.boolean;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ipstr) {
|
||||
ERROR(srv, "%s", "openssl needs a listen parameter");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pemfile) {
|
||||
ERROR(srv, "%s", "openssl needs a pemfile");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ctx = g_slice_new0(openssl_context);
|
||||
|
||||
if (NULL == (ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
|
||||
ERROR(srv, "SSL_CTX_new: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error_free_socket;
|
||||
}
|
||||
|
||||
if (!allow_ssl2) {
|
||||
/* disable SSLv2 */
|
||||
if (SSL_OP_NO_SSLv2 != SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2)) {
|
||||
ERROR(srv, "SSL_CTX_set_options(SSL_OP_NO_SSLv2): %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error_free_socket;
|
||||
}
|
||||
}
|
||||
|
||||
if (ciphers) {
|
||||
/* Disable support for low encryption ciphers */
|
||||
if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, ciphers) != 1) {
|
||||
ERROR(srv, "SSL_CTX_set_cipher_list('%s'): %s", ciphers, ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error_free_socket;
|
||||
}
|
||||
}
|
||||
|
||||
if (ca_file) {
|
||||
if (1 != SSL_CTX_load_verify_locations(ctx->ssl_ctx, ca_file, NULL)) {
|
||||
ERROR(srv, "SSL_CTX_load_verify_locations('%s'): %s", ca_file, ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error_free_socket;
|
||||
}
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pemfile, SSL_FILETYPE_PEM) < 0) {
|
||||
ERROR(srv, "SSL_CTX_use_certificate_file('%s'): %s", pemfile,
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error_free_socket;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file (ctx->ssl_ctx, pemfile, SSL_FILETYPE_PEM) < 0) {
|
||||
ERROR(srv, "SSL_CTX_use_PrivateKey_file('%s'): %s", pemfile,
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error_free_socket;
|
||||
}
|
||||
|
||||
if (SSL_CTX_check_private_key(ctx->ssl_ctx) != 1) {
|
||||
ERROR(srv, "SSL: Private key '%s' does not match the certificate public key, reason: %s", pemfile,
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error_free_socket;
|
||||
}
|
||||
|
||||
SSL_CTX_set_default_read_ahead(ctx->ssl_ctx, 1);
|
||||
SSL_CTX_set_mode(ctx->ssl_ctx, SSL_CTX_get_mode(ctx->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
|
||||
li_angel_listen(srv, ipstr, openssl_setup_listen_cb, ctx);
|
||||
|
||||
return TRUE;
|
||||
|
||||
error_free_socket:
|
||||
if (ctx) {
|
||||
if (ctx->ssl_ctx) SSL_CTX_free(ctx->ssl_ctx);
|
||||
g_slice_free(openssl_context, ctx);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static const liPluginOption options[] = {
|
||||
{ NULL, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static const liPluginAction actions[] = {
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const liPluginSetup setups[] = {
|
||||
{ "openssl", openssl_setup },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
static void plugin_init(liServer *srv, liPlugin *p) {
|
||||
UNUSED(srv);
|
||||
|
||||
p->options = options;
|
||||
p->actions = actions;
|
||||
p->setups = setups;
|
||||
}
|
||||
|
||||
gboolean mod_openssl_init(liModules *mods, liModule *mod) {
|
||||
MODULE_VERSION_CHECK(mods);
|
||||
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
if (0 == RAND_status()) {
|
||||
ERROR(mods->main, "SSL: %s", "not enough entropy in the pool");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mod->config = li_plugin_register(mods->main, "mod_openssl", plugin_init);
|
||||
|
||||
return mod->config != NULL;
|
||||
}
|
||||
|
||||
gboolean mod_openssl_free(liModules *mods, liModule *mod) {
|
||||
if (mod->config)
|
||||
li_plugin_free(mods->main, mod->config);
|
||||
|
||||
return TRUE;
|
||||
}
|
Loading…
Reference in New Issue