1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 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#include "private-lib-tls-mbedtls.h"
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_civoid
29d4afb5ceSopenharmony_cilws_ssl_destroy(struct lws_vhost *vhost)
30d4afb5ceSopenharmony_ci{
31d4afb5ceSopenharmony_ci	if (!lws_check_opt(vhost->context->options,
32d4afb5ceSopenharmony_ci			   LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
33d4afb5ceSopenharmony_ci		return;
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_ci	if (vhost->tls.ssl_ctx)
36d4afb5ceSopenharmony_ci		SSL_CTX_free(vhost->tls.ssl_ctx);
37d4afb5ceSopenharmony_ci	if (!vhost->tls.user_supplied_ssl_ctx && vhost->tls.ssl_client_ctx)
38d4afb5ceSopenharmony_ci		SSL_CTX_free(vhost->tls.ssl_client_ctx);
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci	if (vhost->tls.x509_client_CA)
41d4afb5ceSopenharmony_ci		X509_free(vhost->tls.x509_client_CA);
42d4afb5ceSopenharmony_ci}
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ciint
45d4afb5ceSopenharmony_cilws_ssl_capable_read(struct lws *wsi, unsigned char *buf, size_t len)
46d4afb5ceSopenharmony_ci{
47d4afb5ceSopenharmony_ci	struct lws_context *context = wsi->a.context;
48d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
49d4afb5ceSopenharmony_ci	int n = 0, m;
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_ci	if (!wsi->tls.ssl)
52d4afb5ceSopenharmony_ci		return lws_ssl_capable_read_no_ssl(wsi, buf, len);
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci	errno = 0;
55d4afb5ceSopenharmony_ci	n = SSL_read(wsi->tls.ssl, buf, (int)len);
56d4afb5ceSopenharmony_ci#if defined(LWS_PLAT_FREERTOS)
57d4afb5ceSopenharmony_ci	if (!n && errno == LWS_ENOTCONN) {
58d4afb5ceSopenharmony_ci		lwsl_debug("%s: SSL_read ENOTCONN\n", lws_wsi_tag(wsi));
59d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_ERROR;
60d4afb5ceSopenharmony_ci	}
61d4afb5ceSopenharmony_ci#endif
62d4afb5ceSopenharmony_ci
63d4afb5ceSopenharmony_ci	lwsl_debug("%s: %s: SSL_read says %d\n", __func__, lws_wsi_tag(wsi), n);
64d4afb5ceSopenharmony_ci	/* manpage: returning 0 means connection shut down */
65d4afb5ceSopenharmony_ci	if (!n) {
66d4afb5ceSopenharmony_ci		wsi->socket_is_permanently_unusable = 1;
67d4afb5ceSopenharmony_ci
68d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_ERROR;
69d4afb5ceSopenharmony_ci	}
70d4afb5ceSopenharmony_ci
71d4afb5ceSopenharmony_ci	if (n < 0) {
72d4afb5ceSopenharmony_ci		m = SSL_get_error(wsi->tls.ssl, n);
73d4afb5ceSopenharmony_ci		lwsl_debug("%s: %s: ssl err %d errno %d\n", __func__, lws_wsi_tag(wsi), m, errno);
74d4afb5ceSopenharmony_ci		if (errno == LWS_ENOTCONN)
75d4afb5ceSopenharmony_ci			/* If the socket isn't connected anymore, bail out. */
76d4afb5ceSopenharmony_ci			goto do_err1;
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci#if defined(LWS_PLAT_FREERTOS)
79d4afb5ceSopenharmony_ci		if (errno == LWS_ECONNABORTED)
80d4afb5ceSopenharmony_ci			goto do_err1;
81d4afb5ceSopenharmony_ci#endif
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ci		if (m == SSL_ERROR_ZERO_RETURN ||
84d4afb5ceSopenharmony_ci		    m == SSL_ERROR_SYSCALL)
85d4afb5ceSopenharmony_ci			goto do_err;
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ci		if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) {
88d4afb5ceSopenharmony_ci			lwsl_debug("%s: WANT_READ\n", __func__);
89d4afb5ceSopenharmony_ci			lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi));
90d4afb5ceSopenharmony_ci			return LWS_SSL_CAPABLE_MORE_SERVICE;
91d4afb5ceSopenharmony_ci		}
92d4afb5ceSopenharmony_ci		if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) {
93d4afb5ceSopenharmony_ci			lwsl_info("%s: WANT_WRITE\n", __func__);
94d4afb5ceSopenharmony_ci			lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi));
95d4afb5ceSopenharmony_ci			wsi->tls_read_wanted_write = 1;
96d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi);
97d4afb5ceSopenharmony_ci			return LWS_SSL_CAPABLE_MORE_SERVICE;
98d4afb5ceSopenharmony_ci		}
99d4afb5ceSopenharmony_ci
100d4afb5ceSopenharmony_cido_err1:
101d4afb5ceSopenharmony_ci		wsi->socket_is_permanently_unusable = 1;
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_cido_err:
104d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
105d4afb5ceSopenharmony_ci	if (wsi->a.vhost)
106d4afb5ceSopenharmony_ci		lws_metric_event(wsi->a.vhost->mt_traffic_rx, METRES_NOGO, 0);
107d4afb5ceSopenharmony_ci#endif
108d4afb5ceSopenharmony_ci
109d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_ERROR;
110d4afb5ceSopenharmony_ci	}
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci#if defined(LWS_TLS_LOG_PLAINTEXT_RX)
113d4afb5ceSopenharmony_ci	/*
114d4afb5ceSopenharmony_ci	 * If using mbedtls type tls library, this is the earliest point for all
115d4afb5ceSopenharmony_ci	 * paths to dump what was received as decrypted data from the tls tunnel
116d4afb5ceSopenharmony_ci	 */
117d4afb5ceSopenharmony_ci	lwsl_notice("%s: len %d\n", __func__, n);
118d4afb5ceSopenharmony_ci	lwsl_hexdump_notice(buf, (size_t)n);
119d4afb5ceSopenharmony_ci#endif
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
122d4afb5ceSopenharmony_ci	if (wsi->a.vhost)
123d4afb5ceSopenharmony_ci		lws_metric_event(wsi->a.vhost->mt_traffic_rx,
124d4afb5ceSopenharmony_ci				 METRES_GO /* rx */, (u_mt_t)n);
125d4afb5ceSopenharmony_ci#endif
126d4afb5ceSopenharmony_ci
127d4afb5ceSopenharmony_ci	/*
128d4afb5ceSopenharmony_ci	 * if it was our buffer that limited what we read,
129d4afb5ceSopenharmony_ci	 * check if SSL has additional data pending inside SSL buffers.
130d4afb5ceSopenharmony_ci	 *
131d4afb5ceSopenharmony_ci	 * Because these won't signal at the network layer with POLLIN
132d4afb5ceSopenharmony_ci	 * and if we don't realize, this data will sit there forever
133d4afb5ceSopenharmony_ci	 */
134d4afb5ceSopenharmony_ci	if (n != (int)len)
135d4afb5ceSopenharmony_ci		goto bail;
136d4afb5ceSopenharmony_ci	if (!wsi->tls.ssl)
137d4afb5ceSopenharmony_ci		goto bail;
138d4afb5ceSopenharmony_ci
139d4afb5ceSopenharmony_ci	if (SSL_pending(wsi->tls.ssl)) {
140d4afb5ceSopenharmony_ci		if (lws_dll2_is_detached(&wsi->tls.dll_pending_tls))
141d4afb5ceSopenharmony_ci			lws_dll2_add_head(&wsi->tls.dll_pending_tls,
142d4afb5ceSopenharmony_ci					  &pt->tls.dll_pending_tls_owner);
143d4afb5ceSopenharmony_ci	} else
144d4afb5ceSopenharmony_ci		__lws_ssl_remove_wsi_from_buffered_list(wsi);
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_ci	return n;
147d4afb5ceSopenharmony_cibail:
148d4afb5ceSopenharmony_ci	lws_ssl_remove_wsi_from_buffered_list(wsi);
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci	return n;
151d4afb5ceSopenharmony_ci}
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ciint
154d4afb5ceSopenharmony_cilws_ssl_pending(struct lws *wsi)
155d4afb5ceSopenharmony_ci{
156d4afb5ceSopenharmony_ci	if (!wsi->tls.ssl)
157d4afb5ceSopenharmony_ci		return 0;
158d4afb5ceSopenharmony_ci
159d4afb5ceSopenharmony_ci	return SSL_pending(wsi->tls.ssl);
160d4afb5ceSopenharmony_ci}
161d4afb5ceSopenharmony_ci
162d4afb5ceSopenharmony_ciint
163d4afb5ceSopenharmony_cilws_ssl_capable_write(struct lws *wsi, unsigned char *buf, size_t len)
164d4afb5ceSopenharmony_ci{
165d4afb5ceSopenharmony_ci	int n, m;
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci#if defined(LWS_TLS_LOG_PLAINTEXT_TX)
168d4afb5ceSopenharmony_ci	/*
169d4afb5ceSopenharmony_ci	 * If using mbedtls type tls library, this is the last point for all
170d4afb5ceSopenharmony_ci	 * paths before sending data into the tls tunnel, where you can dump it
171d4afb5ceSopenharmony_ci	 * and see what is being sent.
172d4afb5ceSopenharmony_ci	 */
173d4afb5ceSopenharmony_ci	lwsl_notice("%s: len %d\n", __func__, (int)len);
174d4afb5ceSopenharmony_ci	lwsl_hexdump_notice(buf, len);
175d4afb5ceSopenharmony_ci#endif
176d4afb5ceSopenharmony_ci
177d4afb5ceSopenharmony_ci	if (!wsi->tls.ssl)
178d4afb5ceSopenharmony_ci		return lws_ssl_capable_write_no_ssl(wsi, buf, len);
179d4afb5ceSopenharmony_ci
180d4afb5ceSopenharmony_ci	n = SSL_write(wsi->tls.ssl, buf, (int)len);
181d4afb5ceSopenharmony_ci	if (n > 0) {
182d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
183d4afb5ceSopenharmony_ci		if (wsi->a.vhost)
184d4afb5ceSopenharmony_ci			lws_metric_event(wsi->a.vhost->mt_traffic_tx,
185d4afb5ceSopenharmony_ci					 METRES_GO, (u_mt_t)n);
186d4afb5ceSopenharmony_ci#endif
187d4afb5ceSopenharmony_ci		return n;
188d4afb5ceSopenharmony_ci	}
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ci	m = SSL_get_error(wsi->tls.ssl, n);
191d4afb5ceSopenharmony_ci	if (m != SSL_ERROR_SYSCALL) {
192d4afb5ceSopenharmony_ci		if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) {
193d4afb5ceSopenharmony_ci			lwsl_notice("%s: want read\n", __func__);
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci			return LWS_SSL_CAPABLE_MORE_SERVICE;
196d4afb5ceSopenharmony_ci		}
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ci		if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) {
199d4afb5ceSopenharmony_ci			lws_set_blocking_send(wsi);
200d4afb5ceSopenharmony_ci			lwsl_debug("%s: want write\n", __func__);
201d4afb5ceSopenharmony_ci
202d4afb5ceSopenharmony_ci			return LWS_SSL_CAPABLE_MORE_SERVICE;
203d4afb5ceSopenharmony_ci		}
204d4afb5ceSopenharmony_ci	}
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci	lwsl_debug("%s failed: %d\n",__func__, m);
207d4afb5ceSopenharmony_ci	wsi->socket_is_permanently_unusable = 1;
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
210d4afb5ceSopenharmony_ci		if (wsi->a.vhost)
211d4afb5ceSopenharmony_ci			lws_metric_event(wsi->a.vhost->mt_traffic_tx,
212d4afb5ceSopenharmony_ci					 METRES_NOGO, (u_mt_t)n);
213d4afb5ceSopenharmony_ci#endif
214d4afb5ceSopenharmony_ci
215d4afb5ceSopenharmony_ci	return LWS_SSL_CAPABLE_ERROR;
216d4afb5ceSopenharmony_ci}
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_ciint openssl_SSL_CTX_private_data_index;
219d4afb5ceSopenharmony_ci
220d4afb5ceSopenharmony_civoid
221d4afb5ceSopenharmony_cilws_ssl_info_callback(const SSL *ssl, int where, int ret)
222d4afb5ceSopenharmony_ci{
223d4afb5ceSopenharmony_ci	struct lws *wsi;
224d4afb5ceSopenharmony_ci	struct lws_context *context;
225d4afb5ceSopenharmony_ci	struct lws_ssl_info si;
226d4afb5ceSopenharmony_ci
227d4afb5ceSopenharmony_ci	context = (struct lws_context *)SSL_CTX_get_ex_data(
228d4afb5ceSopenharmony_ci					SSL_get_SSL_CTX(ssl),
229d4afb5ceSopenharmony_ci					openssl_SSL_CTX_private_data_index);
230d4afb5ceSopenharmony_ci	if (!context)
231d4afb5ceSopenharmony_ci		return;
232d4afb5ceSopenharmony_ci	wsi = wsi_from_fd(context, SSL_get_fd(ssl));
233d4afb5ceSopenharmony_ci	if (!wsi)
234d4afb5ceSopenharmony_ci		return;
235d4afb5ceSopenharmony_ci
236d4afb5ceSopenharmony_ci	if (!(where & wsi->a.vhost->tls.ssl_info_event_mask))
237d4afb5ceSopenharmony_ci		return;
238d4afb5ceSopenharmony_ci
239d4afb5ceSopenharmony_ci	si.where = where;
240d4afb5ceSopenharmony_ci	si.ret = ret;
241d4afb5ceSopenharmony_ci
242d4afb5ceSopenharmony_ci	if (user_callback_handle_rxflow(wsi->a.protocol->callback,
243d4afb5ceSopenharmony_ci					wsi, LWS_CALLBACK_SSL_INFO,
244d4afb5ceSopenharmony_ci					wsi->user_space, &si, 0))
245d4afb5ceSopenharmony_ci		lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
246d4afb5ceSopenharmony_ci}
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci
249d4afb5ceSopenharmony_ciint
250d4afb5ceSopenharmony_cilws_ssl_close(struct lws *wsi)
251d4afb5ceSopenharmony_ci{
252d4afb5ceSopenharmony_ci	lws_sockfd_type n;
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ci	if (!wsi->tls.ssl)
255d4afb5ceSopenharmony_ci		return 0; /* not handled */
256d4afb5ceSopenharmony_ci
257d4afb5ceSopenharmony_ci#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
258d4afb5ceSopenharmony_ci	/* kill ssl callbacks, becausse we will remove the fd from the
259d4afb5ceSopenharmony_ci	 * table linking it to the wsi
260d4afb5ceSopenharmony_ci	 */
261d4afb5ceSopenharmony_ci	if (wsi->a.vhost->tls.ssl_info_event_mask)
262d4afb5ceSopenharmony_ci		SSL_set_info_callback(wsi->tls.ssl, NULL);
263d4afb5ceSopenharmony_ci#endif
264d4afb5ceSopenharmony_ci
265d4afb5ceSopenharmony_ci#if defined(LWS_TLS_SYNTHESIZE_CB)
266d4afb5ceSopenharmony_ci	lws_sul_cancel(&wsi->tls.sul_cb_synth);
267d4afb5ceSopenharmony_ci	/*
268d4afb5ceSopenharmony_ci	 * ... check the session in case it did not live long enough to get
269d4afb5ceSopenharmony_ci	 * the scheduled callback to sample it
270d4afb5ceSopenharmony_ci	 */
271d4afb5ceSopenharmony_ci	lws_sess_cache_synth_cb(&wsi->tls.sul_cb_synth);
272d4afb5ceSopenharmony_ci#endif
273d4afb5ceSopenharmony_ci
274d4afb5ceSopenharmony_ci	n = SSL_get_fd(wsi->tls.ssl);
275d4afb5ceSopenharmony_ci	if (!wsi->socket_is_permanently_unusable)
276d4afb5ceSopenharmony_ci		SSL_shutdown(wsi->tls.ssl);
277d4afb5ceSopenharmony_ci	compatible_close(n);
278d4afb5ceSopenharmony_ci	SSL_free(wsi->tls.ssl);
279d4afb5ceSopenharmony_ci	wsi->tls.ssl = NULL;
280d4afb5ceSopenharmony_ci
281d4afb5ceSopenharmony_ci	lws_tls_restrict_return(wsi);
282d4afb5ceSopenharmony_ci
283d4afb5ceSopenharmony_ci	return 1; /* handled */
284d4afb5ceSopenharmony_ci}
285d4afb5ceSopenharmony_ci
286d4afb5ceSopenharmony_civoid
287d4afb5ceSopenharmony_cilws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
288d4afb5ceSopenharmony_ci{
289d4afb5ceSopenharmony_ci	if (vhost->tls.ssl_ctx)
290d4afb5ceSopenharmony_ci		SSL_CTX_free(vhost->tls.ssl_ctx);
291d4afb5ceSopenharmony_ci
292d4afb5ceSopenharmony_ci	if (!vhost->tls.user_supplied_ssl_ctx && vhost->tls.ssl_client_ctx)
293d4afb5ceSopenharmony_ci		SSL_CTX_free(vhost->tls.ssl_client_ctx);
294d4afb5ceSopenharmony_ci#if defined(LWS_WITH_ACME)
295d4afb5ceSopenharmony_ci	lws_tls_acme_sni_cert_destroy(vhost);
296d4afb5ceSopenharmony_ci#endif
297d4afb5ceSopenharmony_ci}
298d4afb5ceSopenharmony_ci
299d4afb5ceSopenharmony_civoid
300d4afb5ceSopenharmony_cilws_ssl_context_destroy(struct lws_context *context)
301d4afb5ceSopenharmony_ci{
302d4afb5ceSopenharmony_ci}
303d4afb5ceSopenharmony_ci
304d4afb5ceSopenharmony_cilws_tls_ctx *
305d4afb5ceSopenharmony_cilws_tls_ctx_from_wsi(struct lws *wsi)
306d4afb5ceSopenharmony_ci{
307d4afb5ceSopenharmony_ci	if (!wsi->tls.ssl)
308d4afb5ceSopenharmony_ci		return NULL;
309d4afb5ceSopenharmony_ci
310d4afb5ceSopenharmony_ci	return SSL_get_SSL_CTX(wsi->tls.ssl);
311d4afb5ceSopenharmony_ci}
312d4afb5ceSopenharmony_ci
313d4afb5ceSopenharmony_cienum lws_ssl_capable_status
314d4afb5ceSopenharmony_ci__lws_tls_shutdown(struct lws *wsi)
315d4afb5ceSopenharmony_ci{
316d4afb5ceSopenharmony_ci	int n = SSL_shutdown(wsi->tls.ssl);
317d4afb5ceSopenharmony_ci
318d4afb5ceSopenharmony_ci	lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd);
319d4afb5ceSopenharmony_ci
320d4afb5ceSopenharmony_ci	switch (n) {
321d4afb5ceSopenharmony_ci	case 1: /* successful completion */
322d4afb5ceSopenharmony_ci		(void)shutdown(wsi->desc.sockfd, SHUT_WR);
323d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_DONE;
324d4afb5ceSopenharmony_ci
325d4afb5ceSopenharmony_ci	case 0: /* needs a retry */
326d4afb5ceSopenharmony_ci		__lws_change_pollfd(wsi, 0, LWS_POLLIN);
327d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE;
328d4afb5ceSopenharmony_ci
329d4afb5ceSopenharmony_ci	default: /* fatal error, or WANT */
330d4afb5ceSopenharmony_ci		n = SSL_get_error(wsi->tls.ssl, n);
331d4afb5ceSopenharmony_ci		if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) {
332d4afb5ceSopenharmony_ci			if (SSL_want_read(wsi->tls.ssl)) {
333d4afb5ceSopenharmony_ci				lwsl_debug("(wants read)\n");
334d4afb5ceSopenharmony_ci				__lws_change_pollfd(wsi, 0, LWS_POLLIN);
335d4afb5ceSopenharmony_ci				return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
336d4afb5ceSopenharmony_ci			}
337d4afb5ceSopenharmony_ci			if (SSL_want_write(wsi->tls.ssl)) {
338d4afb5ceSopenharmony_ci				lwsl_debug("(wants write)\n");
339d4afb5ceSopenharmony_ci				__lws_change_pollfd(wsi, 0, LWS_POLLOUT);
340d4afb5ceSopenharmony_ci				return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
341d4afb5ceSopenharmony_ci			}
342d4afb5ceSopenharmony_ci		}
343d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_ERROR;
344d4afb5ceSopenharmony_ci	}
345d4afb5ceSopenharmony_ci}
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_ci
348d4afb5ceSopenharmony_cistatic int
349d4afb5ceSopenharmony_citops_fake_POLLIN_for_buffered_mbedtls(struct lws_context_per_thread *pt)
350d4afb5ceSopenharmony_ci{
351d4afb5ceSopenharmony_ci	return lws_tls_fake_POLLIN_for_buffered(pt);
352d4afb5ceSopenharmony_ci}
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ciconst struct lws_tls_ops tls_ops_mbedtls = {
355d4afb5ceSopenharmony_ci	/* fake_POLLIN_for_buffered */	tops_fake_POLLIN_for_buffered_mbedtls,
356d4afb5ceSopenharmony_ci};
357