mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
mbedtls: session cache and resume
This commit is contained in:
parent
d5753b6298
commit
e2f1dd1c82
11 changed files with 322 additions and 8 deletions
|
@ -396,8 +396,8 @@ if (LWS_WITH_PLUGINS AND NOT LWS_WITH_SHARED)
|
|||
endif()
|
||||
|
||||
if (LWS_WITH_TLS_SESSIONS)
|
||||
if (NOT LWS_WITH_NETWORK OR NOT LWS_WITH_CLIENT OR LWS_WITH_MBEDTLS)
|
||||
message("TLS_SESSIONS support only covers client on openssl atm, disabling")
|
||||
if (NOT LWS_WITH_NETWORK OR NOT LWS_WITH_CLIENT)
|
||||
message("TLS_SESSIONS support requires client, disabling")
|
||||
set(LWS_WITH_TLS_SESSIONS OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -320,6 +320,9 @@ static const char * const opts_str =
|
|||
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
|
||||
"SSPROX "
|
||||
#endif
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
"MbedTLS "
|
||||
#endif
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
"ASYNC_DNS "
|
||||
#endif
|
||||
|
|
|
@ -122,6 +122,10 @@ if (LWS_WITH_SSL)
|
|||
list(APPEND SOURCES
|
||||
tls/mbedtls/mbedtls-ssl.c)
|
||||
endif()
|
||||
if (LWS_WITH_TLS_SESSIONS)
|
||||
list(APPEND SOURCES
|
||||
tls/mbedtls/mbedtls-session.c)
|
||||
endif()
|
||||
if (LWS_WITH_GENCRYPTO)
|
||||
list(APPEND SOURCES
|
||||
tls/mbedtls/lws-genhash.c
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-tls-mbedtls.h"
|
||||
|
||||
static int
|
||||
OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
|
@ -66,6 +67,11 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_TLS_SESSIONS)
|
||||
if (!(wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE))
|
||||
lws_tls_reuse_session(wsi);
|
||||
#endif
|
||||
|
||||
if (wsi->a.vhost->tls.ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
|
||||
|
||||
|
@ -195,6 +201,9 @@ lws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen)
|
|||
if (n == 1) {
|
||||
SSL_get0_alpn_selected(wsi->tls.ssl, &prot, &len);
|
||||
lws_role_call_alpn_negotiated(wsi, (const char *)prot);
|
||||
#if defined(LWS_WITH_TLS_SESSIONS)
|
||||
lws_tls_session_new_mbedtls(wsi);
|
||||
#endif
|
||||
lwsl_info("client connect OK\n");
|
||||
return LWS_SSL_CAPABLE_DONE;
|
||||
}
|
||||
|
@ -317,6 +326,12 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
|
|||
unsigned long error;
|
||||
int n;
|
||||
|
||||
#if defined(LWS_WITH_TLS_SESSIONS)
|
||||
vh->tls_session_cache_max = info->tls_session_cache_max ?
|
||||
info->tls_session_cache_max : 10;
|
||||
lws_tls_session_cache(vh, info->tls_session_timeout);
|
||||
#endif
|
||||
|
||||
if (!method) {
|
||||
error = (unsigned long)ERR_get_error();
|
||||
lwsl_err("problem creating ssl method %lu: %s\n",
|
||||
|
|
277
lib/tls/mbedtls/mbedtls-session.c
Normal file
277
lib/tls/mbedtls/mbedtls-session.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
|
||||
typedef struct lws_tls_session_cache_mbedtls {
|
||||
lws_dll2_t list;
|
||||
|
||||
mbedtls_ssl_session session;
|
||||
lws_sorted_usec_list_t sul_ttl;
|
||||
|
||||
/* name is overallocated here */
|
||||
} lws_tls_scm_t;
|
||||
|
||||
#define lwsl_tlssess lwsl_notice
|
||||
|
||||
static int
|
||||
lws_tls_session_name_from_wsi(struct lws *wsi, char *buf, size_t len)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/*
|
||||
* We have to include the vhost name in the session tag, since
|
||||
* different vhosts may make connections to the same endpoint using
|
||||
* different client certs.
|
||||
*/
|
||||
|
||||
n = (size_t)lws_snprintf(buf, len, "%s.", wsi->a.vhost->name);
|
||||
|
||||
buf += n;
|
||||
len = len - n;
|
||||
|
||||
lws_sa46_write_numeric_address(&wsi->sa46_peer, buf, len - 8);
|
||||
lws_snprintf(buf + strlen(buf), 8, ":%u", wsi->c_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
__lws_tls_session_destroy(lws_tls_scm_t *ts)
|
||||
{
|
||||
lwsl_tlssess("%s: %s (%u)\n", __func__, (const char *)&ts[1],
|
||||
(unsigned int)(ts->list.owner->count - 1));
|
||||
|
||||
lws_sul_cancel(&ts->sul_ttl);
|
||||
mbedtls_ssl_session_free(&ts->session);
|
||||
lws_dll2_remove(&ts->list); /* vh lock */
|
||||
|
||||
lws_free(ts);
|
||||
}
|
||||
|
||||
static lws_tls_scm_t *
|
||||
__lws_tls_session_lookup_by_name(struct lws_vhost *vh, const char *name)
|
||||
{
|
||||
lws_start_foreach_dll(struct lws_dll2 *, p,
|
||||
lws_dll2_get_head(&vh->tls_sessions)) {
|
||||
lws_tls_scm_t *ts = lws_container_of(p, lws_tls_scm_t, list);
|
||||
const char *ts_name = (const char *)&ts[1];
|
||||
|
||||
if (!strcmp(name, ts_name))
|
||||
return ts;
|
||||
|
||||
} lws_end_foreach_dll(p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If possible, reuse an existing, cached session
|
||||
*/
|
||||
|
||||
void
|
||||
lws_tls_reuse_session(struct lws *wsi)
|
||||
{
|
||||
char buf[16 + 48 + 1 + 8 + 1];
|
||||
mbedtls_ssl_context *msc;
|
||||
lws_tls_scm_t *ts;
|
||||
|
||||
if (!wsi->a.vhost ||
|
||||
wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
|
||||
return;
|
||||
|
||||
lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */
|
||||
lws_vhost_lock(wsi->a.vhost); /* -------------- vh { */
|
||||
|
||||
lws_tls_session_name_from_wsi(wsi, buf, sizeof(buf));
|
||||
ts = __lws_tls_session_lookup_by_name(wsi->a.vhost, buf);
|
||||
|
||||
if (!ts) {
|
||||
lwsl_tlssess("%s: no existing session for %s\n", __func__, buf);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
lwsl_tlssess("%s: %s\n", __func__, (const char *)&ts[1]);
|
||||
wsi->tls_session_reused = 1;
|
||||
|
||||
msc = SSL_mbedtls_ssl_context_from_SSL(wsi->tls.ssl);
|
||||
mbedtls_ssl_set_session(msc, &ts->session);
|
||||
|
||||
/* keep our session list sorted in lru -> mru order */
|
||||
|
||||
lws_dll2_remove(&ts->list);
|
||||
lws_dll2_add_tail(&ts->list, &wsi->a.vhost->tls_sessions);
|
||||
|
||||
bail:
|
||||
lws_vhost_unlock(wsi->a.vhost); /* } vh -------------- */
|
||||
lws_context_unlock(wsi->a.context); /* } cx -------------- */
|
||||
}
|
||||
|
||||
static int
|
||||
lws_tls_session_destroy_dll(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
lws_tls_scm_t *ts = lws_container_of(d, lws_tls_scm_t, list);
|
||||
|
||||
__lws_tls_session_destroy(ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_tls_session_vh_destroy(struct lws_vhost *vh)
|
||||
{
|
||||
lws_dll2_foreach_safe(&vh->tls_sessions, NULL,
|
||||
lws_tls_session_destroy_dll);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_tls_session_expiry_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
lws_tls_scm_t *ts = lws_container_of(sul, lws_tls_scm_t, sul_ttl);
|
||||
struct lws_vhost *vh = lws_container_of(ts->list.owner,
|
||||
struct lws_vhost, tls_sessions);
|
||||
|
||||
lws_context_lock(vh->context, __func__); /* -------------- cx { */
|
||||
lws_vhost_lock(vh); /* -------------- vh { */
|
||||
__lws_tls_session_destroy(ts);
|
||||
lws_vhost_unlock(vh); /* } vh -------------- */
|
||||
lws_context_unlock(vh->context); /* } cx -------------- */
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after SSL_accept on the wsi
|
||||
*/
|
||||
|
||||
int
|
||||
lws_tls_session_new_mbedtls(struct lws *wsi)
|
||||
{
|
||||
char buf[16 + 48 + 1 + 8 + 1];
|
||||
mbedtls_ssl_context *msc;
|
||||
struct lws_vhost *vh;
|
||||
lws_tls_scm_t *ts;
|
||||
size_t nl;
|
||||
#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
|
||||
const char *disposition = "reuse";
|
||||
#endif
|
||||
|
||||
vh = wsi->a.vhost;
|
||||
if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
|
||||
return 0;
|
||||
|
||||
lws_tls_session_name_from_wsi(wsi, buf, sizeof(buf));
|
||||
nl = strlen(buf);
|
||||
|
||||
msc = SSL_mbedtls_ssl_context_from_SSL(wsi->tls.ssl);
|
||||
|
||||
lws_context_lock(vh->context, __func__); /* -------------- cx { */
|
||||
lws_vhost_lock(vh); /* -------------- vh { */
|
||||
|
||||
ts = __lws_tls_session_lookup_by_name(vh, buf);
|
||||
|
||||
if (!ts) {
|
||||
/*
|
||||
* We have to make our own, new session
|
||||
*/
|
||||
|
||||
if (vh->tls_sessions.count == vh->tls_session_cache_max) {
|
||||
|
||||
/*
|
||||
* We have reached the vhost's session cache limit,
|
||||
* prune the LRU / head
|
||||
*/
|
||||
ts = lws_container_of(vh->tls_sessions.head,
|
||||
lws_tls_scm_t, list);
|
||||
|
||||
lwsl_tlssess("%s: pruning oldest session (hit max %u)\n",
|
||||
__func__,
|
||||
(unsigned int)vh->tls_session_cache_max);
|
||||
|
||||
lws_vhost_lock(vh); /* -------------- vh { */
|
||||
__lws_tls_session_destroy(ts);
|
||||
lws_vhost_unlock(vh); /* } vh -------------- */
|
||||
}
|
||||
|
||||
ts = lws_malloc(sizeof(*ts) + nl + 1, __func__);
|
||||
|
||||
if (!ts)
|
||||
goto bail;
|
||||
|
||||
memset(ts, 0, sizeof(*ts));
|
||||
memcpy(&ts[1], buf, nl + 1);
|
||||
|
||||
if (mbedtls_ssl_get_session(msc, &ts->session))
|
||||
/* no joy for whatever reason */
|
||||
goto bail;
|
||||
|
||||
lws_dll2_add_tail(&ts->list, &vh->tls_sessions);
|
||||
|
||||
lws_sul_schedule(wsi->a.context, wsi->tsi, &ts->sul_ttl,
|
||||
lws_tls_session_expiry_cb,
|
||||
(int64_t)vh->tls.tls_session_cache_ttl *
|
||||
LWS_US_PER_SEC);
|
||||
|
||||
#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
|
||||
disposition = "new";
|
||||
#endif
|
||||
} else {
|
||||
|
||||
mbedtls_ssl_session_free(&ts->session);
|
||||
|
||||
if (mbedtls_ssl_get_session(msc, &ts->session))
|
||||
/* no joy for whatever reason */
|
||||
goto bail;
|
||||
|
||||
/* keep our session list sorted in lru -> mru order */
|
||||
|
||||
lws_dll2_remove(&ts->list);
|
||||
lws_dll2_add_tail(&ts->list, &vh->tls_sessions);
|
||||
}
|
||||
|
||||
lws_vhost_unlock(vh); /* } vh -------------- */
|
||||
lws_context_unlock(vh->context); /* } cx -------------- */
|
||||
|
||||
lwsl_tlssess("%s: %s: %s %s, (%s:%u)\n", __func__,
|
||||
wsi->lc.gutag, disposition, buf, vh->name,
|
||||
(unsigned int)vh->tls_sessions.count);
|
||||
|
||||
/*
|
||||
* indicate we will hold on to the SSL_SESSION reference, and take
|
||||
* responsibility to call SSL_SESSION_free() on it ourselves
|
||||
*/
|
||||
|
||||
return 1;
|
||||
|
||||
bail:
|
||||
lws_vhost_unlock(vh); /* } vh -------------- */
|
||||
lws_context_unlock(vh->context); /* } cx -------------- */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl)
|
||||
{
|
||||
/* Default to 1hr max recommendation from RFC5246 F.1.4 */
|
||||
vh->tls.tls_session_cache_ttl = !ttl ? 3600 : ttl;
|
||||
}
|
|
@ -36,3 +36,6 @@ lws_gencrypto_mbedtls_hash_to_MD_TYPE(enum lws_genhash_types hash_type);
|
|||
|
||||
int
|
||||
lws_gencrypto_mbedtls_rngf(void *context, unsigned char *buf, size_t len);
|
||||
|
||||
int
|
||||
lws_tls_session_new_mbedtls(struct lws *wsi);
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
|
||||
SSL *SSL_SSL_from_mbedtls_ssl_context(mbedtls_ssl_context *msc);
|
||||
|
||||
mbedtls_ssl_context *SSL_mbedtls_ssl_context_from_SSL(SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief create a SSL context
|
||||
*
|
||||
|
|
|
@ -885,6 +885,13 @@ SSL *SSL_SSL_from_mbedtls_ssl_context(mbedtls_ssl_context *msc)
|
|||
return ssl_pm->owner;
|
||||
}
|
||||
|
||||
mbedtls_ssl_context *SSL_mbedtls_ssl_context_from_SSL(SSL *ssl)
|
||||
{
|
||||
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
|
||||
|
||||
return &ssl_pm->ssl;
|
||||
}
|
||||
|
||||
#include "ssl_cert.h"
|
||||
|
||||
void SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
|
||||
|
|
|
@ -58,11 +58,5 @@ lws_gencrypto_openssl_hash_to_EVP_MD(enum lws_genhash_types hash_type);
|
|||
int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen);
|
||||
#endif
|
||||
|
||||
void
|
||||
lws_tls_reuse_session(struct lws *wsi);
|
||||
|
||||
void
|
||||
lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -190,6 +190,11 @@ int
|
|||
lws_genec_confirm_curve_allowed_by_tls_id(const char *allowed, int id,
|
||||
struct lws_jwk *jwk);
|
||||
|
||||
void
|
||||
lws_tls_reuse_session(struct lws *wsi);
|
||||
|
||||
void
|
||||
lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl);
|
||||
|
||||
#else /* ! WITH_TLS */
|
||||
|
||||
|
|
|
@ -66,6 +66,10 @@ struct lws_vhost_tls {
|
|||
int allow_non_ssl_on_ssl_port;
|
||||
int ssl_info_event_mask;
|
||||
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
uint32_t tls_session_cache_ttl;
|
||||
#endif
|
||||
|
||||
unsigned int user_supplied_ssl_ctx:1;
|
||||
unsigned int skipped_certs:1;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue