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
27d4afb5ceSopenharmony_ci/*
28d4afb5ceSopenharmony_ci * Care: many openssl apis return 1 for success.  These are translated to the
29d4afb5ceSopenharmony_ci * lws convention of 0 for success.
30d4afb5ceSopenharmony_ci */
31d4afb5ceSopenharmony_ci
32d4afb5ceSopenharmony_ciextern int openssl_websocket_private_data_index,
33d4afb5ceSopenharmony_ci	   openssl_SSL_CTX_private_data_index;
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_ciint lws_openssl_describe_cipher(struct lws *wsi);
36d4afb5ceSopenharmony_ci
37d4afb5ceSopenharmony_cistatic int
38d4afb5ceSopenharmony_ciOpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
39d4afb5ceSopenharmony_ci{
40d4afb5ceSopenharmony_ci	SSL *ssl;
41d4afb5ceSopenharmony_ci	int n;
42d4afb5ceSopenharmony_ci	struct lws *wsi;
43d4afb5ceSopenharmony_ci	union lws_tls_cert_info_results ir;
44d4afb5ceSopenharmony_ci	X509 *topcert = X509_STORE_CTX_get_current_cert(x509_ctx);
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_ci	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
47d4afb5ceSopenharmony_ci		SSL_get_ex_data_X509_STORE_CTX_idx());
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci	/*
50d4afb5ceSopenharmony_ci	 * !!! nasty openssl requires the index to come as a library-scope
51d4afb5ceSopenharmony_ci	 * static
52d4afb5ceSopenharmony_ci	 */
53d4afb5ceSopenharmony_ci	wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
54d4afb5ceSopenharmony_ci
55d4afb5ceSopenharmony_ci	n = lws_tls_openssl_cert_info(topcert, LWS_TLS_CERT_INFO_COMMON_NAME,
56d4afb5ceSopenharmony_ci				      &ir, sizeof(ir.ns.name));
57d4afb5ceSopenharmony_ci	if (!n)
58d4afb5ceSopenharmony_ci		lwsl_info("%s: client cert CN '%s'\n", __func__, ir.ns.name);
59d4afb5ceSopenharmony_ci	else
60d4afb5ceSopenharmony_ci		lwsl_info("%s: couldn't get client cert CN\n", __func__);
61d4afb5ceSopenharmony_ci
62d4afb5ceSopenharmony_ci	n = wsi->a.vhost->protocols[0].callback(wsi,
63d4afb5ceSopenharmony_ci			LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
64d4afb5ceSopenharmony_ci					   x509_ctx, ssl, (unsigned int)preverify_ok);
65d4afb5ceSopenharmony_ci
66d4afb5ceSopenharmony_ci	/* convert return code from 0 = OK to 1 = OK */
67d4afb5ceSopenharmony_ci	return !n;
68d4afb5ceSopenharmony_ci}
69d4afb5ceSopenharmony_ci
70d4afb5ceSopenharmony_ciint
71d4afb5ceSopenharmony_cilws_tls_server_client_cert_verify_config(struct lws_vhost *vh)
72d4afb5ceSopenharmony_ci{
73d4afb5ceSopenharmony_ci	int verify_options = SSL_VERIFY_PEER;
74d4afb5ceSopenharmony_ci
75d4afb5ceSopenharmony_ci	/* as a server, are we requiring clients to identify themselves? */
76d4afb5ceSopenharmony_ci
77d4afb5ceSopenharmony_ci	if (!lws_check_opt(vh->options,
78d4afb5ceSopenharmony_ci			  LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT))
79d4afb5ceSopenharmony_ci		return 0;
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_ci	if (!lws_check_opt(vh->options,
82d4afb5ceSopenharmony_ci			   LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
83d4afb5ceSopenharmony_ci		verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
84d4afb5ceSopenharmony_ci
85d4afb5ceSopenharmony_ci	SSL_CTX_set_session_id_context(vh->tls.ssl_ctx, (uint8_t *)vh->context,
86d4afb5ceSopenharmony_ci				       sizeof(void *));
87d4afb5ceSopenharmony_ci
88d4afb5ceSopenharmony_ci	/* absolutely require the client cert */
89d4afb5ceSopenharmony_ci	SSL_CTX_set_verify(vh->tls.ssl_ctx, verify_options,
90d4afb5ceSopenharmony_ci			   OpenSSL_verify_callback);
91d4afb5ceSopenharmony_ci
92d4afb5ceSopenharmony_ci	return 0;
93d4afb5ceSopenharmony_ci}
94d4afb5ceSopenharmony_ci
95d4afb5ceSopenharmony_ci#if defined(SSL_TLSEXT_ERR_NOACK) && !defined(OPENSSL_NO_TLSEXT)
96d4afb5ceSopenharmony_cistatic int
97d4afb5ceSopenharmony_cilws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
98d4afb5ceSopenharmony_ci{
99d4afb5ceSopenharmony_ci	struct lws_context *context = (struct lws_context *)arg;
100d4afb5ceSopenharmony_ci	struct lws_vhost *vhost, *vh;
101d4afb5ceSopenharmony_ci	const char *servername;
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_ci	if (!ssl)
104d4afb5ceSopenharmony_ci		return SSL_TLSEXT_ERR_NOACK;
105d4afb5ceSopenharmony_ci
106d4afb5ceSopenharmony_ci	/*
107d4afb5ceSopenharmony_ci	 * We can only get ssl accepted connections by using a vhost's ssl_ctx
108d4afb5ceSopenharmony_ci	 * find out which listening one took us and only match vhosts on the
109d4afb5ceSopenharmony_ci	 * same port.
110d4afb5ceSopenharmony_ci	 */
111d4afb5ceSopenharmony_ci	vh = context->vhost_list;
112d4afb5ceSopenharmony_ci	while (vh) {
113d4afb5ceSopenharmony_ci		if (!vh->being_destroyed &&
114d4afb5ceSopenharmony_ci		    vh->tls.ssl_ctx == SSL_get_SSL_CTX(ssl))
115d4afb5ceSopenharmony_ci			break;
116d4afb5ceSopenharmony_ci		vh = vh->vhost_next;
117d4afb5ceSopenharmony_ci	}
118d4afb5ceSopenharmony_ci
119d4afb5ceSopenharmony_ci	if (!vh) {
120d4afb5ceSopenharmony_ci		assert(vh); /* can't match the incoming vh? */
121d4afb5ceSopenharmony_ci		return SSL_TLSEXT_ERR_OK;
122d4afb5ceSopenharmony_ci	}
123d4afb5ceSopenharmony_ci
124d4afb5ceSopenharmony_ci	servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
125d4afb5ceSopenharmony_ci	if (!servername) {
126d4afb5ceSopenharmony_ci		/* the client doesn't know what hostname it wants */
127d4afb5ceSopenharmony_ci		lwsl_info("SNI: Unknown ServerName\n");
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci		return SSL_TLSEXT_ERR_OK;
130d4afb5ceSopenharmony_ci	}
131d4afb5ceSopenharmony_ci
132d4afb5ceSopenharmony_ci	vhost = lws_select_vhost(context, vh->listen_port, servername);
133d4afb5ceSopenharmony_ci	if (!vhost) {
134d4afb5ceSopenharmony_ci		lwsl_info("SNI: none: %s:%d\n", servername, vh->listen_port);
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_ci		return SSL_TLSEXT_ERR_OK;
137d4afb5ceSopenharmony_ci	}
138d4afb5ceSopenharmony_ci
139d4afb5ceSopenharmony_ci	lwsl_info("SNI: Found: %s:%d\n", servername, vh->listen_port);
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_ci	/* select the ssl ctx from the selected vhost for this conn */
142d4afb5ceSopenharmony_ci	SSL_set_SSL_CTX(ssl, vhost->tls.ssl_ctx);
143d4afb5ceSopenharmony_ci
144d4afb5ceSopenharmony_ci	return SSL_TLSEXT_ERR_OK;
145d4afb5ceSopenharmony_ci}
146d4afb5ceSopenharmony_ci#endif
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_ci/*
149d4afb5ceSopenharmony_ci * this may now get called after the vhost creation, when certs become
150d4afb5ceSopenharmony_ci * available.
151d4afb5ceSopenharmony_ci */
152d4afb5ceSopenharmony_ciint
153d4afb5ceSopenharmony_cilws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
154d4afb5ceSopenharmony_ci			  const char *cert, const char *private_key,
155d4afb5ceSopenharmony_ci			  const char *mem_cert, size_t mem_cert_len,
156d4afb5ceSopenharmony_ci			  const char *mem_privkey, size_t mem_privkey_len)
157d4afb5ceSopenharmony_ci{
158d4afb5ceSopenharmony_ci#if !defined(OPENSSL_NO_EC) && defined(LWS_HAVE_EC_KEY_new_by_curve_name) && \
159d4afb5ceSopenharmony_ci    ((OPENSSL_VERSION_NUMBER < 0x30000000l) || \
160d4afb5ceSopenharmony_ci     defined(LWS_SUPPRESS_DEPRECATED_API_WARNINGS))
161d4afb5ceSopenharmony_ci	const char *ecdh_curve = "prime256v1";
162d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_BORINGSSL) && defined(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS)
163d4afb5ceSopenharmony_ci	STACK_OF(X509) *extra_certs = NULL;
164d4afb5ceSopenharmony_ci#endif
165d4afb5ceSopenharmony_ci	EC_KEY *ecdh, *EC_key = NULL;
166d4afb5ceSopenharmony_ci	EVP_PKEY *pkey;
167d4afb5ceSopenharmony_ci	X509 *x = NULL;
168d4afb5ceSopenharmony_ci	int ecdh_nid;
169d4afb5ceSopenharmony_ci	int KeyType;
170d4afb5ceSopenharmony_ci#endif
171d4afb5ceSopenharmony_ci	unsigned long error;
172d4afb5ceSopenharmony_ci	lws_filepos_t flen;
173d4afb5ceSopenharmony_ci	uint8_t *p;
174d4afb5ceSopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10100000L
175d4afb5ceSopenharmony_ci	int ret;
176d4afb5ceSopenharmony_ci#endif
177d4afb5ceSopenharmony_ci	int n = (int)lws_tls_generic_cert_checks(vhost, cert, private_key), m;
178d4afb5ceSopenharmony_ci
179d4afb5ceSopenharmony_ci	if (!cert && !private_key)
180d4afb5ceSopenharmony_ci		n = LWS_TLS_EXTANT_ALTERNATIVE;
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci	if (n == LWS_TLS_EXTANT_NO && (!mem_cert || !mem_privkey))
183d4afb5ceSopenharmony_ci		return 0;
184d4afb5ceSopenharmony_ci	if (n == LWS_TLS_EXTANT_NO)
185d4afb5ceSopenharmony_ci		n = LWS_TLS_EXTANT_ALTERNATIVE;
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci	if (n == LWS_TLS_EXTANT_ALTERNATIVE && (!mem_cert || !mem_privkey))
188d4afb5ceSopenharmony_ci		return 1; /* no alternative */
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ci	if (n == LWS_TLS_EXTANT_ALTERNATIVE) {
191d4afb5ceSopenharmony_ci
192d4afb5ceSopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10100000L
193d4afb5ceSopenharmony_ci
194d4afb5ceSopenharmony_ci		/*
195d4afb5ceSopenharmony_ci		 * Although we have prepared update certs, we no longer have
196d4afb5ceSopenharmony_ci		 * the rights to read our own cert + key we saved.
197d4afb5ceSopenharmony_ci		 *
198d4afb5ceSopenharmony_ci		 * If we were passed copies in memory buffers, use those
199d4afb5ceSopenharmony_ci		 * in favour of the filepaths we normally want.
200d4afb5ceSopenharmony_ci		 */
201d4afb5ceSopenharmony_ci		cert = NULL;
202d4afb5ceSopenharmony_ci		private_key = NULL;
203d4afb5ceSopenharmony_ci	}
204d4afb5ceSopenharmony_ci
205d4afb5ceSopenharmony_ci	/*
206d4afb5ceSopenharmony_ci	 * use the multi-cert interface for backwards compatibility in the
207d4afb5ceSopenharmony_ci	 * both simple files case
208d4afb5ceSopenharmony_ci	 */
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_ci	if (n != LWS_TLS_EXTANT_ALTERNATIVE && cert) {
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci		/* set the local certificate from CertFile */
213d4afb5ceSopenharmony_ci		m = SSL_CTX_use_certificate_chain_file(vhost->tls.ssl_ctx, cert);
214d4afb5ceSopenharmony_ci		if (m != 1) {
215d4afb5ceSopenharmony_ci			const char *s;
216d4afb5ceSopenharmony_ci			error = ERR_get_error();
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_ci			s = ERR_error_string(
219d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
220d4afb5ceSopenharmony_ci				(uint32_t)
221d4afb5ceSopenharmony_ci#endif
222d4afb5ceSopenharmony_ci					error,
223d4afb5ceSopenharmony_ci				       (char *)vhost->context->pt[0].serv_buf);
224d4afb5ceSopenharmony_ci
225d4afb5ceSopenharmony_ci			lwsl_err("problem getting cert '%s' %lu: %s\n",
226d4afb5ceSopenharmony_ci				 cert, error, s);
227d4afb5ceSopenharmony_ci
228d4afb5ceSopenharmony_ci			return 1;
229d4afb5ceSopenharmony_ci		}
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci		if (!private_key) {
232d4afb5ceSopenharmony_ci			lwsl_err("ssl private key not set\n");
233d4afb5ceSopenharmony_ci			return 1;
234d4afb5ceSopenharmony_ci		} else {
235d4afb5ceSopenharmony_ci			/* set the private key from KeyFile */
236d4afb5ceSopenharmony_ci			if (SSL_CTX_use_PrivateKey_file(vhost->tls.ssl_ctx, private_key,
237d4afb5ceSopenharmony_ci							SSL_FILETYPE_PEM) != 1) {
238d4afb5ceSopenharmony_ci				const char *s;
239d4afb5ceSopenharmony_ci				error = ERR_get_error();
240d4afb5ceSopenharmony_ci				s = ERR_error_string(
241d4afb5ceSopenharmony_ci	#if defined(LWS_WITH_BORINGSSL)
242d4afb5ceSopenharmony_ci					(uint32_t)
243d4afb5ceSopenharmony_ci	#endif
244d4afb5ceSopenharmony_ci						error,
245d4afb5ceSopenharmony_ci					       (char *)vhost->context->pt[0].serv_buf);
246d4afb5ceSopenharmony_ci				lwsl_err("ssl problem getting key '%s' %lu: %s\n",
247d4afb5ceSopenharmony_ci					 private_key, error, s);
248d4afb5ceSopenharmony_ci				return 1;
249d4afb5ceSopenharmony_ci			}
250d4afb5ceSopenharmony_ci		}
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci		return 0;
253d4afb5ceSopenharmony_ci	}
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_ci	/* otherwise allow for DER or PEM, file or memory image */
256d4afb5ceSopenharmony_ci
257d4afb5ceSopenharmony_ci	if (lws_tls_alloc_pem_to_der_file(vhost->context, cert, mem_cert,
258d4afb5ceSopenharmony_ci					  mem_cert_len, &p, &flen)) {
259d4afb5ceSopenharmony_ci		lwsl_err("%s: couldn't read cert file\n", __func__);
260d4afb5ceSopenharmony_ci
261d4afb5ceSopenharmony_ci		return 1;
262d4afb5ceSopenharmony_ci	}
263d4afb5ceSopenharmony_ci
264d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
265d4afb5ceSopenharmony_ci	ret = SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx,
266d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
267d4afb5ceSopenharmony_ci				(size_t)
268d4afb5ceSopenharmony_ci#else
269d4afb5ceSopenharmony_ci				(int)
270d4afb5ceSopenharmony_ci#endif
271d4afb5ceSopenharmony_ci				flen, p);
272d4afb5ceSopenharmony_ci#else
273d4afb5ceSopenharmony_ci	ret = wolfSSL_CTX_use_certificate_buffer(vhost->tls.ssl_ctx,
274d4afb5ceSopenharmony_ci						 (uint8_t *)p, (int)flen,
275d4afb5ceSopenharmony_ci						 WOLFSSL_FILETYPE_ASN1);
276d4afb5ceSopenharmony_ci#endif
277d4afb5ceSopenharmony_ci	lws_free_set_NULL(p);
278d4afb5ceSopenharmony_ci	if (ret != 1) {
279d4afb5ceSopenharmony_ci		lwsl_err("%s: Problem loading cert\n", __func__);
280d4afb5ceSopenharmony_ci
281d4afb5ceSopenharmony_ci		return 1;
282d4afb5ceSopenharmony_ci	}
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_ci	if (lws_tls_alloc_pem_to_der_file(vhost->context, private_key,
285d4afb5ceSopenharmony_ci					  mem_privkey, mem_privkey_len,
286d4afb5ceSopenharmony_ci					  &p, &flen)) {
287d4afb5ceSopenharmony_ci		lwsl_notice("unable to convert memory privkey\n");
288d4afb5ceSopenharmony_ci
289d4afb5ceSopenharmony_ci		return 1;
290d4afb5ceSopenharmony_ci	}
291d4afb5ceSopenharmony_ci
292d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
293d4afb5ceSopenharmony_ci	ret = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, vhost->tls.ssl_ctx, p,
294d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
295d4afb5ceSopenharmony_ci			(size_t)
296d4afb5ceSopenharmony_ci#else
297d4afb5ceSopenharmony_ci					  (long)(long long)
298d4afb5ceSopenharmony_ci#endif
299d4afb5ceSopenharmony_ci					  flen);
300d4afb5ceSopenharmony_ci	if (ret != 1) {
301d4afb5ceSopenharmony_ci		ret = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC,
302d4afb5ceSopenharmony_ci						  vhost->tls.ssl_ctx, p,
303d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
304d4afb5ceSopenharmony_ci			(size_t)
305d4afb5ceSopenharmony_ci#else
306d4afb5ceSopenharmony_ci					  (long)(long long)
307d4afb5ceSopenharmony_ci#endif
308d4afb5ceSopenharmony_ci						  flen);
309d4afb5ceSopenharmony_ci	}
310d4afb5ceSopenharmony_ci#else
311d4afb5ceSopenharmony_ci	ret = wolfSSL_CTX_use_PrivateKey_buffer(vhost->tls.ssl_ctx, p, flen,
312d4afb5ceSopenharmony_ci						WOLFSSL_FILETYPE_ASN1);
313d4afb5ceSopenharmony_ci#endif
314d4afb5ceSopenharmony_ci	lws_free_set_NULL(p);
315d4afb5ceSopenharmony_ci	if (ret != 1)  {
316d4afb5ceSopenharmony_ci		lwsl_notice("unable to use memory privkey\n");
317d4afb5ceSopenharmony_ci
318d4afb5ceSopenharmony_ci		return 1;
319d4afb5ceSopenharmony_ci	}
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_ci#else
322d4afb5ceSopenharmony_ci		/*
323d4afb5ceSopenharmony_ci		 * Although we have prepared update certs, we no longer have
324d4afb5ceSopenharmony_ci		 * the rights to read our own cert + key we saved.
325d4afb5ceSopenharmony_ci		 *
326d4afb5ceSopenharmony_ci		 * If we were passed copies in memory buffers, use those
327d4afb5ceSopenharmony_ci		 * instead.
328d4afb5ceSopenharmony_ci		 *
329d4afb5ceSopenharmony_ci		 * The passed memory-buffer cert image is in DER, and the
330d4afb5ceSopenharmony_ci		 * memory-buffer private key image is PEM.
331d4afb5ceSopenharmony_ci		 */
332d4afb5ceSopenharmony_ci#ifndef USE_WOLFSSL
333d4afb5ceSopenharmony_ci		if (lws_tls_alloc_pem_to_der_file(vhost->context, cert, mem_cert,
334d4afb5ceSopenharmony_ci						  mem_cert_len, &p, &flen)) {
335d4afb5ceSopenharmony_ci			lwsl_err("%s: couldn't convert pem to der\n", __func__);
336d4afb5ceSopenharmony_ci			return 1;
337d4afb5ceSopenharmony_ci		}
338d4afb5ceSopenharmony_ci		if (SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx,
339d4afb5ceSopenharmony_ci						 (int)flen,
340d4afb5ceSopenharmony_ci						 (uint8_t *)p) != 1) {
341d4afb5ceSopenharmony_ci#else
342d4afb5ceSopenharmony_ci		if (wolfSSL_CTX_use_certificate_buffer(vhost->tls.ssl_ctx,
343d4afb5ceSopenharmony_ci						 (uint8_t *)mem_cert,
344d4afb5ceSopenharmony_ci						 (int)mem_cert_len,
345d4afb5ceSopenharmony_ci						 WOLFSSL_FILETYPE_ASN1) != 1) {
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_ci#endif
348d4afb5ceSopenharmony_ci			lwsl_err("Problem loading update cert\n");
349d4afb5ceSopenharmony_ci
350d4afb5ceSopenharmony_ci			return 1;
351d4afb5ceSopenharmony_ci		}
352d4afb5ceSopenharmony_ci
353d4afb5ceSopenharmony_ci		if (lws_tls_alloc_pem_to_der_file(vhost->context, NULL,
354d4afb5ceSopenharmony_ci						  mem_privkey, mem_privkey_len,
355d4afb5ceSopenharmony_ci						  &p, &flen)) {
356d4afb5ceSopenharmony_ci			lwsl_notice("unable to convert memory privkey\n");
357d4afb5ceSopenharmony_ci
358d4afb5ceSopenharmony_ci			return 1;
359d4afb5ceSopenharmony_ci		}
360d4afb5ceSopenharmony_ci#ifndef USE_WOLFSSL
361d4afb5ceSopenharmony_ci		if (SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA,
362d4afb5ceSopenharmony_ci						vhost->tls.ssl_ctx, p,
363d4afb5ceSopenharmony_ci						(long)(long long)flen) != 1) {
364d4afb5ceSopenharmony_ci#else
365d4afb5ceSopenharmony_ci		if (wolfSSL_CTX_use_PrivateKey_buffer(vhost->tls.ssl_ctx, p,
366d4afb5ceSopenharmony_ci					    (long)flen, WOLFSSL_FILETYPE_ASN1) != 1) {
367d4afb5ceSopenharmony_ci#endif
368d4afb5ceSopenharmony_ci			lwsl_notice("unable to use memory privkey\n");
369d4afb5ceSopenharmony_ci
370d4afb5ceSopenharmony_ci			return 1;
371d4afb5ceSopenharmony_ci		}
372d4afb5ceSopenharmony_ci
373d4afb5ceSopenharmony_ci		goto check_key;
374d4afb5ceSopenharmony_ci	}
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci	/* set the local certificate from CertFile */
377d4afb5ceSopenharmony_ci	m = SSL_CTX_use_certificate_chain_file(vhost->tls.ssl_ctx, cert);
378d4afb5ceSopenharmony_ci	if (m != 1) {
379d4afb5ceSopenharmony_ci		error = ERR_get_error();
380d4afb5ceSopenharmony_ci		lwsl_err("problem getting cert '%s' %lu: %s\n",
381d4afb5ceSopenharmony_ci			 cert, error, ERR_error_string(error,
382d4afb5ceSopenharmony_ci			       (char *)vhost->context->pt[0].serv_buf));
383d4afb5ceSopenharmony_ci
384d4afb5ceSopenharmony_ci		return 1;
385d4afb5ceSopenharmony_ci	}
386d4afb5ceSopenharmony_ci
387d4afb5ceSopenharmony_ci	if (n == LWS_TLS_EXTANT_ALTERNATIVE || !private_key) {
388d4afb5ceSopenharmony_ci		lwsl_err("ssl private key not set\n");
389d4afb5ceSopenharmony_ci		return 1;
390d4afb5ceSopenharmony_ci	} else {
391d4afb5ceSopenharmony_ci		/* set the private key from KeyFile */
392d4afb5ceSopenharmony_ci		if (SSL_CTX_use_PrivateKey_file(vhost->tls.ssl_ctx, private_key,
393d4afb5ceSopenharmony_ci					        SSL_FILETYPE_PEM) != 1) {
394d4afb5ceSopenharmony_ci			error = ERR_get_error();
395d4afb5ceSopenharmony_ci			lwsl_err("ssl problem getting key '%s' %lu: %s\n",
396d4afb5ceSopenharmony_ci				 private_key, error,
397d4afb5ceSopenharmony_ci				 ERR_error_string(error,
398d4afb5ceSopenharmony_ci				      (char *)vhost->context->pt[0].serv_buf));
399d4afb5ceSopenharmony_ci			return 1;
400d4afb5ceSopenharmony_ci		}
401d4afb5ceSopenharmony_ci	}
402d4afb5ceSopenharmony_ci
403d4afb5ceSopenharmony_cicheck_key:
404d4afb5ceSopenharmony_ci#endif
405d4afb5ceSopenharmony_ci
406d4afb5ceSopenharmony_ci	/* verify private key */
407d4afb5ceSopenharmony_ci	if (!SSL_CTX_check_private_key(vhost->tls.ssl_ctx)) {
408d4afb5ceSopenharmony_ci		lwsl_err("Private SSL key doesn't match cert\n");
409d4afb5ceSopenharmony_ci
410d4afb5ceSopenharmony_ci		return 1;
411d4afb5ceSopenharmony_ci	}
412d4afb5ceSopenharmony_ci
413d4afb5ceSopenharmony_ci
414d4afb5ceSopenharmony_ci#if !defined(OPENSSL_NO_EC) && defined(LWS_HAVE_EC_KEY_new_by_curve_name) && \
415d4afb5ceSopenharmony_ci    ((OPENSSL_VERSION_NUMBER < 0x30000000l) || \
416d4afb5ceSopenharmony_ci     defined(LWS_SUPPRESS_DEPRECATED_API_WARNINGS))
417d4afb5ceSopenharmony_ci	if (vhost->tls.ecdh_curve[0])
418d4afb5ceSopenharmony_ci		ecdh_curve = vhost->tls.ecdh_curve;
419d4afb5ceSopenharmony_ci
420d4afb5ceSopenharmony_ci	ecdh_nid = OBJ_sn2nid(ecdh_curve);
421d4afb5ceSopenharmony_ci	if (NID_undef == ecdh_nid) {
422d4afb5ceSopenharmony_ci		lwsl_err("SSL: Unknown curve name '%s'", ecdh_curve);
423d4afb5ceSopenharmony_ci		return 1;
424d4afb5ceSopenharmony_ci	}
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci	ecdh = EC_KEY_new_by_curve_name(ecdh_nid);
427d4afb5ceSopenharmony_ci	if (NULL == ecdh) {
428d4afb5ceSopenharmony_ci		lwsl_err("SSL: Unable to create curve '%s'", ecdh_curve);
429d4afb5ceSopenharmony_ci		return 1;
430d4afb5ceSopenharmony_ci	}
431d4afb5ceSopenharmony_ci	SSL_CTX_set_tmp_ecdh(vhost->tls.ssl_ctx, ecdh);
432d4afb5ceSopenharmony_ci	EC_KEY_free(ecdh);
433d4afb5ceSopenharmony_ci
434d4afb5ceSopenharmony_ci	SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
435d4afb5ceSopenharmony_ci
436d4afb5ceSopenharmony_ci	lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve);
437d4afb5ceSopenharmony_ci
438d4afb5ceSopenharmony_ci	if (lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_SSL_ECDH))
439d4afb5ceSopenharmony_ci		lwsl_notice(" Using ECDH certificate support\n");
440d4afb5ceSopenharmony_ci
441d4afb5ceSopenharmony_ci	/* Get X509 certificate from ssl context */
442d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_BORINGSSL)
443d4afb5ceSopenharmony_ci#if !defined(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS)
444d4afb5ceSopenharmony_ci	x = sk_X509_value(vhost->tls.ssl_ctx->extra_certs, 0);
445d4afb5ceSopenharmony_ci#else
446d4afb5ceSopenharmony_ci	SSL_CTX_get_extra_chain_certs_only(vhost->tls.ssl_ctx, &extra_certs);
447d4afb5ceSopenharmony_ci	if (extra_certs)
448d4afb5ceSopenharmony_ci		x = sk_X509_value(extra_certs, 0);
449d4afb5ceSopenharmony_ci	else
450d4afb5ceSopenharmony_ci		lwsl_info("%s: no extra certs\n", __func__);
451d4afb5ceSopenharmony_ci#endif
452d4afb5ceSopenharmony_ci	if (!x) {
453d4afb5ceSopenharmony_ci		//lwsl_err("%s: x is NULL\n", __func__);
454d4afb5ceSopenharmony_ci		goto post_ecdh;
455d4afb5ceSopenharmony_ci	}
456d4afb5ceSopenharmony_ci#else
457d4afb5ceSopenharmony_ci	return 0;
458d4afb5ceSopenharmony_ci#endif /* !boringssl */
459d4afb5ceSopenharmony_ci
460d4afb5ceSopenharmony_ci	/* Get the public key from certificate */
461d4afb5ceSopenharmony_ci	pkey = X509_get_pubkey(x);
462d4afb5ceSopenharmony_ci	if (!pkey) {
463d4afb5ceSopenharmony_ci		lwsl_err("%s: pkey is NULL\n", __func__);
464d4afb5ceSopenharmony_ci
465d4afb5ceSopenharmony_ci		return 1;
466d4afb5ceSopenharmony_ci	}
467d4afb5ceSopenharmony_ci	/* Get the key type */
468d4afb5ceSopenharmony_ci	KeyType = EVP_PKEY_type(EVP_PKEY_id(pkey));
469d4afb5ceSopenharmony_ci
470d4afb5ceSopenharmony_ci	if (EVP_PKEY_EC != KeyType) {
471d4afb5ceSopenharmony_ci		lwsl_notice("Key type is not EC\n");
472d4afb5ceSopenharmony_ci		return 0;
473d4afb5ceSopenharmony_ci	}
474d4afb5ceSopenharmony_ci	/* Get the key */
475d4afb5ceSopenharmony_ci	EC_key = EVP_PKEY_get1_EC_KEY(pkey);
476d4afb5ceSopenharmony_ci	/* Set ECDH parameter */
477d4afb5ceSopenharmony_ci	if (!EC_key) {
478d4afb5ceSopenharmony_ci		lwsl_err("%s: ECDH key is NULL \n", __func__);
479d4afb5ceSopenharmony_ci		return 1;
480d4afb5ceSopenharmony_ci	}
481d4afb5ceSopenharmony_ci	SSL_CTX_set_tmp_ecdh(vhost->tls.ssl_ctx, EC_key);
482d4afb5ceSopenharmony_ci
483d4afb5ceSopenharmony_ci	EC_KEY_free(EC_key);
484d4afb5ceSopenharmony_ci
485d4afb5ceSopenharmony_ci#if !defined(OPENSSL_NO_EC) && !defined(LWS_WITH_BORINGSSL)
486d4afb5ceSopenharmony_cipost_ecdh:
487d4afb5ceSopenharmony_ci#endif
488d4afb5ceSopenharmony_ci	vhost->tls.skipped_certs = 0;
489d4afb5ceSopenharmony_ci#else
490d4afb5ceSopenharmony_ci	lwsl_notice(" OpenSSL doesn't support ECDH\n");
491d4afb5ceSopenharmony_ci#endif
492d4afb5ceSopenharmony_ci
493d4afb5ceSopenharmony_ci	return 0;
494d4afb5ceSopenharmony_ci}
495d4afb5ceSopenharmony_ci
496d4afb5ceSopenharmony_ciint
497d4afb5ceSopenharmony_cilws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info,
498d4afb5ceSopenharmony_ci				  struct lws_vhost *vhost, struct lws *wsi)
499d4afb5ceSopenharmony_ci{
500d4afb5ceSopenharmony_ci	unsigned long error;
501d4afb5ceSopenharmony_ci	SSL_METHOD *method = (SSL_METHOD *)SSLv23_server_method();
502d4afb5ceSopenharmony_ci
503d4afb5ceSopenharmony_ci	if (!method) {
504d4afb5ceSopenharmony_ci		const char *s;
505d4afb5ceSopenharmony_ci		error = ERR_get_error();
506d4afb5ceSopenharmony_ci		s = ERR_error_string(
507d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
508d4afb5ceSopenharmony_ci			(uint32_t)
509d4afb5ceSopenharmony_ci#endif
510d4afb5ceSopenharmony_ci				error,
511d4afb5ceSopenharmony_ci			       (char *)vhost->context->pt[0].serv_buf);
512d4afb5ceSopenharmony_ci
513d4afb5ceSopenharmony_ci		lwsl_err("problem creating ssl method %lu: %s\n",
514d4afb5ceSopenharmony_ci				error, s);
515d4afb5ceSopenharmony_ci		return 1;
516d4afb5ceSopenharmony_ci	}
517d4afb5ceSopenharmony_ci	vhost->tls.ssl_ctx = SSL_CTX_new(method);	/* create context */
518d4afb5ceSopenharmony_ci	if (!vhost->tls.ssl_ctx) {
519d4afb5ceSopenharmony_ci		const char *s;
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci		error = ERR_get_error();
522d4afb5ceSopenharmony_ci		s = ERR_error_string(
523d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
524d4afb5ceSopenharmony_ci			(uint32_t)
525d4afb5ceSopenharmony_ci#endif
526d4afb5ceSopenharmony_ci				error,
527d4afb5ceSopenharmony_ci			       (char *)vhost->context->pt[0].serv_buf);
528d4afb5ceSopenharmony_ci		lwsl_err("problem creating ssl context %lu: %s\n",
529d4afb5ceSopenharmony_ci				error, s);
530d4afb5ceSopenharmony_ci		return 1;
531d4afb5ceSopenharmony_ci	}
532d4afb5ceSopenharmony_ci
533d4afb5ceSopenharmony_ci	SSL_CTX_set_ex_data(vhost->tls.ssl_ctx,
534d4afb5ceSopenharmony_ci			    openssl_SSL_CTX_private_data_index,
535d4afb5ceSopenharmony_ci			    (char *)vhost->context);
536d4afb5ceSopenharmony_ci	/* Disable SSLv2 and SSLv3 */
537d4afb5ceSopenharmony_ci	SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_NO_SSLv2 |
538d4afb5ceSopenharmony_ci						SSL_OP_NO_SSLv3);
539d4afb5ceSopenharmony_ci#ifdef SSL_OP_NO_COMPRESSION
540d4afb5ceSopenharmony_ci	SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_NO_COMPRESSION);
541d4afb5ceSopenharmony_ci#endif
542d4afb5ceSopenharmony_ci	SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_SINGLE_DH_USE);
543d4afb5ceSopenharmony_ci	SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
544d4afb5ceSopenharmony_ci
545d4afb5ceSopenharmony_ci	if (info->ssl_cipher_list)
546d4afb5ceSopenharmony_ci		SSL_CTX_set_cipher_list(vhost->tls.ssl_ctx, info->ssl_cipher_list);
547d4afb5ceSopenharmony_ci
548d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_set_ciphersuites)
549d4afb5ceSopenharmony_ci	if (info->tls1_3_plus_cipher_list)
550d4afb5ceSopenharmony_ci		SSL_CTX_set_ciphersuites(vhost->tls.ssl_ctx,
551d4afb5ceSopenharmony_ci					 info->tls1_3_plus_cipher_list);
552d4afb5ceSopenharmony_ci#endif
553d4afb5ceSopenharmony_ci
554d4afb5ceSopenharmony_ci#if !defined(OPENSSL_NO_TLSEXT)
555d4afb5ceSopenharmony_ci	SSL_CTX_set_tlsext_servername_callback(vhost->tls.ssl_ctx,
556d4afb5ceSopenharmony_ci					       lws_ssl_server_name_cb);
557d4afb5ceSopenharmony_ci	SSL_CTX_set_tlsext_servername_arg(vhost->tls.ssl_ctx, vhost->context);
558d4afb5ceSopenharmony_ci#endif
559d4afb5ceSopenharmony_ci
560d4afb5ceSopenharmony_ci	if (info->ssl_ca_filepath &&
561d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_load_verify_file)
562d4afb5ceSopenharmony_ci	    !SSL_CTX_load_verify_file(vhost->tls.ssl_ctx,
563d4afb5ceSopenharmony_ci				      info->ssl_ca_filepath)) {
564d4afb5ceSopenharmony_ci#else
565d4afb5ceSopenharmony_ci	    !SSL_CTX_load_verify_locations(vhost->tls.ssl_ctx,
566d4afb5ceSopenharmony_ci					   info->ssl_ca_filepath, NULL)) {
567d4afb5ceSopenharmony_ci#endif
568d4afb5ceSopenharmony_ci		lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n",
569d4afb5ceSopenharmony_ci			 __func__);
570d4afb5ceSopenharmony_ci	}
571d4afb5ceSopenharmony_ci
572d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL)
573d4afb5ceSopenharmony_ci		long
574d4afb5ceSopenharmony_ci#else
575d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
576d4afb5ceSopenharmony_ci		uint32_t
577d4afb5ceSopenharmony_ci#else
578d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */
579d4afb5ceSopenharmony_ci		unsigned long
580d4afb5ceSopenharmony_ci#else
581d4afb5ceSopenharmony_ci		long
582d4afb5ceSopenharmony_ci#endif
583d4afb5ceSopenharmony_ci#endif
584d4afb5ceSopenharmony_ci#endif
585d4afb5ceSopenharmony_ci			ssl_options_set_value =
586d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL)
587d4afb5ceSopenharmony_ci				(long)
588d4afb5ceSopenharmony_ci#else
589d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
590d4afb5ceSopenharmony_ci				(uint32_t)
591d4afb5ceSopenharmony_ci#else
592d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */
593d4afb5ceSopenharmony_ci				(unsigned long)
594d4afb5ceSopenharmony_ci#else
595d4afb5ceSopenharmony_ci				(long)
596d4afb5ceSopenharmony_ci#endif
597d4afb5ceSopenharmony_ci#endif
598d4afb5ceSopenharmony_ci#endif
599d4afb5ceSopenharmony_ci					info->ssl_options_set;
600d4afb5ceSopenharmony_ci
601d4afb5ceSopenharmony_ci	if (info->ssl_options_set)
602d4afb5ceSopenharmony_ci		SSL_CTX_set_options(vhost->tls.ssl_ctx, ssl_options_set_value);
603d4afb5ceSopenharmony_ci
604d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
605d4afb5ceSopenharmony_ci
606d4afb5ceSopenharmony_ci/* SSL_clear_options introduced in 0.9.8m */
607d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
608d4afb5ceSopenharmony_ci	uint32_t
609d4afb5ceSopenharmony_ci#else
610d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l)  && !defined(LIBRESSL_VERSION_NUMBER)/* not documented by openssl */
611d4afb5ceSopenharmony_ci	unsigned long
612d4afb5ceSopenharmony_ci#else
613d4afb5ceSopenharmony_ci	long
614d4afb5ceSopenharmony_ci#endif
615d4afb5ceSopenharmony_ci#endif
616d4afb5ceSopenharmony_ci
617d4afb5ceSopenharmony_ci	ssl_options_clear_value =
618d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL)
619d4afb5ceSopenharmony_ci				(uint32_t)
620d4afb5ceSopenharmony_ci#else
621d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l)  && !defined(LIBRESSL_VERSION_NUMBER)/* not documented by openssl */
622d4afb5ceSopenharmony_ci				(unsigned long)
623d4afb5ceSopenharmony_ci#else
624d4afb5ceSopenharmony_ci				(long)
625d4afb5ceSopenharmony_ci#endif
626d4afb5ceSopenharmony_ci#endif
627d4afb5ceSopenharmony_ci					info->ssl_options_clear;
628d4afb5ceSopenharmony_ci
629d4afb5ceSopenharmony_ci	if (info->ssl_options_clear) {
630d4afb5ceSopenharmony_ci		SSL_CTX_clear_options(vhost->tls.ssl_ctx, ssl_options_clear_value);
631d4afb5ceSopenharmony_ci	}
632d4afb5ceSopenharmony_ci
633d4afb5ceSopenharmony_ci	lwsl_info(" SSL options 0x%lX\n",
634d4afb5ceSopenharmony_ci			(unsigned long)SSL_CTX_get_options(vhost->tls.ssl_ctx));
635d4afb5ceSopenharmony_ci#endif
636d4afb5ceSopenharmony_ci
637d4afb5ceSopenharmony_ci	if (!vhost->tls.use_ssl ||
638d4afb5ceSopenharmony_ci	    (!info->ssl_cert_filepath && !info->server_ssl_cert_mem))
639d4afb5ceSopenharmony_ci		return 0;
640d4afb5ceSopenharmony_ci
641d4afb5ceSopenharmony_ci	lws_ssl_bind_passphrase(vhost->tls.ssl_ctx, 0, info);
642d4afb5ceSopenharmony_ci
643d4afb5ceSopenharmony_ci	return lws_tls_server_certs_load(vhost, wsi, info->ssl_cert_filepath,
644d4afb5ceSopenharmony_ci					 info->ssl_private_key_filepath,
645d4afb5ceSopenharmony_ci					 info->server_ssl_cert_mem,
646d4afb5ceSopenharmony_ci					 info->server_ssl_cert_mem_len,
647d4afb5ceSopenharmony_ci					 info->server_ssl_private_key_mem,
648d4afb5ceSopenharmony_ci					 info->server_ssl_private_key_mem_len);
649d4afb5ceSopenharmony_ci}
650d4afb5ceSopenharmony_ci
651d4afb5ceSopenharmony_ciint
652d4afb5ceSopenharmony_cilws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
653d4afb5ceSopenharmony_ci{
654d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL)
655d4afb5ceSopenharmony_ci	BIO *bio;
656d4afb5ceSopenharmony_ci#endif
657d4afb5ceSopenharmony_ci
658d4afb5ceSopenharmony_ci	errno = 0;
659d4afb5ceSopenharmony_ci	ERR_clear_error();
660d4afb5ceSopenharmony_ci	wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_ctx);
661d4afb5ceSopenharmony_ci	if (wsi->tls.ssl == NULL) {
662d4afb5ceSopenharmony_ci		lwsl_err("SSL_new failed: %d (errno %d)\n",
663d4afb5ceSopenharmony_ci			 lws_ssl_get_error(wsi, 0), errno);
664d4afb5ceSopenharmony_ci
665d4afb5ceSopenharmony_ci		lws_tls_err_describe_clear();
666d4afb5ceSopenharmony_ci		return 1;
667d4afb5ceSopenharmony_ci	}
668d4afb5ceSopenharmony_ci
669d4afb5ceSopenharmony_ci	SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index, wsi);
670d4afb5ceSopenharmony_ci	SSL_set_fd(wsi->tls.ssl, (int)(lws_intptr_t)accept_fd);
671d4afb5ceSopenharmony_ci
672d4afb5ceSopenharmony_ci#ifdef USE_WOLFSSL
673d4afb5ceSopenharmony_ci#ifdef USE_OLD_CYASSL
674d4afb5ceSopenharmony_ci	CyaSSL_set_using_nonblock(wsi->tls.ssl, 1);
675d4afb5ceSopenharmony_ci#else
676d4afb5ceSopenharmony_ci	wolfSSL_set_using_nonblock(wsi->tls.ssl, 1);
677d4afb5ceSopenharmony_ci#endif
678d4afb5ceSopenharmony_ci#else
679d4afb5ceSopenharmony_ci
680d4afb5ceSopenharmony_ci	SSL_set_mode(wsi->tls.ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
681d4afb5ceSopenharmony_ci				   SSL_MODE_RELEASE_BUFFERS);
682d4afb5ceSopenharmony_ci	bio = SSL_get_rbio(wsi->tls.ssl);
683d4afb5ceSopenharmony_ci	if (bio)
684d4afb5ceSopenharmony_ci		BIO_set_nbio(bio, 1); /* nonblocking */
685d4afb5ceSopenharmony_ci	else
686d4afb5ceSopenharmony_ci		lwsl_notice("NULL rbio\n");
687d4afb5ceSopenharmony_ci	bio = SSL_get_wbio(wsi->tls.ssl);
688d4afb5ceSopenharmony_ci	if (bio)
689d4afb5ceSopenharmony_ci		BIO_set_nbio(bio, 1); /* nonblocking */
690d4afb5ceSopenharmony_ci	else
691d4afb5ceSopenharmony_ci		lwsl_notice("NULL rbio\n");
692d4afb5ceSopenharmony_ci#endif
693d4afb5ceSopenharmony_ci
694d4afb5ceSopenharmony_ci#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
695d4afb5ceSopenharmony_ci		if (wsi->a.vhost->tls.ssl_info_event_mask)
696d4afb5ceSopenharmony_ci			SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
697d4afb5ceSopenharmony_ci#endif
698d4afb5ceSopenharmony_ci
699d4afb5ceSopenharmony_ci	return 0;
700d4afb5ceSopenharmony_ci}
701d4afb5ceSopenharmony_ci
702d4afb5ceSopenharmony_cienum lws_ssl_capable_status
703d4afb5ceSopenharmony_cilws_tls_server_abort_connection(struct lws *wsi)
704d4afb5ceSopenharmony_ci{
705d4afb5ceSopenharmony_ci	if (wsi->tls.use_ssl)
706d4afb5ceSopenharmony_ci		SSL_shutdown(wsi->tls.ssl);
707d4afb5ceSopenharmony_ci	SSL_free(wsi->tls.ssl);
708d4afb5ceSopenharmony_ci
709d4afb5ceSopenharmony_ci	return LWS_SSL_CAPABLE_DONE;
710d4afb5ceSopenharmony_ci}
711d4afb5ceSopenharmony_ci
712d4afb5ceSopenharmony_cienum lws_ssl_capable_status
713d4afb5ceSopenharmony_cilws_tls_server_accept(struct lws *wsi)
714d4afb5ceSopenharmony_ci{
715d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
716d4afb5ceSopenharmony_ci	union lws_tls_cert_info_results ir;
717d4afb5ceSopenharmony_ci	int m, n;
718d4afb5ceSopenharmony_ci
719d4afb5ceSopenharmony_ci	errno = 0;
720d4afb5ceSopenharmony_ci	ERR_clear_error();
721d4afb5ceSopenharmony_ci	n = SSL_accept(wsi->tls.ssl);
722d4afb5ceSopenharmony_ci
723d4afb5ceSopenharmony_ci	wsi->skip_fallback = 1;
724d4afb5ceSopenharmony_ci
725d4afb5ceSopenharmony_ci	if (n == 1) {
726d4afb5ceSopenharmony_ci		n = lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME, &ir,
727d4afb5ceSopenharmony_ci					   sizeof(ir.ns.name));
728d4afb5ceSopenharmony_ci		if (!n)
729d4afb5ceSopenharmony_ci			lwsl_notice("%s: client cert CN '%s'\n", __func__,
730d4afb5ceSopenharmony_ci				    ir.ns.name);
731d4afb5ceSopenharmony_ci		else
732d4afb5ceSopenharmony_ci			lwsl_info("%s: no client cert CN\n", __func__);
733d4afb5ceSopenharmony_ci
734d4afb5ceSopenharmony_ci		lws_openssl_describe_cipher(wsi);
735d4afb5ceSopenharmony_ci
736d4afb5ceSopenharmony_ci		if (SSL_pending(wsi->tls.ssl) &&
737d4afb5ceSopenharmony_ci		    lws_dll2_is_detached(&wsi->tls.dll_pending_tls))
738d4afb5ceSopenharmony_ci			lws_dll2_add_head(&wsi->tls.dll_pending_tls,
739d4afb5ceSopenharmony_ci					  &pt->tls.dll_pending_tls_owner);
740d4afb5ceSopenharmony_ci
741d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_DONE;
742d4afb5ceSopenharmony_ci	}
743d4afb5ceSopenharmony_ci
744d4afb5ceSopenharmony_ci	m = lws_ssl_get_error(wsi, n);
745d4afb5ceSopenharmony_ci	lws_tls_err_describe_clear();
746d4afb5ceSopenharmony_ci
747d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL)
748d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_ERROR;
749d4afb5ceSopenharmony_ci
750d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_WANT_READ ||
751d4afb5ceSopenharmony_ci	    (m != SSL_ERROR_ZERO_RETURN && SSL_want_read(wsi->tls.ssl))) {
752d4afb5ceSopenharmony_ci		if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
753d4afb5ceSopenharmony_ci			lwsl_info("%s: WANT_READ change_pollfd failed\n",
754d4afb5ceSopenharmony_ci				  __func__);
755d4afb5ceSopenharmony_ci			return LWS_SSL_CAPABLE_ERROR;
756d4afb5ceSopenharmony_ci		}
757d4afb5ceSopenharmony_ci
758d4afb5ceSopenharmony_ci		lwsl_info("SSL_ERROR_WANT_READ: m %d\n", m);
759d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
760d4afb5ceSopenharmony_ci	}
761d4afb5ceSopenharmony_ci	if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) {
762d4afb5ceSopenharmony_ci		lwsl_debug("%s: WANT_WRITE\n", __func__);
763d4afb5ceSopenharmony_ci
764d4afb5ceSopenharmony_ci		if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
765d4afb5ceSopenharmony_ci			lwsl_info("%s: WANT_WRITE change_pollfd failed\n",
766d4afb5ceSopenharmony_ci				  __func__);
767d4afb5ceSopenharmony_ci			return LWS_SSL_CAPABLE_ERROR;
768d4afb5ceSopenharmony_ci		}
769d4afb5ceSopenharmony_ci		return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
770d4afb5ceSopenharmony_ci	}
771d4afb5ceSopenharmony_ci
772d4afb5ceSopenharmony_ci	return LWS_SSL_CAPABLE_ERROR;
773d4afb5ceSopenharmony_ci}
774d4afb5ceSopenharmony_ci
775d4afb5ceSopenharmony_ci#if defined(LWS_WITH_ACME)
776d4afb5ceSopenharmony_cistatic int
777d4afb5ceSopenharmony_cilws_tls_openssl_rsa_new_key(RSA **rsa, int bits)
778d4afb5ceSopenharmony_ci{
779d4afb5ceSopenharmony_ci	BIGNUM *bn = BN_new();
780d4afb5ceSopenharmony_ci	int n;
781d4afb5ceSopenharmony_ci
782d4afb5ceSopenharmony_ci	if (!bn)
783d4afb5ceSopenharmony_ci		return 1;
784d4afb5ceSopenharmony_ci
785d4afb5ceSopenharmony_ci	if (BN_set_word(bn, RSA_F4) != 1) {
786d4afb5ceSopenharmony_ci		BN_free(bn);
787d4afb5ceSopenharmony_ci		return 1;
788d4afb5ceSopenharmony_ci	}
789d4afb5ceSopenharmony_ci
790d4afb5ceSopenharmony_ci	*rsa = RSA_new();
791d4afb5ceSopenharmony_ci	if (!*rsa) {
792d4afb5ceSopenharmony_ci		BN_free(bn);
793d4afb5ceSopenharmony_ci		return 1;
794d4afb5ceSopenharmony_ci	}
795d4afb5ceSopenharmony_ci
796d4afb5ceSopenharmony_ci	n = RSA_generate_key_ex(*rsa, bits, bn, NULL);
797d4afb5ceSopenharmony_ci	BN_free(bn);
798d4afb5ceSopenharmony_ci	if (n == 1)
799d4afb5ceSopenharmony_ci		return 0;
800d4afb5ceSopenharmony_ci
801d4afb5ceSopenharmony_ci	RSA_free(*rsa);
802d4afb5ceSopenharmony_ci	*rsa = NULL;
803d4afb5ceSopenharmony_ci
804d4afb5ceSopenharmony_ci	return 1;
805d4afb5ceSopenharmony_ci}
806d4afb5ceSopenharmony_ci
807d4afb5ceSopenharmony_cistruct lws_tls_ss_pieces {
808d4afb5ceSopenharmony_ci	X509 *x509;
809d4afb5ceSopenharmony_ci	EVP_PKEY *pkey;
810d4afb5ceSopenharmony_ci	RSA *rsa;
811d4afb5ceSopenharmony_ci};
812d4afb5ceSopenharmony_ci
813d4afb5ceSopenharmony_ciint
814d4afb5ceSopenharmony_cilws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
815d4afb5ceSopenharmony_ci			     const char *san_b)
816d4afb5ceSopenharmony_ci{
817d4afb5ceSopenharmony_ci	GENERAL_NAMES *gens = sk_GENERAL_NAME_new_null();
818d4afb5ceSopenharmony_ci	GENERAL_NAME *gen = NULL;
819d4afb5ceSopenharmony_ci	ASN1_IA5STRING *ia5 = NULL;
820d4afb5ceSopenharmony_ci	X509_NAME *name;
821d4afb5ceSopenharmony_ci
822d4afb5ceSopenharmony_ci	if (!gens)
823d4afb5ceSopenharmony_ci		return 1;
824d4afb5ceSopenharmony_ci
825d4afb5ceSopenharmony_ci	vhost->tls.ss = lws_zalloc(sizeof(*vhost->tls.ss), "sni cert");
826d4afb5ceSopenharmony_ci	if (!vhost->tls.ss) {
827d4afb5ceSopenharmony_ci		GENERAL_NAMES_free(gens);
828d4afb5ceSopenharmony_ci		return 1;
829d4afb5ceSopenharmony_ci	}
830d4afb5ceSopenharmony_ci
831d4afb5ceSopenharmony_ci	vhost->tls.ss->x509 = X509_new();
832d4afb5ceSopenharmony_ci	if (!vhost->tls.ss->x509)
833d4afb5ceSopenharmony_ci		goto bail;
834d4afb5ceSopenharmony_ci
835d4afb5ceSopenharmony_ci	ASN1_INTEGER_set(X509_get_serialNumber(vhost->tls.ss->x509), 1);
836d4afb5ceSopenharmony_ci	X509_gmtime_adj(X509_get_notBefore(vhost->tls.ss->x509), 0);
837d4afb5ceSopenharmony_ci	X509_gmtime_adj(X509_get_notAfter(vhost->tls.ss->x509), 3600);
838d4afb5ceSopenharmony_ci
839d4afb5ceSopenharmony_ci	vhost->tls.ss->pkey = EVP_PKEY_new();
840d4afb5ceSopenharmony_ci	if (!vhost->tls.ss->pkey)
841d4afb5ceSopenharmony_ci		goto bail0;
842d4afb5ceSopenharmony_ci
843d4afb5ceSopenharmony_ci	if (lws_tls_openssl_rsa_new_key(&vhost->tls.ss->rsa, 4096))
844d4afb5ceSopenharmony_ci		goto bail1;
845d4afb5ceSopenharmony_ci
846d4afb5ceSopenharmony_ci	if (!EVP_PKEY_assign_RSA(vhost->tls.ss->pkey, vhost->tls.ss->rsa))
847d4afb5ceSopenharmony_ci		goto bail2;
848d4afb5ceSopenharmony_ci
849d4afb5ceSopenharmony_ci	X509_set_pubkey(vhost->tls.ss->x509, vhost->tls.ss->pkey);
850d4afb5ceSopenharmony_ci
851d4afb5ceSopenharmony_ci	name = X509_get_subject_name(vhost->tls.ss->x509);
852d4afb5ceSopenharmony_ci	X509_NAME_add_entry_by_txt(name, "C",  MBSTRING_ASC,
853d4afb5ceSopenharmony_ci				   (unsigned char *)"GB",          -1, -1, 0);
854d4afb5ceSopenharmony_ci	X509_NAME_add_entry_by_txt(name, "O",  MBSTRING_ASC,
855d4afb5ceSopenharmony_ci				   (unsigned char *)"somecompany", -1, -1, 0);
856d4afb5ceSopenharmony_ci	if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_UTF8,
857d4afb5ceSopenharmony_ci				   (unsigned char *)"temp.acme.invalid",
858d4afb5ceSopenharmony_ci				   	   	   -1, -1, 0) != 1) {
859d4afb5ceSopenharmony_ci		lwsl_notice("failed to add CN\n");
860d4afb5ceSopenharmony_ci		goto bail2;
861d4afb5ceSopenharmony_ci	}
862d4afb5ceSopenharmony_ci	X509_set_issuer_name(vhost->tls.ss->x509, name);
863d4afb5ceSopenharmony_ci
864d4afb5ceSopenharmony_ci	/* add the SAN payloads */
865d4afb5ceSopenharmony_ci
866d4afb5ceSopenharmony_ci	gen = GENERAL_NAME_new();
867d4afb5ceSopenharmony_ci	ia5 = ASN1_IA5STRING_new();
868d4afb5ceSopenharmony_ci	if (!ASN1_STRING_set(ia5, san_a, -1)) {
869d4afb5ceSopenharmony_ci		lwsl_notice("failed to set ia5\n");
870d4afb5ceSopenharmony_ci		GENERAL_NAME_free(gen);
871d4afb5ceSopenharmony_ci		goto bail2;
872d4afb5ceSopenharmony_ci	}
873d4afb5ceSopenharmony_ci	GENERAL_NAME_set0_value(gen, GEN_DNS, ia5);
874d4afb5ceSopenharmony_ci	sk_GENERAL_NAME_push(gens, gen);
875d4afb5ceSopenharmony_ci
876d4afb5ceSopenharmony_ci	if (X509_add1_ext_i2d(vhost->tls.ss->x509, NID_subject_alt_name,
877d4afb5ceSopenharmony_ci			    gens, 0, X509V3_ADD_APPEND) != 1)
878d4afb5ceSopenharmony_ci		goto bail2;
879d4afb5ceSopenharmony_ci
880d4afb5ceSopenharmony_ci	GENERAL_NAMES_free(gens);
881d4afb5ceSopenharmony_ci
882d4afb5ceSopenharmony_ci	if (san_b && san_b[0]) {
883d4afb5ceSopenharmony_ci		gens = sk_GENERAL_NAME_new_null();
884d4afb5ceSopenharmony_ci		gen = GENERAL_NAME_new();
885d4afb5ceSopenharmony_ci		ia5 = ASN1_IA5STRING_new();
886d4afb5ceSopenharmony_ci		if (!ASN1_STRING_set(ia5, san_a, -1)) {
887d4afb5ceSopenharmony_ci			lwsl_notice("failed to set ia5\n");
888d4afb5ceSopenharmony_ci			GENERAL_NAME_free(gen);
889d4afb5ceSopenharmony_ci			goto bail2;
890d4afb5ceSopenharmony_ci		}
891d4afb5ceSopenharmony_ci		GENERAL_NAME_set0_value(gen, GEN_DNS, ia5);
892d4afb5ceSopenharmony_ci		sk_GENERAL_NAME_push(gens, gen);
893d4afb5ceSopenharmony_ci
894d4afb5ceSopenharmony_ci		if (X509_add1_ext_i2d(vhost->tls.ss->x509, NID_subject_alt_name,
895d4afb5ceSopenharmony_ci				    gens, 0, X509V3_ADD_APPEND) != 1)
896d4afb5ceSopenharmony_ci			goto bail2;
897d4afb5ceSopenharmony_ci
898d4afb5ceSopenharmony_ci		GENERAL_NAMES_free(gens);
899d4afb5ceSopenharmony_ci	}
900d4afb5ceSopenharmony_ci
901d4afb5ceSopenharmony_ci	/* sign it with our private key */
902d4afb5ceSopenharmony_ci	if (!X509_sign(vhost->tls.ss->x509, vhost->tls.ss->pkey, EVP_sha256()))
903d4afb5ceSopenharmony_ci		goto bail2;
904d4afb5ceSopenharmony_ci
905d4afb5ceSopenharmony_ci#if 0
906d4afb5ceSopenharmony_ci	{/* useful to take a sample of a working cert for mbedtls to crib */
907d4afb5ceSopenharmony_ci		FILE *fp = fopen("/tmp/acme-temp-cert", "w+");
908d4afb5ceSopenharmony_ci
909d4afb5ceSopenharmony_ci		i2d_X509_fp(fp, vhost->tls.ss->x509);
910d4afb5ceSopenharmony_ci		fclose(fp);
911d4afb5ceSopenharmony_ci	}
912d4afb5ceSopenharmony_ci#endif
913d4afb5ceSopenharmony_ci
914d4afb5ceSopenharmony_ci	/* tell the vhost to use our crafted certificate */
915d4afb5ceSopenharmony_ci	SSL_CTX_use_certificate(vhost->tls.ssl_ctx, vhost->tls.ss->x509);
916d4afb5ceSopenharmony_ci	/* and to use our generated private key */
917d4afb5ceSopenharmony_ci	SSL_CTX_use_PrivateKey(vhost->tls.ssl_ctx, vhost->tls.ss->pkey);
918d4afb5ceSopenharmony_ci
919d4afb5ceSopenharmony_ci	return 0;
920d4afb5ceSopenharmony_ci
921d4afb5ceSopenharmony_cibail2:
922d4afb5ceSopenharmony_ci	RSA_free(vhost->tls.ss->rsa);
923d4afb5ceSopenharmony_cibail1:
924d4afb5ceSopenharmony_ci	EVP_PKEY_free(vhost->tls.ss->pkey);
925d4afb5ceSopenharmony_cibail0:
926d4afb5ceSopenharmony_ci	X509_free(vhost->tls.ss->x509);
927d4afb5ceSopenharmony_cibail:
928d4afb5ceSopenharmony_ci	lws_free(vhost->tls.ss);
929d4afb5ceSopenharmony_ci	GENERAL_NAMES_free(gens);
930d4afb5ceSopenharmony_ci
931d4afb5ceSopenharmony_ci	return 1;
932d4afb5ceSopenharmony_ci}
933d4afb5ceSopenharmony_ci
934d4afb5ceSopenharmony_civoid
935d4afb5ceSopenharmony_cilws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost)
936d4afb5ceSopenharmony_ci{
937d4afb5ceSopenharmony_ci	if (!vhost->tls.ss)
938d4afb5ceSopenharmony_ci		return;
939d4afb5ceSopenharmony_ci
940d4afb5ceSopenharmony_ci	EVP_PKEY_free(vhost->tls.ss->pkey);
941d4afb5ceSopenharmony_ci	X509_free(vhost->tls.ss->x509);
942d4afb5ceSopenharmony_ci	lws_free_set_NULL(vhost->tls.ss);
943d4afb5ceSopenharmony_ci}
944d4afb5ceSopenharmony_ci
945d4afb5ceSopenharmony_cistatic int
946d4afb5ceSopenharmony_cilws_tls_openssl_add_nid(X509_NAME *name, int nid, const char *value)
947d4afb5ceSopenharmony_ci{
948d4afb5ceSopenharmony_ci	X509_NAME_ENTRY *e;
949d4afb5ceSopenharmony_ci	int n;
950d4afb5ceSopenharmony_ci
951d4afb5ceSopenharmony_ci	if (!value || value[0] == '\0')
952d4afb5ceSopenharmony_ci		value = "none";
953d4afb5ceSopenharmony_ci
954d4afb5ceSopenharmony_ci	e = X509_NAME_ENTRY_create_by_NID(NULL, nid, MBSTRING_ASC,
955d4afb5ceSopenharmony_ci					  (unsigned char *)value, -1);
956d4afb5ceSopenharmony_ci	if (!e)
957d4afb5ceSopenharmony_ci		return 1;
958d4afb5ceSopenharmony_ci	n = X509_NAME_add_entry(name, e, -1, 0);
959d4afb5ceSopenharmony_ci	X509_NAME_ENTRY_free(e);
960d4afb5ceSopenharmony_ci
961d4afb5ceSopenharmony_ci	return n != 1;
962d4afb5ceSopenharmony_ci}
963d4afb5ceSopenharmony_ci
964d4afb5ceSopenharmony_cistatic int nid_list[] = {
965d4afb5ceSopenharmony_ci	NID_countryName,		/* LWS_TLS_REQ_ELEMENT_COUNTRY */
966d4afb5ceSopenharmony_ci	NID_stateOrProvinceName,	/* LWS_TLS_REQ_ELEMENT_STATE */
967d4afb5ceSopenharmony_ci	NID_localityName,		/* LWS_TLS_REQ_ELEMENT_LOCALITY */
968d4afb5ceSopenharmony_ci	NID_organizationName,		/* LWS_TLS_REQ_ELEMENT_ORGANIZATION */
969d4afb5ceSopenharmony_ci	NID_commonName,			/* LWS_TLS_REQ_ELEMENT_COMMON_NAME */
970d4afb5ceSopenharmony_ci	NID_subject_alt_name,		/* LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME */
971d4afb5ceSopenharmony_ci	NID_pkcs9_emailAddress,		/* LWS_TLS_REQ_ELEMENT_EMAIL */
972d4afb5ceSopenharmony_ci};
973d4afb5ceSopenharmony_ci
974d4afb5ceSopenharmony_ciint
975d4afb5ceSopenharmony_cilws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
976d4afb5ceSopenharmony_ci			    uint8_t *csr, size_t csr_len, char **privkey_pem,
977d4afb5ceSopenharmony_ci			    size_t *privkey_len)
978d4afb5ceSopenharmony_ci{
979d4afb5ceSopenharmony_ci	uint8_t *csr_in = csr;
980d4afb5ceSopenharmony_ci	RSA *rsakey;
981d4afb5ceSopenharmony_ci	X509_REQ *req;
982d4afb5ceSopenharmony_ci	X509_NAME *subj;
983d4afb5ceSopenharmony_ci	EVP_PKEY *pkey;
984d4afb5ceSopenharmony_ci	char *p, *end;
985d4afb5ceSopenharmony_ci	BIO *bio;
986d4afb5ceSopenharmony_ci	long bio_len;
987d4afb5ceSopenharmony_ci	int n, ret = -1;
988d4afb5ceSopenharmony_ci
989d4afb5ceSopenharmony_ci	if (lws_tls_openssl_rsa_new_key(&rsakey, 4096))
990d4afb5ceSopenharmony_ci		return -1;
991d4afb5ceSopenharmony_ci
992d4afb5ceSopenharmony_ci	pkey = EVP_PKEY_new();
993d4afb5ceSopenharmony_ci	if (!pkey)
994d4afb5ceSopenharmony_ci		goto bail0;
995d4afb5ceSopenharmony_ci	if (!EVP_PKEY_set1_RSA(pkey, rsakey))
996d4afb5ceSopenharmony_ci		goto bail1;
997d4afb5ceSopenharmony_ci
998d4afb5ceSopenharmony_ci	req = X509_REQ_new();
999d4afb5ceSopenharmony_ci	if (!req)
1000d4afb5ceSopenharmony_ci	        goto bail1;
1001d4afb5ceSopenharmony_ci
1002d4afb5ceSopenharmony_ci	X509_REQ_set_pubkey(req, pkey);
1003d4afb5ceSopenharmony_ci
1004d4afb5ceSopenharmony_ci	subj = X509_NAME_new();
1005d4afb5ceSopenharmony_ci	if (!subj)
1006d4afb5ceSopenharmony_ci		goto bail2;
1007d4afb5ceSopenharmony_ci
1008d4afb5ceSopenharmony_ci	for (n = 0; n < LWS_TLS_REQ_ELEMENT_COUNT; n++)
1009d4afb5ceSopenharmony_ci		if (elements[n] &&
1010d4afb5ceSopenharmony_ci			lws_tls_openssl_add_nid(subj, nid_list[n],
1011d4afb5ceSopenharmony_ci				elements[n])) {
1012d4afb5ceSopenharmony_ci				lwsl_notice("%s: failed to add element %d\n",
1013d4afb5ceSopenharmony_ci						__func__, n);
1014d4afb5ceSopenharmony_ci			goto bail3;
1015d4afb5ceSopenharmony_ci		}
1016d4afb5ceSopenharmony_ci
1017d4afb5ceSopenharmony_ci	if (X509_REQ_set_subject_name(req, subj) != 1)
1018d4afb5ceSopenharmony_ci		goto bail3;
1019d4afb5ceSopenharmony_ci
1020d4afb5ceSopenharmony_ci	if (elements[LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME]) {
1021d4afb5ceSopenharmony_ci		STACK_OF(X509_EXTENSION) *exts;
1022d4afb5ceSopenharmony_ci		X509_EXTENSION *ext;
1023d4afb5ceSopenharmony_ci		char san[256];
1024d4afb5ceSopenharmony_ci
1025d4afb5ceSopenharmony_ci		exts = sk_X509_EXTENSION_new_null();
1026d4afb5ceSopenharmony_ci		if (!exts)
1027d4afb5ceSopenharmony_ci			goto bail3;
1028d4afb5ceSopenharmony_ci
1029d4afb5ceSopenharmony_ci		lws_snprintf(san, sizeof(san), "DNS:%s,DNS:%s",
1030d4afb5ceSopenharmony_ci				elements[LWS_TLS_REQ_ELEMENT_COMMON_NAME],
1031d4afb5ceSopenharmony_ci				elements[LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME]);
1032d4afb5ceSopenharmony_ci
1033d4afb5ceSopenharmony_ci		ext = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name,
1034d4afb5ceSopenharmony_ci				san);
1035d4afb5ceSopenharmony_ci		if (!ext) {
1036d4afb5ceSopenharmony_ci			sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
1037d4afb5ceSopenharmony_ci			goto bail3;
1038d4afb5ceSopenharmony_ci		}
1039d4afb5ceSopenharmony_ci		sk_X509_EXTENSION_push(exts, ext);
1040d4afb5ceSopenharmony_ci
1041d4afb5ceSopenharmony_ci		if (!X509_REQ_add_extensions(req, exts)) {
1042d4afb5ceSopenharmony_ci			sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
1043d4afb5ceSopenharmony_ci			goto bail3;
1044d4afb5ceSopenharmony_ci		}
1045d4afb5ceSopenharmony_ci		sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
1046d4afb5ceSopenharmony_ci	}
1047d4afb5ceSopenharmony_ci
1048d4afb5ceSopenharmony_ci	if (!X509_REQ_sign(req, pkey, EVP_sha256()))
1049d4afb5ceSopenharmony_ci		goto bail3;
1050d4afb5ceSopenharmony_ci
1051d4afb5ceSopenharmony_ci	/*
1052d4afb5ceSopenharmony_ci	 * issue the CSR as PEM to a BIO, and translate to b64urlenc without
1053d4afb5ceSopenharmony_ci	 * headers, trailers, or whitespace
1054d4afb5ceSopenharmony_ci	 */
1055d4afb5ceSopenharmony_ci
1056d4afb5ceSopenharmony_ci	bio = BIO_new(BIO_s_mem());
1057d4afb5ceSopenharmony_ci	if (!bio)
1058d4afb5ceSopenharmony_ci		goto bail3;
1059d4afb5ceSopenharmony_ci
1060d4afb5ceSopenharmony_ci	if (PEM_write_bio_X509_REQ(bio, req) != 1) {
1061d4afb5ceSopenharmony_ci		BIO_free(bio);
1062d4afb5ceSopenharmony_ci		goto bail3;
1063d4afb5ceSopenharmony_ci	}
1064d4afb5ceSopenharmony_ci
1065d4afb5ceSopenharmony_ci	bio_len = BIO_get_mem_data(bio, &p);
1066d4afb5ceSopenharmony_ci	end = p + bio_len;
1067d4afb5ceSopenharmony_ci
1068d4afb5ceSopenharmony_ci	/* strip the header line */
1069d4afb5ceSopenharmony_ci	while (p < end && *p != '\n')
1070d4afb5ceSopenharmony_ci		p++;
1071d4afb5ceSopenharmony_ci
1072d4afb5ceSopenharmony_ci	while (p < end && csr_len) {
1073d4afb5ceSopenharmony_ci		if (*p == '\n') {
1074d4afb5ceSopenharmony_ci			p++;
1075d4afb5ceSopenharmony_ci			continue;
1076d4afb5ceSopenharmony_ci		}
1077d4afb5ceSopenharmony_ci
1078d4afb5ceSopenharmony_ci		if (*p == '-')
1079d4afb5ceSopenharmony_ci			break;
1080d4afb5ceSopenharmony_ci
1081d4afb5ceSopenharmony_ci		if (*p == '+')
1082d4afb5ceSopenharmony_ci			*csr++ = '-';
1083d4afb5ceSopenharmony_ci		else
1084d4afb5ceSopenharmony_ci			if (*p == '/')
1085d4afb5ceSopenharmony_ci				*csr++ = '_';
1086d4afb5ceSopenharmony_ci			else
1087d4afb5ceSopenharmony_ci				*csr++ = (uint8_t)*p;
1088d4afb5ceSopenharmony_ci		p++;
1089d4afb5ceSopenharmony_ci		csr_len--;
1090d4afb5ceSopenharmony_ci	}
1091d4afb5ceSopenharmony_ci	BIO_free(bio);
1092d4afb5ceSopenharmony_ci	if (!csr_len) {
1093d4afb5ceSopenharmony_ci		lwsl_notice("%s: need %ld for CSR\n", __func__, bio_len);
1094d4afb5ceSopenharmony_ci		goto bail3;
1095d4afb5ceSopenharmony_ci	}
1096d4afb5ceSopenharmony_ci
1097d4afb5ceSopenharmony_ci	/*
1098d4afb5ceSopenharmony_ci	 * Also return the private key as a PEM in memory
1099d4afb5ceSopenharmony_ci	 * (platform may not have a filesystem)
1100d4afb5ceSopenharmony_ci	 */
1101d4afb5ceSopenharmony_ci	bio = BIO_new(BIO_s_mem());
1102d4afb5ceSopenharmony_ci	if (!bio)
1103d4afb5ceSopenharmony_ci		goto bail3;
1104d4afb5ceSopenharmony_ci
1105d4afb5ceSopenharmony_ci	if (PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, 0, NULL) != 1) {
1106d4afb5ceSopenharmony_ci		BIO_free(bio);
1107d4afb5ceSopenharmony_ci		goto bail3;
1108d4afb5ceSopenharmony_ci	}
1109d4afb5ceSopenharmony_ci	bio_len = BIO_get_mem_data(bio, &p);
1110d4afb5ceSopenharmony_ci	*privkey_pem = malloc((unsigned long)bio_len); /* malloc so user code can own / free */
1111d4afb5ceSopenharmony_ci	*privkey_len = (size_t)bio_len;
1112d4afb5ceSopenharmony_ci	if (!*privkey_pem) {
1113d4afb5ceSopenharmony_ci		lwsl_notice("%s: need %ld for private key\n", __func__,
1114d4afb5ceSopenharmony_ci			    bio_len);
1115d4afb5ceSopenharmony_ci		BIO_free(bio);
1116d4afb5ceSopenharmony_ci		goto bail3;
1117d4afb5ceSopenharmony_ci	}
1118d4afb5ceSopenharmony_ci	memcpy(*privkey_pem, p, (unsigned int)(int)(long long)bio_len);
1119d4afb5ceSopenharmony_ci	BIO_free(bio);
1120d4afb5ceSopenharmony_ci
1121d4afb5ceSopenharmony_ci	ret = lws_ptr_diff(csr, csr_in);
1122d4afb5ceSopenharmony_ci
1123d4afb5ceSopenharmony_cibail3:
1124d4afb5ceSopenharmony_ci	X509_NAME_free(subj);
1125d4afb5ceSopenharmony_cibail2:
1126d4afb5ceSopenharmony_ci	X509_REQ_free(req);
1127d4afb5ceSopenharmony_cibail1:
1128d4afb5ceSopenharmony_ci	EVP_PKEY_free(pkey);
1129d4afb5ceSopenharmony_cibail0:
1130d4afb5ceSopenharmony_ci	RSA_free(rsakey);
1131d4afb5ceSopenharmony_ci
1132d4afb5ceSopenharmony_ci	return ret;
1133d4afb5ceSopenharmony_ci}
1134d4afb5ceSopenharmony_ci#endif
1135