mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-30 00:00:16 +01:00
tls: client: session cache synthetic cb
This commit is contained in:
parent
f1ff43ddea
commit
3ae611cdca
9 changed files with 139 additions and 14 deletions
|
@ -59,6 +59,20 @@ be treated with caution.
|
||||||
Filling, expiring and consulting the session cache for client connections is
|
Filling, expiring and consulting the session cache for client connections is
|
||||||
performed automatically.
|
performed automatically.
|
||||||
|
|
||||||
|
### tls library differences
|
||||||
|
|
||||||
|
Mbedtls supports clientside session caching in lws, but it does not have a
|
||||||
|
session message arrival callback to synchronize updating the client session
|
||||||
|
cache like openssl does.
|
||||||
|
|
||||||
|
Separately, the session cb in boringssl is reportedly nonfunctional at the
|
||||||
|
moment.
|
||||||
|
|
||||||
|
To solve both cases, lws will schedule a check for the session at +500ms after
|
||||||
|
the tls negotiation completed, and for the case the connection doesn't last
|
||||||
|
500ms or the server is slow issuing the message, also attempt to update the
|
||||||
|
cache at the time the tls connection object is closing.
|
||||||
|
|
||||||
### Session namespacing in lws
|
### Session namespacing in lws
|
||||||
|
|
||||||
Internally sessions are referred to by a vhostname.hostname.port tuple.
|
Internally sessions are referred to by a vhostname.hostname.port tuple.
|
||||||
|
|
|
@ -268,6 +268,28 @@ bail:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LWS_TLS_SYNTHESIZE_CB)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On openssl, there is an async cb coming when the server issues the session
|
||||||
|
* information on the link, so we can pick it up and update the cache at the
|
||||||
|
* right time.
|
||||||
|
*
|
||||||
|
* On mbedtls and some version at least of borning ssl, this cb is either not
|
||||||
|
* part of the tls library apis or fails to arrive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
lws_sess_cache_synth_cb(lws_sorted_usec_list_t *sul)
|
||||||
|
{
|
||||||
|
struct lws_lws_tls *tls = lws_container_of(sul, struct lws_lws_tls,
|
||||||
|
sul_cb_synth);
|
||||||
|
struct lws *wsi = lws_container_of(tls, struct lws, tls);
|
||||||
|
|
||||||
|
lws_tls_session_new_mbedtls(wsi);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl)
|
lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl)
|
||||||
{
|
{
|
||||||
|
|
|
@ -255,6 +255,15 @@ lws_ssl_close(struct lws *wsi)
|
||||||
SSL_set_info_callback(wsi->tls.ssl, NULL);
|
SSL_set_info_callback(wsi->tls.ssl, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(LWS_TLS_SYNTHESIZE_CB)
|
||||||
|
lws_sul_cancel(&wsi->tls.sul_cb_synth);
|
||||||
|
/*
|
||||||
|
* ... check the session in case it did not live long enough to get
|
||||||
|
* the scheduled callback to sample it
|
||||||
|
*/
|
||||||
|
lws_sess_cache_synth_cb(&wsi->tls.sul_cb_synth);
|
||||||
|
#endif
|
||||||
|
|
||||||
n = SSL_get_fd(wsi->tls.ssl);
|
n = SSL_get_fd(wsi->tls.ssl);
|
||||||
if (!wsi->socket_is_permanently_unusable)
|
if (!wsi->socket_is_permanently_unusable)
|
||||||
SSL_shutdown(wsi->tls.ssl);
|
SSL_shutdown(wsi->tls.ssl);
|
||||||
|
|
|
@ -499,6 +499,12 @@ lws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen)
|
||||||
|
|
||||||
lws_role_call_alpn_negotiated(wsi, (const char *)a);
|
lws_role_call_alpn_negotiated(wsi, (const char *)a);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(LWS_TLS_SYNTHESIZE_CB)
|
||||||
|
lws_sul_schedule(wsi->a.context, wsi->tsi,
|
||||||
|
&wsi->tls.sul_cb_synth,
|
||||||
|
lws_sess_cache_synth_cb, 500 * LWS_US_PER_MS);
|
||||||
|
#endif
|
||||||
|
|
||||||
lwsl_info("client connect OK\n");
|
lwsl_info("client connect OK\n");
|
||||||
lws_openssl_describe_cipher(wsi);
|
lws_openssl_describe_cipher(wsi);
|
||||||
return LWS_SSL_CAPABLE_DONE;
|
return LWS_SSL_CAPABLE_DONE;
|
||||||
|
|
|
@ -91,9 +91,22 @@ lws_tls_reuse_session(struct lws *wsi)
|
||||||
}
|
}
|
||||||
|
|
||||||
lwsl_tlssess("%s: %s\n", __func__, (const char *)&ts[1]);
|
lwsl_tlssess("%s: %s\n", __func__, (const char *)&ts[1]);
|
||||||
wsi->tls_session_reused = 1;
|
|
||||||
|
|
||||||
SSL_set_session(wsi->tls.ssl, ts->session);
|
if (!SSL_set_session(wsi->tls.ssl, ts->session)) {
|
||||||
|
lwsl_err("%s: session not set for %s\n", __func__, tag);
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(USE_WOLFSSL)
|
||||||
|
/* extend session lifetime */
|
||||||
|
SSL_SESSION_set_time(ts->session,
|
||||||
|
#if defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
(unsigned long)
|
||||||
|
#else
|
||||||
|
(long)
|
||||||
|
#endif
|
||||||
|
time(NULL));
|
||||||
|
#endif
|
||||||
|
|
||||||
/* keep our session list sorted in lru -> mru order */
|
/* keep our session list sorted in lru -> mru order */
|
||||||
|
|
||||||
|
@ -144,7 +157,6 @@ lws_tls_session_expiry_cb(lws_sorted_usec_list_t *sul)
|
||||||
struct lws_vhost *vh = lws_container_of(ts->list.owner,
|
struct lws_vhost *vh = lws_container_of(ts->list.owner,
|
||||||
struct lws_vhost, tls_sessions);
|
struct lws_vhost, tls_sessions);
|
||||||
|
|
||||||
lws_sul_cancel(&ts->sul_ttl);
|
|
||||||
lws_context_lock(vh->context, __func__); /* -------------- cx { */
|
lws_context_lock(vh->context, __func__); /* -------------- cx { */
|
||||||
lws_vhost_lock(vh); /* -------------- vh { */
|
lws_vhost_lock(vh); /* -------------- vh { */
|
||||||
__lws_tls_session_destroy(ts);
|
__lws_tls_session_destroy(ts);
|
||||||
|
@ -280,6 +292,47 @@ bail:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LWS_TLS_SYNTHESIZE_CB)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On openssl, there is an async cb coming when the server issues the session
|
||||||
|
* information on the link, so we can pick it up and update the cache at the
|
||||||
|
* right time.
|
||||||
|
*
|
||||||
|
* On mbedtls and some version at least of borning ssl, this cb is either not
|
||||||
|
* part of the tls library apis or fails to arrive.
|
||||||
|
*
|
||||||
|
* This synthetic cb is called instead for those build cases, scheduled for
|
||||||
|
* +500ms after the tls negotiation completed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
lws_sess_cache_synth_cb(lws_sorted_usec_list_t *sul)
|
||||||
|
{
|
||||||
|
struct lws_lws_tls *tls = lws_container_of(sul, struct lws_lws_tls,
|
||||||
|
sul_cb_synth);
|
||||||
|
struct lws *wsi = lws_container_of(tls, struct lws, tls);
|
||||||
|
SSL_SESSION *sess;
|
||||||
|
|
||||||
|
if (lws_tls_session_is_reused(wsi))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sess = SSL_get1_session(tls->ssl);
|
||||||
|
if (!sess)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!SSL_SESSION_is_resumable(sess) || /* not worth caching, or... */
|
||||||
|
!lws_tls_session_new_cb(tls->ssl, sess)) { /* ...cb didn't keep it */
|
||||||
|
/*
|
||||||
|
* For now the policy if no session message after the wait,
|
||||||
|
* is just let it be. Typically the session info is sent
|
||||||
|
* early.
|
||||||
|
*/
|
||||||
|
SSL_SESSION_free(sess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl)
|
lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl)
|
||||||
{
|
{
|
||||||
|
@ -363,7 +416,7 @@ lws_tls_session_dump_load(struct lws_vhost *vh, const char *host, uint16_t port,
|
||||||
{
|
{
|
||||||
struct lws_tls_session_dump d;
|
struct lws_tls_session_dump d;
|
||||||
lws_tls_sco_t *ts;
|
lws_tls_sco_t *ts;
|
||||||
SSL_SESSION *sess;
|
SSL_SESSION *sess = NULL; /* allow it to "bail" early */
|
||||||
void *v;
|
void *v;
|
||||||
|
|
||||||
if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
|
if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
|
||||||
|
|
|
@ -449,6 +449,15 @@ lws_ssl_close(struct lws *wsi)
|
||||||
SSL_set_info_callback(wsi->tls.ssl, NULL);
|
SSL_set_info_callback(wsi->tls.ssl, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(LWS_TLS_SYNTHESIZE_CB)
|
||||||
|
lws_sul_cancel(&wsi->tls.sul_cb_synth);
|
||||||
|
/*
|
||||||
|
* ... check the session in case it did not live long enough to get
|
||||||
|
* the scheduled callback to sample it
|
||||||
|
*/
|
||||||
|
lws_sess_cache_synth_cb(&wsi->tls.sul_cb_synth);
|
||||||
|
#endif
|
||||||
|
|
||||||
n = SSL_get_fd(wsi->tls.ssl);
|
n = SSL_get_fd(wsi->tls.ssl);
|
||||||
if (!wsi->socket_is_permanently_unusable)
|
if (!wsi->socket_is_permanently_unusable)
|
||||||
SSL_shutdown(wsi->tls.ssl);
|
SSL_shutdown(wsi->tls.ssl);
|
||||||
|
|
|
@ -118,6 +118,11 @@ enum lws_tls_extant {
|
||||||
|
|
||||||
#if defined(LWS_WITH_TLS)
|
#if defined(LWS_WITH_TLS)
|
||||||
|
|
||||||
|
#if defined(LWS_WITH_TLS_SESSIONS) && defined(LWS_WITH_CLIENT) && \
|
||||||
|
(defined(LWS_WITH_MBEDTLS) || defined(OPENSSL_IS_BORINGSSL))
|
||||||
|
#define LWS_TLS_SYNTHESIZE_CB 1
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
lws_tls_restrict_borrow(struct lws_context *context);
|
lws_tls_restrict_borrow(struct lws_context *context);
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,9 @@ struct lws_vhost_tls {
|
||||||
struct lws_lws_tls {
|
struct lws_lws_tls {
|
||||||
lws_tls_conn *ssl;
|
lws_tls_conn *ssl;
|
||||||
lws_tls_bio *client_bio;
|
lws_tls_bio *client_bio;
|
||||||
|
#if defined(LWS_TLS_SYNTHESIZE_CB)
|
||||||
|
lws_sorted_usec_list_t sul_cb_synth;
|
||||||
|
#endif
|
||||||
struct lws_dll2 dll_pending_tls;
|
struct lws_dll2 dll_pending_tls;
|
||||||
char err_helper[32];
|
char err_helper[32];
|
||||||
unsigned int use_ssl;
|
unsigned int use_ssl;
|
||||||
|
@ -95,6 +98,10 @@ lws_ssl_pending(struct lws *wsi);
|
||||||
int LWS_WARN_UNUSED_RESULT
|
int LWS_WARN_UNUSED_RESULT
|
||||||
lws_server_socket_service_ssl(struct lws *new_wsi, lws_sockfd_type accept_fd,
|
lws_server_socket_service_ssl(struct lws *new_wsi, lws_sockfd_type accept_fd,
|
||||||
char is_pollin);
|
char is_pollin);
|
||||||
|
|
||||||
|
void
|
||||||
|
lws_sess_cache_synth_cb(lws_sorted_usec_list_t *sul);
|
||||||
|
|
||||||
int
|
int
|
||||||
lws_ssl_close(struct lws *wsi);
|
lws_ssl_close(struct lws *wsi);
|
||||||
void
|
void
|
||||||
|
|
|
@ -51,9 +51,6 @@ if (requirements)
|
||||||
|
|
||||||
|
|
||||||
add_test(NAME http-client-warmcat-h1 COMMAND lws-minimal-http-client --h1)
|
add_test(NAME http-client-warmcat-h1 COMMAND lws-minimal-http-client --h1)
|
||||||
set_tests_properties(${mytests} PROPERTIES
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client
|
|
||||||
TIMEOUT 20)
|
|
||||||
|
|
||||||
if (has_fault_injection)
|
if (has_fault_injection)
|
||||||
|
|
||||||
|
@ -139,6 +136,9 @@ if (requirements)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set_tests_properties(${mytests} PROPERTIES
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client
|
||||||
|
TIMEOUT 20)
|
||||||
|
|
||||||
if (DEFINED ENV{SAI_OVN})
|
if (DEFINED ENV{SAI_OVN})
|
||||||
set_tests_properties(${mytests} PROPERTIES
|
set_tests_properties(${mytests} PROPERTIES
|
||||||
|
|
Loading…
Add table
Reference in a new issue