1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_civoid
28d4afb5ceSopenharmony_cilws_tls_kid_copy(union lws_tls_cert_info_results *ci, lws_tls_kid_t *kid)
29d4afb5ceSopenharmony_ci{
30d4afb5ceSopenharmony_ci
31d4afb5ceSopenharmony_ci	/*
32d4afb5ceSopenharmony_ci	 * KIDs all seem to be 20 bytes / SHA1 or less.  If we get one that
33d4afb5ceSopenharmony_ci	 * is bigger, treat only the first 20 bytes as significant.
34d4afb5ceSopenharmony_ci	 */
35d4afb5ceSopenharmony_ci
36d4afb5ceSopenharmony_ci	if ((size_t)ci->ns.len > sizeof(kid->kid))
37d4afb5ceSopenharmony_ci		kid->kid_len = sizeof(kid->kid);
38d4afb5ceSopenharmony_ci	else
39d4afb5ceSopenharmony_ci		kid->kid_len = (uint8_t)ci->ns.len;
40d4afb5ceSopenharmony_ci
41d4afb5ceSopenharmony_ci	memcpy(kid->kid, ci->ns.name, kid->kid_len);
42d4afb5ceSopenharmony_ci}
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_civoid
45d4afb5ceSopenharmony_cilws_tls_kid_copy_kid(lws_tls_kid_t *kid, const lws_tls_kid_t *src)
46d4afb5ceSopenharmony_ci{
47d4afb5ceSopenharmony_ci	int klen = sizeof(kid->kid);
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci	if (src->kid_len < klen)
50d4afb5ceSopenharmony_ci		klen = src->kid_len;
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_ci	kid->kid_len = (uint8_t)klen;
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci	memcpy(kid->kid, src->kid, (size_t)klen);
55d4afb5ceSopenharmony_ci}
56d4afb5ceSopenharmony_ci
57d4afb5ceSopenharmony_ciint
58d4afb5ceSopenharmony_cilws_tls_kid_cmp(const lws_tls_kid_t *a, const lws_tls_kid_t *b)
59d4afb5ceSopenharmony_ci{
60d4afb5ceSopenharmony_ci	if (a->kid_len != b->kid_len)
61d4afb5ceSopenharmony_ci		return 1;
62d4afb5ceSopenharmony_ci
63d4afb5ceSopenharmony_ci	return memcmp(a->kid, b->kid, a->kid_len);
64d4afb5ceSopenharmony_ci}
65d4afb5ceSopenharmony_ci
66d4afb5ceSopenharmony_ci/*
67d4afb5ceSopenharmony_ci * We have the SKID and AKID for every peer cert captured, but they may be
68d4afb5ceSopenharmony_ci * in any order, and eg, falsely have sent the root CA, or an attacker may
69d4afb5ceSopenharmony_ci * send unresolveable self-referencing loops of KIDs.
70d4afb5ceSopenharmony_ci *
71d4afb5ceSopenharmony_ci * Let's sort them into the SKID -> AKID hierarchy, so the last entry is the
72d4afb5ceSopenharmony_ci * server cert and the first entry is the highest parent that the server sent.
73d4afb5ceSopenharmony_ci * Normally the top one will be an intermediate, and its AKID is the ID of the
74d4afb5ceSopenharmony_ci * root CA cert we would need to trust to validate the chain.
75d4afb5ceSopenharmony_ci *
76d4afb5ceSopenharmony_ci * It's not unknown the server is misconfigured to also send the root CA, if so
77d4afb5ceSopenharmony_ci * the top slot's AKID is empty and we should look for its SKID in the trust
78d4afb5ceSopenharmony_ci * blob.
79d4afb5ceSopenharmony_ci *
80d4afb5ceSopenharmony_ci * If we return 0, we succeeded and the AKID of ch[0] is the SKID we want to see
81d4afb5ceSopenharmony_ci * try to import from the trust blob.
82d4afb5ceSopenharmony_ci *
83d4afb5ceSopenharmony_ci * If we return nonzero, we can't identify what we want and should abandon the
84d4afb5ceSopenharmony_ci * connection.
85d4afb5ceSopenharmony_ci */
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ciint
88d4afb5ceSopenharmony_cilws_tls_jit_trust_sort_kids(struct lws *wsi, lws_tls_kid_chain_t *ch)
89d4afb5ceSopenharmony_ci{
90d4afb5ceSopenharmony_ci	size_t hl;
91d4afb5ceSopenharmony_ci	lws_tls_jit_inflight_t *inf;
92d4afb5ceSopenharmony_ci	int n, m, sanity = 10;
93d4afb5ceSopenharmony_ci	const char *host = wsi->cli_hostname_copy;
94d4afb5ceSopenharmony_ci	char more = 1;
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ci	lwsl_info("%s\n", __func__);
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci	if (!host) {
99d4afb5ceSopenharmony_ci		if (wsi->stash && wsi->stash->cis[CIS_HOST])
100d4afb5ceSopenharmony_ci			host = wsi->stash->cis[CIS_HOST];
101d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
102d4afb5ceSopenharmony_ci		else
103d4afb5ceSopenharmony_ci			host = lws_hdr_simple_ptr(wsi,
104d4afb5ceSopenharmony_ci					      _WSI_TOKEN_CLIENT_PEER_ADDRESS);
105d4afb5ceSopenharmony_ci	}
106d4afb5ceSopenharmony_ci#endif
107d4afb5ceSopenharmony_ci	if (!host)
108d4afb5ceSopenharmony_ci		return 1;
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_ci	hl = strlen(host);
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci	/* something to work with? */
113d4afb5ceSopenharmony_ci
114d4afb5ceSopenharmony_ci	if (!ch->count)
115d4afb5ceSopenharmony_ci		return 1;
116d4afb5ceSopenharmony_ci
117d4afb5ceSopenharmony_ci	/* do we need to sort? */
118d4afb5ceSopenharmony_ci
119d4afb5ceSopenharmony_ci	if (ch->count > 1) {
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci		/* okie... */
122d4afb5ceSopenharmony_ci
123d4afb5ceSopenharmony_ci		while (more) {
124d4afb5ceSopenharmony_ci
125d4afb5ceSopenharmony_ci			if (!sanity--)
126d4afb5ceSopenharmony_ci				/* let's not get fooled into spinning */
127d4afb5ceSopenharmony_ci				return 1;
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci			more = 0;
130d4afb5ceSopenharmony_ci			for (n = 0; n < ch->count - 1; n++) {
131d4afb5ceSopenharmony_ci
132d4afb5ceSopenharmony_ci				if (!lws_tls_kid_cmp(&ch->skid[n],
133d4afb5ceSopenharmony_ci						     &ch->akid[n + 1]))
134d4afb5ceSopenharmony_ci					/* next belongs with this one */
135d4afb5ceSopenharmony_ci					continue;
136d4afb5ceSopenharmony_ci
137d4afb5ceSopenharmony_ci				/*
138d4afb5ceSopenharmony_ci				 * next doesn't belong with this one, let's
139d4afb5ceSopenharmony_ci				 * try to figure out where this one does belong
140d4afb5ceSopenharmony_ci				 * then
141d4afb5ceSopenharmony_ci				 */
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci				for (m = 0; m < ch->count; m++) {
144d4afb5ceSopenharmony_ci					if (n == m)
145d4afb5ceSopenharmony_ci						continue;
146d4afb5ceSopenharmony_ci					if (!lws_tls_kid_cmp(&ch->skid[n],
147d4afb5ceSopenharmony_ci							     &ch->akid[m])) {
148d4afb5ceSopenharmony_ci						lws_tls_kid_t t;
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci						/*
151d4afb5ceSopenharmony_ci						 * m references us, so we
152d4afb5ceSopenharmony_ci						 * need to go one step above m,
153d4afb5ceSopenharmony_ci						 * swap m and n
154d4afb5ceSopenharmony_ci						 */
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci						more = 1;
157d4afb5ceSopenharmony_ci						t = ch->akid[m];
158d4afb5ceSopenharmony_ci						ch->akid[m] = ch->akid[n];
159d4afb5ceSopenharmony_ci						ch->akid[n] = t;
160d4afb5ceSopenharmony_ci						t = ch->skid[m];
161d4afb5ceSopenharmony_ci						ch->skid[m] = ch->skid[n];
162d4afb5ceSopenharmony_ci						ch->skid[n] = t;
163d4afb5ceSopenharmony_ci
164d4afb5ceSopenharmony_ci						break;
165d4afb5ceSopenharmony_ci					}
166d4afb5ceSopenharmony_ci				}
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci				if (more)
169d4afb5ceSopenharmony_ci					break;
170d4afb5ceSopenharmony_ci			}
171d4afb5ceSopenharmony_ci		}
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci		/* then we should be sorted */
174d4afb5ceSopenharmony_ci	}
175d4afb5ceSopenharmony_ci
176d4afb5ceSopenharmony_ci	for (n = 0; n < ch->count; n++) {
177d4afb5ceSopenharmony_ci		lwsl_info("%s: AKID[%d]\n", __func__, n);
178d4afb5ceSopenharmony_ci		lwsl_hexdump_info(ch->akid[n].kid, ch->akid[n].kid_len);
179d4afb5ceSopenharmony_ci		lwsl_info("%s: SKID[%d]\n", __func__, n);
180d4afb5ceSopenharmony_ci		lwsl_hexdump_info(ch->skid[n].kid, ch->skid[n].kid_len);
181d4afb5ceSopenharmony_ci	}
182d4afb5ceSopenharmony_ci
183d4afb5ceSopenharmony_ci	/* to go further, user must provide a lookup helper */
184d4afb5ceSopenharmony_ci
185d4afb5ceSopenharmony_ci	if (!wsi->a.context->system_ops ||
186d4afb5ceSopenharmony_ci	    !wsi->a.context->system_ops->jit_trust_query)
187d4afb5ceSopenharmony_ci		return 1;
188d4afb5ceSopenharmony_ci
189d4afb5ceSopenharmony_ci	/*
190d4afb5ceSopenharmony_ci	 * If there's already a pending lookup for this host, let's bail and
191d4afb5ceSopenharmony_ci	 * just wait for that to complete (since it will be done async if we
192d4afb5ceSopenharmony_ci	 * can see it)
193d4afb5ceSopenharmony_ci	 */
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci	lws_start_foreach_dll(struct lws_dll2 *, d,
196d4afb5ceSopenharmony_ci			      wsi->a.context->jit_inflight.head) {
197d4afb5ceSopenharmony_ci		inf = lws_container_of(d, lws_tls_jit_inflight_t, list);
198d4afb5ceSopenharmony_ci
199d4afb5ceSopenharmony_ci		if (!strcmp((const char *)&inf[1], host))
200d4afb5ceSopenharmony_ci			/* already being handled */
201d4afb5ceSopenharmony_ci			return 1;
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ci	} lws_end_foreach_dll(d);
204d4afb5ceSopenharmony_ci
205d4afb5ceSopenharmony_ci	/*
206d4afb5ceSopenharmony_ci	 * No... let's make an inflight entry for this host, then
207d4afb5ceSopenharmony_ci	 */
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci	inf = lws_zalloc(sizeof(*inf) + hl + 1, __func__);
210d4afb5ceSopenharmony_ci	if (!inf)
211d4afb5ceSopenharmony_ci		return 1;
212d4afb5ceSopenharmony_ci
213d4afb5ceSopenharmony_ci	memcpy(&inf[1], host, hl + 1);
214d4afb5ceSopenharmony_ci	inf->refcount = (char)ch->count;
215d4afb5ceSopenharmony_ci	lws_dll2_add_tail(&inf->list, &wsi->a.context->jit_inflight);
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_ci	/*
218d4afb5ceSopenharmony_ci	 * ...kid_chain[0] AKID should indicate the right CA SKID that we want.
219d4afb5ceSopenharmony_ci	 *
220d4afb5ceSopenharmony_ci	 * Because of cross-signing, we check all of them and accept we may get
221d4afb5ceSopenharmony_ci	 * multiple (the inflight accepts up to 2) CAs needed.
222d4afb5ceSopenharmony_ci	 */
223d4afb5ceSopenharmony_ci
224d4afb5ceSopenharmony_ci	for (n = 0; n < ch->count; n++)
225d4afb5ceSopenharmony_ci		wsi->a.context->system_ops->jit_trust_query(wsi->a.context,
226d4afb5ceSopenharmony_ci			ch->akid[n].kid, (size_t)ch->akid[n].kid_len,
227d4afb5ceSopenharmony_ci			(void *)inf);
228d4afb5ceSopenharmony_ci
229d4afb5ceSopenharmony_ci	return 0;
230d4afb5ceSopenharmony_ci}
231d4afb5ceSopenharmony_ci
232d4afb5ceSopenharmony_cistatic void
233d4afb5ceSopenharmony_citag_to_vh_name(char *result, size_t max, uint32_t tag)
234d4afb5ceSopenharmony_ci{
235d4afb5ceSopenharmony_ci	lws_snprintf(result, max, "jitt-%08X", tag);
236d4afb5ceSopenharmony_ci}
237d4afb5ceSopenharmony_ci
238d4afb5ceSopenharmony_ciint
239d4afb5ceSopenharmony_cilws_tls_jit_trust_vhost_bind(struct lws_context *cx, const char *address,
240d4afb5ceSopenharmony_ci			     struct lws_vhost **pvh)
241d4afb5ceSopenharmony_ci{
242d4afb5ceSopenharmony_ci	lws_tls_jit_cache_item_t *ci, jci;
243d4afb5ceSopenharmony_ci	lws_tls_jit_inflight_t *inf;
244d4afb5ceSopenharmony_ci	char vhtag[32];
245d4afb5ceSopenharmony_ci	size_t size;
246d4afb5ceSopenharmony_ci	int n;
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci	if (lws_cache_item_get(cx->trust_cache, address, (const void **)&ci,
249d4afb5ceSopenharmony_ci									&size))
250d4afb5ceSopenharmony_ci		/*
251d4afb5ceSopenharmony_ci		 * There's no cached info, we have to start from scratch on
252d4afb5ceSopenharmony_ci		 * this one
253d4afb5ceSopenharmony_ci		 */
254d4afb5ceSopenharmony_ci		return 1;
255d4afb5ceSopenharmony_ci
256d4afb5ceSopenharmony_ci	/* gotten cache item may be evicted by jit_trust_query */
257d4afb5ceSopenharmony_ci	jci = *ci;
258d4afb5ceSopenharmony_ci
259d4afb5ceSopenharmony_ci	/*
260d4afb5ceSopenharmony_ci	 * We have some trust cache information for this host already, it tells
261d4afb5ceSopenharmony_ci	 * us the trusted CA SKIDs we found before, and the xor tag used to name
262d4afb5ceSopenharmony_ci	 * the vhost configured for these trust CAs in its SSL_CTX.
263d4afb5ceSopenharmony_ci	 *
264d4afb5ceSopenharmony_ci	 * Let's check first if the correct prepared vhost already exists, if
265d4afb5ceSopenharmony_ci	 * so, we can just bind to that and go.
266d4afb5ceSopenharmony_ci	 */
267d4afb5ceSopenharmony_ci
268d4afb5ceSopenharmony_ci	tag_to_vh_name(vhtag, sizeof(vhtag), jci.xor_tag);
269d4afb5ceSopenharmony_ci
270d4afb5ceSopenharmony_ci	*pvh = lws_get_vhost_by_name(cx, vhtag);
271d4afb5ceSopenharmony_ci	if (*pvh) {
272d4afb5ceSopenharmony_ci		lwsl_info("%s: %s -> existing %s\n", __func__, address, vhtag);
273d4afb5ceSopenharmony_ci		/* hit, let's just use that then */
274d4afb5ceSopenharmony_ci		return 0;
275d4afb5ceSopenharmony_ci	}
276d4afb5ceSopenharmony_ci
277d4afb5ceSopenharmony_ci	/*
278d4afb5ceSopenharmony_ci	 * ... so, we know the SKIDs of the missing CAs, but we don't have the
279d4afb5ceSopenharmony_ci	 * DERs for them, and so no configured vhost trusting them yet.  We have
280d4afb5ceSopenharmony_ci	 * had the DERs at some point, but we can't afford to cache them, so
281d4afb5ceSopenharmony_ci	 * we will have to get them again.
282d4afb5ceSopenharmony_ci	 *
283d4afb5ceSopenharmony_ci	 * Let's make an inflight for this, it will create the vhost when it
284d4afb5ceSopenharmony_ci	 * completes.  If syncrhronous, then it will complete before we leave
285d4afb5ceSopenharmony_ci	 * here, otherwise it will have a life of its own until all the
286d4afb5ceSopenharmony_ci	 * queries use the cb to succeed or fail.
287d4afb5ceSopenharmony_ci	 */
288d4afb5ceSopenharmony_ci
289d4afb5ceSopenharmony_ci	size = strlen(address);
290d4afb5ceSopenharmony_ci	inf = lws_zalloc(sizeof(*inf) + size + 1, __func__);
291d4afb5ceSopenharmony_ci	if (!inf)
292d4afb5ceSopenharmony_ci		return 1;
293d4afb5ceSopenharmony_ci
294d4afb5ceSopenharmony_ci	memcpy(&inf[1], address, size + 1);
295d4afb5ceSopenharmony_ci	inf->refcount = (char)jci.count_skids;
296d4afb5ceSopenharmony_ci	lws_dll2_add_tail(&inf->list, &cx->jit_inflight);
297d4afb5ceSopenharmony_ci
298d4afb5ceSopenharmony_ci	/*
299d4afb5ceSopenharmony_ci	 * ...kid_chain[0] AKID should indicate the right CA SKID that we want.
300d4afb5ceSopenharmony_ci	 *
301d4afb5ceSopenharmony_ci	 * Because of cross-signing, we check all of them and accept we may get
302d4afb5ceSopenharmony_ci	 * multiple (we can handle 3) CAs needed.
303d4afb5ceSopenharmony_ci	 */
304d4afb5ceSopenharmony_ci
305d4afb5ceSopenharmony_ci	for (n = 0; n < jci.count_skids; n++)
306d4afb5ceSopenharmony_ci		cx->system_ops->jit_trust_query(cx, jci.skids[n].kid,
307d4afb5ceSopenharmony_ci						(size_t)jci.skids[n].kid_len,
308d4afb5ceSopenharmony_ci						(void *)inf);
309d4afb5ceSopenharmony_ci
310d4afb5ceSopenharmony_ci	/* ... in case synchronous and it already finished the queries */
311d4afb5ceSopenharmony_ci
312d4afb5ceSopenharmony_ci	*pvh = lws_get_vhost_by_name(cx, vhtag);
313d4afb5ceSopenharmony_ci	if (*pvh) {
314d4afb5ceSopenharmony_ci		/* hit, let's just use that then */
315d4afb5ceSopenharmony_ci		lwsl_info("%s: bind to created vhost %s\n", __func__, vhtag);
316d4afb5ceSopenharmony_ci		return 0;
317d4afb5ceSopenharmony_ci	} else
318d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to bind to %s\n", __func__, vhtag);
319d4afb5ceSopenharmony_ci
320d4afb5ceSopenharmony_ci	/* right now, nothing to offer */
321d4afb5ceSopenharmony_ci
322d4afb5ceSopenharmony_ci	return 1;
323d4afb5ceSopenharmony_ci}
324d4afb5ceSopenharmony_ci
325d4afb5ceSopenharmony_civoid
326d4afb5ceSopenharmony_cilws_tls_jit_trust_inflight_destroy(lws_tls_jit_inflight_t *inf)
327d4afb5ceSopenharmony_ci{
328d4afb5ceSopenharmony_ci	int n;
329d4afb5ceSopenharmony_ci
330d4afb5ceSopenharmony_ci	for (n = 0; n < inf->ders; n++)
331d4afb5ceSopenharmony_ci		lws_free_set_NULL(inf->der[n]);
332d4afb5ceSopenharmony_ci	lws_dll2_remove(&inf->list);
333d4afb5ceSopenharmony_ci
334d4afb5ceSopenharmony_ci	lws_free(inf);
335d4afb5ceSopenharmony_ci}
336d4afb5ceSopenharmony_ci
337d4afb5ceSopenharmony_cistatic int
338d4afb5ceSopenharmony_ciinflight_destroy(struct lws_dll2 *d, void *user)
339d4afb5ceSopenharmony_ci{
340d4afb5ceSopenharmony_ci	lws_tls_jit_inflight_t *inf;
341d4afb5ceSopenharmony_ci
342d4afb5ceSopenharmony_ci	inf = lws_container_of(d, lws_tls_jit_inflight_t, list);
343d4afb5ceSopenharmony_ci
344d4afb5ceSopenharmony_ci	lws_tls_jit_trust_inflight_destroy(inf);
345d4afb5ceSopenharmony_ci
346d4afb5ceSopenharmony_ci	return 0;
347d4afb5ceSopenharmony_ci}
348d4afb5ceSopenharmony_ci
349d4afb5ceSopenharmony_civoid
350d4afb5ceSopenharmony_cilws_tls_jit_trust_inflight_destroy_all(struct lws_context *cx)
351d4afb5ceSopenharmony_ci{
352d4afb5ceSopenharmony_ci	lws_dll2_foreach_safe(&cx->jit_inflight, cx, inflight_destroy);
353d4afb5ceSopenharmony_ci}
354d4afb5ceSopenharmony_ci
355d4afb5ceSopenharmony_cistatic void
356d4afb5ceSopenharmony_ciunref_vh_grace_cb(lws_sorted_usec_list_t *sul)
357d4afb5ceSopenharmony_ci{
358d4afb5ceSopenharmony_ci	struct lws_vhost *vh = lws_container_of(sul, struct lws_vhost,
359d4afb5ceSopenharmony_ci						sul_unref);
360d4afb5ceSopenharmony_ci
361d4afb5ceSopenharmony_ci	lwsl_info("%s: %s\n", __func__, vh->lc.gutag);
362d4afb5ceSopenharmony_ci
363d4afb5ceSopenharmony_ci	lws_vhost_destroy(vh);
364d4afb5ceSopenharmony_ci}
365d4afb5ceSopenharmony_ci
366d4afb5ceSopenharmony_civoid
367d4afb5ceSopenharmony_cilws_tls_jit_trust_vh_start_grace(struct lws_vhost *vh)
368d4afb5ceSopenharmony_ci{
369d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: unused, grace %dms\n", __func__, vh->lc.gutag,
370d4afb5ceSopenharmony_ci			vh->context->vh_idle_grace_ms);
371d4afb5ceSopenharmony_ci	lws_sul_schedule(vh->context, 0, &vh->sul_unref, unref_vh_grace_cb,
372d4afb5ceSopenharmony_ci			 (lws_usec_t)vh->context->vh_idle_grace_ms *
373d4afb5ceSopenharmony_ci								LWS_US_PER_MS);
374d4afb5ceSopenharmony_ci}
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci#if defined(_DEBUG)
377d4afb5ceSopenharmony_cistatic void
378d4afb5ceSopenharmony_cilws_tls_jit_trust_cert_info(const uint8_t *der, size_t der_len)
379d4afb5ceSopenharmony_ci{
380d4afb5ceSopenharmony_ci	struct lws_x509_cert *x;
381d4afb5ceSopenharmony_ci	union lws_tls_cert_info_results *u;
382d4afb5ceSopenharmony_ci	char p = 0, buf[192 + sizeof(*u)];
383d4afb5ceSopenharmony_ci
384d4afb5ceSopenharmony_ci	if (lws_x509_create(&x))
385d4afb5ceSopenharmony_ci		return;
386d4afb5ceSopenharmony_ci
387d4afb5ceSopenharmony_ci	if (!lws_x509_parse_from_pem(x, der, der_len)) {
388d4afb5ceSopenharmony_ci
389d4afb5ceSopenharmony_ci		u = (union lws_tls_cert_info_results *)buf;
390d4afb5ceSopenharmony_ci
391d4afb5ceSopenharmony_ci		if (!lws_x509_info(x, LWS_TLS_CERT_INFO_ISSUER_NAME, u, 192)) {
392d4afb5ceSopenharmony_ci			lwsl_info("ISS: %s\n", u->ns.name);
393d4afb5ceSopenharmony_ci			p = 1;
394d4afb5ceSopenharmony_ci		}
395d4afb5ceSopenharmony_ci		if (!lws_x509_info(x, LWS_TLS_CERT_INFO_COMMON_NAME, u, 192)) {
396d4afb5ceSopenharmony_ci			lwsl_info("CN: %s\n", u->ns.name);
397d4afb5ceSopenharmony_ci			p = 1;
398d4afb5ceSopenharmony_ci		}
399d4afb5ceSopenharmony_ci
400d4afb5ceSopenharmony_ci		if (!p) {
401d4afb5ceSopenharmony_ci			lwsl_err("%s: unable to get any info\n", __func__);
402d4afb5ceSopenharmony_ci			lwsl_hexdump_err(der, der_len);
403d4afb5ceSopenharmony_ci		}
404d4afb5ceSopenharmony_ci	} else
405d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to load DER\n", __func__);
406d4afb5ceSopenharmony_ci
407d4afb5ceSopenharmony_ci	lws_x509_destroy(&x);
408d4afb5ceSopenharmony_ci}
409d4afb5ceSopenharmony_ci#endif
410d4afb5ceSopenharmony_ci
411d4afb5ceSopenharmony_ci/*
412d4afb5ceSopenharmony_ci * This processes the JIT Trust lookup results independent of the tls backend.
413d4afb5ceSopenharmony_ci */
414d4afb5ceSopenharmony_ci
415d4afb5ceSopenharmony_ciint
416d4afb5ceSopenharmony_cilws_tls_jit_trust_got_cert_cb(struct lws_context *cx, void *got_opaque,
417d4afb5ceSopenharmony_ci			      const uint8_t *skid, size_t skid_len,
418d4afb5ceSopenharmony_ci			      const uint8_t *der, size_t der_len)
419d4afb5ceSopenharmony_ci{
420d4afb5ceSopenharmony_ci	lws_tls_jit_inflight_t *inf = (lws_tls_jit_inflight_t *)got_opaque;
421d4afb5ceSopenharmony_ci	struct lws_context_creation_info info;
422d4afb5ceSopenharmony_ci	lws_tls_jit_cache_item_t jci;
423d4afb5ceSopenharmony_ci	struct lws_vhost *v;
424d4afb5ceSopenharmony_ci	char vhtag[20];
425d4afb5ceSopenharmony_ci	char hit = 0;
426d4afb5ceSopenharmony_ci	int n;
427d4afb5ceSopenharmony_ci
428d4afb5ceSopenharmony_ci	/*
429d4afb5ceSopenharmony_ci	 * Before anything else, check the inf is still valid.  In the low
430d4afb5ceSopenharmony_ci	 * probability but possible case it was reallocated to be a different
431d4afb5ceSopenharmony_ci	 * inflight, that may cause different CA certs to apply to a connection,
432d4afb5ceSopenharmony_ci	 * but since mbedtls will then validate the server cert using the wrong
433d4afb5ceSopenharmony_ci	 * trusted CA, it will just cause temporary conn fail.
434d4afb5ceSopenharmony_ci	 */
435d4afb5ceSopenharmony_ci
436d4afb5ceSopenharmony_ci	lws_start_foreach_dll(struct lws_dll2 *, e, cx->jit_inflight.head) {
437d4afb5ceSopenharmony_ci		lws_tls_jit_inflight_t *i = lws_container_of(e,
438d4afb5ceSopenharmony_ci						lws_tls_jit_inflight_t, list);
439d4afb5ceSopenharmony_ci		if (i == inf) {
440d4afb5ceSopenharmony_ci			hit = 1;
441d4afb5ceSopenharmony_ci			break;
442d4afb5ceSopenharmony_ci		}
443d4afb5ceSopenharmony_ci
444d4afb5ceSopenharmony_ci	} lws_end_foreach_dll(e);
445d4afb5ceSopenharmony_ci
446d4afb5ceSopenharmony_ci	if (!hit)
447d4afb5ceSopenharmony_ci		/* inf has already gone */
448d4afb5ceSopenharmony_ci		return 1;
449d4afb5ceSopenharmony_ci
450d4afb5ceSopenharmony_ci	inf->refcount--;
451d4afb5ceSopenharmony_ci
452d4afb5ceSopenharmony_ci	if (skid_len >= 4)
453d4afb5ceSopenharmony_ci		inf->tag ^= *((uint32_t *)skid);
454d4afb5ceSopenharmony_ci
455d4afb5ceSopenharmony_ci	if (der && inf->ders < (int)LWS_ARRAY_SIZE(inf->der) && inf->refcount) {
456d4afb5ceSopenharmony_ci		/*
457d4afb5ceSopenharmony_ci		 * We have a trusted CA, but more results coming... stash it
458d4afb5ceSopenharmony_ci		 * in heap.
459d4afb5ceSopenharmony_ci		 */
460d4afb5ceSopenharmony_ci
461d4afb5ceSopenharmony_ci		inf->kid[inf->ders].kid_len = (uint8_t)((skid_len >
462d4afb5ceSopenharmony_ci				     (uint8_t)sizeof(inf->kid[inf->ders].kid)) ?
463d4afb5ceSopenharmony_ci				     sizeof(inf->kid[inf->ders].kid) : skid_len);
464d4afb5ceSopenharmony_ci		memcpy(inf->kid[inf->ders].kid, skid,
465d4afb5ceSopenharmony_ci		       inf->kid[inf->ders].kid_len);
466d4afb5ceSopenharmony_ci
467d4afb5ceSopenharmony_ci		inf->der[inf->ders] = lws_malloc(der_len, __func__);
468d4afb5ceSopenharmony_ci		if (!inf->der[inf->ders])
469d4afb5ceSopenharmony_ci			return 1;
470d4afb5ceSopenharmony_ci		memcpy(inf->der[inf->ders], der, der_len);
471d4afb5ceSopenharmony_ci		inf->der_len[inf->ders] = (short)der_len;
472d4afb5ceSopenharmony_ci		inf->ders++;
473d4afb5ceSopenharmony_ci
474d4afb5ceSopenharmony_ci		return 0;
475d4afb5ceSopenharmony_ci	}
476d4afb5ceSopenharmony_ci
477d4afb5ceSopenharmony_ci	/*
478d4afb5ceSopenharmony_ci	 * We accept up to three valid CA, and then end the inflight early.
479d4afb5ceSopenharmony_ci	 * Any further pending results are dropped, since we got all we could
480d4afb5ceSopenharmony_ci	 * use.  Up to two valid CA would be held in the inflight and the other
481d4afb5ceSopenharmony_ci	 * provided in the params.
482d4afb5ceSopenharmony_ci	 *
483d4afb5ceSopenharmony_ci	 * If we did not already fill up the inflight, keep waiting for any
484d4afb5ceSopenharmony_ci	 * others expected
485d4afb5ceSopenharmony_ci	 */
486d4afb5ceSopenharmony_ci
487d4afb5ceSopenharmony_ci	if (inf->refcount && inf->ders < (int)LWS_ARRAY_SIZE(inf->der))
488d4afb5ceSopenharmony_ci		return 0;
489d4afb5ceSopenharmony_ci
490d4afb5ceSopenharmony_ci	if (!der && !inf->ders) {
491d4afb5ceSopenharmony_ci		lwsl_warn("%s: no trusted CA certs matching\n", __func__);
492d4afb5ceSopenharmony_ci
493d4afb5ceSopenharmony_ci		goto destroy_inf;
494d4afb5ceSopenharmony_ci	}
495d4afb5ceSopenharmony_ci
496d4afb5ceSopenharmony_ci	tag_to_vh_name(vhtag, sizeof(vhtag), inf->tag);
497d4afb5ceSopenharmony_ci
498d4afb5ceSopenharmony_ci	/*
499d4afb5ceSopenharmony_ci	 * We have got at least one CA, it's all the CAs we're going to get,
500d4afb5ceSopenharmony_ci	 * or that we can handle.  So we have to process and drop the inf.
501d4afb5ceSopenharmony_ci	 *
502d4afb5ceSopenharmony_ci	 * First let's make a cache entry with a shortish ttl, mapping the
503d4afb5ceSopenharmony_ci	 * hostname we were trying to connect to, to the SKIDs that actually
504d4afb5ceSopenharmony_ci	 * had trust results.  This may come in handy later when we want to
505d4afb5ceSopenharmony_ci	 * connect to the same host again, but any vhost from before has been
506d4afb5ceSopenharmony_ci	 * removed... we can just ask for the specific CAs to regenerate the
507d4afb5ceSopenharmony_ci	 * vhost, without having to first fail the connection attempt to get the
508d4afb5ceSopenharmony_ci	 * server cert.
509d4afb5ceSopenharmony_ci	 *
510d4afb5ceSopenharmony_ci	 * The cache entry can be evicted at any time, so it is selfcontained.
511d4afb5ceSopenharmony_ci	 * If it's also lost, we start over with the initial failing connection
512d4afb5ceSopenharmony_ci	 * to figure out what we need to make it work.
513d4afb5ceSopenharmony_ci	 */
514d4afb5ceSopenharmony_ci
515d4afb5ceSopenharmony_ci	memset(&jci, 0, sizeof(jci));
516d4afb5ceSopenharmony_ci
517d4afb5ceSopenharmony_ci	jci.xor_tag = inf->tag;
518d4afb5ceSopenharmony_ci
519d4afb5ceSopenharmony_ci	/* copy the SKIDs from the inflight and params into the cache item */
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci	for (n = 0; n < (int)LWS_ARRAY_SIZE(inf->der); n++)
522d4afb5ceSopenharmony_ci		if (inf->kid[n].kid_len)
523d4afb5ceSopenharmony_ci			lws_tls_kid_copy_kid(&jci.skids[jci.count_skids++],
524d4afb5ceSopenharmony_ci						&inf->kid[n]);
525d4afb5ceSopenharmony_ci
526d4afb5ceSopenharmony_ci	if (skid_len) {
527d4afb5ceSopenharmony_ci		if (skid_len > sizeof(inf->kid[0].kid))
528d4afb5ceSopenharmony_ci			skid_len = sizeof(inf->kid[0].kid);
529d4afb5ceSopenharmony_ci		jci.skids[jci.count_skids].kid_len = (uint8_t)skid_len;
530d4afb5ceSopenharmony_ci		memcpy(jci.skids[jci.count_skids++].kid, skid, skid_len);
531d4afb5ceSopenharmony_ci	}
532d4afb5ceSopenharmony_ci
533d4afb5ceSopenharmony_ci	lwsl_info("%s: adding cache mapping %s -> %s\n", __func__,
534d4afb5ceSopenharmony_ci			(const char *)&inf[1], vhtag);
535d4afb5ceSopenharmony_ci
536d4afb5ceSopenharmony_ci	if (lws_cache_write_through(cx->trust_cache, (const char *)&inf[1],
537d4afb5ceSopenharmony_ci				    (const uint8_t *)&jci, sizeof(jci),
538d4afb5ceSopenharmony_ci				    lws_now_usecs() + (3600ll *LWS_US_PER_SEC),
539d4afb5ceSopenharmony_ci				    NULL))
540d4afb5ceSopenharmony_ci		lwsl_warn("%s: add to cache failed\n", __func__);
541d4afb5ceSopenharmony_ci
542d4afb5ceSopenharmony_ci	/* is there already a vhost for this commutative-xor SKID trust? */
543d4afb5ceSopenharmony_ci
544d4afb5ceSopenharmony_ci	if (lws_get_vhost_by_name(cx, vhtag)) {
545d4afb5ceSopenharmony_ci		lwsl_info("%s: tag vhost %s already exists, skipping\n",
546d4afb5ceSopenharmony_ci				__func__, vhtag);
547d4afb5ceSopenharmony_ci		goto destroy_inf;
548d4afb5ceSopenharmony_ci	}
549d4afb5ceSopenharmony_ci
550d4afb5ceSopenharmony_ci	/*
551d4afb5ceSopenharmony_ci	 * We only end up here when we attempted a connection to this hostname.
552d4afb5ceSopenharmony_ci	 *
553d4afb5ceSopenharmony_ci	 * We have the identified CA trust DER(s) to hand, let's create the
554d4afb5ceSopenharmony_ci	 * necessary vhost + prepared SSL_CTX for it to use on the retry, it
555d4afb5ceSopenharmony_ci	 * will be used straight away if the retry comes before the idle vhost
556d4afb5ceSopenharmony_ci	 * timeout.
557d4afb5ceSopenharmony_ci	 *
558d4afb5ceSopenharmony_ci	 * We also use this path in the case we have the cache entry but no
559d4afb5ceSopenharmony_ci	 * matching vhost already existing, to create one.
560d4afb5ceSopenharmony_ci	 */
561d4afb5ceSopenharmony_ci
562d4afb5ceSopenharmony_ci	memset(&info, 0, sizeof(info));
563d4afb5ceSopenharmony_ci	info.vhost_name = vhtag;
564d4afb5ceSopenharmony_ci	info.port = CONTEXT_PORT_NO_LISTEN;
565d4afb5ceSopenharmony_ci	info.options = cx->options;
566d4afb5ceSopenharmony_ci
567d4afb5ceSopenharmony_ci	/*
568d4afb5ceSopenharmony_ci	 * We have to create the vhost with the first valid trusted DER...
569d4afb5ceSopenharmony_ci	 * if we have a params one, use that so the rest are all from inflight
570d4afb5ceSopenharmony_ci	 */
571d4afb5ceSopenharmony_ci
572d4afb5ceSopenharmony_ci	if (der) {
573d4afb5ceSopenharmony_ci		info.client_ssl_ca_mem = der;
574d4afb5ceSopenharmony_ci		info.client_ssl_ca_mem_len = (unsigned int)der_len;
575d4afb5ceSopenharmony_ci		n = 0;
576d4afb5ceSopenharmony_ci	} else {
577d4afb5ceSopenharmony_ci		info.client_ssl_ca_mem = inf->der[0];
578d4afb5ceSopenharmony_ci		info.client_ssl_ca_mem_len = (unsigned int)inf->der_len[0];
579d4afb5ceSopenharmony_ci		n = 1;
580d4afb5ceSopenharmony_ci	}
581d4afb5ceSopenharmony_ci
582d4afb5ceSopenharmony_ci#if defined(_DEBUG)
583d4afb5ceSopenharmony_ci	lws_tls_jit_trust_cert_info(info.client_ssl_ca_mem,
584d4afb5ceSopenharmony_ci				    info.client_ssl_ca_mem_len);
585d4afb5ceSopenharmony_ci#endif
586d4afb5ceSopenharmony_ci
587d4afb5ceSopenharmony_ci	info.protocols = cx->protocols_copy;
588d4afb5ceSopenharmony_ci
589d4afb5ceSopenharmony_ci	v = lws_create_vhost(cx, &info);
590d4afb5ceSopenharmony_ci	if (!v)
591d4afb5ceSopenharmony_ci		lwsl_err("%s: failed to create vh %s\n", __func__, vhtag);
592d4afb5ceSopenharmony_ci
593d4afb5ceSopenharmony_ci	v->grace_after_unref = 1;
594d4afb5ceSopenharmony_ci	lws_tls_jit_trust_vh_start_grace(v);
595d4afb5ceSopenharmony_ci
596d4afb5ceSopenharmony_ci	/*
597d4afb5ceSopenharmony_ci	 * Do we need to add more trusted certs from inflight?
598d4afb5ceSopenharmony_ci	 */
599d4afb5ceSopenharmony_ci
600d4afb5ceSopenharmony_ci	while (n < inf->ders) {
601d4afb5ceSopenharmony_ci
602d4afb5ceSopenharmony_ci#if defined(_DEBUG)
603d4afb5ceSopenharmony_ci		lws_tls_jit_trust_cert_info(inf->der[n],
604d4afb5ceSopenharmony_ci					    (size_t)inf->der_len[n]);
605d4afb5ceSopenharmony_ci#endif
606d4afb5ceSopenharmony_ci
607d4afb5ceSopenharmony_ci		if (lws_tls_client_vhost_extra_cert_mem(v, inf->der[n],
608d4afb5ceSopenharmony_ci						(size_t)inf->der_len[n]))
609d4afb5ceSopenharmony_ci			lwsl_err("%s: add extra cert failed\n", __func__);
610d4afb5ceSopenharmony_ci		n++;
611d4afb5ceSopenharmony_ci	}
612d4afb5ceSopenharmony_ci
613d4afb5ceSopenharmony_ci	lwsl_info("%s: created jitt %s -> vh %s\n", __func__,
614d4afb5ceSopenharmony_ci				(const char *)&inf[1], vhtag);
615d4afb5ceSopenharmony_ci
616d4afb5ceSopenharmony_cidestroy_inf:
617d4afb5ceSopenharmony_ci	lws_tls_jit_trust_inflight_destroy(inf);
618d4afb5ceSopenharmony_ci
619d4afb5ceSopenharmony_ci	return 0;
620d4afb5ceSopenharmony_ci}
621d4afb5ceSopenharmony_ci
622d4afb5ceSopenharmony_ci/*
623d4afb5ceSopenharmony_ci * Refer to ./READMEs/README.jit-trust.md for blob layout specification
624d4afb5ceSopenharmony_ci */
625d4afb5ceSopenharmony_ci
626d4afb5ceSopenharmony_ciint
627d4afb5ceSopenharmony_cilws_tls_jit_trust_blob_queury_skid(const void *_blob, size_t blen,
628d4afb5ceSopenharmony_ci				   const uint8_t *skid, size_t skid_len,
629d4afb5ceSopenharmony_ci				   const uint8_t **prpder, size_t *prder_len)
630d4afb5ceSopenharmony_ci{
631d4afb5ceSopenharmony_ci	const uint8_t *pskidlen, *pskids, *pder, *blob = (uint8_t *)_blob;
632d4afb5ceSopenharmony_ci	const uint16_t *pderlen;
633d4afb5ceSopenharmony_ci	int certs;
634d4afb5ceSopenharmony_ci
635d4afb5ceSopenharmony_ci	/* sanity check blob length and magic */
636d4afb5ceSopenharmony_ci
637d4afb5ceSopenharmony_ci	if (blen < 32768 ||
638d4afb5ceSopenharmony_ci	   lws_ser_ru32be(blob) != LWS_JIT_TRUST_MAGIC_BE ||
639d4afb5ceSopenharmony_ci	   lws_ser_ru32be(blob + LJT_OFS_END) != blen) {
640d4afb5ceSopenharmony_ci		lwsl_err("%s: blob not sane\n", __func__);
641d4afb5ceSopenharmony_ci
642d4afb5ceSopenharmony_ci		return -1;
643d4afb5ceSopenharmony_ci	}
644d4afb5ceSopenharmony_ci
645d4afb5ceSopenharmony_ci	if (!skid_len)
646d4afb5ceSopenharmony_ci		return 1;
647d4afb5ceSopenharmony_ci
648d4afb5ceSopenharmony_ci	/* point into the various sub-tables */
649d4afb5ceSopenharmony_ci
650d4afb5ceSopenharmony_ci	certs		= (int)lws_ser_ru16be(blob + LJT_OFS_32_COUNT_CERTS);
651d4afb5ceSopenharmony_ci
652d4afb5ceSopenharmony_ci	pderlen		= (uint16_t *)(blob + lws_ser_ru32be(blob +
653d4afb5ceSopenharmony_ci							LJT_OFS_32_DERLEN));
654d4afb5ceSopenharmony_ci	pskidlen	= blob + lws_ser_ru32be(blob + LJT_OFS_32_SKIDLEN);
655d4afb5ceSopenharmony_ci	pskids		= blob + lws_ser_ru32be(blob + LJT_OFS_32_SKID);
656d4afb5ceSopenharmony_ci	pder		= blob + LJT_OFS_DER;
657d4afb5ceSopenharmony_ci
658d4afb5ceSopenharmony_ci	/* check each cert SKID in turn, return the DER if found */
659d4afb5ceSopenharmony_ci
660d4afb5ceSopenharmony_ci	while (certs--) {
661d4afb5ceSopenharmony_ci
662d4afb5ceSopenharmony_ci		/* paranoia / sanity */
663d4afb5ceSopenharmony_ci
664d4afb5ceSopenharmony_ci		assert(pskids < blob + blen);
665d4afb5ceSopenharmony_ci		assert(pder < blob + blen);
666d4afb5ceSopenharmony_ci		assert(pskidlen < blob + blen);
667d4afb5ceSopenharmony_ci		assert((uint8_t *)pderlen < blob + blen);
668d4afb5ceSopenharmony_ci
669d4afb5ceSopenharmony_ci		/* we will accept to match on truncated SKIDs */
670d4afb5ceSopenharmony_ci
671d4afb5ceSopenharmony_ci		if (*pskidlen >= skid_len &&
672d4afb5ceSopenharmony_ci		    !memcmp(skid, pskids, skid_len)) {
673d4afb5ceSopenharmony_ci			/*
674d4afb5ceSopenharmony_ci			 * We found a trusted CA cert of the right SKID
675d4afb5ceSopenharmony_ci			 */
676d4afb5ceSopenharmony_ci		        *prpder = pder;
677d4afb5ceSopenharmony_ci		        *prder_len = lws_ser_ru16be((uint8_t *)pderlen);
678d4afb5ceSopenharmony_ci
679d4afb5ceSopenharmony_ci		        return 0;
680d4afb5ceSopenharmony_ci		}
681d4afb5ceSopenharmony_ci
682d4afb5ceSopenharmony_ci		pder += lws_ser_ru16be((uint8_t *)pderlen);
683d4afb5ceSopenharmony_ci		pskids += *pskidlen;
684d4afb5ceSopenharmony_ci		pderlen++;
685d4afb5ceSopenharmony_ci		pskidlen++;
686d4afb5ceSopenharmony_ci	}
687d4afb5ceSopenharmony_ci
688d4afb5ceSopenharmony_ci	return 1;
689d4afb5ceSopenharmony_ci}
690