mirror of
https://github.com/civetweb/civetweb
synced 2025-03-28 21:13:27 +00:00
Add GnutTLS support.
Signed-off-by: catch-error <mirko.kraft@gmx.ch>
This commit is contained in:
parent
4e356787f6
commit
cf1e77659d
@ -237,8 +237,11 @@ message(STATUS "Compile for OpenSSL 1.1 API - ${CIVETWEB_SSL_OPENSSL_API_1_1}")
|
||||
option(CIVETWEB_SSL_OPENSSL_API_3_0 "Use the OpenSSL 3.0 API" OFF)
|
||||
message(STATUS "Compile for OpenSSL 3.0 API - ${CIVETWEB_SSL_OPENSSL_API_3_0}")
|
||||
|
||||
option(CIVETWEB_ENABLE_GNUTLS "Use the GnuTls" OFF)
|
||||
message(STATUS "SSL support (GnuTLS) - ${CIVETWEB_ENABLE_GNUTLS}")
|
||||
|
||||
option(CIVETWEB_ENABLE_MBEDTLS "Use the MbedTls" OFF)
|
||||
message(STATUS "SSL support - ${CIVETWEB_ENABLE_MBEDTLS}")
|
||||
message(STATUS "SSL support (MbedTLS) - ${CIVETWEB_ENABLE_MBEDTLS}")
|
||||
|
||||
# Dynamically load or link the SSL libraries
|
||||
cmake_dependent_option(
|
||||
@ -538,6 +541,8 @@ if (CIVETWEB_ENABLE_MEMORY_DEBUGGING)
|
||||
endif()
|
||||
if (NOT CIVETWEB_ENABLE_SSL)
|
||||
add_definitions(-DNO_SSL)
|
||||
elseif (CIVETWEB_ENABLE_GNUTLS)
|
||||
add_definitions(-DUSE_GNUTLS)
|
||||
elseif (CIVETWEB_ENABLE_MBEDTLS)
|
||||
add_definitions(-DUSE_MBEDTLS)
|
||||
elseif (NOT CIVETWEB_ENABLE_SSL_DYNAMIC_LOADING)
|
||||
|
4
Makefile
4
Makefile
@ -97,6 +97,9 @@ endif
|
||||
|
||||
ifdef NO_SSL
|
||||
CFLAGS += -DNO_SSL
|
||||
else ifdef WITH_GNUTLS
|
||||
CFLAGS += -DUSE_GNUTLS
|
||||
LIBS += -lgnutls -lhogweed -lgmp -lnettle
|
||||
else ifdef WITH_MBEDTLS
|
||||
CFLAGS += -DUSE_MBEDTLS
|
||||
LIBS += -lmbedcrypto -lmbedtls -lmbedx509
|
||||
@ -303,6 +306,7 @@ help:
|
||||
@echo " WITH_CPP=1 build library with c++ classes"
|
||||
@echo " WITH_EXPERIMENTAL=1 build with experimental features"
|
||||
@echo " WITH_DAEMONIZE=1 build with daemonize."
|
||||
@echo " WITH_GNUTLS=1 build with GnuTLS support."
|
||||
@echo " WITH_MBEDTLS=1 build with mbedTLS support."
|
||||
@echo " WITH_OPENSSL_API_1_0=1 build with OpenSSL 1.0.x support."
|
||||
@echo " WITH_OPENSSL_API_1_1=1 build with OpenSSL 1.1.x support."
|
||||
|
@ -134,6 +134,8 @@ simplicity by a carefully selected list of features:
|
||||
|
||||
[Mbed TLS](https://github.com/ARMmbed/mbedtls)
|
||||
|
||||
[GNU TLS](https://gnutls.org)
|
||||
|
||||
|
||||
Support
|
||||
-------
|
||||
|
@ -179,8 +179,9 @@ make build COPT="-DNDEBUG -DNO_CGI"
|
||||
| `SSL_ALREADY_INITIALIZED` | do not initialize libcrypto |
|
||||
| `OPENSSL_API_1_0` | Use OpenSSL V1.0.x interface |
|
||||
| `OPENSSL_API_1_1` | Use OpenSSL V1.1.x interface |
|
||||
| `OPENSSL_API_3_0` | Use OpenSSL V3.0.x interface |
|
||||
| `USE_MBEDTLS` | Use MbedTLS (cannot be combined with OPENSSL_API_*) |
|
||||
| `OPENSSL_API_3_0` | Use OpenSSL V3.0.x interface |
|
||||
| `USE_GNUTLS` | Use GnuTLS (cannot be combined with OPENSSL_API_* or USE_MBEDTLS) |
|
||||
| `USE_MBEDTLS` | Use MbedTLS (cannot be combined with OPENSSL_API_* or USE_GNUTLS) |
|
||||
| | |
|
||||
| `BUILD_DATE` | define as a string to be used as build id instead of __DATE__ |
|
||||
| | |
|
||||
|
@ -692,7 +692,8 @@ The OpenSSL cipher string uses different cipher names than IANA
|
||||
(see [this mapping](https://testssl.sh/openssl-iana.mapping.html)).
|
||||
|
||||
In case CivetWeb is built with a TLS library other than OpenSSL
|
||||
(e.g., [mbedTLS](https://tls.mbed.org/supported-ssl-ciphersuites)),
|
||||
(e.g., [mbedTLS](https://tls.mbed.org/supported-ssl-ciphersuites)
|
||||
or [GnuTLS](https://www.gnutls.org/manual/html_node/Supported-ciphersuites.html)),
|
||||
the cipher names may be different.
|
||||
|
||||
### ssl\_default\_verify\_paths `yes`
|
||||
|
20
docs/gnutls.md
Normal file
20
docs/gnutls.md
Normal file
@ -0,0 +1,20 @@
|
||||
#### Use GnuTLS instead of OpenSSL
|
||||
=====
|
||||
|
||||
1 [Build libgmp](https://gmplib.org)
|
||||
|
||||
- 1.1 [Download source](https://gmplib.org/#DOWNLOAD)
|
||||
- 1.2 ./configure && make && make install
|
||||
|
||||
2 [Build libhogweed and libnettle](https://www.lysator.liu.se/~nisse/nettle/)
|
||||
|
||||
- 2.1 [Download source](https://ftp.gnu.org/gnu/nettle/)
|
||||
- 2.2 ./configure && make && make install
|
||||
|
||||
3 Build civetweb
|
||||
|
||||
- make build WITH_GNUTLS=1
|
||||
|
||||
4 Run civetweb
|
||||
- export LD_LIBRARY_PATH=/usr/local/lib/:$LD_LIBRARY_PATH
|
||||
- ./civetweb -listening_ports 8443s -ssl_certificate resources/cert/server.pem -document_root ./test/htmldir/
|
@ -17,6 +17,7 @@ clang-format -i src/handle_form.inl
|
||||
clang-format -i src/response.inl
|
||||
clang-format -i src/http2.inl
|
||||
clang-format -i src/mod_mbedtls.inl
|
||||
clang-format -i src/mod_gnutls.inl
|
||||
|
||||
clang-format -i src/third_party/civetweb_lua.h
|
||||
|
||||
|
@ -47,7 +47,12 @@ endif()
|
||||
|
||||
# We need to link OpenSSL if not dynamically loading
|
||||
if (CIVETWEB_ENABLE_SSL)
|
||||
if (CIVETWEB_ENABLE_MBEDTLS)
|
||||
if (CIVETWEB_ENABLE_GNUTLS)
|
||||
find_package(GnuTLS)
|
||||
include_directories(${GNUTLS_INCLUDE_DIR})
|
||||
message(STATUS "GnuTLS include directory: ${GNUTLS_INCLUDE_DIR}")
|
||||
target_link_libraries(civetweb-c-library ${GNUTLS_LIBRARIES})
|
||||
elseif (CIVETWEB_ENABLE_MBEDTLS)
|
||||
find_package(MbedTLS)
|
||||
include_directories(${MbedTLS_INCLUDE_DIR})
|
||||
message(STATUS "MbedTLS include directory: ${MbedTLS_INCLUDE_DIR}")
|
||||
|
164
src/civetweb.c
164
src/civetweb.c
@ -1594,8 +1594,9 @@ static int mg_init_library_called = 0;
|
||||
static int mg_openssl_initialized = 0;
|
||||
#endif
|
||||
#if !defined(OPENSSL_API_1_0) && !defined(OPENSSL_API_1_1) \
|
||||
&& !defined(OPENSSL_API_3_0) && !defined(USE_MBEDTLS)
|
||||
#error "Please define OPENSSL_API_#_# or USE_MBEDTLS"
|
||||
&& !defined(OPENSSL_API_3_0) && !defined(USE_MBEDTLS) \
|
||||
&& !defined(USE_GNUTLS)
|
||||
#error "Please define OPENSSL_API_#_# or USE_MBEDTLS or USE_GNUTLS"
|
||||
#endif
|
||||
#if defined(OPENSSL_API_1_0) && defined(OPENSSL_API_1_1)
|
||||
#error "Multiple OPENSSL_API versions defined"
|
||||
@ -1608,7 +1609,10 @@ static int mg_openssl_initialized = 0;
|
||||
#endif
|
||||
#if (defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1) \
|
||||
|| defined(OPENSSL_API_3_0)) \
|
||||
&& defined(USE_MBEDTLS)
|
||||
&& (defined(USE_MBEDTLS) || defined(USE_GNUTLS))
|
||||
#error "Multiple SSL libraries defined"
|
||||
#endif
|
||||
#if defined(USE_MBEDTLS) && defined(USE_GNUTLS)
|
||||
#error "Multiple SSL libraries defined"
|
||||
#endif
|
||||
#endif
|
||||
@ -1773,11 +1777,15 @@ typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
|
||||
/* SSL: mbedTLS vs. no-ssl vs. OpenSSL */
|
||||
/* SSL: mbedTLS vs. GnuTLS vs. no-ssl vs. OpenSSL */
|
||||
#if defined(USE_MBEDTLS)
|
||||
/* mbedTLS */
|
||||
#include "mod_mbedtls.inl"
|
||||
|
||||
#elif defined(USE_GNUTLS)
|
||||
/* GnuTLS */
|
||||
#include "mod_gnutls.inl"
|
||||
|
||||
#elif defined(NO_SSL)
|
||||
/* no SSL */
|
||||
typedef struct SSL SSL; /* dummy for SSL argument to push/pull */
|
||||
@ -2564,7 +2572,6 @@ struct mg_connection {
|
||||
* versions. For the current definition, see
|
||||
* mg_get_connection_info_impl */
|
||||
#endif
|
||||
|
||||
SSL *ssl; /* SSL descriptor */
|
||||
struct socket client; /* Connected client */
|
||||
time_t conn_birth_time; /* Time (wall clock) when connection was
|
||||
@ -6131,7 +6138,7 @@ push_inner(struct mg_context *ctx,
|
||||
return -2;
|
||||
}
|
||||
|
||||
#if defined(NO_SSL) && !defined(USE_MBEDTLS)
|
||||
#if defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS)
|
||||
if (ssl) {
|
||||
return -2;
|
||||
}
|
||||
@ -6157,6 +6164,16 @@ push_inner(struct mg_context *ctx,
|
||||
err = 0;
|
||||
}
|
||||
} else
|
||||
#elif defined(USE_GNUTLS)
|
||||
if (ssl != NULL) {
|
||||
n = gtls_ssl_write(ssl, (const unsigned char *)buf, (size_t) len);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "SSL write failed (%d): %s", n, gnutls_strerror(n));
|
||||
return -2;
|
||||
} else {
|
||||
err = 0;
|
||||
}
|
||||
} else
|
||||
#elif !defined(NO_SSL)
|
||||
if (ssl != NULL) {
|
||||
ERR_clear_error();
|
||||
@ -6413,6 +6430,62 @@ pull_inner(FILE *fp,
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
#elif defined(USE_GNUTLS)
|
||||
} else if (conn->ssl != NULL) {
|
||||
struct mg_pollfd pfd[2];
|
||||
size_t to_read;
|
||||
int pollres;
|
||||
unsigned int num_sock = 1;
|
||||
|
||||
to_read = gnutls_record_check_pending(conn->ssl->sess);
|
||||
|
||||
if (to_read > 0) {
|
||||
/* We already know there is no more data buffered in conn->buf
|
||||
* but there is more available in the SSL layer. So don't poll
|
||||
* conn->client.sock yet. */
|
||||
|
||||
pollres = 1;
|
||||
if (to_read > (size_t)len)
|
||||
to_read = (size_t)len;
|
||||
} else {
|
||||
pfd[0].fd = conn->client.sock;
|
||||
pfd[0].events = POLLIN;
|
||||
|
||||
if (conn->phys_ctx->context_type == CONTEXT_SERVER) {
|
||||
pfd[num_sock].fd =
|
||||
conn->phys_ctx->thread_shutdown_notification_socket;
|
||||
pfd[num_sock].events = POLLIN;
|
||||
num_sock++;
|
||||
}
|
||||
|
||||
to_read = (size_t)len;
|
||||
|
||||
pollres = mg_poll(pfd,
|
||||
num_sock,
|
||||
(int)(timeout * 1000.0),
|
||||
&(conn->phys_ctx->stop_flag));
|
||||
|
||||
if (!STOP_FLAG_IS_ZERO(&conn->phys_ctx->stop_flag)) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
if (pollres > 0) {
|
||||
nread = gtls_ssl_read(conn->ssl, (unsigned char *)buf, to_read);
|
||||
if (nread < 0) {
|
||||
fprintf(stderr, "SSL read failed (%d): %s", nread, gnutls_strerror(nread));
|
||||
return -2;
|
||||
} else {
|
||||
err = 0;
|
||||
}
|
||||
} else if (pollres < 0) {
|
||||
/* Error */
|
||||
return -2;
|
||||
} else {
|
||||
/* pollres = 0 means timeout */
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
#elif !defined(NO_SSL)
|
||||
} else if (conn->ssl != NULL) {
|
||||
int ssl_pending;
|
||||
@ -9555,7 +9628,7 @@ connect_socket(
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(NO_SSL_DL)
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS) && !defined(NO_SSL_DL)
|
||||
#if defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)
|
||||
if (use_ssl && (TLS_client_method == NULL)) {
|
||||
if (error != NULL) {
|
||||
@ -16660,6 +16733,37 @@ mg_sslctx_init(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
|
||||
: 0;
|
||||
}
|
||||
|
||||
#elif defined(USE_GNUTLS)
|
||||
/* Check if SSL is required.
|
||||
* If so, set up ctx->ssl_ctx pointer. */
|
||||
static int
|
||||
mg_sslctx_init(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
|
||||
{
|
||||
if (!phys_ctx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dom_ctx) {
|
||||
dom_ctx = &(phys_ctx->dd);
|
||||
}
|
||||
|
||||
if (!is_ssl_port_used(dom_ctx->config[LISTENING_PORTS])) {
|
||||
/* No SSL port is set. No need to setup SSL. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
dom_ctx->ssl_ctx = (SSL_CTX *)mg_calloc(1, sizeof(*dom_ctx->ssl_ctx));
|
||||
if (dom_ctx->ssl_ctx == NULL) {
|
||||
fprintf(stderr, "ssl_ctx malloc failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gtls_sslctx_init(dom_ctx->ssl_ctx, dom_ctx->config[SSL_CERTIFICATE])
|
||||
== 0
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
#elif !defined(NO_SSL)
|
||||
|
||||
static int ssl_use_pem_file(struct mg_context *phys_ctx,
|
||||
@ -17935,7 +18039,7 @@ uninitialize_openssl(void)
|
||||
#endif /* OPENSSL_API_1_1 || OPENSSL_API_3_0 */
|
||||
}
|
||||
}
|
||||
#endif /* !defined(NO_SSL) && !defined(USE_MBEDTLS) */
|
||||
#endif /* !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS) */
|
||||
|
||||
|
||||
#if !defined(NO_FILESYSTEMS)
|
||||
@ -18207,6 +18311,11 @@ close_connection(struct mg_connection *conn)
|
||||
mbed_ssl_close(conn->ssl);
|
||||
conn->ssl = NULL;
|
||||
}
|
||||
#elif defined(USE_GNUTLS)
|
||||
if (conn->ssl != NULL) {
|
||||
gtls_ssl_close(conn->ssl);
|
||||
conn->ssl = NULL;
|
||||
}
|
||||
#elif !defined(NO_SSL)
|
||||
if (conn->ssl != NULL) {
|
||||
/* Run SSL_shutdown twice to ensure completely close SSL connection
|
||||
@ -18278,7 +18387,7 @@ mg_close_connection(struct mg_connection *conn)
|
||||
|
||||
close_connection(conn);
|
||||
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) // TODO: mbedTLS client
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS) // TODO: mbedTLS client
|
||||
if (((conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT)
|
||||
|| (conn->phys_ctx->context_type == CONTEXT_WS_CLIENT))
|
||||
&& (conn->phys_ctx->dd.ssl_ctx != NULL)) {
|
||||
@ -18380,7 +18489,7 @@ mg_connect_client_impl(const struct mg_client_options *client_options,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) // TODO: mbedTLS client
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS) // TODO: mbedTLS client
|
||||
#if (defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)) \
|
||||
&& !defined(NO_SSL_DL)
|
||||
|
||||
@ -18457,7 +18566,7 @@ mg_connect_client_impl(const struct mg_client_options *client_options,
|
||||
error->text_buffer_size,
|
||||
"Can not create mutex");
|
||||
}
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) // TODO: mbedTLS client
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS) // TODO: mbedTLS client
|
||||
SSL_CTX_free(conn->dom_ctx->ssl_ctx);
|
||||
#endif
|
||||
closesocket(sock);
|
||||
@ -18465,7 +18574,7 @@ mg_connect_client_impl(const struct mg_client_options *client_options,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) // TODO: mbedTLS client
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS) // TODO: mbedTLS client
|
||||
if (use_ssl) {
|
||||
/* TODO: Check ssl_verify_peer and ssl_ca_path here.
|
||||
* SSL_CTX_set_verify call is needed to switch off server
|
||||
@ -20186,6 +20295,24 @@ worker_thread_run(struct mg_connection *conn)
|
||||
close_connection(conn);
|
||||
}
|
||||
|
||||
#elif defined(USE_GNUTLS)
|
||||
/* HTTPS connection */
|
||||
if (gtls_ssl_accept(&(conn->ssl),
|
||||
conn->dom_ctx->ssl_ctx,
|
||||
conn->client.sock,
|
||||
conn->phys_ctx)
|
||||
== 0) {
|
||||
/* conn->dom_ctx is set in get_request */
|
||||
/* process HTTPS connection */
|
||||
init_connection(conn);
|
||||
conn->connection_type = CONNECTION_TYPE_REQUEST;
|
||||
conn->protocol_type = PROTOCOL_TYPE_HTTP1;
|
||||
process_new_connection(conn);
|
||||
} else {
|
||||
/* make sure the connection is cleaned up on SSL failure */
|
||||
close_connection(conn);
|
||||
}
|
||||
|
||||
#elif !defined(NO_SSL)
|
||||
/* HTTPS connection */
|
||||
if (sslize(conn, SSL_accept, NULL)) {
|
||||
@ -20693,6 +20820,13 @@ free_context(struct mg_context *ctx)
|
||||
ctx->dd.ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
#elif defined(USE_GNUTLS)
|
||||
if (ctx->dd.ssl_ctx != NULL) {
|
||||
gtls_sslctx_uninit(ctx->dd.ssl_ctx);
|
||||
mg_free(ctx->dd.ssl_ctx);
|
||||
ctx->dd.ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
#elif !defined(NO_SSL)
|
||||
/* Deallocate SSL context */
|
||||
if (ctx->dd.ssl_ctx != NULL) {
|
||||
@ -21383,7 +21517,7 @@ mg_start2(struct mg_init_data *init, struct mg_error_data *error)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_MBEDTLS)
|
||||
#if defined(USE_MBEDTLS) || defined(USE_GNUTLS)
|
||||
if (!mg_sslctx_init(ctx, NULL)) {
|
||||
const char *err_msg = "Error initializing SSL context";
|
||||
/* Fatal error - abort start. */
|
||||
@ -21868,7 +22002,7 @@ mg_start_domain2(struct mg_context *ctx,
|
||||
new_dom->shared_lua_websockets = NULL;
|
||||
#endif
|
||||
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS)
|
||||
#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS)
|
||||
if (!init_ssl_ctx(ctx, new_dom)) {
|
||||
/* Init SSL failed */
|
||||
if (error != NULL) {
|
||||
@ -21947,7 +22081,7 @@ mg_check_feature(unsigned feature)
|
||||
#if !defined(NO_FILES)
|
||||
| MG_FEATURES_FILES
|
||||
#endif
|
||||
#if !defined(NO_SSL) || defined(USE_MBEDTLS)
|
||||
#if !defined(NO_SSL) || defined(USE_MBEDTLS) || defined(USE_GNUTLS)
|
||||
| MG_FEATURES_SSL
|
||||
#endif
|
||||
#if !defined(NO_CGI)
|
||||
|
240
src/mod_gnutls.inl
Normal file
240
src/mod_gnutls.inl
Normal file
@ -0,0 +1,240 @@
|
||||
#if defined(USE_GNUTLS) // USE_GNUTLS used with NO_SSL
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/x509.h>
|
||||
|
||||
typedef struct {
|
||||
gnutls_session_t sess;
|
||||
} SSL;
|
||||
typedef struct {
|
||||
gnutls_certificate_credentials_t cred;
|
||||
gnutls_priority_t prio;
|
||||
} SSL_CTX;
|
||||
|
||||
|
||||
/* public api */
|
||||
CIVETWEB_API int gtls_sslctx_init(SSL_CTX *ctx, const char *crt);
|
||||
CIVETWEB_API void gtls_sslctx_uninit(SSL_CTX *ctx);
|
||||
CIVETWEB_API void gtls_ssl_close(SSL *ssl);
|
||||
CIVETWEB_API int gtls_ssl_accept(SSL **ssl,
|
||||
SSL_CTX *ssl_ctx,
|
||||
int sock,
|
||||
struct mg_context *phys_ctx);
|
||||
CIVETWEB_API int gtls_ssl_read(SSL *ssl, unsigned char *buf, size_t len);
|
||||
CIVETWEB_API int gtls_ssl_write(SSL *ssl, const unsigned char *buf, size_t len);
|
||||
|
||||
|
||||
CIVETWEB_API int
|
||||
gtls_sslctx_init(SSL_CTX *ctx, const char *crt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (ctx == NULL || crt == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_TRACE("%s", "Initializing GnuTLS SSL");
|
||||
|
||||
rc = gnutls_certificate_allocate_credentials(&ctx->cred);
|
||||
if (rc != GNUTLS_E_SUCCESS) {
|
||||
DEBUG_TRACE("Failed to allocate credentials (%d): %s",
|
||||
rc,
|
||||
gnutls_strerror(rc));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
rc = gnutls_priority_init(&ctx->prio, NULL, NULL);
|
||||
if (rc != GNUTLS_E_SUCCESS) {
|
||||
DEBUG_TRACE("Failed to allocate priority cache (%d): %s",
|
||||
rc,
|
||||
gnutls_strerror(rc));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
rc = gnutls_certificate_set_x509_key_file2(ctx->cred,
|
||||
crt,
|
||||
crt,
|
||||
GNUTLS_X509_FMT_PEM,
|
||||
NULL,
|
||||
GNUTLS_PKCS_PLAIN
|
||||
| GNUTLS_PKCS_NULL_PASSWORD);
|
||||
if (rc != GNUTLS_E_SUCCESS) {
|
||||
DEBUG_TRACE("TLS parse crt/key file failed (%d): %s",
|
||||
rc,
|
||||
gnutls_strerror(rc));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
gtls_sslctx_uninit(ctx);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
CIVETWEB_API void
|
||||
gtls_sslctx_uninit(SSL_CTX *ctx)
|
||||
{
|
||||
if (ctx != NULL) {
|
||||
gnutls_certificate_free_credentials(ctx->cred);
|
||||
gnutls_priority_deinit(ctx->prio);
|
||||
ctx->cred = NULL;
|
||||
ctx->prio = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CIVETWEB_API int
|
||||
gtls_ssl_accept(SSL **ssl,
|
||||
SSL_CTX *ssl_ctx,
|
||||
int sock,
|
||||
struct mg_context *phys_ctx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (ssl == NULL || ssl_ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_TRACE("TLS accept processing %p", ssl);
|
||||
|
||||
*ssl = (SSL *)mg_calloc_ctx(1, sizeof(SSL), phys_ctx);
|
||||
if (*ssl == NULL) {
|
||||
DEBUG_TRACE("Failed to allocate memory for session %zu", sizeof(SSL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gnutls_init(&(*ssl)->sess, GNUTLS_SERVER);
|
||||
if (rc != GNUTLS_E_SUCCESS) {
|
||||
DEBUG_TRACE("Failed to initialize session (%d): %s",
|
||||
rc,
|
||||
gnutls_strerror(rc));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
rc = gnutls_priority_set((*ssl)->sess, ssl_ctx->prio);
|
||||
if (rc != GNUTLS_E_SUCCESS) {
|
||||
DEBUG_TRACE("TLS set priortities failed (%d): %s",
|
||||
rc,
|
||||
gnutls_strerror(rc));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
rc = gnutls_credentials_set((*ssl)->sess,
|
||||
GNUTLS_CRD_CERTIFICATE,
|
||||
ssl_ctx->cred);
|
||||
if (rc != GNUTLS_E_SUCCESS) {
|
||||
DEBUG_TRACE("TLS set credentials failed (%d): %s",
|
||||
rc,
|
||||
gnutls_strerror(rc));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
gnutls_certificate_send_x509_rdn_sequence((*ssl)->sess, 1);
|
||||
gnutls_certificate_server_set_request((*ssl)->sess, GNUTLS_CERT_IGNORE);
|
||||
gnutls_handshake_set_timeout((*ssl)->sess,
|
||||
GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
|
||||
gnutls_transport_set_int((*ssl)->sess, sock);
|
||||
|
||||
while ((rc = gnutls_handshake((*ssl)->sess)) != GNUTLS_E_SUCCESS) {
|
||||
if (gnutls_error_is_fatal(rc)) {
|
||||
if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
|
||||
DEBUG_TRACE("TLS fatal alert received: %s",
|
||||
gnutls_alert_get_name(
|
||||
gnutls_alert_get((*ssl)->sess)));
|
||||
} else {
|
||||
DEBUG_TRACE("TLS handshake failed (%d): %s",
|
||||
rc,
|
||||
gnutls_strerror(rc));
|
||||
}
|
||||
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_TRACE("TLS connection %p accepted", *ssl);
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
gnutls_deinit((*ssl)->sess);
|
||||
mg_free(*ssl);
|
||||
*ssl = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
CIVETWEB_API void
|
||||
gtls_ssl_close(SSL *ssl)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (ssl == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((rc = gnutls_bye(ssl->sess, GNUTLS_SHUT_RDWR)) != GNUTLS_E_SUCCESS) {
|
||||
switch (rc) {
|
||||
case GNUTLS_E_AGAIN: /* fall through */
|
||||
case GNUTLS_E_INTERRUPTED:
|
||||
continue;
|
||||
default: /* should actually never happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_TRACE("TLS connection %p closed", ssl);
|
||||
gnutls_deinit(ssl->sess);
|
||||
mg_free(ssl);
|
||||
}
|
||||
|
||||
|
||||
CIVETWEB_API int
|
||||
gtls_ssl_read(SSL *ssl, unsigned char *buf, size_t len)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
if (ssl == NULL) {
|
||||
return GNUTLS_E_INVALID_SESSION;
|
||||
}
|
||||
|
||||
while ((rc = gnutls_record_recv(ssl->sess, buf, len)) < 0) {
|
||||
switch (rc) {
|
||||
case GNUTLS_E_AGAIN: /* fall through */
|
||||
case GNUTLS_E_INTERRUPTED:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* DEBUG_TRACE("gnutls_record_recv: %d", rc); */
|
||||
return (int)rc;
|
||||
}
|
||||
|
||||
|
||||
CIVETWEB_API int
|
||||
gtls_ssl_write(SSL *ssl, const unsigned char *buf, size_t len)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
if (ssl == NULL) {
|
||||
return GNUTLS_E_INVALID_SESSION;
|
||||
}
|
||||
|
||||
while ((rc = gnutls_record_send(ssl->sess, buf, len)) < 0) {
|
||||
switch (rc) {
|
||||
case GNUTLS_E_AGAIN: /* fall through */
|
||||
case GNUTLS_E_INTERRUPTED:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* DEBUG_TRACE("gnutls_record_send: %d", rc); */
|
||||
return (int)rc;
|
||||
}
|
||||
|
||||
#endif /* USE_GNUTLS */
|
Loading…
x
Reference in New Issue
Block a user