1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2022 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "private-lib-core.h" 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_citypedef struct lws_tls_session_cache_openssl { 28d4afb5ceSopenharmony_ci lws_dll2_t list; 29d4afb5ceSopenharmony_ci 30d4afb5ceSopenharmony_ci SSL_SESSION *session; 31d4afb5ceSopenharmony_ci lws_sorted_usec_list_t sul_ttl; 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_ci /* name is overallocated here */ 34d4afb5ceSopenharmony_ci} lws_tls_sco_t; 35d4afb5ceSopenharmony_ci 36d4afb5ceSopenharmony_ci#define tlssess_loglevel LLL_INFO 37d4afb5ceSopenharmony_ci#if (_LWS_ENABLED_LOGS & tlssess_loglevel) 38d4afb5ceSopenharmony_ci#define lwsl_tlssess(...) _lws_log(tlssess_loglevel, __VA_ARGS__) 39d4afb5ceSopenharmony_ci#else 40d4afb5ceSopenharmony_ci#define lwsl_tlssess(...) 41d4afb5ceSopenharmony_ci#endif 42d4afb5ceSopenharmony_ci 43d4afb5ceSopenharmony_cistatic void 44d4afb5ceSopenharmony_ci__lws_tls_session_destroy(lws_tls_sco_t *ts) 45d4afb5ceSopenharmony_ci{ 46d4afb5ceSopenharmony_ci lwsl_tlssess("%s: %s (%u)\n", __func__, (const char *)&ts[1], 47d4afb5ceSopenharmony_ci ts->list.owner->count - 1); 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci lws_sul_cancel(&ts->sul_ttl); 50d4afb5ceSopenharmony_ci SSL_SESSION_free(ts->session); 51d4afb5ceSopenharmony_ci lws_dll2_remove(&ts->list); /* vh lock */ 52d4afb5ceSopenharmony_ci 53d4afb5ceSopenharmony_ci lws_free(ts); 54d4afb5ceSopenharmony_ci} 55d4afb5ceSopenharmony_ci 56d4afb5ceSopenharmony_cistatic lws_tls_sco_t * 57d4afb5ceSopenharmony_ci__lws_tls_session_lookup_by_name(struct lws_vhost *vh, const char *name) 58d4afb5ceSopenharmony_ci{ 59d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, p, 60d4afb5ceSopenharmony_ci lws_dll2_get_head(&vh->tls_sessions)) { 61d4afb5ceSopenharmony_ci lws_tls_sco_t *ts = lws_container_of(p, lws_tls_sco_t, list); 62d4afb5ceSopenharmony_ci const char *ts_name = (const char *)&ts[1]; 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_ci if (!strcmp(name, ts_name)) 65d4afb5ceSopenharmony_ci return ts; 66d4afb5ceSopenharmony_ci 67d4afb5ceSopenharmony_ci } lws_end_foreach_dll(p); 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci return NULL; 70d4afb5ceSopenharmony_ci} 71d4afb5ceSopenharmony_ci 72d4afb5ceSopenharmony_ci/* 73d4afb5ceSopenharmony_ci * If possible, reuse an existing, cached session 74d4afb5ceSopenharmony_ci */ 75d4afb5ceSopenharmony_ci 76d4afb5ceSopenharmony_civoid 77d4afb5ceSopenharmony_cilws_tls_reuse_session(struct lws *wsi) 78d4afb5ceSopenharmony_ci{ 79d4afb5ceSopenharmony_ci char tag[LWS_SESSION_TAG_LEN]; 80d4afb5ceSopenharmony_ci lws_tls_sco_t *ts; 81d4afb5ceSopenharmony_ci 82d4afb5ceSopenharmony_ci if (!wsi->a.vhost || 83d4afb5ceSopenharmony_ci wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) 84d4afb5ceSopenharmony_ci return; 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_ci lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */ 87d4afb5ceSopenharmony_ci lws_vhost_lock(wsi->a.vhost); /* -------------- vh { */ 88d4afb5ceSopenharmony_ci 89d4afb5ceSopenharmony_ci if (lws_tls_session_tag_from_wsi(wsi, tag, sizeof(tag))) 90d4afb5ceSopenharmony_ci goto bail; 91d4afb5ceSopenharmony_ci ts = __lws_tls_session_lookup_by_name(wsi->a.vhost, tag); 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci if (!ts) { 94d4afb5ceSopenharmony_ci lwsl_tlssess("%s: no existing session for %s\n", __func__, tag); 95d4afb5ceSopenharmony_ci goto bail; 96d4afb5ceSopenharmony_ci } 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci lwsl_tlssess("%s: %s\n", __func__, (const char *)&ts[1]); 99d4afb5ceSopenharmony_ci 100d4afb5ceSopenharmony_ci if (!SSL_set_session(wsi->tls.ssl, ts->session)) { 101d4afb5ceSopenharmony_ci lwsl_err("%s: session not set for %s\n", __func__, tag); 102d4afb5ceSopenharmony_ci goto bail; 103d4afb5ceSopenharmony_ci } 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 106d4afb5ceSopenharmony_ci /* extend session lifetime */ 107d4afb5ceSopenharmony_ci SSL_SESSION_set_time(ts->session, 108d4afb5ceSopenharmony_ci#if defined(OPENSSL_IS_BORINGSSL) 109d4afb5ceSopenharmony_ci (unsigned long) 110d4afb5ceSopenharmony_ci#else 111d4afb5ceSopenharmony_ci (long) 112d4afb5ceSopenharmony_ci#endif 113d4afb5ceSopenharmony_ci time(NULL)); 114d4afb5ceSopenharmony_ci#endif 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci /* keep our session list sorted in lru -> mru order */ 117d4afb5ceSopenharmony_ci 118d4afb5ceSopenharmony_ci lws_dll2_remove(&ts->list); 119d4afb5ceSopenharmony_ci lws_dll2_add_tail(&ts->list, &wsi->a.vhost->tls_sessions); 120d4afb5ceSopenharmony_ci 121d4afb5ceSopenharmony_cibail: 122d4afb5ceSopenharmony_ci lws_vhost_unlock(wsi->a.vhost); /* } vh -------------- */ 123d4afb5ceSopenharmony_ci lws_context_unlock(wsi->a.context); /* } cx -------------- */ 124d4afb5ceSopenharmony_ci} 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_ciint 127d4afb5ceSopenharmony_cilws_tls_session_is_reused(struct lws *wsi) 128d4afb5ceSopenharmony_ci{ 129d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 130d4afb5ceSopenharmony_ci struct lws *nwsi = lws_get_network_wsi(wsi); 131d4afb5ceSopenharmony_ci 132d4afb5ceSopenharmony_ci if (!nwsi || !nwsi->tls.ssl) 133d4afb5ceSopenharmony_ci return 0; 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_ci return (int)SSL_session_reused(nwsi->tls.ssl); 136d4afb5ceSopenharmony_ci#else 137d4afb5ceSopenharmony_ci return 0; 138d4afb5ceSopenharmony_ci#endif 139d4afb5ceSopenharmony_ci} 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_cistatic int 142d4afb5ceSopenharmony_cilws_tls_session_destroy_dll(struct lws_dll2 *d, void *user) 143d4afb5ceSopenharmony_ci{ 144d4afb5ceSopenharmony_ci lws_tls_sco_t *ts = lws_container_of(d, lws_tls_sco_t, list); 145d4afb5ceSopenharmony_ci 146d4afb5ceSopenharmony_ci __lws_tls_session_destroy(ts); 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci return 0; 149d4afb5ceSopenharmony_ci} 150d4afb5ceSopenharmony_ci 151d4afb5ceSopenharmony_civoid 152d4afb5ceSopenharmony_cilws_tls_session_vh_destroy(struct lws_vhost *vh) 153d4afb5ceSopenharmony_ci{ 154d4afb5ceSopenharmony_ci lws_dll2_foreach_safe(&vh->tls_sessions, NULL, 155d4afb5ceSopenharmony_ci lws_tls_session_destroy_dll); 156d4afb5ceSopenharmony_ci} 157d4afb5ceSopenharmony_ci 158d4afb5ceSopenharmony_cistatic void 159d4afb5ceSopenharmony_cilws_tls_session_expiry_cb(lws_sorted_usec_list_t *sul) 160d4afb5ceSopenharmony_ci{ 161d4afb5ceSopenharmony_ci lws_tls_sco_t *ts = lws_container_of(sul, lws_tls_sco_t, sul_ttl); 162d4afb5ceSopenharmony_ci struct lws_vhost *vh = lws_container_of(ts->list.owner, 163d4afb5ceSopenharmony_ci struct lws_vhost, tls_sessions); 164d4afb5ceSopenharmony_ci 165d4afb5ceSopenharmony_ci lws_context_lock(vh->context, __func__); /* -------------- cx { */ 166d4afb5ceSopenharmony_ci lws_vhost_lock(vh); /* -------------- vh { */ 167d4afb5ceSopenharmony_ci __lws_tls_session_destroy(ts); 168d4afb5ceSopenharmony_ci lws_vhost_unlock(vh); /* } vh -------------- */ 169d4afb5ceSopenharmony_ci lws_context_unlock(vh->context); /* } cx -------------- */ 170d4afb5ceSopenharmony_ci} 171d4afb5ceSopenharmony_ci 172d4afb5ceSopenharmony_cistatic lws_tls_sco_t * 173d4afb5ceSopenharmony_cilws_tls_session_add_entry(struct lws_vhost *vh, const char *tag) 174d4afb5ceSopenharmony_ci{ 175d4afb5ceSopenharmony_ci lws_tls_sco_t *ts; 176d4afb5ceSopenharmony_ci size_t nl = strlen(tag); 177d4afb5ceSopenharmony_ci 178d4afb5ceSopenharmony_ci if (vh->tls_sessions.count == (vh->tls_session_cache_max ? 179d4afb5ceSopenharmony_ci vh->tls_session_cache_max : 10)) { 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci /* 182d4afb5ceSopenharmony_ci * We have reached the vhost's session cache limit, 183d4afb5ceSopenharmony_ci * prune the LRU / head 184d4afb5ceSopenharmony_ci */ 185d4afb5ceSopenharmony_ci ts = lws_container_of(vh->tls_sessions.head, 186d4afb5ceSopenharmony_ci lws_tls_sco_t, list); 187d4afb5ceSopenharmony_ci 188d4afb5ceSopenharmony_ci if (ts) { /* centos 7 ... */ 189d4afb5ceSopenharmony_ci lwsl_tlssess("%s: pruning oldest session\n", __func__); 190d4afb5ceSopenharmony_ci 191d4afb5ceSopenharmony_ci lws_vhost_lock(vh); /* -------------- vh { */ 192d4afb5ceSopenharmony_ci __lws_tls_session_destroy(ts); 193d4afb5ceSopenharmony_ci lws_vhost_unlock(vh); /* } vh -------------- */ 194d4afb5ceSopenharmony_ci } 195d4afb5ceSopenharmony_ci } 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci ts = lws_malloc(sizeof(*ts) + nl + 1, __func__); 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_ci if (!ts) 200d4afb5ceSopenharmony_ci return NULL; 201d4afb5ceSopenharmony_ci 202d4afb5ceSopenharmony_ci memset(ts, 0, sizeof(*ts)); 203d4afb5ceSopenharmony_ci memcpy(&ts[1], tag, nl + 1); 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci lws_dll2_add_tail(&ts->list, &vh->tls_sessions); 206d4afb5ceSopenharmony_ci 207d4afb5ceSopenharmony_ci return ts; 208d4afb5ceSopenharmony_ci} 209d4afb5ceSopenharmony_ci 210d4afb5ceSopenharmony_cistatic int 211d4afb5ceSopenharmony_cilws_tls_session_new_cb(SSL *ssl, SSL_SESSION *sess) 212d4afb5ceSopenharmony_ci{ 213d4afb5ceSopenharmony_ci struct lws *wsi = (struct lws *)SSL_get_ex_data(ssl, 214d4afb5ceSopenharmony_ci openssl_websocket_private_data_index); 215d4afb5ceSopenharmony_ci char tag[LWS_SESSION_TAG_LEN]; 216d4afb5ceSopenharmony_ci struct lws_vhost *vh; 217d4afb5ceSopenharmony_ci lws_tls_sco_t *ts; 218d4afb5ceSopenharmony_ci long ttl; 219d4afb5ceSopenharmony_ci#if (_LWS_ENABLED_LOGS & tlssess_loglevel) 220d4afb5ceSopenharmony_ci const char *disposition = "reuse"; 221d4afb5ceSopenharmony_ci#endif 222d4afb5ceSopenharmony_ci 223d4afb5ceSopenharmony_ci if (!wsi) { 224d4afb5ceSopenharmony_ci lwsl_warn("%s: can't get wsi from ssl privdata\n", __func__); 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci return 0; 227d4afb5ceSopenharmony_ci } 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci vh = wsi->a.vhost; 230d4afb5ceSopenharmony_ci if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) 231d4afb5ceSopenharmony_ci return 0; 232d4afb5ceSopenharmony_ci 233d4afb5ceSopenharmony_ci if (lws_tls_session_tag_from_wsi(wsi, tag, sizeof(tag))) 234d4afb5ceSopenharmony_ci return 0; 235d4afb5ceSopenharmony_ci 236d4afb5ceSopenharmony_ci /* api return is long, although we only support setting 237d4afb5ceSopenharmony_ci * default (300s) or max uint32_t */ 238d4afb5ceSopenharmony_ci ttl = SSL_SESSION_get_timeout(sess); 239d4afb5ceSopenharmony_ci 240d4afb5ceSopenharmony_ci lws_context_lock(vh->context, __func__); /* -------------- cx { */ 241d4afb5ceSopenharmony_ci lws_vhost_lock(vh); /* -------------- vh { */ 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci ts = __lws_tls_session_lookup_by_name(vh, tag); 244d4afb5ceSopenharmony_ci 245d4afb5ceSopenharmony_ci if (!ts) { 246d4afb5ceSopenharmony_ci ts = lws_tls_session_add_entry(vh, tag); 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_ci if (!ts) 249d4afb5ceSopenharmony_ci goto bail; 250d4afb5ceSopenharmony_ci 251d4afb5ceSopenharmony_ci lws_sul_schedule(wsi->a.context, wsi->tsi, &ts->sul_ttl, 252d4afb5ceSopenharmony_ci lws_tls_session_expiry_cb, 253d4afb5ceSopenharmony_ci ttl * LWS_US_PER_SEC); 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci#if (_LWS_ENABLED_LOGS & tlssess_loglevel) 256d4afb5ceSopenharmony_ci disposition = "new"; 257d4afb5ceSopenharmony_ci#endif 258d4afb5ceSopenharmony_ci 259d4afb5ceSopenharmony_ci /* 260d4afb5ceSopenharmony_ci * We don't have to do a SSL_SESSION_up_ref() here, because 261d4afb5ceSopenharmony_ci * we will return from this callback indicating that we kept the 262d4afb5ceSopenharmony_ci * ref 263d4afb5ceSopenharmony_ci */ 264d4afb5ceSopenharmony_ci } else { 265d4afb5ceSopenharmony_ci /* 266d4afb5ceSopenharmony_ci * Give up our refcount on the session we are about to replace 267d4afb5ceSopenharmony_ci * with a newer one 268d4afb5ceSopenharmony_ci */ 269d4afb5ceSopenharmony_ci SSL_SESSION_free(ts->session); 270d4afb5ceSopenharmony_ci 271d4afb5ceSopenharmony_ci /* keep our session list sorted in lru -> mru order */ 272d4afb5ceSopenharmony_ci 273d4afb5ceSopenharmony_ci lws_dll2_remove(&ts->list); 274d4afb5ceSopenharmony_ci lws_dll2_add_tail(&ts->list, &vh->tls_sessions); 275d4afb5ceSopenharmony_ci } 276d4afb5ceSopenharmony_ci 277d4afb5ceSopenharmony_ci ts->session = sess; 278d4afb5ceSopenharmony_ci 279d4afb5ceSopenharmony_ci lws_vhost_unlock(vh); /* } vh -------------- */ 280d4afb5ceSopenharmony_ci lws_context_unlock(vh->context); /* } cx -------------- */ 281d4afb5ceSopenharmony_ci 282d4afb5ceSopenharmony_ci lwsl_tlssess("%s: %p: %s: %s %s, ttl %lds (%s:%u)\n", __func__, 283d4afb5ceSopenharmony_ci sess, wsi->lc.gutag, disposition, tag, ttl, vh->name, 284d4afb5ceSopenharmony_ci vh->tls_sessions.count); 285d4afb5ceSopenharmony_ci 286d4afb5ceSopenharmony_ci /* 287d4afb5ceSopenharmony_ci * indicate we will hold on to the SSL_SESSION reference, and take 288d4afb5ceSopenharmony_ci * responsibility to call SSL_SESSION_free() on it ourselves 289d4afb5ceSopenharmony_ci */ 290d4afb5ceSopenharmony_ci 291d4afb5ceSopenharmony_ci return 1; 292d4afb5ceSopenharmony_ci 293d4afb5ceSopenharmony_cibail: 294d4afb5ceSopenharmony_ci lws_vhost_unlock(vh); /* } vh -------------- */ 295d4afb5ceSopenharmony_ci lws_context_unlock(vh->context); /* } cx -------------- */ 296d4afb5ceSopenharmony_ci 297d4afb5ceSopenharmony_ci return 0; 298d4afb5ceSopenharmony_ci} 299d4afb5ceSopenharmony_ci 300d4afb5ceSopenharmony_ci#if defined(LWS_TLS_SYNTHESIZE_CB) 301d4afb5ceSopenharmony_ci 302d4afb5ceSopenharmony_ci/* 303d4afb5ceSopenharmony_ci * On openssl, there is an async cb coming when the server issues the session 304d4afb5ceSopenharmony_ci * information on the link, so we can pick it up and update the cache at the 305d4afb5ceSopenharmony_ci * right time. 306d4afb5ceSopenharmony_ci * 307d4afb5ceSopenharmony_ci * On mbedtls and some version at least of borning ssl, this cb is either not 308d4afb5ceSopenharmony_ci * part of the tls library apis or fails to arrive. 309d4afb5ceSopenharmony_ci * 310d4afb5ceSopenharmony_ci * This synthetic cb is called instead for those build cases, scheduled for 311d4afb5ceSopenharmony_ci * +500ms after the tls negotiation completed. 312d4afb5ceSopenharmony_ci */ 313d4afb5ceSopenharmony_ci 314d4afb5ceSopenharmony_civoid 315d4afb5ceSopenharmony_cilws_sess_cache_synth_cb(lws_sorted_usec_list_t *sul) 316d4afb5ceSopenharmony_ci{ 317d4afb5ceSopenharmony_ci struct lws_lws_tls *tls = lws_container_of(sul, struct lws_lws_tls, 318d4afb5ceSopenharmony_ci sul_cb_synth); 319d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(tls, struct lws, tls); 320d4afb5ceSopenharmony_ci SSL_SESSION *sess; 321d4afb5ceSopenharmony_ci 322d4afb5ceSopenharmony_ci if (lws_tls_session_is_reused(wsi)) 323d4afb5ceSopenharmony_ci return; 324d4afb5ceSopenharmony_ci 325d4afb5ceSopenharmony_ci sess = SSL_get1_session(tls->ssl); 326d4afb5ceSopenharmony_ci if (!sess) 327d4afb5ceSopenharmony_ci return; 328d4afb5ceSopenharmony_ci 329d4afb5ceSopenharmony_ci if (!SSL_SESSION_is_resumable(sess) || /* not worth caching, or... */ 330d4afb5ceSopenharmony_ci !lws_tls_session_new_cb(tls->ssl, sess)) { /* ...cb didn't keep it */ 331d4afb5ceSopenharmony_ci /* 332d4afb5ceSopenharmony_ci * For now the policy if no session message after the wait, 333d4afb5ceSopenharmony_ci * is just let it be. Typically the session info is sent 334d4afb5ceSopenharmony_ci * early. 335d4afb5ceSopenharmony_ci */ 336d4afb5ceSopenharmony_ci SSL_SESSION_free(sess); 337d4afb5ceSopenharmony_ci } 338d4afb5ceSopenharmony_ci} 339d4afb5ceSopenharmony_ci#endif 340d4afb5ceSopenharmony_ci 341d4afb5ceSopenharmony_civoid 342d4afb5ceSopenharmony_cilws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl) 343d4afb5ceSopenharmony_ci{ 344d4afb5ceSopenharmony_ci long cmode; 345d4afb5ceSopenharmony_ci 346d4afb5ceSopenharmony_ci if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) 347d4afb5ceSopenharmony_ci return; 348d4afb5ceSopenharmony_ci 349d4afb5ceSopenharmony_ci cmode = SSL_CTX_get_session_cache_mode(vh->tls.ssl_client_ctx); 350d4afb5ceSopenharmony_ci 351d4afb5ceSopenharmony_ci SSL_CTX_set_session_cache_mode(vh->tls.ssl_client_ctx, 352d4afb5ceSopenharmony_ci (int)(cmode | SSL_SESS_CACHE_CLIENT)); 353d4afb5ceSopenharmony_ci 354d4afb5ceSopenharmony_ci SSL_CTX_sess_set_new_cb(vh->tls.ssl_client_ctx, lws_tls_session_new_cb); 355d4afb5ceSopenharmony_ci 356d4afb5ceSopenharmony_ci if (!ttl) 357d4afb5ceSopenharmony_ci return; 358d4afb5ceSopenharmony_ci 359d4afb5ceSopenharmony_ci#if defined(OPENSSL_IS_BORINGSSL) 360d4afb5ceSopenharmony_ci SSL_CTX_set_timeout(vh->tls.ssl_client_ctx, ttl); 361d4afb5ceSopenharmony_ci#else 362d4afb5ceSopenharmony_ci SSL_CTX_set_timeout(vh->tls.ssl_client_ctx, (long)ttl); 363d4afb5ceSopenharmony_ci#endif 364d4afb5ceSopenharmony_ci} 365d4afb5ceSopenharmony_ci 366d4afb5ceSopenharmony_ciint 367d4afb5ceSopenharmony_cilws_tls_session_dump_save(struct lws_vhost *vh, const char *host, uint16_t port, 368d4afb5ceSopenharmony_ci lws_tls_sess_cb_t cb_save, void *opq) 369d4afb5ceSopenharmony_ci{ 370d4afb5ceSopenharmony_ci struct lws_tls_session_dump d; 371d4afb5ceSopenharmony_ci lws_tls_sco_t *ts; 372d4afb5ceSopenharmony_ci int ret = 1, bl; 373d4afb5ceSopenharmony_ci void *v; 374d4afb5ceSopenharmony_ci 375d4afb5ceSopenharmony_ci if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) 376d4afb5ceSopenharmony_ci return 1; 377d4afb5ceSopenharmony_ci 378d4afb5ceSopenharmony_ci lws_tls_session_tag_discrete(vh->name, host, port, d.tag, sizeof(d.tag)); 379d4afb5ceSopenharmony_ci 380d4afb5ceSopenharmony_ci lws_context_lock(vh->context, __func__); /* -------------- cx { */ 381d4afb5ceSopenharmony_ci lws_vhost_lock(vh); /* -------------- vh { */ 382d4afb5ceSopenharmony_ci 383d4afb5ceSopenharmony_ci ts = __lws_tls_session_lookup_by_name(vh, d.tag); 384d4afb5ceSopenharmony_ci if (!ts) 385d4afb5ceSopenharmony_ci goto bail; 386d4afb5ceSopenharmony_ci 387d4afb5ceSopenharmony_ci /* We have a ref on the session, exit via bail to clean it... */ 388d4afb5ceSopenharmony_ci 389d4afb5ceSopenharmony_ci bl = i2d_SSL_SESSION(ts->session, NULL); 390d4afb5ceSopenharmony_ci if (!bl) 391d4afb5ceSopenharmony_ci goto bail; 392d4afb5ceSopenharmony_ci 393d4afb5ceSopenharmony_ci d.blob_len = (size_t)bl; 394d4afb5ceSopenharmony_ci v = d.blob = lws_malloc(d.blob_len, __func__); 395d4afb5ceSopenharmony_ci 396d4afb5ceSopenharmony_ci if (d.blob) { 397d4afb5ceSopenharmony_ci 398d4afb5ceSopenharmony_ci /* this advances d.blob by the blob size ;-) */ 399d4afb5ceSopenharmony_ci i2d_SSL_SESSION(ts->session, (uint8_t **)&d.blob); 400d4afb5ceSopenharmony_ci 401d4afb5ceSopenharmony_ci d.opaque = opq; 402d4afb5ceSopenharmony_ci d.blob = v; 403d4afb5ceSopenharmony_ci if (cb_save(vh->context, &d)) 404d4afb5ceSopenharmony_ci lwsl_notice("%s: save failed\n", __func__); 405d4afb5ceSopenharmony_ci else 406d4afb5ceSopenharmony_ci ret = 0; 407d4afb5ceSopenharmony_ci 408d4afb5ceSopenharmony_ci lws_free(v); 409d4afb5ceSopenharmony_ci } 410d4afb5ceSopenharmony_ci 411d4afb5ceSopenharmony_cibail: 412d4afb5ceSopenharmony_ci lws_vhost_unlock(vh); /* } vh -------------- */ 413d4afb5ceSopenharmony_ci lws_context_unlock(vh->context); /* } cx -------------- */ 414d4afb5ceSopenharmony_ci 415d4afb5ceSopenharmony_ci return ret; 416d4afb5ceSopenharmony_ci} 417d4afb5ceSopenharmony_ci 418d4afb5ceSopenharmony_ciint 419d4afb5ceSopenharmony_cilws_tls_session_dump_load(struct lws_vhost *vh, const char *host, uint16_t port, 420d4afb5ceSopenharmony_ci lws_tls_sess_cb_t cb_load, void *opq) 421d4afb5ceSopenharmony_ci{ 422d4afb5ceSopenharmony_ci struct lws_tls_session_dump d; 423d4afb5ceSopenharmony_ci lws_tls_sco_t *ts; 424d4afb5ceSopenharmony_ci SSL_SESSION *sess = NULL; /* allow it to "bail" early */ 425d4afb5ceSopenharmony_ci void *v; 426d4afb5ceSopenharmony_ci 427d4afb5ceSopenharmony_ci if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) 428d4afb5ceSopenharmony_ci return 1; 429d4afb5ceSopenharmony_ci 430d4afb5ceSopenharmony_ci d.opaque = opq; 431d4afb5ceSopenharmony_ci lws_tls_session_tag_discrete(vh->name, host, port, d.tag, sizeof(d.tag)); 432d4afb5ceSopenharmony_ci 433d4afb5ceSopenharmony_ci lws_context_lock(vh->context, __func__); /* -------------- cx { */ 434d4afb5ceSopenharmony_ci lws_vhost_lock(vh); /* -------------- vh { */ 435d4afb5ceSopenharmony_ci 436d4afb5ceSopenharmony_ci ts = __lws_tls_session_lookup_by_name(vh, d.tag); 437d4afb5ceSopenharmony_ci 438d4afb5ceSopenharmony_ci if (ts) { 439d4afb5ceSopenharmony_ci /* 440d4afb5ceSopenharmony_ci * Since we are getting this out of cold storage, we should 441d4afb5ceSopenharmony_ci * not replace any existing session since it is likely newer 442d4afb5ceSopenharmony_ci */ 443d4afb5ceSopenharmony_ci lwsl_notice("%s: session already exists for %s\n", __func__, 444d4afb5ceSopenharmony_ci d.tag); 445d4afb5ceSopenharmony_ci goto bail1; 446d4afb5ceSopenharmony_ci } 447d4afb5ceSopenharmony_ci 448d4afb5ceSopenharmony_ci if (cb_load(vh->context, &d)) { 449d4afb5ceSopenharmony_ci lwsl_warn("%s: load failed\n", __func__); 450d4afb5ceSopenharmony_ci 451d4afb5ceSopenharmony_ci goto bail1; 452d4afb5ceSopenharmony_ci } 453d4afb5ceSopenharmony_ci 454d4afb5ceSopenharmony_ci /* the callback has allocated the blob and set d.blob / d.blob_len */ 455d4afb5ceSopenharmony_ci 456d4afb5ceSopenharmony_ci v = d.blob; 457d4afb5ceSopenharmony_ci /* this advances d.blob by the blob size ;-) */ 458d4afb5ceSopenharmony_ci sess = d2i_SSL_SESSION(NULL, (const uint8_t **)&d.blob, 459d4afb5ceSopenharmony_ci (long)d.blob_len); 460d4afb5ceSopenharmony_ci free(v); /* user code will have used malloc() */ 461d4afb5ceSopenharmony_ci if (!sess) { 462d4afb5ceSopenharmony_ci lwsl_warn("%s: d2i_SSL_SESSION failed\n", __func__); 463d4afb5ceSopenharmony_ci goto bail; 464d4afb5ceSopenharmony_ci } 465d4afb5ceSopenharmony_ci 466d4afb5ceSopenharmony_ci lws_vhost_lock(vh); /* -------------- vh { */ 467d4afb5ceSopenharmony_ci ts = lws_tls_session_add_entry(vh, d.tag); 468d4afb5ceSopenharmony_ci lws_vhost_unlock(vh); /* } vh -------------- */ 469d4afb5ceSopenharmony_ci 470d4afb5ceSopenharmony_ci if (!ts) { 471d4afb5ceSopenharmony_ci lwsl_warn("%s: unable to add cache entry\n", __func__); 472d4afb5ceSopenharmony_ci goto bail; 473d4afb5ceSopenharmony_ci } 474d4afb5ceSopenharmony_ci 475d4afb5ceSopenharmony_ci ts->session = sess; 476d4afb5ceSopenharmony_ci lwsl_tlssess("%s: session loaded OK\n", __func__); 477d4afb5ceSopenharmony_ci 478d4afb5ceSopenharmony_ci lws_vhost_unlock(vh); /* } vh -------------- */ 479d4afb5ceSopenharmony_ci lws_context_unlock(vh->context); /* } cx -------------- */ 480d4afb5ceSopenharmony_ci 481d4afb5ceSopenharmony_ci return 0; 482d4afb5ceSopenharmony_ci 483d4afb5ceSopenharmony_cibail: 484d4afb5ceSopenharmony_ci SSL_SESSION_free(sess); 485d4afb5ceSopenharmony_cibail1: 486d4afb5ceSopenharmony_ci 487d4afb5ceSopenharmony_ci lws_vhost_unlock(vh); /* } vh -------------- */ 488d4afb5ceSopenharmony_ci lws_context_unlock(vh->context); /* } cx -------------- */ 489d4afb5ceSopenharmony_ci 490d4afb5ceSopenharmony_ci return 1; 491d4afb5ceSopenharmony_ci} 492