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