Add testapps support for client certs and CRLs
authorAlexander Bruines <alexander.bruines@gmail.com>
Wed, 13 Apr 2016 20:17:05 +0000 (22:17 +0200)
committerAndy Green <andy@warmcat.com>
Thu, 14 Apr 2016 12:59:16 +0000 (20:59 +0800)
AG: plumb into cmake to avoid travis mac blowing up

CMakeLists.txt
lws_config.h.in
test-server/test-client.c
test-server/test-server-http.c
test-server/test-server.c
test-server/test-server.h

index 41ebbc1..a4a4219 100644 (file)
@@ -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}")
index 5e6b206..3630d3d 100644 (file)
@@ -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
index b35260d..aeb752c 100644 (file)
 
 #include "../lib/libwebsockets.h"
 
+#ifdef LWS_OPENSSL_SUPPORT
+#include <openssl/err.h>
+#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");
index af40609..b3c1bb1 100644 (file)
  *                             using this protocol, including the sender
  */
 
+#ifdef LWS_OPENSSL_SUPPORT
+#include <openssl/err.h>
+#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;
        }
index f5e4f32..76715b9 100644 (file)
@@ -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=<p>] [--ssl] "
index c468a69..41602ae 100644 (file)
@@ -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);