1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 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_ci#if defined(LWS_WITH_TLS_JIT_TRUST)
29d4afb5ceSopenharmony_ci
30d4afb5ceSopenharmony_ci/*
31d4afb5ceSopenharmony_ci * We get called for each peer certificate that was provided in turn.
32d4afb5ceSopenharmony_ci *
33d4afb5ceSopenharmony_ci * Our job is just to collect the AKID and SKIDs into ssl->kid_chain, and walk
34d4afb5ceSopenharmony_ci * later at verification result time if it failed.
35d4afb5ceSopenharmony_ci *
36d4afb5ceSopenharmony_ci * None of these should be trusted, even if a misconfigured server sends us
37d4afb5ceSopenharmony_ci * his root CA.
38d4afb5ceSopenharmony_ci */
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_cistatic int
41d4afb5ceSopenharmony_cilws_mbedtls_client_verify_callback(SSL *ssl, mbedtls_x509_crt *x509)
42d4afb5ceSopenharmony_ci{
43d4afb5ceSopenharmony_ci	union lws_tls_cert_info_results ci;
44d4afb5ceSopenharmony_ci
45d4afb5ceSopenharmony_ci	/* we reached the max we can hold? */
46d4afb5ceSopenharmony_ci
47d4afb5ceSopenharmony_ci	if (ssl->kid_chain.count == LWS_ARRAY_SIZE(ssl->kid_chain.akid))
48d4afb5ceSopenharmony_ci		return 0;
49d4afb5ceSopenharmony_ci
50d4afb5ceSopenharmony_ci	/* if not, stash the SKID and AKID into the next kid slot */
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_ci	if (!lws_tls_mbedtls_cert_info(x509, LWS_TLS_CERT_INFO_SUBJECT_KEY_ID,
53d4afb5ceSopenharmony_ci				       &ci, 0))
54d4afb5ceSopenharmony_ci		lws_tls_kid_copy(&ci,
55d4afb5ceSopenharmony_ci				 &ssl->kid_chain.skid[ssl->kid_chain.count]);
56d4afb5ceSopenharmony_ci
57d4afb5ceSopenharmony_ci	if (!lws_tls_mbedtls_cert_info(x509, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID,
58d4afb5ceSopenharmony_ci				       &ci, 0))
59d4afb5ceSopenharmony_ci		lws_tls_kid_copy(&ci,
60d4afb5ceSopenharmony_ci				 &ssl->kid_chain.akid[ssl->kid_chain.count]);
61d4afb5ceSopenharmony_ci
62d4afb5ceSopenharmony_ci	ssl->kid_chain.count++;
63d4afb5ceSopenharmony_ci
64d4afb5ceSopenharmony_ci	// lwsl_notice("%s: %u\n", __func__, ssl->kid_chain.count);
65d4afb5ceSopenharmony_ci
66d4afb5ceSopenharmony_ci	return 0;
67d4afb5ceSopenharmony_ci}
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_ci#endif
70d4afb5ceSopenharmony_ci
71d4afb5ceSopenharmony_ciint
72d4afb5ceSopenharmony_cilws_ssl_client_bio_create(struct lws *wsi)
73d4afb5ceSopenharmony_ci{
74d4afb5ceSopenharmony_ci	char hostname[128], *p;
75d4afb5ceSopenharmony_ci	const char *alpn_comma = wsi->a.context->tls.alpn_default;
76d4afb5ceSopenharmony_ci	struct alpn_ctx protos;
77d4afb5ceSopenharmony_ci	int fl = SSL_VERIFY_PEER;
78d4afb5ceSopenharmony_ci
79d4afb5ceSopenharmony_ci	if (wsi->stash)
80d4afb5ceSopenharmony_ci		lws_strncpy(hostname, wsi->stash->cis[CIS_HOST], sizeof(hostname));
81d4afb5ceSopenharmony_ci	else
82d4afb5ceSopenharmony_ci		if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
83d4afb5ceSopenharmony_ci				_WSI_TOKEN_CLIENT_HOST) <= 0) {
84d4afb5ceSopenharmony_ci			lwsl_err("%s: Unable to get hostname\n", __func__);
85d4afb5ceSopenharmony_ci
86d4afb5ceSopenharmony_ci			return -1;
87d4afb5ceSopenharmony_ci		}
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_ci	/*
90d4afb5ceSopenharmony_ci	 * remove any :port part on the hostname... necessary for network
91d4afb5ceSopenharmony_ci	 * connection but typical certificates do not contain it
92d4afb5ceSopenharmony_ci	 */
93d4afb5ceSopenharmony_ci	p = hostname;
94d4afb5ceSopenharmony_ci	while (*p) {
95d4afb5ceSopenharmony_ci		if (*p == ':') {
96d4afb5ceSopenharmony_ci			*p = '\0';
97d4afb5ceSopenharmony_ci			break;
98d4afb5ceSopenharmony_ci		}
99d4afb5ceSopenharmony_ci		p++;
100d4afb5ceSopenharmony_ci	}
101d4afb5ceSopenharmony_ci
102d4afb5ceSopenharmony_ci	wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_client_ctx);
103d4afb5ceSopenharmony_ci	if (!wsi->tls.ssl) {
104d4afb5ceSopenharmony_ci		lwsl_info("%s: SSL_new() failed\n", __func__);
105d4afb5ceSopenharmony_ci		return -1;
106d4afb5ceSopenharmony_ci	}
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS)
109d4afb5ceSopenharmony_ci	if (!(wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE))
110d4afb5ceSopenharmony_ci		lws_tls_reuse_session(wsi);
111d4afb5ceSopenharmony_ci#endif
112d4afb5ceSopenharmony_ci
113d4afb5ceSopenharmony_ci	if (wsi->a.vhost->tls.ssl_info_event_mask)
114d4afb5ceSopenharmony_ci		SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci	if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
117d4afb5ceSopenharmony_ci		X509_VERIFY_PARAM *param = SSL_get0_param(wsi->tls.ssl);
118d4afb5ceSopenharmony_ci		/* Enable automatic hostname checks */
119d4afb5ceSopenharmony_ci	//	X509_VERIFY_PARAM_set_hostflags(param,
120d4afb5ceSopenharmony_ci	//				X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
121d4afb5ceSopenharmony_ci		lwsl_info("%s: setting hostname %s\n", __func__, hostname);
122d4afb5ceSopenharmony_ci		if (X509_VERIFY_PARAM_set1_host(param, hostname, 0) != 1)
123d4afb5ceSopenharmony_ci			return -1;
124d4afb5ceSopenharmony_ci	}
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci	if (wsi->a.vhost->tls.alpn)
127d4afb5ceSopenharmony_ci		alpn_comma = wsi->a.vhost->tls.alpn;
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci	if (wsi->stash) {
130d4afb5ceSopenharmony_ci		lws_strncpy(hostname, wsi->stash->cis[CIS_HOST],
131d4afb5ceSopenharmony_ci				sizeof(hostname));
132d4afb5ceSopenharmony_ci		if (wsi->stash->cis[CIS_ALPN])
133d4afb5ceSopenharmony_ci			alpn_comma = wsi->stash->cis[CIS_ALPN];
134d4afb5ceSopenharmony_ci	} else {
135d4afb5ceSopenharmony_ci		if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
136d4afb5ceSopenharmony_ci				_WSI_TOKEN_CLIENT_ALPN) > 0)
137d4afb5ceSopenharmony_ci			alpn_comma = hostname;
138d4afb5ceSopenharmony_ci	}
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci	protos.len = (uint8_t)lws_alpn_comma_to_openssl(alpn_comma, protos.data,
141d4afb5ceSopenharmony_ci					       sizeof(protos.data) - 1);
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: client conn sending ALPN list '%s' (protos.len %d)\n",
144d4afb5ceSopenharmony_ci		  __func__, lws_wsi_tag(wsi), alpn_comma, protos.len);
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_ci	/* with mbedtls, protos is not pointed to after exit from this call */
147d4afb5ceSopenharmony_ci	SSL_set_alpn_select_cb(wsi->tls.ssl, &protos);
148d4afb5ceSopenharmony_ci
149d4afb5ceSopenharmony_ci	if (wsi->flags & LCCSCF_ALLOW_SELFSIGNED) {
150d4afb5ceSopenharmony_ci		lwsl_notice("%s: allowing selfsigned\n", __func__);
151d4afb5ceSopenharmony_ci		fl = SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
152d4afb5ceSopenharmony_ci	}
153d4afb5ceSopenharmony_ci
154d4afb5ceSopenharmony_ci	if (wsi->flags & LCCSCF_ALLOW_INSECURE)
155d4afb5ceSopenharmony_ci		fl = SSL_VERIFY_NONE;
156d4afb5ceSopenharmony_ci
157d4afb5ceSopenharmony_ci	/*
158d4afb5ceSopenharmony_ci	 * use server name indication (SNI), if supported,
159d4afb5ceSopenharmony_ci	 * when establishing connection
160d4afb5ceSopenharmony_ci	 */
161d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST)
162d4afb5ceSopenharmony_ci	SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER,
163d4afb5ceSopenharmony_ci			lws_mbedtls_client_verify_callback);
164d4afb5ceSopenharmony_ci	(void)fl;
165d4afb5ceSopenharmony_ci#else
166d4afb5ceSopenharmony_ci	SSL_set_verify(wsi->tls.ssl, fl, NULL);
167d4afb5ceSopenharmony_ci#endif
168d4afb5ceSopenharmony_ci
169d4afb5ceSopenharmony_ci	SSL_set_fd(wsi->tls.ssl, (int)wsi->desc.sockfd);
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci	if (wsi->sys_tls_client_cert) {
172d4afb5ceSopenharmony_ci		lws_system_blob_t *b = lws_system_get_blob(wsi->a.context,
173d4afb5ceSopenharmony_ci					LWS_SYSBLOB_TYPE_CLIENT_CERT_DER,
174d4afb5ceSopenharmony_ci					wsi->sys_tls_client_cert - 1);
175d4afb5ceSopenharmony_ci		const uint8_t *pem_data = NULL;
176d4afb5ceSopenharmony_ci		uint8_t *data = NULL;
177d4afb5ceSopenharmony_ci		lws_filepos_t flen;
178d4afb5ceSopenharmony_ci		size_t size;
179d4afb5ceSopenharmony_ci		int err = 0;
180d4afb5ceSopenharmony_ci
181d4afb5ceSopenharmony_ci		if (!b)
182d4afb5ceSopenharmony_ci			goto no_client_cert;
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_ci		/*
185d4afb5ceSopenharmony_ci		 * Set up the per-connection client cert
186d4afb5ceSopenharmony_ci		 */
187d4afb5ceSopenharmony_ci
188d4afb5ceSopenharmony_ci		size = lws_system_blob_get_size(b);
189d4afb5ceSopenharmony_ci		if (!size)
190d4afb5ceSopenharmony_ci			goto no_client_cert;
191d4afb5ceSopenharmony_ci
192d4afb5ceSopenharmony_ci		if (lws_system_blob_get_single_ptr(b, &pem_data))
193d4afb5ceSopenharmony_ci			goto no_client_cert;
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci		if (lws_tls_alloc_pem_to_der_file(wsi->a.context, NULL,
196d4afb5ceSopenharmony_ci						  (const char *)pem_data, size,
197d4afb5ceSopenharmony_ci						  &data, &flen))
198d4afb5ceSopenharmony_ci			goto no_client_cert;
199d4afb5ceSopenharmony_ci		size = (size_t) flen;
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci		err = SSL_use_certificate_ASN1(wsi->tls.ssl, data, (int)size);
202d4afb5ceSopenharmony_ci		lws_free_set_NULL(data);
203d4afb5ceSopenharmony_ci		if (err != 1)
204d4afb5ceSopenharmony_ci			goto no_client_cert;
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci		b = lws_system_get_blob(wsi->a.context,
207d4afb5ceSopenharmony_ci					LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
208d4afb5ceSopenharmony_ci					wsi->sys_tls_client_cert - 1);
209d4afb5ceSopenharmony_ci		if (!b)
210d4afb5ceSopenharmony_ci			goto no_client_cert;
211d4afb5ceSopenharmony_ci		size = lws_system_blob_get_size(b);
212d4afb5ceSopenharmony_ci		if (!size)
213d4afb5ceSopenharmony_ci			goto no_client_cert;
214d4afb5ceSopenharmony_ci
215d4afb5ceSopenharmony_ci		if (lws_system_blob_get_single_ptr(b, &pem_data))
216d4afb5ceSopenharmony_ci			goto no_client_cert;
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_ci		if (lws_tls_alloc_pem_to_der_file(wsi->a.context, NULL,
219d4afb5ceSopenharmony_ci						  (const char *)pem_data, size,
220d4afb5ceSopenharmony_ci						  &data, &flen))
221d4afb5ceSopenharmony_ci			goto no_client_cert;
222d4afb5ceSopenharmony_ci		size = (size_t) flen;
223d4afb5ceSopenharmony_ci
224d4afb5ceSopenharmony_ci		err = SSL_use_PrivateKey_ASN1(0, wsi->tls.ssl, data, (int)size);
225d4afb5ceSopenharmony_ci		lws_free_set_NULL(data);
226d4afb5ceSopenharmony_ci		if (err != 1)
227d4afb5ceSopenharmony_ci			goto no_client_cert;
228d4afb5ceSopenharmony_ci
229d4afb5ceSopenharmony_ci		/* no wrapper api for check key */
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci		lwsl_notice("%s: set system client cert %u\n", __func__,
232d4afb5ceSopenharmony_ci				wsi->sys_tls_client_cert - 1);
233d4afb5ceSopenharmony_ci	}
234d4afb5ceSopenharmony_ci
235d4afb5ceSopenharmony_ci	return 0;
236d4afb5ceSopenharmony_ci
237d4afb5ceSopenharmony_cino_client_cert:
238d4afb5ceSopenharmony_ci	lwsl_err("%s: unable to set up system client cert %d\n", __func__,
239d4afb5ceSopenharmony_ci			wsi->sys_tls_client_cert - 1);
240d4afb5ceSopenharmony_ci
241d4afb5ceSopenharmony_ci	return 1;
242d4afb5ceSopenharmony_ci}
243d4afb5ceSopenharmony_ci
244d4afb5ceSopenharmony_ciint ERR_get_error(void)
245d4afb5ceSopenharmony_ci{
246d4afb5ceSopenharmony_ci	return 0;
247d4afb5ceSopenharmony_ci}
248d4afb5ceSopenharmony_ci
249d4afb5ceSopenharmony_cienum lws_ssl_capable_status
250d4afb5ceSopenharmony_cilws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen)
251d4afb5ceSopenharmony_ci{
252d4afb5ceSopenharmony_ci	int m, n = SSL_connect(wsi->tls.ssl), en;
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ci	if (n == 1) {
255d4afb5ceSopenharmony_ci		lws_tls_server_conn_alpn(wsi);
256d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS)
257d4afb5ceSopenharmony_ci		lws_tls_session_new_mbedtls(wsi);
258d4afb5ceSopenharmony_ci#endif
259d4afb5ceSopenharmony_ci		lwsl_info("%s: client connect OK\n", __func__);
260d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_DONE;
261d4afb5ceSopenharmony_ci	}
262d4afb5ceSopenharmony_ci
263d4afb5ceSopenharmony_ci	en = (int)LWS_ERRNO;
264d4afb5ceSopenharmony_ci	m = SSL_get_error(wsi->tls.ssl, n);
265d4afb5ceSopenharmony_ci
266d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl))
267d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
268d4afb5ceSopenharmony_ci
269d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl))
270d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
271d4afb5ceSopenharmony_ci
272d4afb5ceSopenharmony_ci	if (!n) /* we don't know what he wants, but he says to retry */
273d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE;
274d4afb5ceSopenharmony_ci
275d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_SYSCALL && !en && n >= 0) /* otherwise we miss explicit failures and spin
276d4afb5ceSopenharmony_ci						      * in hs state 17 until timeout... */
277d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE;
278d4afb5ceSopenharmony_ci
279d4afb5ceSopenharmony_ci	lws_snprintf(errbuf, elen, "mbedtls connect %d %d %d", n, m, en);
280d4afb5ceSopenharmony_ci
281d4afb5ceSopenharmony_ci	return LWS_SSL_CAPABLE_ERROR;
282d4afb5ceSopenharmony_ci}
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_ciint
285d4afb5ceSopenharmony_cilws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, size_t ebuf_len)
286d4afb5ceSopenharmony_ci{
287d4afb5ceSopenharmony_ci	int n;
288d4afb5ceSopenharmony_ci	unsigned int avoid = 0;
289d4afb5ceSopenharmony_ci	X509 *peer = SSL_get_peer_certificate(wsi->tls.ssl);
290d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
291d4afb5ceSopenharmony_ci	const char *type = "";
292d4afb5ceSopenharmony_ci	char *sb = (char *)&pt->serv_buf[0];
293d4afb5ceSopenharmony_ci
294d4afb5ceSopenharmony_ci	if (!peer) {
295d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
296d4afb5ceSopenharmony_ci		lws_metrics_hist_bump_describe_wsi(wsi, lws_metrics_priv_to_pub(
297d4afb5ceSopenharmony_ci					wsi->a.context->mth_conn_failures),
298d4afb5ceSopenharmony_ci						   "tls=\"nocert\"");
299d4afb5ceSopenharmony_ci#endif
300d4afb5ceSopenharmony_ci		lwsl_info("peer did not provide cert\n");
301d4afb5ceSopenharmony_ci		lws_snprintf(ebuf, ebuf_len, "no peer cert");
302d4afb5ceSopenharmony_ci
303d4afb5ceSopenharmony_ci		return -1;
304d4afb5ceSopenharmony_ci	}
305d4afb5ceSopenharmony_ci
306d4afb5ceSopenharmony_ci	n = (int)SSL_get_verify_result(wsi->tls.ssl);
307d4afb5ceSopenharmony_ci	lwsl_debug("get_verify says %d\n", n);
308d4afb5ceSopenharmony_ci
309d4afb5ceSopenharmony_ci	switch (n) {
310d4afb5ceSopenharmony_ci	case X509_V_OK:
311d4afb5ceSopenharmony_ci		return 0;
312d4afb5ceSopenharmony_ci
313d4afb5ceSopenharmony_ci	case X509_V_ERR_HOSTNAME_MISMATCH:
314d4afb5ceSopenharmony_ci		type = "hostname";
315d4afb5ceSopenharmony_ci		avoid = LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
316d4afb5ceSopenharmony_ci		break;
317d4afb5ceSopenharmony_ci
318d4afb5ceSopenharmony_ci	case X509_V_ERR_INVALID_CA:
319d4afb5ceSopenharmony_ci		type = "invalidca";
320d4afb5ceSopenharmony_ci		avoid = LCCSCF_ALLOW_SELFSIGNED;
321d4afb5ceSopenharmony_ci		break;
322d4afb5ceSopenharmony_ci
323d4afb5ceSopenharmony_ci	case X509_V_ERR_CERT_NOT_YET_VALID:
324d4afb5ceSopenharmony_ci		type = "notyetvalid";
325d4afb5ceSopenharmony_ci		avoid = LCCSCF_ALLOW_EXPIRED;
326d4afb5ceSopenharmony_ci		break;
327d4afb5ceSopenharmony_ci
328d4afb5ceSopenharmony_ci	case X509_V_ERR_CERT_HAS_EXPIRED:
329d4afb5ceSopenharmony_ci		type = "expired";
330d4afb5ceSopenharmony_ci		avoid = LCCSCF_ALLOW_EXPIRED;
331d4afb5ceSopenharmony_ci		break;
332d4afb5ceSopenharmony_ci	}
333d4afb5ceSopenharmony_ci
334d4afb5ceSopenharmony_ci	lwsl_info("%s: cert problem: %s\n", __func__, type);
335d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
336d4afb5ceSopenharmony_ci	{
337d4afb5ceSopenharmony_ci		char buckname[64];
338d4afb5ceSopenharmony_ci		lws_snprintf(buckname, sizeof(buckname), "tls=\"%s\"", type);
339d4afb5ceSopenharmony_ci		lws_metrics_hist_bump_describe_wsi(wsi,
340d4afb5ceSopenharmony_ci		     lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures),
341d4afb5ceSopenharmony_ci			      buckname);
342d4afb5ceSopenharmony_ci	}
343d4afb5ceSopenharmony_ci#endif
344d4afb5ceSopenharmony_ci	if (wsi->tls.use_ssl & avoid) {
345d4afb5ceSopenharmony_ci		lwsl_info("%s: allowing anyway\n", __func__);
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_ci		return 0;
348d4afb5ceSopenharmony_ci	}
349d4afb5ceSopenharmony_ci
350d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST)
351d4afb5ceSopenharmony_ci	if (n == X509_V_ERR_INVALID_CA)
352d4afb5ceSopenharmony_ci	    lws_tls_jit_trust_sort_kids(wsi, &wsi->tls.ssl->kid_chain);
353d4afb5ceSopenharmony_ci#endif
354d4afb5ceSopenharmony_ci	lws_snprintf(ebuf, ebuf_len,
355d4afb5ceSopenharmony_ci		"server's cert didn't look good, %s (use_ssl 0x%x) X509_V_ERR = %d: %s\n",
356d4afb5ceSopenharmony_ci		type, (unsigned int)wsi->tls.use_ssl, n,
357d4afb5ceSopenharmony_ci		ERR_error_string((unsigned long)n, sb));
358d4afb5ceSopenharmony_ci
359d4afb5ceSopenharmony_ci	lwsl_info("%s\n", ebuf);
360d4afb5ceSopenharmony_ci
361d4afb5ceSopenharmony_ci	lws_tls_err_describe_clear();
362d4afb5ceSopenharmony_ci
363d4afb5ceSopenharmony_ci	return -1;
364d4afb5ceSopenharmony_ci}
365d4afb5ceSopenharmony_ci
366d4afb5ceSopenharmony_ciint
367d4afb5ceSopenharmony_cilws_tls_client_create_vhost_context(struct lws_vhost *vh,
368d4afb5ceSopenharmony_ci				    const struct lws_context_creation_info *info,
369d4afb5ceSopenharmony_ci				    const char *cipher_list,
370d4afb5ceSopenharmony_ci				    const char *ca_filepath,
371d4afb5ceSopenharmony_ci				    const void *ca_mem,
372d4afb5ceSopenharmony_ci				    unsigned int ca_mem_len,
373d4afb5ceSopenharmony_ci				    const char *cert_filepath,
374d4afb5ceSopenharmony_ci				    const void *cert_mem,
375d4afb5ceSopenharmony_ci				    unsigned int cert_mem_len,
376d4afb5ceSopenharmony_ci				    const char *private_key_filepath,
377d4afb5ceSopenharmony_ci					const void *key_mem,
378d4afb5ceSopenharmony_ci					unsigned int key_mem_len
379d4afb5ceSopenharmony_ci					)
380d4afb5ceSopenharmony_ci{
381d4afb5ceSopenharmony_ci	X509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len);
382d4afb5ceSopenharmony_ci	SSL_METHOD *method = (SSL_METHOD *)TLS_client_method();
383d4afb5ceSopenharmony_ci	unsigned long error;
384d4afb5ceSopenharmony_ci	int n;
385d4afb5ceSopenharmony_ci
386d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS)
387d4afb5ceSopenharmony_ci	vh->tls_session_cache_max = info->tls_session_cache_max ?
388d4afb5ceSopenharmony_ci				    info->tls_session_cache_max : 10;
389d4afb5ceSopenharmony_ci	lws_tls_session_cache(vh, info->tls_session_timeout);
390d4afb5ceSopenharmony_ci#endif
391d4afb5ceSopenharmony_ci
392d4afb5ceSopenharmony_ci	if (!method) {
393d4afb5ceSopenharmony_ci		error = (unsigned long)ERR_get_error();
394d4afb5ceSopenharmony_ci		lwsl_err("problem creating ssl method %lu: %s\n",
395d4afb5ceSopenharmony_ci			error, ERR_error_string(error,
396d4afb5ceSopenharmony_ci				      (char *)vh->context->pt[0].serv_buf));
397d4afb5ceSopenharmony_ci		return 1;
398d4afb5ceSopenharmony_ci	}
399d4afb5ceSopenharmony_ci	/* create context */
400d4afb5ceSopenharmony_ci	vh->tls.ssl_client_ctx = SSL_CTX_new(method, &vh->context->mcdc);
401d4afb5ceSopenharmony_ci	if (!vh->tls.ssl_client_ctx) {
402d4afb5ceSopenharmony_ci		error = (unsigned long)ERR_get_error();
403d4afb5ceSopenharmony_ci		lwsl_err("problem creating ssl context %lu: %s\n",
404d4afb5ceSopenharmony_ci			error, ERR_error_string(error,
405d4afb5ceSopenharmony_ci				      (char *)vh->context->pt[0].serv_buf));
406d4afb5ceSopenharmony_ci		return 1;
407d4afb5ceSopenharmony_ci	}
408d4afb5ceSopenharmony_ci
409d4afb5ceSopenharmony_ci	if (!ca_filepath && (!ca_mem || !ca_mem_len))
410d4afb5ceSopenharmony_ci		return 0;
411d4afb5ceSopenharmony_ci
412d4afb5ceSopenharmony_ci	if (ca_filepath) {
413d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE)
414d4afb5ceSopenharmony_ci		uint8_t *buf;
415d4afb5ceSopenharmony_ci		lws_filepos_t len;
416d4afb5ceSopenharmony_ci
417d4afb5ceSopenharmony_ci		if (alloc_file(vh->context, ca_filepath, &buf, &len)) {
418d4afb5ceSopenharmony_ci			lwsl_err("Load CA cert file %s failed\n", ca_filepath);
419d4afb5ceSopenharmony_ci			return 1;
420d4afb5ceSopenharmony_ci		}
421d4afb5ceSopenharmony_ci		vh->tls.x509_client_CA = d2i_X509(NULL, buf, (long)len);
422d4afb5ceSopenharmony_ci		free(buf);
423d4afb5ceSopenharmony_ci
424d4afb5ceSopenharmony_ci		lwsl_info("Loading vh %s client CA for verification %s\n", vh->name, ca_filepath);
425d4afb5ceSopenharmony_ci#endif
426d4afb5ceSopenharmony_ci	} else {
427d4afb5ceSopenharmony_ci		vh->tls.x509_client_CA = d2i_X509(NULL, (uint8_t*)ca_mem, (long)ca_mem_len);
428d4afb5ceSopenharmony_ci		lwsl_info("%s: using mem client CA cert %d\n",
429d4afb5ceSopenharmony_ci			    __func__, ca_mem_len);
430d4afb5ceSopenharmony_ci	}
431d4afb5ceSopenharmony_ci
432d4afb5ceSopenharmony_ci	if (!vh->tls.x509_client_CA) {
433d4afb5ceSopenharmony_ci		lwsl_err("client CA: x509 parse failed\n");
434d4afb5ceSopenharmony_ci		return 1;
435d4afb5ceSopenharmony_ci	}
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_ci	if (!vh->tls.ssl_ctx)
438d4afb5ceSopenharmony_ci		SSL_CTX_add_client_CA(vh->tls.ssl_client_ctx, vh->tls.x509_client_CA);
439d4afb5ceSopenharmony_ci	else
440d4afb5ceSopenharmony_ci		SSL_CTX_add_client_CA(vh->tls.ssl_ctx, vh->tls.x509_client_CA);
441d4afb5ceSopenharmony_ci
442d4afb5ceSopenharmony_ci	/* support for client-side certificate authentication */
443d4afb5ceSopenharmony_ci	if (cert_filepath) {
444d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE)
445d4afb5ceSopenharmony_ci		uint8_t *buf;
446d4afb5ceSopenharmony_ci		lws_filepos_t amount;
447d4afb5ceSopenharmony_ci
448d4afb5ceSopenharmony_ci		if (lws_tls_use_any_upgrade_check_extant(cert_filepath) !=
449d4afb5ceSopenharmony_ci				LWS_TLS_EXTANT_YES &&
450d4afb5ceSopenharmony_ci		    (info->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT))
451d4afb5ceSopenharmony_ci			return 0;
452d4afb5ceSopenharmony_ci
453d4afb5ceSopenharmony_ci		lwsl_notice("%s: doing cert filepath %s\n", __func__,
454d4afb5ceSopenharmony_ci				cert_filepath);
455d4afb5ceSopenharmony_ci
456d4afb5ceSopenharmony_ci		if (alloc_file(vh->context, cert_filepath, &buf, &amount))
457d4afb5ceSopenharmony_ci			return 1;
458d4afb5ceSopenharmony_ci
459d4afb5ceSopenharmony_ci		buf[amount++] = '\0';
460d4afb5ceSopenharmony_ci
461d4afb5ceSopenharmony_ci		n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx,
462d4afb5ceSopenharmony_ci				(int)amount, buf);
463d4afb5ceSopenharmony_ci		lws_free(buf);
464d4afb5ceSopenharmony_ci		if (n < 1) {
465d4afb5ceSopenharmony_ci			lwsl_err("problem %d getting cert '%s'\n", n,
466d4afb5ceSopenharmony_ci				 cert_filepath);
467d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
468d4afb5ceSopenharmony_ci			return 1;
469d4afb5ceSopenharmony_ci		}
470d4afb5ceSopenharmony_ci
471d4afb5ceSopenharmony_ci		lwsl_info("Loaded client cert %s\n", cert_filepath);
472d4afb5ceSopenharmony_ci#endif
473d4afb5ceSopenharmony_ci	} else if (cert_mem && cert_mem_len) {
474d4afb5ceSopenharmony_ci		/* lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); */
475d4afb5ceSopenharmony_ci		n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx,
476d4afb5ceSopenharmony_ci						 (int)cert_mem_len, cert_mem);
477d4afb5ceSopenharmony_ci		if (n < 1) {
478d4afb5ceSopenharmony_ci			lwsl_err("%s: (mbedtls) problem interpreting client cert\n",
479d4afb5ceSopenharmony_ci				 __func__);
480d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
481d4afb5ceSopenharmony_ci			return 1;
482d4afb5ceSopenharmony_ci		}
483d4afb5ceSopenharmony_ci		lwsl_info("%s: using mem client cert %d\n",
484d4afb5ceSopenharmony_ci			    __func__, cert_mem_len);
485d4afb5ceSopenharmony_ci	}
486d4afb5ceSopenharmony_ci
487d4afb5ceSopenharmony_ci	if (private_key_filepath) {
488d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE)
489d4afb5ceSopenharmony_ci
490d4afb5ceSopenharmony_ci		uint8_t *buf;
491d4afb5ceSopenharmony_ci		lws_filepos_t amount;
492d4afb5ceSopenharmony_ci
493d4afb5ceSopenharmony_ci		lwsl_notice("%s: doing private key filepath %s\n", __func__,
494d4afb5ceSopenharmony_ci				private_key_filepath);
495d4afb5ceSopenharmony_ci		if (alloc_file(vh->context, private_key_filepath, &buf, &amount))
496d4afb5ceSopenharmony_ci			return 1;
497d4afb5ceSopenharmony_ci
498d4afb5ceSopenharmony_ci		buf[amount++] = '\0';
499d4afb5ceSopenharmony_ci
500d4afb5ceSopenharmony_ci		n = SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx,
501d4afb5ceSopenharmony_ci				buf, (long)amount);
502d4afb5ceSopenharmony_ci
503d4afb5ceSopenharmony_ci		lws_free(buf);
504d4afb5ceSopenharmony_ci		if (n < 1) {
505d4afb5ceSopenharmony_ci			lwsl_err("problem %d getting private key '%s'\n", n,
506d4afb5ceSopenharmony_ci				 private_key_filepath);
507d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
508d4afb5ceSopenharmony_ci			return 1;
509d4afb5ceSopenharmony_ci		}
510d4afb5ceSopenharmony_ci
511d4afb5ceSopenharmony_ci		lwsl_notice("Loaded private key %s\n", private_key_filepath);
512d4afb5ceSopenharmony_ci#endif
513d4afb5ceSopenharmony_ci	} else if (key_mem && key_mem_len) {
514d4afb5ceSopenharmony_ci		/* lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); */
515d4afb5ceSopenharmony_ci		n = SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx,
516d4afb5ceSopenharmony_ci				key_mem, (long)key_mem_len - 1);
517d4afb5ceSopenharmony_ci
518d4afb5ceSopenharmony_ci		if (n < 1) {
519d4afb5ceSopenharmony_ci			lwsl_err("%s: (mbedtls) problem interpreting private key\n",
520d4afb5ceSopenharmony_ci				 __func__);
521d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
522d4afb5ceSopenharmony_ci			return 1;
523d4afb5ceSopenharmony_ci		}
524d4afb5ceSopenharmony_ci		lwsl_info("%s: using mem private key %d\n",
525d4afb5ceSopenharmony_ci			    __func__, key_mem_len);
526d4afb5ceSopenharmony_ci
527d4afb5ceSopenharmony_ci	}
528d4afb5ceSopenharmony_ci	return 0;
529d4afb5ceSopenharmony_ci}
530d4afb5ceSopenharmony_ci
531d4afb5ceSopenharmony_ciint
532d4afb5ceSopenharmony_cilws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh,
533d4afb5ceSopenharmony_ci                const uint8_t *der, size_t der_len)
534d4afb5ceSopenharmony_ci{
535d4afb5ceSopenharmony_ci	if (SSL_CTX_add_client_CA_ASN1(vh->tls.ssl_client_ctx, (int)der_len, der) != 1) {
536d4afb5ceSopenharmony_ci		lwsl_err("%s: failed\n", __func__);
537d4afb5ceSopenharmony_ci			return 1;
538d4afb5ceSopenharmony_ci	}
539d4afb5ceSopenharmony_ci
540d4afb5ceSopenharmony_ci	return 0;
541d4afb5ceSopenharmony_ci}
542d4afb5ceSopenharmony_ci
543