1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci#include "private-lib-tls.h"
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci#if defined(LWS_WITH_NETWORK)
29d4afb5ceSopenharmony_ci#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
30d4afb5ceSopenharmony_ci				  OPENSSL_VERSION_NUMBER >= 0x10002000L)
31d4afb5ceSopenharmony_cistatic int
32d4afb5ceSopenharmony_cialpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen,
33d4afb5ceSopenharmony_ci	const unsigned char *in, unsigned int inlen, void *arg)
34d4afb5ceSopenharmony_ci{
35d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_MBEDTLS)
36d4afb5ceSopenharmony_ci	struct alpn_ctx *alpn_ctx = (struct alpn_ctx *)arg;
37d4afb5ceSopenharmony_ci
38d4afb5ceSopenharmony_ci	if (SSL_select_next_proto((unsigned char **)out, outlen, alpn_ctx->data,
39d4afb5ceSopenharmony_ci				  alpn_ctx->len, in, inlen) !=
40d4afb5ceSopenharmony_ci	    OPENSSL_NPN_NEGOTIATED)
41d4afb5ceSopenharmony_ci		return SSL_TLSEXT_ERR_NOACK;
42d4afb5ceSopenharmony_ci#endif
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ci	return SSL_TLSEXT_ERR_OK;
45d4afb5ceSopenharmony_ci}
46d4afb5ceSopenharmony_ci#endif
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_ciint
49d4afb5ceSopenharmony_cilws_tls_restrict_borrow(struct lws *wsi)
50d4afb5ceSopenharmony_ci{
51d4afb5ceSopenharmony_ci	struct lws_context *cx = wsi->a.context;
52d4afb5ceSopenharmony_ci
53d4afb5ceSopenharmony_ci	if (cx->simultaneous_ssl_restriction &&
54d4afb5ceSopenharmony_ci	    cx->simultaneous_ssl >= cx->simultaneous_ssl_restriction) {
55d4afb5ceSopenharmony_ci		lwsl_notice("%s: tls connection limit %d\n", __func__,
56d4afb5ceSopenharmony_ci			    cx->simultaneous_ssl);
57d4afb5ceSopenharmony_ci		return 1;
58d4afb5ceSopenharmony_ci	}
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_ci	if (cx->simultaneous_ssl_handshake_restriction &&
61d4afb5ceSopenharmony_ci	    cx->simultaneous_ssl_handshake >=
62d4afb5ceSopenharmony_ci			    cx->simultaneous_ssl_handshake_restriction) {
63d4afb5ceSopenharmony_ci		lwsl_notice("%s: tls handshake limit %d\n", __func__,
64d4afb5ceSopenharmony_ci			    cx->simultaneous_ssl);
65d4afb5ceSopenharmony_ci		return 1;
66d4afb5ceSopenharmony_ci	}
67d4afb5ceSopenharmony_ci
68d4afb5ceSopenharmony_ci	cx->simultaneous_ssl++;
69d4afb5ceSopenharmony_ci	cx->simultaneous_ssl_handshake++;
70d4afb5ceSopenharmony_ci	wsi->tls_borrowed_hs = 1;
71d4afb5ceSopenharmony_ci	wsi->tls_borrowed = 1;
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci	lwsl_info("%s: %d -> %d\n", __func__,
74d4afb5ceSopenharmony_ci		  cx->simultaneous_ssl - 1,
75d4afb5ceSopenharmony_ci		  cx->simultaneous_ssl);
76d4afb5ceSopenharmony_ci
77d4afb5ceSopenharmony_ci	assert(!cx->simultaneous_ssl_restriction ||
78d4afb5ceSopenharmony_ci			cx->simultaneous_ssl <=
79d4afb5ceSopenharmony_ci				cx->simultaneous_ssl_restriction);
80d4afb5ceSopenharmony_ci	assert(!cx->simultaneous_ssl_handshake_restriction ||
81d4afb5ceSopenharmony_ci			cx->simultaneous_ssl_handshake <=
82d4afb5ceSopenharmony_ci				cx->simultaneous_ssl_handshake_restriction);
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
85d4afb5ceSopenharmony_ci	lws_gate_accepts(cx,
86d4afb5ceSopenharmony_ci			(cx->simultaneous_ssl_restriction &&
87d4afb5ceSopenharmony_ci			 cx->simultaneous_ssl == cx->simultaneous_ssl_restriction) ||
88d4afb5ceSopenharmony_ci			(cx->simultaneous_ssl_handshake_restriction &&
89d4afb5ceSopenharmony_ci			 cx->simultaneous_ssl_handshake == cx->simultaneous_ssl_handshake_restriction));
90d4afb5ceSopenharmony_ci#endif
91d4afb5ceSopenharmony_ci
92d4afb5ceSopenharmony_ci	return 0;
93d4afb5ceSopenharmony_ci}
94d4afb5ceSopenharmony_ci
95d4afb5ceSopenharmony_cistatic void
96d4afb5ceSopenharmony_ci_lws_tls_restrict_return(struct lws *wsi)
97d4afb5ceSopenharmony_ci{
98d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
99d4afb5ceSopenharmony_ci	struct lws_context *cx = wsi->a.context;
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ci	assert(cx->simultaneous_ssl_handshake >= 0);
102d4afb5ceSopenharmony_ci	assert(cx->simultaneous_ssl >= 0);
103d4afb5ceSopenharmony_ci
104d4afb5ceSopenharmony_ci	lws_gate_accepts(cx,
105d4afb5ceSopenharmony_ci			(cx->simultaneous_ssl_restriction &&
106d4afb5ceSopenharmony_ci			 cx->simultaneous_ssl == cx->simultaneous_ssl_restriction) ||
107d4afb5ceSopenharmony_ci			(cx->simultaneous_ssl_handshake_restriction &&
108d4afb5ceSopenharmony_ci			 cx->simultaneous_ssl_handshake == cx->simultaneous_ssl_handshake_restriction));
109d4afb5ceSopenharmony_ci#endif
110d4afb5ceSopenharmony_ci}
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_civoid
113d4afb5ceSopenharmony_cilws_tls_restrict_return_handshake(struct lws *wsi)
114d4afb5ceSopenharmony_ci{
115d4afb5ceSopenharmony_ci	struct lws_context *cx = wsi->a.context;
116d4afb5ceSopenharmony_ci
117d4afb5ceSopenharmony_ci	/* we're just returning the hs part */
118d4afb5ceSopenharmony_ci
119d4afb5ceSopenharmony_ci	if (!wsi->tls_borrowed_hs)
120d4afb5ceSopenharmony_ci		return;
121d4afb5ceSopenharmony_ci
122d4afb5ceSopenharmony_ci	wsi->tls_borrowed_hs = 0; /* return it one time per wsi */
123d4afb5ceSopenharmony_ci	cx->simultaneous_ssl_handshake--;
124d4afb5ceSopenharmony_ci
125d4afb5ceSopenharmony_ci	lwsl_info("%s:  %d -> %d\n", __func__,
126d4afb5ceSopenharmony_ci		  cx->simultaneous_ssl_handshake + 1,
127d4afb5ceSopenharmony_ci		  cx->simultaneous_ssl_handshake);
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci	_lws_tls_restrict_return(wsi);
130d4afb5ceSopenharmony_ci}
131d4afb5ceSopenharmony_ci
132d4afb5ceSopenharmony_civoid
133d4afb5ceSopenharmony_cilws_tls_restrict_return(struct lws *wsi)
134d4afb5ceSopenharmony_ci{
135d4afb5ceSopenharmony_ci	struct lws_context *cx = wsi->a.context;
136d4afb5ceSopenharmony_ci
137d4afb5ceSopenharmony_ci	if (!wsi->tls_borrowed)
138d4afb5ceSopenharmony_ci		return;
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci	wsi->tls_borrowed = 0;
141d4afb5ceSopenharmony_ci	cx->simultaneous_ssl--;
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci	lwsl_info("%s: %d -> %d\n", __func__,
144d4afb5ceSopenharmony_ci		  cx->simultaneous_ssl + 1,
145d4afb5ceSopenharmony_ci		  cx->simultaneous_ssl);
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ci	/* We're returning everything, even if hs didn't complete */
148d4afb5ceSopenharmony_ci
149d4afb5ceSopenharmony_ci	if (wsi->tls_borrowed_hs)
150d4afb5ceSopenharmony_ci		lws_tls_restrict_return_handshake(wsi);
151d4afb5ceSopenharmony_ci	else
152d4afb5ceSopenharmony_ci		_lws_tls_restrict_return(wsi);
153d4afb5ceSopenharmony_ci}
154d4afb5ceSopenharmony_ci
155d4afb5ceSopenharmony_civoid
156d4afb5ceSopenharmony_cilws_context_init_alpn(struct lws_vhost *vhost)
157d4afb5ceSopenharmony_ci{
158d4afb5ceSopenharmony_ci#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
159d4afb5ceSopenharmony_ci				  OPENSSL_VERSION_NUMBER >= 0x10002000L)
160d4afb5ceSopenharmony_ci	const char *alpn_comma = vhost->context->tls.alpn_default;
161d4afb5ceSopenharmony_ci
162d4afb5ceSopenharmony_ci	if (vhost->tls.alpn)
163d4afb5ceSopenharmony_ci		alpn_comma = vhost->tls.alpn;
164d4afb5ceSopenharmony_ci
165d4afb5ceSopenharmony_ci	lwsl_info(" Server '%s' advertising ALPN: %s\n",
166d4afb5ceSopenharmony_ci		    vhost->name, alpn_comma);
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci	vhost->tls.alpn_ctx.len = (uint8_t)lws_alpn_comma_to_openssl(alpn_comma,
169d4afb5ceSopenharmony_ci					vhost->tls.alpn_ctx.data,
170d4afb5ceSopenharmony_ci					sizeof(vhost->tls.alpn_ctx.data) - 1);
171d4afb5ceSopenharmony_ci
172d4afb5ceSopenharmony_ci	SSL_CTX_set_alpn_select_cb(vhost->tls.ssl_ctx, alpn_cb,
173d4afb5ceSopenharmony_ci				   &vhost->tls.alpn_ctx);
174d4afb5ceSopenharmony_ci#else
175d4afb5ceSopenharmony_ci	lwsl_err(" HTTP2 / ALPN configured "
176d4afb5ceSopenharmony_ci		 "but not supported by OpenSSL 0x%lx\n",
177d4afb5ceSopenharmony_ci		 OPENSSL_VERSION_NUMBER);
178d4afb5ceSopenharmony_ci#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
179d4afb5ceSopenharmony_ci}
180d4afb5ceSopenharmony_ci
181d4afb5ceSopenharmony_ciint
182d4afb5ceSopenharmony_cilws_tls_server_conn_alpn(struct lws *wsi)
183d4afb5ceSopenharmony_ci{
184d4afb5ceSopenharmony_ci#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
185d4afb5ceSopenharmony_ci				  OPENSSL_VERSION_NUMBER >= 0x10002000L)
186d4afb5ceSopenharmony_ci	const unsigned char *name = NULL;
187d4afb5ceSopenharmony_ci	char cstr[10];
188d4afb5ceSopenharmony_ci	unsigned len;
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ci	lwsl_info("%s\n", __func__);
191d4afb5ceSopenharmony_ci
192d4afb5ceSopenharmony_ci	if (!wsi->tls.ssl) {
193d4afb5ceSopenharmony_ci		lwsl_err("%s: non-ssl\n", __func__);
194d4afb5ceSopenharmony_ci		return 0;
195d4afb5ceSopenharmony_ci	}
196d4afb5ceSopenharmony_ci
197d4afb5ceSopenharmony_ci	SSL_get0_alpn_selected(wsi->tls.ssl, &name, &len);
198d4afb5ceSopenharmony_ci	if (!len) {
199d4afb5ceSopenharmony_ci		lwsl_info("no ALPN upgrade\n");
200d4afb5ceSopenharmony_ci		return 0;
201d4afb5ceSopenharmony_ci	}
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ci	if (len > sizeof(cstr) - 1)
204d4afb5ceSopenharmony_ci		len = sizeof(cstr) - 1;
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci	memcpy(cstr, name, len);
207d4afb5ceSopenharmony_ci	cstr[len] = '\0';
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci	lwsl_info("%s: negotiated '%s' using ALPN\n", __func__, cstr);
210d4afb5ceSopenharmony_ci	wsi->tls.use_ssl |= LCCSCF_USE_SSL;
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci	return lws_role_call_alpn_negotiated(wsi, (const char *)cstr);
213d4afb5ceSopenharmony_ci#else
214d4afb5ceSopenharmony_ci	lwsl_err("%s: openssl too old\n", __func__);
215d4afb5ceSopenharmony_ci#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_ci	return 0;
218d4afb5ceSopenharmony_ci}
219d4afb5ceSopenharmony_ci#endif
220d4afb5ceSopenharmony_ci
221d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
222d4afb5ceSopenharmony_ci#if defined(LWS_PLAT_FREERTOS) && !defined(LWS_AMAZON_RTOS)
223d4afb5ceSopenharmony_ciint alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
224d4afb5ceSopenharmony_ci	       lws_filepos_t *amount)
225d4afb5ceSopenharmony_ci{
226d4afb5ceSopenharmony_ci	nvs_handle nvh;
227d4afb5ceSopenharmony_ci	size_t s;
228d4afb5ceSopenharmony_ci	int n = 0;
229d4afb5ceSopenharmony_ci
230d4afb5ceSopenharmony_ci	ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
231d4afb5ceSopenharmony_ci	if (nvs_get_blob(nvh, filename, NULL, &s) != ESP_OK) {
232d4afb5ceSopenharmony_ci		n = 1;
233d4afb5ceSopenharmony_ci		goto bail;
234d4afb5ceSopenharmony_ci	}
235d4afb5ceSopenharmony_ci	*buf = lws_malloc(s + 1, "alloc_file");
236d4afb5ceSopenharmony_ci	if (!*buf) {
237d4afb5ceSopenharmony_ci		n = 2;
238d4afb5ceSopenharmony_ci		goto bail;
239d4afb5ceSopenharmony_ci	}
240d4afb5ceSopenharmony_ci	if (nvs_get_blob(nvh, filename, (char *)*buf, &s) != ESP_OK) {
241d4afb5ceSopenharmony_ci		lws_free(*buf);
242d4afb5ceSopenharmony_ci		n = 1;
243d4afb5ceSopenharmony_ci		goto bail;
244d4afb5ceSopenharmony_ci	}
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci	*amount = s;
247d4afb5ceSopenharmony_ci	(*buf)[s] = '\0';
248d4afb5ceSopenharmony_ci
249d4afb5ceSopenharmony_ci	lwsl_notice("%s: nvs: read %s, %d bytes\n", __func__, filename, (int)s);
250d4afb5ceSopenharmony_ci
251d4afb5ceSopenharmony_cibail:
252d4afb5ceSopenharmony_ci	nvs_close(nvh);
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ci	return n;
255d4afb5ceSopenharmony_ci}
256d4afb5ceSopenharmony_ci#else
257d4afb5ceSopenharmony_ciint alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
258d4afb5ceSopenharmony_ci		lws_filepos_t *amount)
259d4afb5ceSopenharmony_ci{
260d4afb5ceSopenharmony_ci	FILE *f;
261d4afb5ceSopenharmony_ci	size_t s;
262d4afb5ceSopenharmony_ci	ssize_t m;
263d4afb5ceSopenharmony_ci	int n = 0;
264d4afb5ceSopenharmony_ci
265d4afb5ceSopenharmony_ci	f = fopen(filename, "rb");
266d4afb5ceSopenharmony_ci	if (f == NULL) {
267d4afb5ceSopenharmony_ci		n = 1;
268d4afb5ceSopenharmony_ci		goto bail;
269d4afb5ceSopenharmony_ci	}
270d4afb5ceSopenharmony_ci
271d4afb5ceSopenharmony_ci	if (fseek(f, 0, SEEK_END) != 0) {
272d4afb5ceSopenharmony_ci		n = 1;
273d4afb5ceSopenharmony_ci		goto bail;
274d4afb5ceSopenharmony_ci	}
275d4afb5ceSopenharmony_ci
276d4afb5ceSopenharmony_ci	m = (ssize_t)ftell(f);
277d4afb5ceSopenharmony_ci	if (m == -1l) {
278d4afb5ceSopenharmony_ci		n = 1;
279d4afb5ceSopenharmony_ci		goto bail;
280d4afb5ceSopenharmony_ci	}
281d4afb5ceSopenharmony_ci	s = (size_t)m;
282d4afb5ceSopenharmony_ci
283d4afb5ceSopenharmony_ci	if (fseek(f, 0, SEEK_SET) != 0) {
284d4afb5ceSopenharmony_ci		n = 1;
285d4afb5ceSopenharmony_ci		goto bail;
286d4afb5ceSopenharmony_ci	}
287d4afb5ceSopenharmony_ci
288d4afb5ceSopenharmony_ci	*buf = lws_malloc(s + 1, "alloc_file");
289d4afb5ceSopenharmony_ci	if (!*buf) {
290d4afb5ceSopenharmony_ci		n = 2;
291d4afb5ceSopenharmony_ci		goto bail;
292d4afb5ceSopenharmony_ci	}
293d4afb5ceSopenharmony_ci
294d4afb5ceSopenharmony_ci	if (fread(*buf, s, 1, f) != 1) {
295d4afb5ceSopenharmony_ci		lws_free(*buf);
296d4afb5ceSopenharmony_ci		n = 1;
297d4afb5ceSopenharmony_ci		goto bail;
298d4afb5ceSopenharmony_ci	}
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci	*amount = s;
301d4afb5ceSopenharmony_ci
302d4afb5ceSopenharmony_cibail:
303d4afb5ceSopenharmony_ci	if (f)
304d4afb5ceSopenharmony_ci		fclose(f);
305d4afb5ceSopenharmony_ci
306d4afb5ceSopenharmony_ci	return n;
307d4afb5ceSopenharmony_ci
308d4afb5ceSopenharmony_ci}
309d4afb5ceSopenharmony_ci#endif
310d4afb5ceSopenharmony_ci
311d4afb5ceSopenharmony_ci/*
312d4afb5ceSopenharmony_ci * filename: NULL means use buffer inbuf length inlen directly, otherwise
313d4afb5ceSopenharmony_ci *           load the file "filename" into an allocated buffer.
314d4afb5ceSopenharmony_ci *
315d4afb5ceSopenharmony_ci * Allocates a separate DER output buffer if inbuf / inlen are the input,
316d4afb5ceSopenharmony_ci * since the
317d4afb5ceSopenharmony_ci *
318d4afb5ceSopenharmony_ci * Contents may be PEM or DER: returns with buf pointing to DER and amount
319d4afb5ceSopenharmony_ci * set to the DER length.
320d4afb5ceSopenharmony_ci */
321d4afb5ceSopenharmony_ci
322d4afb5ceSopenharmony_ciint
323d4afb5ceSopenharmony_cilws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
324d4afb5ceSopenharmony_ci			      const char *inbuf, lws_filepos_t inlen,
325d4afb5ceSopenharmony_ci			      uint8_t **buf, lws_filepos_t *amount)
326d4afb5ceSopenharmony_ci{
327d4afb5ceSopenharmony_ci	uint8_t *pem = NULL, *p, *end, *opem;
328d4afb5ceSopenharmony_ci	lws_filepos_t len;
329d4afb5ceSopenharmony_ci	uint8_t *q;
330d4afb5ceSopenharmony_ci	int n;
331d4afb5ceSopenharmony_ci
332d4afb5ceSopenharmony_ci	if (filename) {
333d4afb5ceSopenharmony_ci		n = alloc_file(context, filename, (uint8_t **)&pem, &len);
334d4afb5ceSopenharmony_ci		if (n)
335d4afb5ceSopenharmony_ci			return n;
336d4afb5ceSopenharmony_ci	} else {
337d4afb5ceSopenharmony_ci		pem = (uint8_t *)inbuf;
338d4afb5ceSopenharmony_ci		len = inlen;
339d4afb5ceSopenharmony_ci	}
340d4afb5ceSopenharmony_ci
341d4afb5ceSopenharmony_ci	opem = p = pem;
342d4afb5ceSopenharmony_ci	end = p + len;
343d4afb5ceSopenharmony_ci
344d4afb5ceSopenharmony_ci	if (strncmp((char *)p, "-----", 5)) {
345d4afb5ceSopenharmony_ci
346d4afb5ceSopenharmony_ci		/* take it as being already DER */
347d4afb5ceSopenharmony_ci
348d4afb5ceSopenharmony_ci		pem = lws_malloc((size_t)inlen, "alloc_der");
349d4afb5ceSopenharmony_ci		if (!pem)
350d4afb5ceSopenharmony_ci			return 1;
351d4afb5ceSopenharmony_ci
352d4afb5ceSopenharmony_ci		memcpy(pem, inbuf, (size_t)inlen);
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci		*buf = pem;
355d4afb5ceSopenharmony_ci		*amount = inlen;
356d4afb5ceSopenharmony_ci
357d4afb5ceSopenharmony_ci		return 0;
358d4afb5ceSopenharmony_ci	}
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci	/* PEM -> DER */
361d4afb5ceSopenharmony_ci
362d4afb5ceSopenharmony_ci	if (!filename) {
363d4afb5ceSopenharmony_ci		/* we don't know if it's in const memory... alloc the output */
364d4afb5ceSopenharmony_ci		pem = lws_malloc(((size_t)inlen * 3) / 4, "alloc_der");
365d4afb5ceSopenharmony_ci		if (!pem) {
366d4afb5ceSopenharmony_ci			lwsl_err("a\n");
367d4afb5ceSopenharmony_ci			return 1;
368d4afb5ceSopenharmony_ci		}
369d4afb5ceSopenharmony_ci
370d4afb5ceSopenharmony_ci
371d4afb5ceSopenharmony_ci	} /* else overwrite the allocated, b64 input with decoded DER */
372d4afb5ceSopenharmony_ci
373d4afb5ceSopenharmony_ci	/* trim the first line */
374d4afb5ceSopenharmony_ci
375d4afb5ceSopenharmony_ci	p += 5;
376d4afb5ceSopenharmony_ci	while (p < end && *p != '\n' && *p != '-')
377d4afb5ceSopenharmony_ci		p++;
378d4afb5ceSopenharmony_ci
379d4afb5ceSopenharmony_ci	if (*p != '-') {
380d4afb5ceSopenharmony_ci		goto bail;
381d4afb5ceSopenharmony_ci	}
382d4afb5ceSopenharmony_ci
383d4afb5ceSopenharmony_ci	while (p < end && *p != '\n')
384d4afb5ceSopenharmony_ci		p++;
385d4afb5ceSopenharmony_ci
386d4afb5ceSopenharmony_ci	if (p >= end) {
387d4afb5ceSopenharmony_ci		goto bail;
388d4afb5ceSopenharmony_ci	}
389d4afb5ceSopenharmony_ci
390d4afb5ceSopenharmony_ci	p++;
391d4afb5ceSopenharmony_ci
392d4afb5ceSopenharmony_ci	/* trim the last line */
393d4afb5ceSopenharmony_ci
394d4afb5ceSopenharmony_ci	q = (uint8_t *)end - 2;
395d4afb5ceSopenharmony_ci
396d4afb5ceSopenharmony_ci	while (q > opem && *q != '\n')
397d4afb5ceSopenharmony_ci		q--;
398d4afb5ceSopenharmony_ci
399d4afb5ceSopenharmony_ci	if (*q != '\n')
400d4afb5ceSopenharmony_ci		goto bail;
401d4afb5ceSopenharmony_ci
402d4afb5ceSopenharmony_ci	/* we can't write into the input buffer for mem, since it may be in RO
403d4afb5ceSopenharmony_ci	 * const segment
404d4afb5ceSopenharmony_ci	 */
405d4afb5ceSopenharmony_ci	if (filename)
406d4afb5ceSopenharmony_ci		*q = '\0';
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_ci	n = lws_ptr_diff(q, p);
409d4afb5ceSopenharmony_ci	if (n == -1) /* coverity */
410d4afb5ceSopenharmony_ci		goto bail;
411d4afb5ceSopenharmony_ci	*amount = (unsigned int)lws_b64_decode_string_len((char *)p, n,
412d4afb5ceSopenharmony_ci					    (char *)pem, (int)(long long)len);
413d4afb5ceSopenharmony_ci	*buf = (uint8_t *)pem;
414d4afb5ceSopenharmony_ci
415d4afb5ceSopenharmony_ci	return 0;
416d4afb5ceSopenharmony_ci
417d4afb5ceSopenharmony_cibail:
418d4afb5ceSopenharmony_ci	lws_free((uint8_t *)pem);
419d4afb5ceSopenharmony_ci
420d4afb5ceSopenharmony_ci	return 4;
421d4afb5ceSopenharmony_ci}
422d4afb5ceSopenharmony_ci
423d4afb5ceSopenharmony_ci
424d4afb5ceSopenharmony_ci#endif
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
427d4afb5ceSopenharmony_ci
428d4afb5ceSopenharmony_ci
429d4afb5ceSopenharmony_cistatic int
430d4afb5ceSopenharmony_cilws_tls_extant(const char *name)
431d4afb5ceSopenharmony_ci{
432d4afb5ceSopenharmony_ci	/* it exists if we can open it... */
433d4afb5ceSopenharmony_ci	int fd = open(name, O_RDONLY);
434d4afb5ceSopenharmony_ci	char buf[1];
435d4afb5ceSopenharmony_ci	ssize_t n;
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_ci	if (fd < 0)
438d4afb5ceSopenharmony_ci		return 1;
439d4afb5ceSopenharmony_ci
440d4afb5ceSopenharmony_ci	/* and we can read at least one byte out of it */
441d4afb5ceSopenharmony_ci	n = read(fd, buf, 1);
442d4afb5ceSopenharmony_ci	close(fd);
443d4afb5ceSopenharmony_ci
444d4afb5ceSopenharmony_ci	return n != 1;
445d4afb5ceSopenharmony_ci}
446d4afb5ceSopenharmony_ci#endif
447d4afb5ceSopenharmony_ci/*
448d4afb5ceSopenharmony_ci * Returns 0 if the filepath "name" exists and can be read from.
449d4afb5ceSopenharmony_ci *
450d4afb5ceSopenharmony_ci * In addition, if "name".upd exists, backup "name" to "name.old.1"
451d4afb5ceSopenharmony_ci * and rename "name".upd to "name" before reporting its existence.
452d4afb5ceSopenharmony_ci *
453d4afb5ceSopenharmony_ci * There are four situations and three results possible:
454d4afb5ceSopenharmony_ci *
455d4afb5ceSopenharmony_ci * 1) LWS_TLS_EXTANT_NO: There are no certs at all (we are waiting for them to
456d4afb5ceSopenharmony_ci *    be provisioned).  We also feel like this if we need privs we don't have
457d4afb5ceSopenharmony_ci *    any more to look in the directory.
458d4afb5ceSopenharmony_ci *
459d4afb5ceSopenharmony_ci * 2) There are provisioned certs written (xxx.upd) and we still have root
460d4afb5ceSopenharmony_ci *    privs... in this case we rename any existing cert to have a backup name
461d4afb5ceSopenharmony_ci *    and move the upd cert into place with the correct name.  This then becomes
462d4afb5ceSopenharmony_ci *    situation 4 for the caller.
463d4afb5ceSopenharmony_ci *
464d4afb5ceSopenharmony_ci * 3) LWS_TLS_EXTANT_ALTERNATIVE: There are provisioned certs written (xxx.upd)
465d4afb5ceSopenharmony_ci *    but we no longer have the privs needed to read or rename them.  In this
466d4afb5ceSopenharmony_ci *    case, indicate that the caller should use temp copies if any we do have
467d4afb5ceSopenharmony_ci *    rights to access.  This is normal after we have updated the cert.
468d4afb5ceSopenharmony_ci *
469d4afb5ceSopenharmony_ci *    But if we dropped privs, we can't detect the provisioned xxx.upd cert +
470d4afb5ceSopenharmony_ci *    key, because we can't see in the dir.  So we have to upgrade NO to
471d4afb5ceSopenharmony_ci *    ALTERNATIVE when we actually have the in-memory alternative.
472d4afb5ceSopenharmony_ci *
473d4afb5ceSopenharmony_ci * 4) LWS_TLS_EXTANT_YES: The certs are present with the correct name and we
474d4afb5ceSopenharmony_ci *    have the rights to read them.
475d4afb5ceSopenharmony_ci */
476d4afb5ceSopenharmony_ci
477d4afb5ceSopenharmony_cienum lws_tls_extant
478d4afb5ceSopenharmony_cilws_tls_use_any_upgrade_check_extant(const char *name)
479d4afb5ceSopenharmony_ci{
480d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_AMAZON_RTOS)
481d4afb5ceSopenharmony_ci
482d4afb5ceSopenharmony_ci	int n;
483d4afb5ceSopenharmony_ci
484d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS)
485d4afb5ceSopenharmony_ci	char buf[256];
486d4afb5ceSopenharmony_ci
487d4afb5ceSopenharmony_ci	lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", name);
488d4afb5ceSopenharmony_ci	if (!lws_tls_extant(buf)) {
489d4afb5ceSopenharmony_ci		/* ah there is an updated file... how about the desired file? */
490d4afb5ceSopenharmony_ci		if (!lws_tls_extant(name)) {
491d4afb5ceSopenharmony_ci			/* rename the desired file */
492d4afb5ceSopenharmony_ci			for (n = 0; n < 50; n++) {
493d4afb5ceSopenharmony_ci				lws_snprintf(buf, sizeof(buf) - 1,
494d4afb5ceSopenharmony_ci					     "%s.old.%d", name, n);
495d4afb5ceSopenharmony_ci				if (!rename(name, buf))
496d4afb5ceSopenharmony_ci					break;
497d4afb5ceSopenharmony_ci			}
498d4afb5ceSopenharmony_ci			if (n == 50) {
499d4afb5ceSopenharmony_ci				lwsl_notice("unable to rename %s\n", name);
500d4afb5ceSopenharmony_ci
501d4afb5ceSopenharmony_ci				return LWS_TLS_EXTANT_ALTERNATIVE;
502d4afb5ceSopenharmony_ci			}
503d4afb5ceSopenharmony_ci			lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", name);
504d4afb5ceSopenharmony_ci		}
505d4afb5ceSopenharmony_ci		/* desired file is out of the way, rename the updated file */
506d4afb5ceSopenharmony_ci		if (rename(buf, name)) {
507d4afb5ceSopenharmony_ci			lwsl_notice("unable to rename %s to %s\n", buf, name);
508d4afb5ceSopenharmony_ci
509d4afb5ceSopenharmony_ci			return LWS_TLS_EXTANT_ALTERNATIVE;
510d4afb5ceSopenharmony_ci		}
511d4afb5ceSopenharmony_ci	}
512d4afb5ceSopenharmony_ci
513d4afb5ceSopenharmony_ci	if (lws_tls_extant(name))
514d4afb5ceSopenharmony_ci		return LWS_TLS_EXTANT_NO;
515d4afb5ceSopenharmony_ci#else
516d4afb5ceSopenharmony_ci	nvs_handle nvh;
517d4afb5ceSopenharmony_ci	size_t s = 8192;
518d4afb5ceSopenharmony_ci
519d4afb5ceSopenharmony_ci	if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
520d4afb5ceSopenharmony_ci		lwsl_notice("%s: can't open nvs\n", __func__);
521d4afb5ceSopenharmony_ci		return LWS_TLS_EXTANT_NO;
522d4afb5ceSopenharmony_ci	}
523d4afb5ceSopenharmony_ci
524d4afb5ceSopenharmony_ci	n = nvs_get_blob(nvh, name, NULL, &s);
525d4afb5ceSopenharmony_ci	nvs_close(nvh);
526d4afb5ceSopenharmony_ci
527d4afb5ceSopenharmony_ci	if (n)
528d4afb5ceSopenharmony_ci		return LWS_TLS_EXTANT_NO;
529d4afb5ceSopenharmony_ci#endif
530d4afb5ceSopenharmony_ci#endif
531d4afb5ceSopenharmony_ci	return LWS_TLS_EXTANT_YES;
532d4afb5ceSopenharmony_ci}
533