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 "lws_config.h"
26d4afb5ceSopenharmony_ci#ifdef LWS_HAVE_X509_VERIFY_PARAM_set1_host
27d4afb5ceSopenharmony_ci/* Before glibc 2.10, strnlen required _GNU_SOURCE */
28d4afb5ceSopenharmony_ci#if !defined(_GNU_SOURCE)
29d4afb5ceSopenharmony_ci#define _GNU_SOURCE
30d4afb5ceSopenharmony_ci#endif
31d4afb5ceSopenharmony_ci#endif
32d4afb5ceSopenharmony_ci#include <string.h>
33d4afb5ceSopenharmony_ci
34d4afb5ceSopenharmony_ci#include "private-lib-core.h"
35d4afb5ceSopenharmony_ci#include "private-lib-tls-openssl.h"
36d4afb5ceSopenharmony_ci
37d4afb5ceSopenharmony_cistatic const int MAX_CLIENT_SSL_CA_NUMBER = 10;
38d4afb5ceSopenharmony_ci
39d4afb5ceSopenharmony_ci/*
40d4afb5ceSopenharmony_ci * Care: many openssl apis return 1 for success.  These are translated to the
41d4afb5ceSopenharmony_ci * lws convention of 0 for success.
42d4afb5ceSopenharmony_ci */
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ciint lws_openssl_describe_cipher(struct lws *wsi);
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_ciextern int openssl_websocket_private_data_index,
47d4afb5ceSopenharmony_ci    openssl_SSL_CTX_private_data_index;
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_ci#if 0
52d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST)
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci/*
55d4afb5ceSopenharmony_ci * Completion of sync or async JIT trust lookup
56d4afb5ceSopenharmony_ci */
57d4afb5ceSopenharmony_ci
58d4afb5ceSopenharmony_ciint
59d4afb5ceSopenharmony_cilws_tls_jit_trust_got_cert_cb(void *got_opaque, const uint8_t *der,
60d4afb5ceSopenharmony_ci			      size_t der_len)
61d4afb5ceSopenharmony_ci{
62d4afb5ceSopenharmony_ci	X509 *x = d2i_X509(NULL, &der, (long)der_len);
63d4afb5ceSopenharmony_ci	/** !!! this is not safe for async atm */
64d4afb5ceSopenharmony_ci	struct lws *wsi = (struct lws *)got_opaque;
65d4afb5ceSopenharmony_ci	X509_STORE *xs;
66d4afb5ceSopenharmony_ci	int ret = 0;
67d4afb5ceSopenharmony_ci
68d4afb5ceSopenharmony_ci	if (!x) {
69d4afb5ceSopenharmony_ci		lwsl_err("%s: failed\n", __func__);
70d4afb5ceSopenharmony_ci		return 1;
71d4afb5ceSopenharmony_ci	}
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci	xs = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(wsi->tls.ssl));
74d4afb5ceSopenharmony_ci	if (xs) {
75d4afb5ceSopenharmony_ci		if (X509_STORE_add_cert(xs, x) != 1) {
76d4afb5ceSopenharmony_ci			lwsl_warn("%s: unable to set trusted CA\n", __func__);
77d4afb5ceSopenharmony_ci			ret = 1;
78d4afb5ceSopenharmony_ci		} else
79d4afb5ceSopenharmony_ci			lwsl_notice("%s: added trusted CA to CTX for next time\n",
80d4afb5ceSopenharmony_ci					__func__);
81d4afb5ceSopenharmony_ci	} else
82d4afb5ceSopenharmony_ci		lwsl_warn("%s: couldn't get cert store\n", __func__);
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci	X509_free(x);
85d4afb5ceSopenharmony_ci
86d4afb5ceSopenharmony_ci	return ret;
87d4afb5ceSopenharmony_ci}
88d4afb5ceSopenharmony_ci#endif
89d4afb5ceSopenharmony_ci#endif
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_cistatic int
92d4afb5ceSopenharmony_ciOpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
93d4afb5ceSopenharmony_ci{
94d4afb5ceSopenharmony_ci	SSL *ssl;
95d4afb5ceSopenharmony_ci	int n, err = 0;
96d4afb5ceSopenharmony_ci	struct lws *wsi;
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci	/* keep old behaviour accepting self-signed server certs */
99d4afb5ceSopenharmony_ci	if (!preverify_ok) {
100d4afb5ceSopenharmony_ci		err = X509_STORE_CTX_get_error(x509_ctx);
101d4afb5ceSopenharmony_ci
102d4afb5ceSopenharmony_ci		if (err != X509_V_OK) {
103d4afb5ceSopenharmony_ci			ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
104d4afb5ceSopenharmony_ci					SSL_get_ex_data_X509_STORE_CTX_idx());
105d4afb5ceSopenharmony_ci			wsi = SSL_get_ex_data(ssl,
106d4afb5ceSopenharmony_ci					openssl_websocket_private_data_index);
107d4afb5ceSopenharmony_ci			if (!wsi) {
108d4afb5ceSopenharmony_ci				lwsl_err("%s: can't get wsi from ssl privdata\n",
109d4afb5ceSopenharmony_ci					 __func__);
110d4afb5ceSopenharmony_ci
111d4afb5ceSopenharmony_ci				return 0;
112d4afb5ceSopenharmony_ci			}
113d4afb5ceSopenharmony_ci
114d4afb5ceSopenharmony_ci			if ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
115d4afb5ceSopenharmony_ci			     err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
116d4afb5ceSopenharmony_ci			     wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED) {
117d4afb5ceSopenharmony_ci				lwsl_notice("accepting self-signed "
118d4afb5ceSopenharmony_ci					    "certificate (verify_callback)\n");
119d4afb5ceSopenharmony_ci				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
120d4afb5ceSopenharmony_ci				return 1;	// ok
121d4afb5ceSopenharmony_ci		} else if ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ||
122d4afb5ceSopenharmony_ci			    err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) &&
123d4afb5ceSopenharmony_ci			    wsi->tls.use_ssl & LCCSCF_ALLOW_INSECURE) {
124d4afb5ceSopenharmony_ci				lwsl_notice("accepting non-trusted certificate\n");
125d4afb5ceSopenharmony_ci				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
126d4afb5ceSopenharmony_ci				return 1;  /* ok */
127d4afb5ceSopenharmony_ci			} else if ((err == X509_V_ERR_CERT_NOT_YET_VALID ||
128d4afb5ceSopenharmony_ci				    err == X509_V_ERR_CERT_HAS_EXPIRED) &&
129d4afb5ceSopenharmony_ci				    wsi->tls.use_ssl & LCCSCF_ALLOW_EXPIRED) {
130d4afb5ceSopenharmony_ci				if (err == X509_V_ERR_CERT_NOT_YET_VALID)
131d4afb5ceSopenharmony_ci					lwsl_notice("accepting not yet valid "
132d4afb5ceSopenharmony_ci						    "certificate (verify_"
133d4afb5ceSopenharmony_ci						    "callback)\n");
134d4afb5ceSopenharmony_ci				else if (err == X509_V_ERR_CERT_HAS_EXPIRED)
135d4afb5ceSopenharmony_ci					lwsl_notice("accepting expired "
136d4afb5ceSopenharmony_ci						    "certificate (verify_"
137d4afb5ceSopenharmony_ci						    "callback)\n");
138d4afb5ceSopenharmony_ci				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
139d4afb5ceSopenharmony_ci				return 1;	// ok
140d4afb5ceSopenharmony_ci			}
141d4afb5ceSopenharmony_ci		}
142d4afb5ceSopenharmony_ci	}
143d4afb5ceSopenharmony_ci
144d4afb5ceSopenharmony_ci	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
145d4afb5ceSopenharmony_ci					 SSL_get_ex_data_X509_STORE_CTX_idx());
146d4afb5ceSopenharmony_ci	wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
147d4afb5ceSopenharmony_ci	if (!wsi) {
148d4afb5ceSopenharmony_ci		lwsl_err("%s: can't get wsi from ssl privdata\n",  __func__);
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci		return 0;
151d4afb5ceSopenharmony_ci	}
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST)
154d4afb5ceSopenharmony_ci	if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) {
155d4afb5ceSopenharmony_ci		union lws_tls_cert_info_results ci;
156d4afb5ceSopenharmony_ci		STACK_OF(X509) *x509_stack;
157d4afb5ceSopenharmony_ci
158d4afb5ceSopenharmony_ci		x509_stack = X509_STORE_CTX_get1_chain(x509_ctx);
159d4afb5ceSopenharmony_ci		if (x509_stack) {
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci			for (n = 0; n < OPENSSL_sk_num((const OPENSSL_STACK *)x509_stack) &&
162d4afb5ceSopenharmony_ci				    wsi->tls.kid_chain.count !=
163d4afb5ceSopenharmony_ci				     LWS_ARRAY_SIZE(wsi->tls.kid_chain.akid); n++) {
164d4afb5ceSopenharmony_ci				X509 *x509 = OPENSSL_sk_value((const OPENSSL_STACK *)x509_stack, n);
165d4afb5ceSopenharmony_ci
166d4afb5ceSopenharmony_ci				if (!lws_tls_openssl_cert_info(x509,
167d4afb5ceSopenharmony_ci					    LWS_TLS_CERT_INFO_SUBJECT_KEY_ID,
168d4afb5ceSopenharmony_ci					    &ci, 0))
169d4afb5ceSopenharmony_ci					lws_tls_kid_copy(&ci,
170d4afb5ceSopenharmony_ci						&wsi->tls.kid_chain.skid[
171d4afb5ceSopenharmony_ci						     wsi->tls.kid_chain.count]);
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci				if (!lws_tls_openssl_cert_info(x509,
174d4afb5ceSopenharmony_ci					     LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID,
175d4afb5ceSopenharmony_ci					     &ci, 0))
176d4afb5ceSopenharmony_ci					lws_tls_kid_copy(&ci,
177d4afb5ceSopenharmony_ci						 &wsi->tls.kid_chain.akid[
178d4afb5ceSopenharmony_ci						     wsi->tls.kid_chain.count]);
179d4afb5ceSopenharmony_ci
180d4afb5ceSopenharmony_ci				wsi->tls.kid_chain.count++;
181d4afb5ceSopenharmony_ci			}
182d4afb5ceSopenharmony_ci
183d4afb5ceSopenharmony_ci			sk_X509_pop_free(x509_stack, X509_free);
184d4afb5ceSopenharmony_ci		}
185d4afb5ceSopenharmony_ci
186d4afb5ceSopenharmony_ci		lws_tls_jit_trust_sort_kids(wsi, &wsi->tls.kid_chain);
187d4afb5ceSopenharmony_ci	}
188d4afb5ceSopenharmony_ci#endif
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ci	n = lws_get_context_protocol(wsi->a.context, 0).callback(wsi,
191d4afb5ceSopenharmony_ci			LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION,
192d4afb5ceSopenharmony_ci			x509_ctx, ssl, (unsigned int)preverify_ok);
193d4afb5ceSopenharmony_ci
194d4afb5ceSopenharmony_ci	/* keep old behaviour if something wrong with server certs */
195d4afb5ceSopenharmony_ci	/* if ssl error is overruled in callback and cert is ok,
196d4afb5ceSopenharmony_ci	 * X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); must be set and
197d4afb5ceSopenharmony_ci	 * return value is 0 from callback */
198d4afb5ceSopenharmony_ci	if (!preverify_ok) {
199d4afb5ceSopenharmony_ci		int err = X509_STORE_CTX_get_error(x509_ctx);
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci		if (err != X509_V_OK) {
202d4afb5ceSopenharmony_ci			/* cert validation error was not handled in callback */
203d4afb5ceSopenharmony_ci			int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
204d4afb5ceSopenharmony_ci			const char *msg = X509_verify_cert_error_string(err);
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci			lws_strncpy(wsi->tls.err_helper, msg,
207d4afb5ceSopenharmony_ci				    sizeof(wsi->tls.err_helper));
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci			lwsl_err("SSL error: %s (preverify_ok=%d;err=%d;"
210d4afb5ceSopenharmony_ci				 "depth=%d)\n", msg, preverify_ok, err, depth);
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
213d4afb5ceSopenharmony_ci			{
214d4afb5ceSopenharmony_ci				char buckname[64];
215d4afb5ceSopenharmony_ci
216d4afb5ceSopenharmony_ci				lws_snprintf(buckname, sizeof(buckname),
217d4afb5ceSopenharmony_ci					     "tls=\"%s\"", msg);
218d4afb5ceSopenharmony_ci				lws_metrics_hist_bump_describe_wsi(wsi,
219d4afb5ceSopenharmony_ci					lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures),
220d4afb5ceSopenharmony_ci					buckname);
221d4afb5ceSopenharmony_ci			}
222d4afb5ceSopenharmony_ci#endif
223d4afb5ceSopenharmony_ci
224d4afb5ceSopenharmony_ci			return preverify_ok;	// not ok
225d4afb5ceSopenharmony_ci		}
226d4afb5ceSopenharmony_ci	}
227d4afb5ceSopenharmony_ci	/*
228d4afb5ceSopenharmony_ci	 * convert callback return code from 0 = OK to verify callback
229d4afb5ceSopenharmony_ci	 * return value 1 = OK
230d4afb5ceSopenharmony_ci	 */
231d4afb5ceSopenharmony_ci	return !n;
232d4afb5ceSopenharmony_ci}
233d4afb5ceSopenharmony_ci#endif
234d4afb5ceSopenharmony_ci
235d4afb5ceSopenharmony_ciint
236d4afb5ceSopenharmony_cilws_ssl_client_bio_create(struct lws *wsi)
237d4afb5ceSopenharmony_ci{
238d4afb5ceSopenharmony_ci	char hostname[128], *p;
239d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \
240d4afb5ceSopenharmony_ci    defined(LWS_HAVE_SSL_get0_alpn_selected)
241d4afb5ceSopenharmony_ci	uint8_t openssl_alpn[40];
242d4afb5ceSopenharmony_ci	const char *alpn_comma = wsi->a.context->tls.alpn_default;
243d4afb5ceSopenharmony_ci	int n;
244d4afb5ceSopenharmony_ci#endif
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci	if (wsi->stash) {
247d4afb5ceSopenharmony_ci		lws_strncpy(hostname, wsi->stash->cis[CIS_HOST], sizeof(hostname));
248d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \
249d4afb5ceSopenharmony_ci    defined(LWS_HAVE_SSL_get0_alpn_selected)
250d4afb5ceSopenharmony_ci		alpn_comma = wsi->stash->cis[CIS_ALPN];
251d4afb5ceSopenharmony_ci#endif
252d4afb5ceSopenharmony_ci	} else {
253d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
254d4afb5ceSopenharmony_ci		if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
255d4afb5ceSopenharmony_ci				 _WSI_TOKEN_CLIENT_HOST) <= 0)
256d4afb5ceSopenharmony_ci#endif
257d4afb5ceSopenharmony_ci		{
258d4afb5ceSopenharmony_ci			lwsl_err("%s: Unable to get hostname\n", __func__);
259d4afb5ceSopenharmony_ci
260d4afb5ceSopenharmony_ci			return -1;
261d4afb5ceSopenharmony_ci		}
262d4afb5ceSopenharmony_ci	}
263d4afb5ceSopenharmony_ci
264d4afb5ceSopenharmony_ci	/*
265d4afb5ceSopenharmony_ci	 * remove any :port part on the hostname... necessary for network
266d4afb5ceSopenharmony_ci	 * connection but typical certificates do not contain it
267d4afb5ceSopenharmony_ci	 */
268d4afb5ceSopenharmony_ci	p = hostname;
269d4afb5ceSopenharmony_ci	while (*p) {
270d4afb5ceSopenharmony_ci		if (*p == ':') {
271d4afb5ceSopenharmony_ci			*p = '\0';
272d4afb5ceSopenharmony_ci			break;
273d4afb5ceSopenharmony_ci		}
274d4afb5ceSopenharmony_ci		p++;
275d4afb5ceSopenharmony_ci	}
276d4afb5ceSopenharmony_ci
277d4afb5ceSopenharmony_ci	wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_client_ctx);
278d4afb5ceSopenharmony_ci	if (!wsi->tls.ssl) {
279d4afb5ceSopenharmony_ci		const char *es = ERR_error_string(
280d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
281d4afb5ceSopenharmony_ci	(uint32_t)
282d4afb5ceSopenharmony_ci#else
283d4afb5ceSopenharmony_ci	(unsigned long)
284d4afb5ceSopenharmony_ci#endif
285d4afb5ceSopenharmony_ci	lws_ssl_get_error(wsi, 0), NULL);
286d4afb5ceSopenharmony_ci		lwsl_err("SSL_new failed: %s\n", es);
287d4afb5ceSopenharmony_ci		lws_tls_err_describe_clear();
288d4afb5ceSopenharmony_ci		return -1;
289d4afb5ceSopenharmony_ci	}
290d4afb5ceSopenharmony_ci
291d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS)
292d4afb5ceSopenharmony_ci	if (!(wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE))
293d4afb5ceSopenharmony_ci		lws_tls_reuse_session(wsi);
294d4afb5ceSopenharmony_ci#endif
295d4afb5ceSopenharmony_ci
296d4afb5ceSopenharmony_ci#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
297d4afb5ceSopenharmony_ci	if (wsi->a.vhost->tls.ssl_info_event_mask)
298d4afb5ceSopenharmony_ci		SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
299d4afb5ceSopenharmony_ci#endif
300d4afb5ceSopenharmony_ci
301d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_X509_VERIFY_PARAM_set1_host)
302d4afb5ceSopenharmony_ci	if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
303d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
304d4afb5ceSopenharmony_ci
305d4afb5ceSopenharmony_ci		X509_VERIFY_PARAM *param = SSL_get0_param(wsi->tls.ssl);
306d4afb5ceSopenharmony_ci
307d4afb5ceSopenharmony_ci		/* Enable automatic hostname checks */
308d4afb5ceSopenharmony_ci		X509_VERIFY_PARAM_set_hostflags(param,
309d4afb5ceSopenharmony_ci					X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
310d4afb5ceSopenharmony_ci		/* Handle the case where the hostname is an IP address */
311d4afb5ceSopenharmony_ci		if (!X509_VERIFY_PARAM_set1_ip_asc(param, hostname))
312d4afb5ceSopenharmony_ci			X509_VERIFY_PARAM_set1_host(param, hostname,
313d4afb5ceSopenharmony_ci					strnlen(hostname, sizeof(hostname)));
314d4afb5ceSopenharmony_ci#endif
315d4afb5ceSopenharmony_ci
316d4afb5ceSopenharmony_ci	}
317d4afb5ceSopenharmony_ci#else
318d4afb5ceSopenharmony_ci	if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
319d4afb5ceSopenharmony_ci		lwsl_err("%s: your tls lib is too old to have "
320d4afb5ceSopenharmony_ci			 "X509_VERIFY_PARAM_set1_host, failing all client tls\n",
321d4afb5ceSopenharmony_ci			 __func__);
322d4afb5ceSopenharmony_ci		return -1;
323d4afb5ceSopenharmony_ci	}
324d4afb5ceSopenharmony_ci#endif
325d4afb5ceSopenharmony_ci
326d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
327d4afb5ceSopenharmony_ci#ifndef USE_OLD_CYASSL
328d4afb5ceSopenharmony_ci	/* OpenSSL_client_verify_callback will be called @ SSL_connect() */
329d4afb5ceSopenharmony_ci	SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER,
330d4afb5ceSopenharmony_ci		       OpenSSL_client_verify_callback);
331d4afb5ceSopenharmony_ci#endif
332d4afb5ceSopenharmony_ci#endif
333d4afb5ceSopenharmony_ci
334d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
335d4afb5ceSopenharmony_ci	SSL_set_mode(wsi->tls.ssl,  SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
336d4afb5ceSopenharmony_ci#endif
337d4afb5ceSopenharmony_ci	/*
338d4afb5ceSopenharmony_ci	 * use server name indication (SNI), if supported,
339d4afb5ceSopenharmony_ci	 * when establishing connection
340d4afb5ceSopenharmony_ci	 */
341d4afb5ceSopenharmony_ci#ifdef USE_WOLFSSL
342d4afb5ceSopenharmony_ci#ifdef USE_OLD_CYASSL
343d4afb5ceSopenharmony_ci#ifdef CYASSL_SNI_HOST_NAME
344d4afb5ceSopenharmony_ci	CyaSSL_UseSNI(wsi->tls.ssl, CYASSL_SNI_HOST_NAME, hostname,
345d4afb5ceSopenharmony_ci		      strlen(hostname));
346d4afb5ceSopenharmony_ci#endif
347d4afb5ceSopenharmony_ci#else
348d4afb5ceSopenharmony_ci#if defined(WOLFSSL_SNI_HOST_NAME) || defined(HAVE_SNI)
349d4afb5ceSopenharmony_ci	wolfSSL_UseSNI(wsi->tls.ssl, WOLFSSL_SNI_HOST_NAME, hostname,
350d4afb5ceSopenharmony_ci		       (unsigned short)strlen(hostname));
351d4afb5ceSopenharmony_ci#endif
352d4afb5ceSopenharmony_ci#endif
353d4afb5ceSopenharmony_ci#else
354d4afb5ceSopenharmony_ci#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
355d4afb5ceSopenharmony_ci	SSL_set_tlsext_host_name(wsi->tls.ssl, hostname);
356d4afb5ceSopenharmony_ci#endif
357d4afb5ceSopenharmony_ci#endif
358d4afb5ceSopenharmony_ci
359d4afb5ceSopenharmony_ci#ifdef USE_WOLFSSL
360d4afb5ceSopenharmony_ci	/*
361d4afb5ceSopenharmony_ci	 * wolfSSL/CyaSSL does certificate verification differently
362d4afb5ceSopenharmony_ci	 * from OpenSSL.
363d4afb5ceSopenharmony_ci	 * If we should ignore the certificate, we need to set
364d4afb5ceSopenharmony_ci	 * this before SSL_new and SSL_connect is called.
365d4afb5ceSopenharmony_ci	 * Otherwise the connect will simply fail with error code -155
366d4afb5ceSopenharmony_ci	 */
367d4afb5ceSopenharmony_ci#ifdef USE_OLD_CYASSL
368d4afb5ceSopenharmony_ci	if (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)
369d4afb5ceSopenharmony_ci		CyaSSL_set_verify(wsi->tls.ssl, SSL_VERIFY_NONE, NULL);
370d4afb5ceSopenharmony_ci#else
371d4afb5ceSopenharmony_ci	if (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)
372d4afb5ceSopenharmony_ci		wolfSSL_set_verify(wsi->tls.ssl, SSL_VERIFY_NONE, NULL);
373d4afb5ceSopenharmony_ci#endif
374d4afb5ceSopenharmony_ci#endif /* USE_WOLFSSL */
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci	wsi->tls.client_bio = BIO_new_socket((int)(lws_intptr_t)wsi->desc.sockfd,
377d4afb5ceSopenharmony_ci					     BIO_NOCLOSE);
378d4afb5ceSopenharmony_ci	SSL_set_bio(wsi->tls.ssl, wsi->tls.client_bio, wsi->tls.client_bio);
379d4afb5ceSopenharmony_ci
380d4afb5ceSopenharmony_ci#ifdef USE_WOLFSSL
381d4afb5ceSopenharmony_ci#ifdef USE_OLD_CYASSL
382d4afb5ceSopenharmony_ci	CyaSSL_set_using_nonblock(wsi->tls.ssl, 1);
383d4afb5ceSopenharmony_ci#else
384d4afb5ceSopenharmony_ci	wolfSSL_set_using_nonblock(wsi->tls.ssl, 1);
385d4afb5ceSopenharmony_ci#endif
386d4afb5ceSopenharmony_ci#else
387d4afb5ceSopenharmony_ci	BIO_set_nbio(wsi->tls.client_bio, 1); /* nonblocking */
388d4afb5ceSopenharmony_ci#endif
389d4afb5ceSopenharmony_ci
390d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \
391d4afb5ceSopenharmony_ci    defined(LWS_HAVE_SSL_get0_alpn_selected)
392d4afb5ceSopenharmony_ci	if (wsi->a.vhost->tls.alpn)
393d4afb5ceSopenharmony_ci		alpn_comma = wsi->a.vhost->tls.alpn;
394d4afb5ceSopenharmony_ci	if (wsi->stash)
395d4afb5ceSopenharmony_ci		alpn_comma = wsi->stash->cis[CIS_ALPN];
396d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
397d4afb5ceSopenharmony_ci	if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
398d4afb5ceSopenharmony_ci			 _WSI_TOKEN_CLIENT_ALPN) > 0)
399d4afb5ceSopenharmony_ci		alpn_comma = hostname;
400d4afb5ceSopenharmony_ci#endif
401d4afb5ceSopenharmony_ci
402d4afb5ceSopenharmony_ci	lwsl_info("%s client conn using alpn list '%s'\n", wsi->role_ops->name, alpn_comma);
403d4afb5ceSopenharmony_ci
404d4afb5ceSopenharmony_ci	n = lws_alpn_comma_to_openssl(alpn_comma, openssl_alpn,
405d4afb5ceSopenharmony_ci				      sizeof(openssl_alpn) - 1);
406d4afb5ceSopenharmony_ci
407d4afb5ceSopenharmony_ci	SSL_set_alpn_protos(wsi->tls.ssl, openssl_alpn, (unsigned int)n);
408d4afb5ceSopenharmony_ci#endif
409d4afb5ceSopenharmony_ci
410d4afb5ceSopenharmony_ci	SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index,
411d4afb5ceSopenharmony_ci			wsi);
412d4afb5ceSopenharmony_ci
413d4afb5ceSopenharmony_ci	if (wsi->sys_tls_client_cert) {
414d4afb5ceSopenharmony_ci		lws_system_blob_t *b = lws_system_get_blob(wsi->a.context,
415d4afb5ceSopenharmony_ci					LWS_SYSBLOB_TYPE_CLIENT_CERT_DER,
416d4afb5ceSopenharmony_ci					wsi->sys_tls_client_cert - 1);
417d4afb5ceSopenharmony_ci		const uint8_t *data;
418d4afb5ceSopenharmony_ci		size_t size;
419d4afb5ceSopenharmony_ci
420d4afb5ceSopenharmony_ci		if (!b)
421d4afb5ceSopenharmony_ci			goto no_client_cert;
422d4afb5ceSopenharmony_ci
423d4afb5ceSopenharmony_ci		/*
424d4afb5ceSopenharmony_ci		 * Set up the per-connection client cert
425d4afb5ceSopenharmony_ci		 */
426d4afb5ceSopenharmony_ci
427d4afb5ceSopenharmony_ci		size = lws_system_blob_get_size(b);
428d4afb5ceSopenharmony_ci		if (!size)
429d4afb5ceSopenharmony_ci			goto no_client_cert;
430d4afb5ceSopenharmony_ci
431d4afb5ceSopenharmony_ci		if (lws_system_blob_get_single_ptr(b, &data))
432d4afb5ceSopenharmony_ci			goto no_client_cert;
433d4afb5ceSopenharmony_ci
434d4afb5ceSopenharmony_ci		if (SSL_use_certificate_ASN1(wsi->tls.ssl,
435d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL)
436d4afb5ceSopenharmony_ci			(unsigned char *)
437d4afb5ceSopenharmony_ci#endif
438d4afb5ceSopenharmony_ci					data,
439d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
440d4afb5ceSopenharmony_ci					(size_t)
441d4afb5ceSopenharmony_ci#else
442d4afb5ceSopenharmony_ci					(int)
443d4afb5ceSopenharmony_ci#endif
444d4afb5ceSopenharmony_ci					size) != 1) {
445d4afb5ceSopenharmony_ci			lwsl_err("%s: use_certificate failed\n", __func__);
446d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
447d4afb5ceSopenharmony_ci			goto no_client_cert;
448d4afb5ceSopenharmony_ci		}
449d4afb5ceSopenharmony_ci
450d4afb5ceSopenharmony_ci		b = lws_system_get_blob(wsi->a.context,
451d4afb5ceSopenharmony_ci					LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
452d4afb5ceSopenharmony_ci					wsi->sys_tls_client_cert - 1);
453d4afb5ceSopenharmony_ci		if (!b)
454d4afb5ceSopenharmony_ci			goto no_client_cert;
455d4afb5ceSopenharmony_ci
456d4afb5ceSopenharmony_ci		size = lws_system_blob_get_size(b);
457d4afb5ceSopenharmony_ci		if (!size)
458d4afb5ceSopenharmony_ci			goto no_client_cert;
459d4afb5ceSopenharmony_ci
460d4afb5ceSopenharmony_ci		if (lws_system_blob_get_single_ptr(b, &data))
461d4afb5ceSopenharmony_ci			goto no_client_cert;
462d4afb5ceSopenharmony_ci
463d4afb5ceSopenharmony_ci		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, wsi->tls.ssl,
464d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL)
465d4afb5ceSopenharmony_ci			(unsigned char *)
466d4afb5ceSopenharmony_ci#endif
467d4afb5ceSopenharmony_ci
468d4afb5ceSopenharmony_ci					    data,
469d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
470d4afb5ceSopenharmony_ci					(size_t)
471d4afb5ceSopenharmony_ci#else
472d4afb5ceSopenharmony_ci					(int)
473d4afb5ceSopenharmony_ci#endif
474d4afb5ceSopenharmony_ci					    size) != 1 &&
475d4afb5ceSopenharmony_ci		    SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, wsi->tls.ssl,
476d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL)
477d4afb5ceSopenharmony_ci			(unsigned char *)
478d4afb5ceSopenharmony_ci#endif
479d4afb5ceSopenharmony_ci					    data,
480d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
481d4afb5ceSopenharmony_ci					(size_t)
482d4afb5ceSopenharmony_ci#else
483d4afb5ceSopenharmony_ci					(int)
484d4afb5ceSopenharmony_ci#endif
485d4afb5ceSopenharmony_ci					    size) != 1) {
486d4afb5ceSopenharmony_ci			lwsl_err("%s: use_privkey failed\n", __func__);
487d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
488d4afb5ceSopenharmony_ci			goto no_client_cert;
489d4afb5ceSopenharmony_ci		}
490d4afb5ceSopenharmony_ci
491d4afb5ceSopenharmony_ci		if (SSL_check_private_key(wsi->tls.ssl) != 1) {
492d4afb5ceSopenharmony_ci			lwsl_err("Private SSL key doesn't match cert\n");
493d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
494d4afb5ceSopenharmony_ci			return 1;
495d4afb5ceSopenharmony_ci		}
496d4afb5ceSopenharmony_ci
497d4afb5ceSopenharmony_ci		lwsl_notice("%s: set system client cert %u\n", __func__,
498d4afb5ceSopenharmony_ci				wsi->sys_tls_client_cert - 1);
499d4afb5ceSopenharmony_ci	}
500d4afb5ceSopenharmony_ci
501d4afb5ceSopenharmony_ci	return 0;
502d4afb5ceSopenharmony_ci
503d4afb5ceSopenharmony_cino_client_cert:
504d4afb5ceSopenharmony_ci	lwsl_err("%s: unable to set up system client cert %d\n", __func__,
505d4afb5ceSopenharmony_ci			wsi->sys_tls_client_cert - 1);
506d4afb5ceSopenharmony_ci
507d4afb5ceSopenharmony_ci	return 1;
508d4afb5ceSopenharmony_ci}
509d4afb5ceSopenharmony_ci
510d4afb5ceSopenharmony_cienum lws_ssl_capable_status
511d4afb5ceSopenharmony_cilws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen)
512d4afb5ceSopenharmony_ci{
513d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \
514d4afb5ceSopenharmony_ci    defined(LWS_HAVE_SSL_get0_alpn_selected)
515d4afb5ceSopenharmony_ci	const unsigned char *prot;
516d4afb5ceSopenharmony_ci	char a[32];
517d4afb5ceSopenharmony_ci	unsigned int len;
518d4afb5ceSopenharmony_ci#endif
519d4afb5ceSopenharmony_ci	int m, n, en;
520d4afb5ceSopenharmony_ci	unsigned long l;
521d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS) && defined(LWS_HAVE_SSL_SESSION_set_time)
522d4afb5ceSopenharmony_ci	SSL_SESSION *sess;
523d4afb5ceSopenharmony_ci#endif
524d4afb5ceSopenharmony_ci	errno = 0;
525d4afb5ceSopenharmony_ci	ERR_clear_error();
526d4afb5ceSopenharmony_ci	wsi->tls.err_helper[0] = '\0';
527d4afb5ceSopenharmony_ci	n = SSL_connect(wsi->tls.ssl);
528d4afb5ceSopenharmony_ci	en = errno;
529d4afb5ceSopenharmony_ci
530d4afb5ceSopenharmony_ci	m = lws_ssl_get_error(wsi, n);
531d4afb5ceSopenharmony_ci
532d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_SYSCALL
533d4afb5ceSopenharmony_ci#if defined(WIN32)
534d4afb5ceSopenharmony_ci			&& en
535d4afb5ceSopenharmony_ci#endif
536d4afb5ceSopenharmony_ci	) {
537d4afb5ceSopenharmony_ci#if defined(WIN32) || (_LWS_ENABLED_LOGS & LLL_INFO)
538d4afb5ceSopenharmony_ci		lwsl_info("%s: n %d, m %d, errno %d\n", __func__, n, m, en);
539d4afb5ceSopenharmony_ci#endif
540d4afb5ceSopenharmony_ci		lws_snprintf(errbuf, elen, "connect SYSCALL %d", en);
541d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_ERROR;
542d4afb5ceSopenharmony_ci	}
543d4afb5ceSopenharmony_ci
544d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_SSL) {
545d4afb5ceSopenharmony_ci		l = ERR_get_error();
546d4afb5ceSopenharmony_ci		n = lws_snprintf(errbuf, elen, "tls: %s", wsi->tls.err_helper);
547d4afb5ceSopenharmony_ci		if (!wsi->tls.err_helper[0])
548d4afb5ceSopenharmony_ci			ERR_error_string_n((unsigned int)l, errbuf + n, (elen - (unsigned int)n));
549d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_ERROR;
550d4afb5ceSopenharmony_ci	}
551d4afb5ceSopenharmony_ci
552d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS)
553d4afb5ceSopenharmony_ci	if (SSL_session_reused(wsi->tls.ssl)) {
554d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_SESSION_set_time)
555d4afb5ceSopenharmony_ci		sess = SSL_get_session(wsi->tls.ssl);
556d4afb5ceSopenharmony_ci		if (sess) /* should always be true */
557d4afb5ceSopenharmony_ci#if defined(OPENSSL_IS_BORINGSSL)
558d4afb5ceSopenharmony_ci			SSL_SESSION_set_time(sess, (uint64_t)time(NULL)); /* extend session lifetime */
559d4afb5ceSopenharmony_ci#else
560d4afb5ceSopenharmony_ci			SSL_SESSION_set_time(sess, (long)time(NULL)); /* extend session lifetime */
561d4afb5ceSopenharmony_ci#endif
562d4afb5ceSopenharmony_ci#endif
563d4afb5ceSopenharmony_ci	}
564d4afb5ceSopenharmony_ci#endif
565d4afb5ceSopenharmony_ci
566d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl))
567d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
568d4afb5ceSopenharmony_ci
569d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl))
570d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
571d4afb5ceSopenharmony_ci
572d4afb5ceSopenharmony_ci	if (n == 1 || m == SSL_ERROR_SYSCALL) {
573d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \
574d4afb5ceSopenharmony_ci    defined(LWS_HAVE_SSL_get0_alpn_selected)
575d4afb5ceSopenharmony_ci		SSL_get0_alpn_selected(wsi->tls.ssl, &prot, &len);
576d4afb5ceSopenharmony_ci
577d4afb5ceSopenharmony_ci		if (len >= sizeof(a))
578d4afb5ceSopenharmony_ci			len = sizeof(a) - 1;
579d4afb5ceSopenharmony_ci		memcpy(a, (const char *)prot, len);
580d4afb5ceSopenharmony_ci		a[len] = '\0';
581d4afb5ceSopenharmony_ci
582d4afb5ceSopenharmony_ci		lws_role_call_alpn_negotiated(wsi, (const char *)a);
583d4afb5ceSopenharmony_ci#endif
584d4afb5ceSopenharmony_ci#if defined(LWS_TLS_SYNTHESIZE_CB)
585d4afb5ceSopenharmony_ci		lws_sul_schedule(wsi->a.context, wsi->tsi,
586d4afb5ceSopenharmony_ci				 &wsi->tls.sul_cb_synth,
587d4afb5ceSopenharmony_ci				 lws_sess_cache_synth_cb, 500 * LWS_US_PER_MS);
588d4afb5ceSopenharmony_ci#endif
589d4afb5ceSopenharmony_ci
590d4afb5ceSopenharmony_ci		lwsl_info("client connect OK\n");
591d4afb5ceSopenharmony_ci		lws_openssl_describe_cipher(wsi);
592d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_DONE;
593d4afb5ceSopenharmony_ci	}
594d4afb5ceSopenharmony_ci
595d4afb5ceSopenharmony_ci	if (!n) /* we don't know what he wants, but he says to retry */
596d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE;
597d4afb5ceSopenharmony_ci
598d4afb5ceSopenharmony_ci	lws_snprintf(errbuf, elen, "connect unk %d", m);
599d4afb5ceSopenharmony_ci
600d4afb5ceSopenharmony_ci	return LWS_SSL_CAPABLE_ERROR;
601d4afb5ceSopenharmony_ci}
602d4afb5ceSopenharmony_ci
603d4afb5ceSopenharmony_ciint
604d4afb5ceSopenharmony_cilws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, size_t ebuf_len)
605d4afb5ceSopenharmony_ci{
606d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
607d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
608d4afb5ceSopenharmony_ci	char *p = (char *)&pt->serv_buf[0];
609d4afb5ceSopenharmony_ci	const char *es, *type = "";
610d4afb5ceSopenharmony_ci	unsigned int avoid = 0;
611d4afb5ceSopenharmony_ci	char *sb = p;
612d4afb5ceSopenharmony_ci	long n;
613d4afb5ceSopenharmony_ci
614d4afb5ceSopenharmony_ci	errno = 0;
615d4afb5ceSopenharmony_ci	ERR_clear_error();
616d4afb5ceSopenharmony_ci	n = SSL_get_verify_result(wsi->tls.ssl);
617d4afb5ceSopenharmony_ci
618d4afb5ceSopenharmony_ci	switch (n) {
619d4afb5ceSopenharmony_ci	case X509_V_OK:
620d4afb5ceSopenharmony_ci		return 0;
621d4afb5ceSopenharmony_ci
622d4afb5ceSopenharmony_ci	case X509_V_ERR_HOSTNAME_MISMATCH:
623d4afb5ceSopenharmony_ci		type = "tls=hostname";
624d4afb5ceSopenharmony_ci		avoid = LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
625d4afb5ceSopenharmony_ci		break;
626d4afb5ceSopenharmony_ci
627d4afb5ceSopenharmony_ci	case X509_V_ERR_INVALID_CA:
628d4afb5ceSopenharmony_ci	case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
629d4afb5ceSopenharmony_ci	case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
630d4afb5ceSopenharmony_ci		type = "tls=invalidca";
631d4afb5ceSopenharmony_ci		avoid = LCCSCF_ALLOW_SELFSIGNED;
632d4afb5ceSopenharmony_ci		break;
633d4afb5ceSopenharmony_ci
634d4afb5ceSopenharmony_ci	case X509_V_ERR_CERT_NOT_YET_VALID:
635d4afb5ceSopenharmony_ci		type = "tls=notyetvalid";
636d4afb5ceSopenharmony_ci		avoid = LCCSCF_ALLOW_EXPIRED;
637d4afb5ceSopenharmony_ci		break;
638d4afb5ceSopenharmony_ci
639d4afb5ceSopenharmony_ci	case X509_V_ERR_CERT_HAS_EXPIRED:
640d4afb5ceSopenharmony_ci		type = "tls=expired";
641d4afb5ceSopenharmony_ci		avoid = LCCSCF_ALLOW_EXPIRED;
642d4afb5ceSopenharmony_ci		break;
643d4afb5ceSopenharmony_ci	}
644d4afb5ceSopenharmony_ci
645d4afb5ceSopenharmony_ci	lwsl_info("%s: cert problem: %s\n", __func__, type);
646d4afb5ceSopenharmony_ci
647d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
648d4afb5ceSopenharmony_ci	lws_metrics_hist_bump_describe_wsi(wsi,
649d4afb5ceSopenharmony_ci			lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures), type);
650d4afb5ceSopenharmony_ci#endif
651d4afb5ceSopenharmony_ci
652d4afb5ceSopenharmony_ci	if (wsi->tls.use_ssl & avoid) {
653d4afb5ceSopenharmony_ci		lwsl_info("%s: allowing anyway\n", __func__);
654d4afb5ceSopenharmony_ci
655d4afb5ceSopenharmony_ci		return 0;
656d4afb5ceSopenharmony_ci	}
657d4afb5ceSopenharmony_ci
658d4afb5ceSopenharmony_ci	es = ERR_error_string(
659d4afb5ceSopenharmony_ci	#if defined(LWS_WITH_BORINGSSL)
660d4afb5ceSopenharmony_ci					 (uint32_t)
661d4afb5ceSopenharmony_ci	#else
662d4afb5ceSopenharmony_ci					 (unsigned long)
663d4afb5ceSopenharmony_ci	#endif
664d4afb5ceSopenharmony_ci					 n, sb);
665d4afb5ceSopenharmony_ci	lws_snprintf(ebuf, ebuf_len,
666d4afb5ceSopenharmony_ci		"server's cert didn't look good, %s X509_V_ERR = %ld: %s\n",
667d4afb5ceSopenharmony_ci		 type, n, es);
668d4afb5ceSopenharmony_ci	lwsl_info("%s\n", ebuf);
669d4afb5ceSopenharmony_ci	lws_tls_err_describe_clear();
670d4afb5ceSopenharmony_ci
671d4afb5ceSopenharmony_ci	return -1;
672d4afb5ceSopenharmony_ci
673d4afb5ceSopenharmony_ci#else /* USE_WOLFSSL */
674d4afb5ceSopenharmony_ci	return 0;
675d4afb5ceSopenharmony_ci#endif
676d4afb5ceSopenharmony_ci}
677d4afb5ceSopenharmony_ci
678d4afb5ceSopenharmony_ciint
679d4afb5ceSopenharmony_cilws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh,
680d4afb5ceSopenharmony_ci                const uint8_t *der, size_t der_len)
681d4afb5ceSopenharmony_ci{
682d4afb5ceSopenharmony_ci	X509_STORE *st;
683d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL)
684d4afb5ceSopenharmony_ci	X509 *x  = d2i_X509(NULL, &der, (int)der_len);
685d4afb5ceSopenharmony_ci#else
686d4afb5ceSopenharmony_ci	X509 *x  = d2i_X509(NULL, &der, (long)der_len);
687d4afb5ceSopenharmony_ci#endif
688d4afb5ceSopenharmony_ci	int n;
689d4afb5ceSopenharmony_ci
690d4afb5ceSopenharmony_ci	if (!x) {
691d4afb5ceSopenharmony_ci		lwsl_err("%s: Failed to load DER\n", __func__);
692d4afb5ceSopenharmony_ci		lws_tls_err_describe_clear();
693d4afb5ceSopenharmony_ci		return 1;
694d4afb5ceSopenharmony_ci	}
695d4afb5ceSopenharmony_ci
696d4afb5ceSopenharmony_ci	st = SSL_CTX_get_cert_store(vh->tls.ssl_client_ctx);
697d4afb5ceSopenharmony_ci	if (!st) {
698d4afb5ceSopenharmony_ci		lwsl_err("%s: failed to get cert store\n", __func__);
699d4afb5ceSopenharmony_ci		X509_free(x);
700d4afb5ceSopenharmony_ci		return 1;
701d4afb5ceSopenharmony_ci	}
702d4afb5ceSopenharmony_ci
703d4afb5ceSopenharmony_ci	n = X509_STORE_add_cert(st, x);
704d4afb5ceSopenharmony_ci	if (n != 1)
705d4afb5ceSopenharmony_ci		lwsl_err("%s: failed to add cert\n", __func__);
706d4afb5ceSopenharmony_ci
707d4afb5ceSopenharmony_ci	X509_free(x);
708d4afb5ceSopenharmony_ci
709d4afb5ceSopenharmony_ci	return n != 1;
710d4afb5ceSopenharmony_ci}
711d4afb5ceSopenharmony_ci
712d4afb5ceSopenharmony_ciint
713d4afb5ceSopenharmony_cilws_tls_client_create_vhost_context(struct lws_vhost *vh,
714d4afb5ceSopenharmony_ci				    const struct lws_context_creation_info *info,
715d4afb5ceSopenharmony_ci				    const char *cipher_list,
716d4afb5ceSopenharmony_ci				    const char *ca_filepath,
717d4afb5ceSopenharmony_ci				    const void *ca_mem,
718d4afb5ceSopenharmony_ci				    unsigned int ca_mem_len,
719d4afb5ceSopenharmony_ci				    const char *cert_filepath,
720d4afb5ceSopenharmony_ci				    const void *cert_mem,
721d4afb5ceSopenharmony_ci				    unsigned int cert_mem_len,
722d4afb5ceSopenharmony_ci				    const char *private_key_filepath,
723d4afb5ceSopenharmony_ci					const void *key_mem,
724d4afb5ceSopenharmony_ci				    unsigned int key_mem_len
725d4afb5ceSopenharmony_ci					)
726d4afb5ceSopenharmony_ci{
727d4afb5ceSopenharmony_ci	struct lws_tls_client_reuse *tcr;
728d4afb5ceSopenharmony_ci	X509_STORE *x509_store;
729d4afb5ceSopenharmony_ci	unsigned long error;
730d4afb5ceSopenharmony_ci	SSL_METHOD *method;
731d4afb5ceSopenharmony_ci	EVP_MD_CTX *mdctx;
732d4afb5ceSopenharmony_ci	unsigned int len;
733d4afb5ceSopenharmony_ci	uint8_t hash[32];
734d4afb5ceSopenharmony_ci	X509 *client_CA;
735d4afb5ceSopenharmony_ci	char c;
736d4afb5ceSopenharmony_ci	int n;
737d4afb5ceSopenharmony_ci
738d4afb5ceSopenharmony_ci	/* basic openssl init already happened in context init */
739d4afb5ceSopenharmony_ci
740d4afb5ceSopenharmony_ci	/* choose the most recent spin of the api */
741d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_TLS_CLIENT_METHOD)
742d4afb5ceSopenharmony_ci	method = (SSL_METHOD *)TLS_client_method();
743d4afb5ceSopenharmony_ci#elif defined(LWS_HAVE_TLSV1_2_CLIENT_METHOD)
744d4afb5ceSopenharmony_ci	method = (SSL_METHOD *)TLSv1_2_client_method();
745d4afb5ceSopenharmony_ci#else
746d4afb5ceSopenharmony_ci	method = (SSL_METHOD *)SSLv23_client_method();
747d4afb5ceSopenharmony_ci#endif
748d4afb5ceSopenharmony_ci
749d4afb5ceSopenharmony_ci	if (!method) {
750d4afb5ceSopenharmony_ci		const char *es;
751d4afb5ceSopenharmony_ci
752d4afb5ceSopenharmony_ci		error = ERR_get_error();
753d4afb5ceSopenharmony_ci		es = ERR_error_string(
754d4afb5ceSopenharmony_ci		#if defined(LWS_WITH_BORINGSSL)
755d4afb5ceSopenharmony_ci			(uint32_t)
756d4afb5ceSopenharmony_ci		#else
757d4afb5ceSopenharmony_ci			(unsigned long)
758d4afb5ceSopenharmony_ci		#endif
759d4afb5ceSopenharmony_ci			 error, (char *)vh->context->pt[0].serv_buf);
760d4afb5ceSopenharmony_ci		lwsl_err("problem creating ssl method %lu: %s\n",
761d4afb5ceSopenharmony_ci			error, es);
762d4afb5ceSopenharmony_ci		return 1;
763d4afb5ceSopenharmony_ci	}
764d4afb5ceSopenharmony_ci
765d4afb5ceSopenharmony_ci	/*
766d4afb5ceSopenharmony_ci	 * OpenSSL client contexts are quite expensive, because they bring in
767d4afb5ceSopenharmony_ci	 * the system certificate bundle for each one.  So if you have multiple
768d4afb5ceSopenharmony_ci	 * vhosts, each with a client context, it can add up to several
769d4afb5ceSopenharmony_ci	 * megabytes of heap.  In the case the client contexts are configured
770d4afb5ceSopenharmony_ci	 * identically, they could perfectly well have shared just the one.
771d4afb5ceSopenharmony_ci	 *
772d4afb5ceSopenharmony_ci	 * For that reason, use a hash to fingerprint the context configuration
773d4afb5ceSopenharmony_ci	 * and prefer to reuse an existing one with the same fingerprint if
774d4afb5ceSopenharmony_ci	 * possible.
775d4afb5ceSopenharmony_ci	 */
776d4afb5ceSopenharmony_ci
777d4afb5ceSopenharmony_ci	 mdctx = EVP_MD_CTX_create();
778d4afb5ceSopenharmony_ci	 if (!mdctx)
779d4afb5ceSopenharmony_ci		 return 1;
780d4afb5ceSopenharmony_ci
781d4afb5ceSopenharmony_ci	if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) {
782d4afb5ceSopenharmony_ci		EVP_MD_CTX_destroy(mdctx);
783d4afb5ceSopenharmony_ci
784d4afb5ceSopenharmony_ci		return 1;
785d4afb5ceSopenharmony_ci	}
786d4afb5ceSopenharmony_ci
787d4afb5ceSopenharmony_ci	if (info->ssl_client_options_set)
788d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, &info->ssl_client_options_set,
789d4afb5ceSopenharmony_ci				 sizeof(info->ssl_client_options_set));
790d4afb5ceSopenharmony_ci
791d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
792d4afb5ceSopenharmony_ci	if (info->ssl_client_options_clear)
793d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, &info->ssl_client_options_clear,
794d4afb5ceSopenharmony_ci				 sizeof(info->ssl_client_options_clear));
795d4afb5ceSopenharmony_ci#endif
796d4afb5ceSopenharmony_ci
797d4afb5ceSopenharmony_ci	if (cipher_list)
798d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, cipher_list, strlen(cipher_list));
799d4afb5ceSopenharmony_ci
800d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_set_ciphersuites)
801d4afb5ceSopenharmony_ci	if (info->client_tls_1_3_plus_cipher_list)
802d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, info->client_tls_1_3_plus_cipher_list,
803d4afb5ceSopenharmony_ci				 strlen(info->client_tls_1_3_plus_cipher_list));
804d4afb5ceSopenharmony_ci#endif
805d4afb5ceSopenharmony_ci
806d4afb5ceSopenharmony_ci	if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS)) {
807d4afb5ceSopenharmony_ci		c = 1;
808d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, &c, 1);
809d4afb5ceSopenharmony_ci	}
810d4afb5ceSopenharmony_ci
811d4afb5ceSopenharmony_ci	if (ca_filepath)
812d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, ca_filepath, strlen(ca_filepath));
813d4afb5ceSopenharmony_ci
814d4afb5ceSopenharmony_ci	if (cert_filepath)
815d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, cert_filepath, strlen(cert_filepath));
816d4afb5ceSopenharmony_ci
817d4afb5ceSopenharmony_ci	if (private_key_filepath)
818d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, private_key_filepath,
819d4afb5ceSopenharmony_ci				 strlen(private_key_filepath));
820d4afb5ceSopenharmony_ci	if (ca_mem && ca_mem_len)
821d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, ca_mem, ca_mem_len);
822d4afb5ceSopenharmony_ci
823d4afb5ceSopenharmony_ci	if (cert_mem && cert_mem_len)
824d4afb5ceSopenharmony_ci		EVP_DigestUpdate(mdctx, cert_mem, cert_mem_len);
825d4afb5ceSopenharmony_ci
826d4afb5ceSopenharmony_ci	len = sizeof(hash);
827d4afb5ceSopenharmony_ci	EVP_DigestFinal_ex(mdctx, hash, &len);
828d4afb5ceSopenharmony_ci	EVP_MD_CTX_destroy(mdctx);
829d4afb5ceSopenharmony_ci
830d4afb5ceSopenharmony_ci	/* look for existing client context with same config already */
831d4afb5ceSopenharmony_ci
832d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
833d4afb5ceSopenharmony_ci			 lws_dll2_get_head(&vh->context->tls.cc_owner)) {
834d4afb5ceSopenharmony_ci		tcr = lws_container_of(p, struct lws_tls_client_reuse, cc_list);
835d4afb5ceSopenharmony_ci
836d4afb5ceSopenharmony_ci		if (!memcmp(hash, tcr->hash, len)) {
837d4afb5ceSopenharmony_ci
838d4afb5ceSopenharmony_ci			/* it's a match */
839d4afb5ceSopenharmony_ci
840d4afb5ceSopenharmony_ci			tcr->refcount++;
841d4afb5ceSopenharmony_ci			vh->tls.ssl_client_ctx = tcr->ssl_client_ctx;
842d4afb5ceSopenharmony_ci			vh->tls.tcr = tcr;
843d4afb5ceSopenharmony_ci
844d4afb5ceSopenharmony_ci			lwsl_info("%s: vh %s: reusing client ctx %d: use %d\n",
845d4afb5ceSopenharmony_ci				   __func__, vh->name, tcr->index,
846d4afb5ceSopenharmony_ci				   tcr->refcount);
847d4afb5ceSopenharmony_ci
848d4afb5ceSopenharmony_ci			return 0;
849d4afb5ceSopenharmony_ci		}
850d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, tp);
851d4afb5ceSopenharmony_ci
852d4afb5ceSopenharmony_ci	/* no existing one the same... create new client SSL_CTX */
853d4afb5ceSopenharmony_ci
854d4afb5ceSopenharmony_ci	errno = 0;
855d4afb5ceSopenharmony_ci	ERR_clear_error();
856d4afb5ceSopenharmony_ci	vh->tls.ssl_client_ctx = SSL_CTX_new(method);
857d4afb5ceSopenharmony_ci	if (!vh->tls.ssl_client_ctx) {
858d4afb5ceSopenharmony_ci		const char *es;
859d4afb5ceSopenharmony_ci
860d4afb5ceSopenharmony_ci		error = ERR_get_error();
861d4afb5ceSopenharmony_ci		es = ERR_error_string(
862d4afb5ceSopenharmony_ci		#if defined(LWS_WITH_BORINGSSL)
863d4afb5ceSopenharmony_ci			(uint32_t)
864d4afb5ceSopenharmony_ci		#else
865d4afb5ceSopenharmony_ci			(unsigned long)
866d4afb5ceSopenharmony_ci		#endif
867d4afb5ceSopenharmony_ci			 error, (char *)vh->context->pt[0].serv_buf);
868d4afb5ceSopenharmony_ci		lwsl_err("problem creating ssl context %lu: %s\n",
869d4afb5ceSopenharmony_ci			error, es);
870d4afb5ceSopenharmony_ci		return 1;
871d4afb5ceSopenharmony_ci	}
872d4afb5ceSopenharmony_ci
873d4afb5ceSopenharmony_ci	SSL_CTX_set_ex_data(vh->tls.ssl_client_ctx,
874d4afb5ceSopenharmony_ci				openssl_SSL_CTX_private_data_index,
875d4afb5ceSopenharmony_ci				(char *)vh->context);
876d4afb5ceSopenharmony_ci
877d4afb5ceSopenharmony_ci	lws_plat_vhost_tls_client_ctx_init(vh);
878d4afb5ceSopenharmony_ci
879d4afb5ceSopenharmony_ci	tcr = lws_zalloc(sizeof(*tcr), "client ctx tcr");
880d4afb5ceSopenharmony_ci	if (!tcr) {
881d4afb5ceSopenharmony_ci		SSL_CTX_free(vh->tls.ssl_client_ctx);
882d4afb5ceSopenharmony_ci		return 1;
883d4afb5ceSopenharmony_ci	}
884d4afb5ceSopenharmony_ci
885d4afb5ceSopenharmony_ci	tcr->ssl_client_ctx = vh->tls.ssl_client_ctx;
886d4afb5ceSopenharmony_ci	tcr->refcount = 1;
887d4afb5ceSopenharmony_ci	memcpy(tcr->hash, hash, len);
888d4afb5ceSopenharmony_ci	tcr->index = vh->context->tls.count_client_contexts++;
889d4afb5ceSopenharmony_ci	lws_dll2_add_head(&tcr->cc_list, &vh->context->tls.cc_owner);
890d4afb5ceSopenharmony_ci
891d4afb5ceSopenharmony_ci	lwsl_info("%s: vh %s: created new client ctx %d\n", __func__,
892d4afb5ceSopenharmony_ci			vh->name, tcr->index);
893d4afb5ceSopenharmony_ci
894d4afb5ceSopenharmony_ci	/* bind the tcr to the client context */
895d4afb5ceSopenharmony_ci
896d4afb5ceSopenharmony_ci	vh->tls.tcr = tcr;
897d4afb5ceSopenharmony_ci
898d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS)
899d4afb5ceSopenharmony_ci	vh->tls_session_cache_max = info->tls_session_cache_max ?
900d4afb5ceSopenharmony_ci				    info->tls_session_cache_max : 10;
901d4afb5ceSopenharmony_ci	lws_tls_session_cache(vh, info->tls_session_timeout);
902d4afb5ceSopenharmony_ci#endif
903d4afb5ceSopenharmony_ci
904d4afb5ceSopenharmony_ci#ifdef SSL_OP_NO_COMPRESSION
905d4afb5ceSopenharmony_ci	SSL_CTX_set_options(vh->tls.ssl_client_ctx, SSL_OP_NO_COMPRESSION);
906d4afb5ceSopenharmony_ci#endif
907d4afb5ceSopenharmony_ci
908d4afb5ceSopenharmony_ci	SSL_CTX_set_options(vh->tls.ssl_client_ctx,
909d4afb5ceSopenharmony_ci			    SSL_OP_CIPHER_SERVER_PREFERENCE);
910d4afb5ceSopenharmony_ci
911d4afb5ceSopenharmony_ci	SSL_CTX_set_mode(vh->tls.ssl_client_ctx,
912d4afb5ceSopenharmony_ci			 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
913d4afb5ceSopenharmony_ci			 SSL_MODE_RELEASE_BUFFERS);
914d4afb5ceSopenharmony_ci
915d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
916d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
917d4afb5ceSopenharmony_ci				uint32_t
918d4afb5ceSopenharmony_ci#else
919d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \
920d4afb5ceSopenharmony_ci	!defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */
921d4afb5ceSopenharmony_ci		unsigned long
922d4afb5ceSopenharmony_ci#else
923d4afb5ceSopenharmony_ci		long
924d4afb5ceSopenharmony_ci#endif
925d4afb5ceSopenharmony_ci#endif
926d4afb5ceSopenharmony_ci#else
927d4afb5ceSopenharmony_ci		long
928d4afb5ceSopenharmony_ci#endif
929d4afb5ceSopenharmony_ci			ssl_client_options_set_value =
930d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
931d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
932d4afb5ceSopenharmony_ci				(uint32_t)
933d4afb5ceSopenharmony_ci#else
934d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \
935d4afb5ceSopenharmony_ci	!defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */
936d4afb5ceSopenharmony_ci				(unsigned long)
937d4afb5ceSopenharmony_ci#else
938d4afb5ceSopenharmony_ci				(long)
939d4afb5ceSopenharmony_ci#endif
940d4afb5ceSopenharmony_ci#endif
941d4afb5ceSopenharmony_ci#endif
942d4afb5ceSopenharmony_ci			info->ssl_client_options_set;
943d4afb5ceSopenharmony_ci
944d4afb5ceSopenharmony_ci	if (info->ssl_client_options_set)
945d4afb5ceSopenharmony_ci		SSL_CTX_set_options(vh->tls.ssl_client_ctx, ssl_client_options_set_value);
946d4afb5ceSopenharmony_ci
947d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
948d4afb5ceSopenharmony_ci
949d4afb5ceSopenharmony_ci	/* SSL_clear_options introduced in 0.9.8m */
950d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
951d4afb5ceSopenharmony_ci                uint32_t
952d4afb5ceSopenharmony_ci#else
953d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \
954d4afb5ceSopenharmony_ci	!defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */
955d4afb5ceSopenharmony_ci		unsigned long
956d4afb5ceSopenharmony_ci#else
957d4afb5ceSopenharmony_ci		long
958d4afb5ceSopenharmony_ci#endif
959d4afb5ceSopenharmony_ci#endif
960d4afb5ceSopenharmony_ci
961d4afb5ceSopenharmony_ci			ssl_client_options_clear_value =
962d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
963d4afb5ceSopenharmony_ci				(uint32_t)
964d4afb5ceSopenharmony_ci#else
965d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \
966d4afb5ceSopenharmony_ci	!defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */
967d4afb5ceSopenharmony_ci				(unsigned long)
968d4afb5ceSopenharmony_ci#else
969d4afb5ceSopenharmony_ci				(long)
970d4afb5ceSopenharmony_ci#endif
971d4afb5ceSopenharmony_ci#endif
972d4afb5ceSopenharmony_ci			info->ssl_client_options_clear;
973d4afb5ceSopenharmony_ci
974d4afb5ceSopenharmony_ci	if (info->ssl_client_options_clear)
975d4afb5ceSopenharmony_ci		SSL_CTX_clear_options(vh->tls.ssl_client_ctx, ssl_client_options_clear_value);
976d4afb5ceSopenharmony_ci#endif
977d4afb5ceSopenharmony_ci
978d4afb5ceSopenharmony_ci	if (cipher_list)
979d4afb5ceSopenharmony_ci		SSL_CTX_set_cipher_list(vh->tls.ssl_client_ctx, cipher_list);
980d4afb5ceSopenharmony_ci
981d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_set_ciphersuites)
982d4afb5ceSopenharmony_ci	if (info->client_tls_1_3_plus_cipher_list)
983d4afb5ceSopenharmony_ci		SSL_CTX_set_ciphersuites(vh->tls.ssl_client_ctx,
984d4afb5ceSopenharmony_ci					 info->client_tls_1_3_plus_cipher_list);
985d4afb5ceSopenharmony_ci#endif
986d4afb5ceSopenharmony_ci
987d4afb5ceSopenharmony_ci#ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS
988d4afb5ceSopenharmony_ci	if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
989d4afb5ceSopenharmony_ci		/* loads OS default CA certs */
990d4afb5ceSopenharmony_ci		SSL_CTX_set_default_verify_paths(vh->tls.ssl_client_ctx);
991d4afb5ceSopenharmony_ci#endif
992d4afb5ceSopenharmony_ci
993d4afb5ceSopenharmony_ci	/* openssl init for cert verification (for client sockets) */
994d4afb5ceSopenharmony_ci    if (!ca_mem || !ca_mem_len) {
995d4afb5ceSopenharmony_ci        for (int i = 0; i < MAX_CLIENT_SSL_CA_NUMBER; i++) {
996d4afb5ceSopenharmony_ci            if ((info->client_ssl_ca_dirs[i] != NULL) &&
997d4afb5ceSopenharmony_ci                (!SSL_CTX_load_verify_locations(vh->tls.ssl_client_ctx, NULL, info->client_ssl_ca_dirs[i]))) {
998d4afb5ceSopenharmony_ci                lwsl_err(
999d4afb5ceSopenharmony_ci                    "Unable to load SSL Client certs from %s "
1000d4afb5ceSopenharmony_ci                    "(set by info->client_ssl_ca_dirs[%d]) -- "
1001d4afb5ceSopenharmony_ci                    "client ssl isn't going to work\n",
1002d4afb5ceSopenharmony_ci                    info->client_ssl_ca_dirs[i], i);
1003d4afb5ceSopenharmony_ci            }
1004d4afb5ceSopenharmony_ci        }
1005d4afb5ceSopenharmony_ci    }
1006d4afb5ceSopenharmony_ci
1007d4afb5ceSopenharmony_ci	if (!ca_filepath && (!ca_mem || !ca_mem_len)) {
1008d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_load_verify_dir)
1009d4afb5ceSopenharmony_ci		if (!SSL_CTX_load_verify_dir(
1010d4afb5ceSopenharmony_ci			vh->tls.ssl_client_ctx, LWS_OPENSSL_CLIENT_CERTS))
1011d4afb5ceSopenharmony_ci#else
1012d4afb5ceSopenharmony_ci		if (!SSL_CTX_load_verify_locations(
1013d4afb5ceSopenharmony_ci			vh->tls.ssl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS))
1014d4afb5ceSopenharmony_ci#endif
1015d4afb5ceSopenharmony_ci			lwsl_err("Unable to load SSL Client certs from %s "
1016d4afb5ceSopenharmony_ci			    "(set by LWS_OPENSSL_CLIENT_CERTS) -- "
1017d4afb5ceSopenharmony_ci			    "client ssl isn't going to work\n",
1018d4afb5ceSopenharmony_ci			    LWS_OPENSSL_CLIENT_CERTS);
1019d4afb5ceSopenharmony_ci	} else if (ca_filepath) {
1020d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_load_verify_file)
1021d4afb5ceSopenharmony_ci		if (!SSL_CTX_load_verify_file(
1022d4afb5ceSopenharmony_ci			vh->tls.ssl_client_ctx, ca_filepath)) {
1023d4afb5ceSopenharmony_ci#else
1024d4afb5ceSopenharmony_ci		if (!SSL_CTX_load_verify_locations(
1025d4afb5ceSopenharmony_ci			vh->tls.ssl_client_ctx, ca_filepath, NULL)) {
1026d4afb5ceSopenharmony_ci#endif
1027d4afb5ceSopenharmony_ci			lwsl_err(
1028d4afb5ceSopenharmony_ci				"Unable to load SSL Client certs "
1029d4afb5ceSopenharmony_ci				"file from %s -- client ssl isn't "
1030d4afb5ceSopenharmony_ci				"going to work\n", ca_filepath);
1031d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
1032d4afb5ceSopenharmony_ci		}
1033d4afb5ceSopenharmony_ci		else
1034d4afb5ceSopenharmony_ci			lwsl_info("loaded ssl_ca_filepath\n");
1035d4afb5ceSopenharmony_ci	} else {
1036d4afb5ceSopenharmony_ci
1037d4afb5ceSopenharmony_ci		lws_filepos_t amount = 0;
1038d4afb5ceSopenharmony_ci		const uint8_t *up;
1039d4afb5ceSopenharmony_ci		uint8_t *up1;
1040d4afb5ceSopenharmony_ci
1041d4afb5ceSopenharmony_ci		if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, ca_mem,
1042d4afb5ceSopenharmony_ci						  ca_mem_len, &up1, &amount)) {
1043d4afb5ceSopenharmony_ci			lwsl_err("%s: Unable to decode x.509 mem\n", __func__);
1044d4afb5ceSopenharmony_ci			lwsl_hexdump_notice(ca_mem, ca_mem_len);
1045d4afb5ceSopenharmony_ci			return 1;
1046d4afb5ceSopenharmony_ci		}
1047d4afb5ceSopenharmony_ci
1048d4afb5ceSopenharmony_ci		up = up1;
1049d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL)
1050d4afb5ceSopenharmony_ci		client_CA = d2i_X509(NULL, &up, (int)amount);
1051d4afb5ceSopenharmony_ci#else
1052d4afb5ceSopenharmony_ci		client_CA = d2i_X509(NULL, &up, (long)amount);
1053d4afb5ceSopenharmony_ci#endif
1054d4afb5ceSopenharmony_ci		if (!client_CA) {
1055d4afb5ceSopenharmony_ci			lwsl_err("%s: d2i_X509 failed\n", __func__);
1056d4afb5ceSopenharmony_ci			lwsl_hexdump_notice(up1, (size_t)amount);
1057d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
1058d4afb5ceSopenharmony_ci		} else {
1059d4afb5ceSopenharmony_ci			x509_store = X509_STORE_new();
1060d4afb5ceSopenharmony_ci			if (!X509_STORE_add_cert(x509_store, client_CA)) {
1061d4afb5ceSopenharmony_ci				X509_STORE_free(x509_store);
1062d4afb5ceSopenharmony_ci				lwsl_err("Unable to load SSL Client certs from "
1063d4afb5ceSopenharmony_ci					 "ssl_ca_mem -- client ssl isn't going to "
1064d4afb5ceSopenharmony_ci					 "work\n");
1065d4afb5ceSopenharmony_ci				lws_tls_err_describe_clear();
1066d4afb5ceSopenharmony_ci			} else {
1067d4afb5ceSopenharmony_ci				/* it doesn't increment x509_store ref counter */
1068d4afb5ceSopenharmony_ci				SSL_CTX_set_cert_store(vh->tls.ssl_client_ctx,
1069d4afb5ceSopenharmony_ci						       x509_store);
1070d4afb5ceSopenharmony_ci				lwsl_info("loaded ssl_ca_mem\n");
1071d4afb5ceSopenharmony_ci			}
1072d4afb5ceSopenharmony_ci		}
1073d4afb5ceSopenharmony_ci		if (client_CA)
1074d4afb5ceSopenharmony_ci			X509_free(client_CA);
1075d4afb5ceSopenharmony_ci		lws_free(up1);
1076d4afb5ceSopenharmony_ci	//	lws_tls_client_vhost_extra_cert_mem(vh, ca_mem, ca_mem_len);
1077d4afb5ceSopenharmony_ci	}
1078d4afb5ceSopenharmony_ci
1079d4afb5ceSopenharmony_ci	/*
1080d4afb5ceSopenharmony_ci	 * callback allowing user code to load extra verification certs
1081d4afb5ceSopenharmony_ci	 * helping the client to verify server identity
1082d4afb5ceSopenharmony_ci	 */
1083d4afb5ceSopenharmony_ci
1084d4afb5ceSopenharmony_ci	/* support for client-side certificate authentication */
1085d4afb5ceSopenharmony_ci
1086d4afb5ceSopenharmony_ci	if (cert_filepath) {
1087d4afb5ceSopenharmony_ci		if (lws_tls_use_any_upgrade_check_extant(cert_filepath) !=
1088d4afb5ceSopenharmony_ci				LWS_TLS_EXTANT_YES &&
1089d4afb5ceSopenharmony_ci		    (info->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT))
1090d4afb5ceSopenharmony_ci			return 0;
1091d4afb5ceSopenharmony_ci
1092d4afb5ceSopenharmony_ci		lwsl_notice("%s: doing cert filepath %s\n", __func__,
1093d4afb5ceSopenharmony_ci				cert_filepath);
1094d4afb5ceSopenharmony_ci		n = SSL_CTX_use_certificate_chain_file(vh->tls.ssl_client_ctx,
1095d4afb5ceSopenharmony_ci						       cert_filepath);
1096d4afb5ceSopenharmony_ci		if (n < 1) {
1097d4afb5ceSopenharmony_ci			lwsl_err("problem %d getting cert '%s'\n", n,
1098d4afb5ceSopenharmony_ci				 cert_filepath);
1099d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
1100d4afb5ceSopenharmony_ci			return 1;
1101d4afb5ceSopenharmony_ci		}
1102d4afb5ceSopenharmony_ci		lwsl_info("Loaded client cert %s\n", cert_filepath);
1103d4afb5ceSopenharmony_ci
1104d4afb5ceSopenharmony_ci	} else if (cert_mem && cert_mem_len) {
1105d4afb5ceSopenharmony_ci		lws_filepos_t flen;
1106d4afb5ceSopenharmony_ci		uint8_t *p;
1107d4afb5ceSopenharmony_ci
1108d4afb5ceSopenharmony_ci		if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, cert_mem,
1109d4afb5ceSopenharmony_ci						  cert_mem_len, &p, &flen)) {
1110d4afb5ceSopenharmony_ci			lwsl_err("%s: couldn't read cert file\n", __func__);
1111d4afb5ceSopenharmony_ci
1112d4afb5ceSopenharmony_ci			return 1;
1113d4afb5ceSopenharmony_ci		}
1114d4afb5ceSopenharmony_ci
1115d4afb5ceSopenharmony_ci		n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx,
1116d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
1117d4afb5ceSopenharmony_ci				(size_t)
1118d4afb5ceSopenharmony_ci#else
1119d4afb5ceSopenharmony_ci				(int)
1120d4afb5ceSopenharmony_ci#endif
1121d4afb5ceSopenharmony_ci				flen, p);
1122d4afb5ceSopenharmony_ci
1123d4afb5ceSopenharmony_ci		if (n < 1) {
1124d4afb5ceSopenharmony_ci			lwsl_err("%s: problem interpreting client cert\n",  __func__);
1125d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
1126d4afb5ceSopenharmony_ci		}
1127d4afb5ceSopenharmony_ci
1128d4afb5ceSopenharmony_ci		lws_free_set_NULL(p);
1129d4afb5ceSopenharmony_ci
1130d4afb5ceSopenharmony_ci		if (n != 1)
1131d4afb5ceSopenharmony_ci			return 1;
1132d4afb5ceSopenharmony_ci
1133d4afb5ceSopenharmony_ci	}
1134d4afb5ceSopenharmony_ci	if (private_key_filepath) {
1135d4afb5ceSopenharmony_ci		lwsl_info("%s: using private key filepath\n", __func__);
1136d4afb5ceSopenharmony_ci		lws_ssl_bind_passphrase(vh->tls.ssl_client_ctx, 1, info);
1137d4afb5ceSopenharmony_ci		/* set the private key from KeyFile */
1138d4afb5ceSopenharmony_ci		if (SSL_CTX_use_PrivateKey_file(vh->tls.ssl_client_ctx,
1139d4afb5ceSopenharmony_ci		    private_key_filepath, SSL_FILETYPE_PEM) != 1) {
1140d4afb5ceSopenharmony_ci			lwsl_err("use_PrivateKey_file '%s'\n",
1141d4afb5ceSopenharmony_ci				 private_key_filepath);
1142d4afb5ceSopenharmony_ci			lws_tls_err_describe_clear();
1143d4afb5ceSopenharmony_ci			return 1;
1144d4afb5ceSopenharmony_ci		}
1145d4afb5ceSopenharmony_ci		lwsl_info("Loaded client cert private key %s\n",
1146d4afb5ceSopenharmony_ci			    private_key_filepath);
1147d4afb5ceSopenharmony_ci
1148d4afb5ceSopenharmony_ci		/* verify private key */
1149d4afb5ceSopenharmony_ci		if (!SSL_CTX_check_private_key(vh->tls.ssl_client_ctx)) {
1150d4afb5ceSopenharmony_ci			lwsl_err("Private SSL key doesn't match cert\n");
1151d4afb5ceSopenharmony_ci			return 1;
1152d4afb5ceSopenharmony_ci		}
1153d4afb5ceSopenharmony_ci	}
1154d4afb5ceSopenharmony_ci	else if (key_mem && key_mem_len) {
1155d4afb5ceSopenharmony_ci
1156d4afb5ceSopenharmony_ci		lws_filepos_t flen;
1157d4afb5ceSopenharmony_ci		uint8_t *p;
1158d4afb5ceSopenharmony_ci
1159d4afb5ceSopenharmony_ci		if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, key_mem,
1160d4afb5ceSopenharmony_ci						  key_mem_len, &p, &flen)) {
1161d4afb5ceSopenharmony_ci			lwsl_err("%s: couldn't use mem cert\n", __func__);
1162d4afb5ceSopenharmony_ci
1163d4afb5ceSopenharmony_ci			return 1;
1164d4afb5ceSopenharmony_ci		}
1165d4afb5ceSopenharmony_ci
1166d4afb5ceSopenharmony_ci		n = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, vh->tls.ssl_client_ctx, p,
1167d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
1168d4afb5ceSopenharmony_ci				(size_t)
1169d4afb5ceSopenharmony_ci#else
1170d4afb5ceSopenharmony_ci				(long)(lws_intptr_t)
1171d4afb5ceSopenharmony_ci#endif
1172d4afb5ceSopenharmony_ci						flen);
1173d4afb5ceSopenharmony_ci		if (n != 1)
1174d4afb5ceSopenharmony_ci			n = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC,
1175d4afb5ceSopenharmony_ci							vh->tls.ssl_client_ctx, p,
1176d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
1177d4afb5ceSopenharmony_ci				(size_t)
1178d4afb5ceSopenharmony_ci#else
1179d4afb5ceSopenharmony_ci				(long)(lws_intptr_t)
1180d4afb5ceSopenharmony_ci#endif
1181d4afb5ceSopenharmony_ci						flen);
1182d4afb5ceSopenharmony_ci
1183d4afb5ceSopenharmony_ci		lws_free_set_NULL(p);
1184d4afb5ceSopenharmony_ci
1185d4afb5ceSopenharmony_ci		if (n != 1)  {
1186d4afb5ceSopenharmony_ci			lwsl_err("%s: unable to use key_mem\n", __func__);
1187d4afb5ceSopenharmony_ci
1188d4afb5ceSopenharmony_ci			return 1;
1189d4afb5ceSopenharmony_ci		}
1190d4afb5ceSopenharmony_ci	}
1191d4afb5ceSopenharmony_ci
1192d4afb5ceSopenharmony_ci	return 0;
1193d4afb5ceSopenharmony_ci}
1194d4afb5ceSopenharmony_ci
1195d4afb5ceSopenharmony_ci
1196