support openssl info callback
authorAndy Green <andy@warmcat.com>
Tue, 20 Jun 2017 03:46:49 +0000 (11:46 +0800)
committerAndy Green <andy@warmcat.com>
Tue, 20 Jun 2017 03:46:49 +0000 (11:46 +0800)
https://github.com/warmcat/libwebsockets/issues/936

CMakeLists.txt
README.coding.md
lib/context.c
lib/libwebsockets.h
lib/private-libwebsockets.h
lib/ssl-client.c
lib/ssl.c
lws_config.h.in
test-server/test-server-v2.0.c

index b596c20..f625c57 100644 (file)
@@ -1036,6 +1036,7 @@ 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)
+CHECK_FUNCTION_EXISTS(SSL_set_info_callback LWS_HAVE_SSL_SET_INFO_CALLBACK)
 CHECK_FUNCTION_EXISTS(X509_VERIFY_PARAM_set1_host LWS_HAVE_X509_VERIFY_PARAM_set1_host)
 if (LWS_WITH_ESP32)
        set(LWS_HAVE_TLS_CLIENT_METHOD 1)
index 9cd9fdd..c1c4a3f 100644 (file)
@@ -568,6 +568,32 @@ ECDH Certs are now supported.  Enable the CMake option
 
 to build in support and select it at runtime.
 
+@section sslinfo SSL info callbacks
+
+OpenSSL allows you to receive callbacks for various events defined in a
+bitmask in openssl/ssl.h.  The events include stuff like TLS Alerts.
+
+By default, lws doesn't register for these callbacks.
+
+However if you set the info.ssl_info_event_mask to nonzero (ie, set some
+of the bits in it like `SSL_CB_ALERT` at vhost creation time, then
+connections to that vhost will call back using LWS_CALLBACK_SSL_INFO
+for the wsi, and the `in` parameter will be pointing to a struct of
+related args:
+
+```
+struct lws_ssl_info {
+       int where;
+       int ret;
+};
+```
+
+The default callback handler in lws has a handler for LWS_CALLBACK_SSL_INFO
+which prints the related information,  You can test it using the switch
+-S -s  on `libwebsockets-test-server-v2.0`.
+
+Returning nonzero from the callback will close the wsi.
+
 @section smp SMP / Multithreaded service
 
 SMP support is integrated into LWS without any internal threading.  It's
index d9d94eb..7e875ea 100644 (file)
@@ -381,6 +381,16 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                                    "sent %d only %d went", n, args->len);
                return n;
 #endif
+
+       case LWS_CALLBACK_SSL_INFO:
+               {
+                       struct lws_ssl_info *si = in;
+
+                       lwsl_notice("LWS_CALLBACK_SSL_INFO: where: 0x%x, ret: 0x%x\n",
+                                       si->where, si->ret);
+               }
+               break;
+
        default:
                break;
        }
@@ -453,6 +463,7 @@ lws_create_vhost(struct lws_context *context,
        vh->options = info->options;
        vh->pvo = info->pvo;
        vh->headers = info->headers;
+       vh->ssl_info_event_mask = info->ssl_info_event_mask;
        if (info->keepalive_timeout)
                vh->keepalive_timeout = info->keepalive_timeout;
        else
index 23d6588..ad754b0 100644 (file)
@@ -829,6 +829,10 @@ struct lws_extension;
  */
 ///@{
 
+struct lws_ssl_info {
+       int where;
+       int ret;
+};
 
 /*
  * NOTE: These public enums are part of the abi.  If you want to add one,
@@ -1235,6 +1239,12 @@ enum lws_callback_reasons {
        /**< RAW mode file is writeable */
        LWS_CALLBACK_RAW_CLOSE_FILE                             = 66,
        /**< RAW mode wsi that adopted a file is closing */
+       LWS_CALLBACK_SSL_INFO                                   = 67,
+       /**< SSL connections only.  An event you registered an
+        * interest in at the vhost has occurred on a connection
+        * using the vhost.  @in is a pointer to a
+        * struct lws_ssl_info containing information about the
+        * event*/
 
        /****** add new things just above ---^ ******/
 
@@ -2040,6 +2050,12 @@ struct lws_context_creation_info {
         * members added above will see 0 (default) even if the app
         * was not built against the newer headers.
         */
+       int ssl_info_event_mask;
+       /**< VHOST: mask of ssl events to be reported on LWS_CALLBACK_SSL_INFO
+        * callback for connections on this vhost.  The mask values are of
+        * the form SSL_CB_ALERT, defined in openssl/ssl.h.  The default of
+        * 0 means no info events will be reported.
+        */
 
        void *_unused[8]; /**< dummy */
 };
@@ -3574,6 +3590,7 @@ enum pending_timeout {
        PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY           = 19,
        PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY            = 20,
        PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY               = 21,
+       PENDING_TIMEOUT_KILLED_BY_SSL_INFO                      = 22,
 
        /****** add new things just above ---^ ******/
 };
index 845d4a5..420076e 100644 (file)
@@ -890,6 +890,7 @@ struct lws_vhost {
        int ka_probes;
        int ka_interval;
        int keepalive_timeout;
+       int ssl_info_event_mask;
 #ifdef LWS_WITH_ACCESS_LOG
        int log_fd;
 #endif
@@ -1158,6 +1159,7 @@ LWS_EXTERN void lws_feature_status_libevent(struct lws_context_creation_info *in
 #else
 #define LWS_UNIX_SOCK_ENABLED(vhost) (0)
 #endif
+
 enum uri_path_states {
        URIPS_IDLE,
        URIPS_SEEN_SLASH,
@@ -2077,6 +2079,10 @@ lws_http_transaction_completed_client(struct lws *wsi);
 LWS_EXTERN int
 lws_context_init_client_ssl(struct lws_context_creation_info *info,
                            struct lws_vhost *vhost);
+
+LWS_EXTERN void
+lws_ssl_info_callback(const SSL *ssl, int where, int ret);
+
 #else
        #define lws_context_init_client_ssl(_a, _b) (0)
 #endif
index aba337b..dea9538 100644 (file)
@@ -130,6 +130,11 @@ lws_ssl_client_bio_create(struct lws *wsi)
                return -1;
        }
 
+#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
+       if (wsi->vhost->ssl_info_event_mask)
+               SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
+#endif
+
 #if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
        X509_VERIFY_PARAM *param;
        (void)param;
index 651757f..d65923c 100644 (file)
--- a/lib/ssl.c
+++ b/lib/ssl.c
@@ -543,6 +543,35 @@ lws_gate_accepts(struct lws_context *context, int on)
        return 0;
 }
 
+void
+lws_ssl_info_callback(const SSL *ssl, int where, int ret)
+{
+       struct lws *wsi;
+       struct lws_context *context;
+       struct lws_ssl_info si;
+
+       context = (struct lws_context *)SSL_CTX_get_ex_data(
+                                       SSL_get_SSL_CTX(ssl),
+                                       openssl_SSL_CTX_private_data_index);
+       if (!context)
+               return;
+       wsi = wsi_from_fd(context, SSL_get_fd(ssl));
+       if (!wsi)
+               return;
+
+       if (!(where & wsi->vhost->ssl_info_event_mask))
+               return;
+
+       si.where = where;
+       si.ret = ret;
+
+       if (user_callback_handle_rxflow(wsi->protocol->callback,
+                                                  wsi, LWS_CALLBACK_SSL_INFO,
+                                                  wsi->user_space, &si, 0))
+               lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
+}
+
+
 LWS_VISIBLE int
 lws_ssl_close(struct lws *wsi)
 {
@@ -551,6 +580,14 @@ lws_ssl_close(struct lws *wsi)
        if (!wsi->ssl)
                return 0; /* not handled */
 
+#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
+       /* kill ssl callbacks, becausse we will remove the fd from the
+        * table linking it to the wsi
+        */
+       if (wsi->vhost->ssl_info_event_mask)
+               SSL_set_info_callback(wsi->ssl, NULL);
+#endif
+
        n = SSL_get_fd(wsi->ssl);
        SSL_shutdown(wsi->ssl);
        compatible_close(n);
@@ -608,6 +645,10 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                                compatible_close(accept_fd);
                        goto fail;
                }
+#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
+               if (wsi->vhost->ssl_info_event_mask)
+                       SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
+#endif
                if (context->simultaneous_ssl_restriction &&
                    ++context->simultaneous_ssl == context->simultaneous_ssl_restriction)
                        /* that was the last allowed SSL connection */
index c8d5c38..483ad20 100644 (file)
 
 #cmakedefine LWS_HAVE_TLS_CLIENT_METHOD
 #cmakedefine LWS_HAVE_TLSV1_2_CLIENT_METHOD
+#cmakedefine LWS_HAVE_SSL_SET_INFO_CALLBACK
 
 ${LWS_SIZEOFPTR_CODE}
index 6041e70..40e0dd1 100644 (file)
@@ -231,6 +231,7 @@ static const struct option options[] = {
        { "debug",      required_argument,      NULL, 'd' },
        { "port",       required_argument,      NULL, 'p' },
        { "ssl",        no_argument,            NULL, 's' },
+       { "ssl-alerts", no_argument,            NULL, 'S' },
        { "allow-non-ssl",      no_argument,    NULL, 'a' },
        { "interface",  required_argument,      NULL, 'i' },
        { "ssl-cert",  required_argument,       NULL, 'C' },
@@ -281,7 +282,7 @@ int main(int argc, char **argv)
        info.port = 7681;
 
        while (n >= 0) {
-               n = getopt_long(argc, argv, "i:hsap:d:Dr:C:K:A:R:vu:g:",
+               n = getopt_long(argc, argv, "i:hsap:d:Dr:C:K:A:R:vu:g:S",
                                (struct option *)options, NULL);
                if (n < 0)
                        continue;
@@ -306,6 +307,11 @@ int main(int argc, char **argv)
                case 's':
                        use_ssl = 1;
                        break;
+               case 'S':
+#if defined(LWS_OPENSSL_SUPPORT)
+                       info.ssl_info_event_mask |= SSL_CB_ALERT;
+#endif
+                       break;
                case 'a':
                        opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
                        break;