diff --git a/CMakeLists.txt b/CMakeLists.txt index 41ebbc12..a4a4219c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,6 +384,7 @@ SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}") include(CheckFunctionExists) +include(CheckSymbolExists) include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckLibraryExists) @@ -463,15 +464,6 @@ if (NOT LWS_HAVE_REALLOC) set(realloc rpl_realloc) endif() -# Generate the lws_config.h that includes all the public compilation settings. -configure_file( - "${PROJECT_SOURCE_DIR}/lws_config.h.in" - "${PROJECT_BINARY_DIR}/lws_config.h") - -# Generate the lws_config.h that includes all the private compilation settings. -configure_file( - "${PROJECT_SOURCE_DIR}/lws_config_private.h.in" - "${PROJECT_BINARY_DIR}/lws_config_private.h") if (MSVC) # Turn off stupid microsoft security warnings. @@ -864,6 +856,22 @@ foreach (lib ${LWS_LIBRARIES}) target_link_libraries(${lib} ${LIB_LIST}) endforeach() +set (temp ${CMAKE_REQUIRED_LIBRARIES}) +set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST}) +CHECK_FUNCTION_EXISTS(SSL_CTX_set1_param LWS_HAVE_SSL_CTX_set1_param) +set(CMAKE_REQUIRED_LIBRARIES ${temp}) +# Generate the lws_config.h that includes all the public compilation settings. +configure_file( + "${PROJECT_SOURCE_DIR}/lws_config.h.in" + "${PROJECT_BINARY_DIR}/lws_config.h") + +# Generate the lws_config.h that includes all the private compilation settings. +configure_file( + "${PROJECT_SOURCE_DIR}/lws_config_private.h.in" + "${PROJECT_BINARY_DIR}/lws_config_private.h") + + + # # Test applications # @@ -1450,6 +1458,7 @@ message(" LWS_SSL_SERVER_WITH_ECDH_CERT = ${LWS_SSL_SERVER_WITH_ECDH_CERT}") message(" LWS_MAX_SMP = ${LWS_MAX_SMP}") message(" LWS_WITH_CGI = ${LWS_WITH_CGI}") message(" LWS_HAVE_OPENSSL_ECDH_H = ${LWS_HAVE_OPENSSL_ECDH_H}") +message(" LWS_HAVE_SSL_CTX_set1_param = ${LWS_HAVE_SSL_CTX_set1_param}") message(" LWS_WITH_HTTP_PROXY = ${LWS_WITH_HTTP_PROXY}") message(" LIBHUBBUB_LIBRARIES = ${LIBHUBBUB_LIBRARIES}") message(" PLUGINS = ${PLUGINS_LIST}") diff --git a/lws_config.h.in b/lws_config.h.in index 5e6b2069..3630d3d0 100644 --- a/lws_config.h.in +++ b/lws_config.h.in @@ -81,6 +81,7 @@ /* SSL server using ECDH certificate */ #cmakedefine LWS_SSL_SERVER_WITH_ECDH_CERT +#cmakedefine LWS_HAVE_SSL_CTX_set1_param /* CGI apis */ #cmakedefine LWS_WITH_CGI diff --git a/test-server/test-client.c b/test-server/test-client.c index b35260db..aeb752ce 100644 --- a/test-server/test-client.c +++ b/test-server/test-client.c @@ -35,10 +35,17 @@ #include "../lib/libwebsockets.h" +#ifdef LWS_OPENSSL_SUPPORT +#include +#endif + static int deny_deflate, deny_mux, longlived, mirror_lifetime; static struct lws *wsi_dumb, *wsi_mirror; static volatile int force_exit; static unsigned int opts; +#if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) +static char crl_path[1024] = ""; +#endif /* * This demo shows how to connect multiple websockets simultaneously to a @@ -126,6 +133,27 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, force_exit = 1; break; +#if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) + case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: + if (crl_path[0]) { + /* Enable CRL checking of the server certificate */ + X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); + X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); + SSL_CTX_set1_param((SSL_CTX*)user, param); + X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX*)user); + X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + int n = X509_load_cert_crl_file(lookup, crl_path, X509_FILETYPE_PEM); + X509_VERIFY_PARAM_free(param); + if (n != 1) { + char errbuf[256]; + n = ERR_get_error(); + lwsl_err("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: SSL error: %s (%d)\n", ERR_error_string(n, errbuf), n); + return 1; + } + } + break; +#endif + default: break; } @@ -262,6 +290,12 @@ static struct option options[] = { { "undeflated", no_argument, NULL, 'u' }, { "nomux", no_argument, NULL, 'n' }, { "longlived", no_argument, NULL, 'l' }, + { "ssl-cert", required_argument, NULL, 'C' }, + { "ssl-key", required_argument, NULL, 'K' }, + { "ssl-ca", required_argument, NULL, 'A' }, +#if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) + { "ssl-crl", required_argument, NULL, 'R' }, +#endif { NULL, 0, 0, 0 } }; @@ -287,6 +321,9 @@ int main(int argc, char **argv) struct lws_context *context; const char *prot, *p; char path[300]; + char cert_path[1024] = ""; + char key_path[1024] = ""; + char ca_path[1024] = ""; memset(&info, 0, sizeof info); @@ -297,7 +334,7 @@ int main(int argc, char **argv) goto usage; while (n >= 0) { - n = getopt_long(argc, argv, "nuv:hsp:d:l", options, NULL); + n = getopt_long(argc, argv, "nuv:hsp:d:lC:K:A:", options, NULL); if (n < 0) continue; switch (n) { @@ -322,6 +359,20 @@ int main(int argc, char **argv) case 'n': deny_mux = 1; break; + case 'C': + strncpy(cert_path, optarg, sizeof cert_path); + break; + case 'K': + strncpy(key_path, optarg, sizeof key_path); + break; + case 'A': + strncpy(ca_path, optarg, sizeof ca_path); + break; +#if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) + case 'R': + strncpy(crl_path, optarg, sizeof crl_path); + break; +#endif case 'h': goto usage; } @@ -362,9 +413,30 @@ int main(int argc, char **argv) info.gid = -1; info.uid = -1; - if (use_ssl) + if (use_ssl) { info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + /* + * If the server wants us to present a valid SSL client certificate + * then we can set it up here. + */ + + if (cert_path[0]) + info.ssl_cert_filepath = cert_path; + if (key_path[0]) + info.ssl_private_key_filepath = key_path; + + /* + * A CA cert and CRL can be used to validate the cert send by the server + */ + if (ca_path[0]) + info.ssl_ca_filepath = ca_path; +#if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) + else if (crl_path[0]) + lwsl_notice("WARNING, providing a CRL requires a CA cert!\n"); +#endif + } + context = lws_create_context(&info); if (context == NULL) { fprintf(stderr, "Creating libwebsocket context failed\n"); diff --git a/test-server/test-server-http.c b/test-server/test-server-http.c index af40609a..b3c1bb1d 100644 --- a/test-server/test-server-http.c +++ b/test-server/test-server-http.c @@ -34,6 +34,15 @@ * using this protocol, including the sender */ +#ifdef LWS_OPENSSL_SUPPORT +#include +#endif + +#if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) +/* location of the certificate revocation list */ +char crl_path[1024] = ""; +#endif + extern int debug_level; enum demo_protocols { @@ -620,6 +629,39 @@ bail: break; +#if defined(LWS_OPENSSL_SUPPORT) + case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: + /* Verify the client certificate */ + if (!len || (SSL_get_verify_result((SSL*)in) != X509_V_OK)) { + int err = X509_STORE_CTX_get_error((X509_STORE_CTX*)user); + int depth = X509_STORE_CTX_get_error_depth((X509_STORE_CTX*)user); + const char* msg = X509_verify_cert_error_string(err); + lwsl_err("LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: SSL error: %s (%d), depth: %d\n", msg, err, depth); + return 1; + } + break; +#if defined(LWS_HAVE_SSL_CTX_set1_param) + case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: + if (crl_path[0]) { + /* Enable CRL checking */ + X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); + X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); + SSL_CTX_set1_param((SSL_CTX*)user, param); + X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX*)user); + X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + n = X509_load_cert_crl_file(lookup, crl_path, X509_FILETYPE_PEM); + X509_VERIFY_PARAM_free(param); + if (n != 1) { + char errbuf[256]; + n = ERR_get_error(); + lwsl_err("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: SSL error: %s (%d)\n", ERR_error_string(n, errbuf), n); + return 1; + } + } + break; +#endif +#endif + default: break; } diff --git a/test-server/test-server.c b/test-server/test-server.c index f5e4f323..76715b9f 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -165,6 +165,12 @@ static struct option options[] = { { "ssl-cert", required_argument, NULL, 'C' }, { "ssl-key", required_argument, NULL, 'K' }, { "ssl-ca", required_argument, NULL, 'A' }, +#if defined(LWS_OPENSSL_SUPPORT) + { "ssl-verify-client", no_argument, NULL, 'v' }, +#if defined(LWS_HAVE_SSL_CTX_set1_param) + { "ssl-crl", required_argument, NULL, 'R' }, +#endif +#endif { "libev", no_argument, NULL, 'e' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, @@ -201,7 +207,7 @@ int main(int argc, char **argv) info.port = 7681; while (n >= 0) { - n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:u:g:", options, NULL); + n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:", options, NULL); if (n < 0) continue; switch (n) { @@ -258,6 +264,17 @@ int main(int argc, char **argv) case 'A': strncpy(ca_path, optarg, sizeof ca_path); break; +#if defined(LWS_OPENSSL_SUPPORT) + case 'v': + use_ssl = 1; + opts |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT; + break; +#if defined(LWS_HAVE_SSL_CTX_set1_param) + case 'R': + strncpy(crl_path, optarg, sizeof crl_path); + break; +#endif +#endif case 'h': fprintf(stderr, "Usage: test-server " "[--port=

] [--ssl] " diff --git a/test-server/test-server.h b/test-server/test-server.h index c468a69d..41602ae9 100644 --- a/test-server/test-server.h +++ b/test-server/test-server.h @@ -57,6 +57,9 @@ extern int count_pollfds; extern volatile int force_exit; extern struct lws_context *context; extern char *resource_path; +#if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) +extern char crl_path[1024]; +#endif extern void test_server_lock(int care); extern void test_server_unlock(int care);