1
0
Fork 0
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:
Catalin Raceanu 2021-04-28 16:54:08 +01:00 committed by Andy Green
parent f1ff43ddea
commit 3ae611cdca
9 changed files with 139 additions and 14 deletions

View file

@ -59,6 +59,20 @@ be treated with caution.
Filling, expiring and consulting the session cache for client connections is
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
Internally sessions are referred to by a vhostname.hostname.port tuple.

View file

@ -268,6 +268,28 @@ bail:
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
lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl)
{

View file

@ -255,6 +255,15 @@ lws_ssl_close(struct lws *wsi)
SSL_set_info_callback(wsi->tls.ssl, NULL);
#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);
if (!wsi->socket_is_permanently_unusable)
SSL_shutdown(wsi->tls.ssl);

View file

@ -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);
#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");
lws_openssl_describe_cipher(wsi);
return LWS_SSL_CAPABLE_DONE;

View file

@ -91,9 +91,22 @@ lws_tls_reuse_session(struct lws *wsi)
}
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 */
@ -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, tls_sessions);
lws_sul_cancel(&ts->sul_ttl);
lws_context_lock(vh->context, __func__); /* -------------- cx { */
lws_vhost_lock(vh); /* -------------- vh { */
__lws_tls_session_destroy(ts);
@ -280,6 +292,47 @@ bail:
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
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;
lws_tls_sco_t *ts;
SSL_SESSION *sess;
SSL_SESSION *sess = NULL; /* allow it to "bail" early */
void *v;
if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)

View file

@ -449,6 +449,15 @@ lws_ssl_close(struct lws *wsi)
SSL_set_info_callback(wsi->tls.ssl, NULL);
#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);
if (!wsi->socket_is_permanently_unusable)
SSL_shutdown(wsi->tls.ssl);

View file

@ -118,6 +118,11 @@ enum lws_tls_extant {
#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
lws_tls_restrict_borrow(struct lws_context *context);

View file

@ -75,12 +75,15 @@ struct lws_vhost_tls {
};
struct lws_lws_tls {
lws_tls_conn *ssl;
lws_tls_bio *client_bio;
struct lws_dll2 dll_pending_tls;
char err_helper[32];
unsigned int use_ssl;
unsigned int redirect_to_https:1;
lws_tls_conn *ssl;
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;
char err_helper[32];
unsigned int use_ssl;
unsigned int redirect_to_https:1;
};
@ -95,6 +98,10 @@ lws_ssl_pending(struct lws *wsi);
int LWS_WARN_UNUSED_RESULT
lws_server_socket_service_ssl(struct lws *new_wsi, lws_sockfd_type accept_fd,
char is_pollin);
void
lws_sess_cache_synth_cb(lws_sorted_usec_list_t *sul);
int
lws_ssl_close(struct lws *wsi);
void

View file

@ -51,9 +51,6 @@ if (requirements)
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)
@ -138,7 +135,10 @@ if (requirements)
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})
set_tests_properties(${mytests} PROPERTIES