support openssl info callback

https://github.com/warmcat/libwebsockets/issues/936
This commit is contained in:
Andy Green 2017-06-20 11:46:49 +08:00
parent 1725332d47
commit 3ff720ff66
9 changed files with 115 additions and 1 deletions

View 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)

View 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

View 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

View 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 ---^ ******/
};

View 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

View 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;

View file

@ -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 */

View file

@ -147,5 +147,6 @@
#cmakedefine LWS_HAVE_TLS_CLIENT_METHOD
#cmakedefine LWS_HAVE_TLSV1_2_CLIENT_METHOD
#cmakedefine LWS_HAVE_SSL_SET_INFO_CALLBACK
${LWS_SIZEOFPTR_CODE}

View 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;