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-jose-jws.h"
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci/*
29d4afb5ceSopenharmony_ci * Currently only support flattened or compact (implicitly single signature)
30d4afb5ceSopenharmony_ci */
31d4afb5ceSopenharmony_ci
32d4afb5ceSopenharmony_cistatic const char * const jws_json[] = {
33d4afb5ceSopenharmony_ci	"protected", /* base64u */
34d4afb5ceSopenharmony_ci	"header", /* JSON */
35d4afb5ceSopenharmony_ci	"payload", /* base64u payload */
36d4afb5ceSopenharmony_ci	"signature", /* base64u signature */
37d4afb5ceSopenharmony_ci
38d4afb5ceSopenharmony_ci	//"signatures[].protected",
39d4afb5ceSopenharmony_ci	//"signatures[].header",
40d4afb5ceSopenharmony_ci	//"signatures[].signature"
41d4afb5ceSopenharmony_ci};
42d4afb5ceSopenharmony_ci
43d4afb5ceSopenharmony_cienum lws_jws_json_tok {
44d4afb5ceSopenharmony_ci	LJWSJT_PROTECTED,
45d4afb5ceSopenharmony_ci	LJWSJT_HEADER,
46d4afb5ceSopenharmony_ci	LJWSJT_PAYLOAD,
47d4afb5ceSopenharmony_ci	LJWSJT_SIGNATURE,
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci	// LJWSJT_SIGNATURES_PROTECTED,
50d4afb5ceSopenharmony_ci	// LJWSJT_SIGNATURES_HEADER,
51d4afb5ceSopenharmony_ci	// LJWSJT_SIGNATURES_SIGNATURE,
52d4afb5ceSopenharmony_ci};
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci/* parse a JWS complete or flattened JSON object */
55d4afb5ceSopenharmony_ci
56d4afb5ceSopenharmony_cistruct jws_cb_args {
57d4afb5ceSopenharmony_ci	struct lws_jws *jws;
58d4afb5ceSopenharmony_ci
59d4afb5ceSopenharmony_ci	char *temp;
60d4afb5ceSopenharmony_ci	int *temp_len;
61d4afb5ceSopenharmony_ci};
62d4afb5ceSopenharmony_ci
63d4afb5ceSopenharmony_cistatic signed char
64d4afb5ceSopenharmony_cilws_jws_json_cb(struct lejp_ctx *ctx, char reason)
65d4afb5ceSopenharmony_ci{
66d4afb5ceSopenharmony_ci	struct jws_cb_args *args = (struct jws_cb_args *)ctx->user;
67d4afb5ceSopenharmony_ci	int n, m;
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_ci	if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
70d4afb5ceSopenharmony_ci		return 0;
71d4afb5ceSopenharmony_ci
72d4afb5ceSopenharmony_ci	switch (ctx->path_match - 1) {
73d4afb5ceSopenharmony_ci
74d4afb5ceSopenharmony_ci	/* strings */
75d4afb5ceSopenharmony_ci
76d4afb5ceSopenharmony_ci	case LJWSJT_PROTECTED:  /* base64u: JOSE: must contain 'alg' */
77d4afb5ceSopenharmony_ci		m = LJWS_JOSE;
78d4afb5ceSopenharmony_ci		goto append_string;
79d4afb5ceSopenharmony_ci	case LJWSJT_PAYLOAD:	/* base64u */
80d4afb5ceSopenharmony_ci		m = LJWS_PYLD;
81d4afb5ceSopenharmony_ci		goto append_string;
82d4afb5ceSopenharmony_ci	case LJWSJT_SIGNATURE:  /* base64u */
83d4afb5ceSopenharmony_ci		m = LJWS_SIG;
84d4afb5ceSopenharmony_ci		goto append_string;
85d4afb5ceSopenharmony_ci
86d4afb5ceSopenharmony_ci	case LJWSJT_HEADER:	/* unprotected freeform JSON */
87d4afb5ceSopenharmony_ci		break;
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_ci	default:
90d4afb5ceSopenharmony_ci		return -1;
91d4afb5ceSopenharmony_ci	}
92d4afb5ceSopenharmony_ci
93d4afb5ceSopenharmony_ci	return 0;
94d4afb5ceSopenharmony_ci
95d4afb5ceSopenharmony_ciappend_string:
96d4afb5ceSopenharmony_ci
97d4afb5ceSopenharmony_ci	if (*args->temp_len < ctx->npos) {
98d4afb5ceSopenharmony_ci		lwsl_err("%s: out of parsing space\n", __func__);
99d4afb5ceSopenharmony_ci		return -1;
100d4afb5ceSopenharmony_ci	}
101d4afb5ceSopenharmony_ci
102d4afb5ceSopenharmony_ci	/*
103d4afb5ceSopenharmony_ci	 * We keep both b64u and decoded in temp mapped using map / map_b64,
104d4afb5ceSopenharmony_ci	 * the jws signature is actually over the b64 content not the plaintext,
105d4afb5ceSopenharmony_ci	 * and we can't do it until we see the protected alg.
106d4afb5ceSopenharmony_ci	 */
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci	if (!args->jws->map_b64.buf[m]) {
109d4afb5ceSopenharmony_ci		args->jws->map_b64.buf[m] = args->temp;
110d4afb5ceSopenharmony_ci		args->jws->map_b64.len[m] = 0;
111d4afb5ceSopenharmony_ci	}
112d4afb5ceSopenharmony_ci
113d4afb5ceSopenharmony_ci	memcpy(args->temp, ctx->buf, ctx->npos);
114d4afb5ceSopenharmony_ci	args->temp += ctx->npos;
115d4afb5ceSopenharmony_ci	*args->temp_len -= ctx->npos;
116d4afb5ceSopenharmony_ci	args->jws->map_b64.len[m] += ctx->npos;
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci	if (reason == LEJPCB_VAL_STR_END) {
119d4afb5ceSopenharmony_ci		args->jws->map.buf[m] = args->temp;
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci		n = lws_b64_decode_string_len(
122d4afb5ceSopenharmony_ci			(const char *)args->jws->map_b64.buf[m],
123d4afb5ceSopenharmony_ci			(int)args->jws->map_b64.len[m],
124d4afb5ceSopenharmony_ci			(char *)args->temp, *args->temp_len);
125d4afb5ceSopenharmony_ci		if (n < 0) {
126d4afb5ceSopenharmony_ci			lwsl_err("%s: b64 decode failed: in len %d, m %d\n", __func__, (int)args->jws->map_b64.len[m], m);
127d4afb5ceSopenharmony_ci			return -1;
128d4afb5ceSopenharmony_ci		}
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci		args->temp += n;
131d4afb5ceSopenharmony_ci		*args->temp_len -= n;
132d4afb5ceSopenharmony_ci		args->jws->map.len[m] = (unsigned int)n;
133d4afb5ceSopenharmony_ci	}
134d4afb5ceSopenharmony_ci
135d4afb5ceSopenharmony_ci	return 0;
136d4afb5ceSopenharmony_ci}
137d4afb5ceSopenharmony_ci
138d4afb5ceSopenharmony_cistatic int
139d4afb5ceSopenharmony_cilws_jws_json_parse(struct lws_jws *jws, const uint8_t *buf, int len,
140d4afb5ceSopenharmony_ci		   char *temp, int *temp_len)
141d4afb5ceSopenharmony_ci{
142d4afb5ceSopenharmony_ci	struct jws_cb_args args;
143d4afb5ceSopenharmony_ci	struct lejp_ctx jctx;
144d4afb5ceSopenharmony_ci	int m = 0;
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_ci	args.jws = jws;
147d4afb5ceSopenharmony_ci	args.temp = temp;
148d4afb5ceSopenharmony_ci	args.temp_len = temp_len;
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci	lejp_construct(&jctx, lws_jws_json_cb, &args, jws_json,
151d4afb5ceSopenharmony_ci		       LWS_ARRAY_SIZE(jws_json));
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	m = lejp_parse(&jctx, (uint8_t *)buf, len);
154d4afb5ceSopenharmony_ci	lejp_destruct(&jctx);
155d4afb5ceSopenharmony_ci	if (m < 0) {
156d4afb5ceSopenharmony_ci		lwsl_notice("%s: parse returned %d\n", __func__, m);
157d4afb5ceSopenharmony_ci		return -1;
158d4afb5ceSopenharmony_ci	}
159d4afb5ceSopenharmony_ci
160d4afb5ceSopenharmony_ci	return 0;
161d4afb5ceSopenharmony_ci}
162d4afb5ceSopenharmony_ci
163d4afb5ceSopenharmony_civoid
164d4afb5ceSopenharmony_cilws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk,
165d4afb5ceSopenharmony_ci	     struct lws_context *context)
166d4afb5ceSopenharmony_ci{
167d4afb5ceSopenharmony_ci	memset(jws, 0, sizeof(*jws));
168d4afb5ceSopenharmony_ci	jws->context = context;
169d4afb5ceSopenharmony_ci	jws->jwk = jwk;
170d4afb5ceSopenharmony_ci}
171d4afb5ceSopenharmony_ci
172d4afb5ceSopenharmony_cistatic void
173d4afb5ceSopenharmony_cilws_jws_map_bzero(struct lws_jws_map *map)
174d4afb5ceSopenharmony_ci{
175d4afb5ceSopenharmony_ci	int n;
176d4afb5ceSopenharmony_ci
177d4afb5ceSopenharmony_ci	/* no need to scrub first jose header element (it can be canned then) */
178d4afb5ceSopenharmony_ci
179d4afb5ceSopenharmony_ci	for (n = 1; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++)
180d4afb5ceSopenharmony_ci		if (map->buf[n])
181d4afb5ceSopenharmony_ci			lws_explicit_bzero((void *)map->buf[n], map->len[n]);
182d4afb5ceSopenharmony_ci}
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_civoid
185d4afb5ceSopenharmony_cilws_jws_destroy(struct lws_jws *jws)
186d4afb5ceSopenharmony_ci{
187d4afb5ceSopenharmony_ci	lws_jws_map_bzero(&jws->map);
188d4afb5ceSopenharmony_ci	jws->jwk = NULL;
189d4afb5ceSopenharmony_ci}
190d4afb5ceSopenharmony_ci
191d4afb5ceSopenharmony_ciint
192d4afb5ceSopenharmony_cilws_jws_dup_element(struct lws_jws_map *map, int idx, char *temp, int *temp_len,
193d4afb5ceSopenharmony_ci		    const void *in, size_t in_len, size_t actual_alloc)
194d4afb5ceSopenharmony_ci{
195d4afb5ceSopenharmony_ci	if (!actual_alloc)
196d4afb5ceSopenharmony_ci		actual_alloc = in_len;
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ci	if ((size_t)*temp_len < actual_alloc)
199d4afb5ceSopenharmony_ci		return -1;
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci	memcpy(temp, in, in_len);
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ci	map->len[idx] = (uint32_t)in_len;
204d4afb5ceSopenharmony_ci	map->buf[idx] = temp;
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci	*temp_len -= (int)actual_alloc;
207d4afb5ceSopenharmony_ci
208d4afb5ceSopenharmony_ci	return 0;
209d4afb5ceSopenharmony_ci}
210d4afb5ceSopenharmony_ci
211d4afb5ceSopenharmony_ciint
212d4afb5ceSopenharmony_cilws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
213d4afb5ceSopenharmony_ci			   char *temp, int *temp_len, const void *in,
214d4afb5ceSopenharmony_ci			   size_t in_len)
215d4afb5ceSopenharmony_ci{
216d4afb5ceSopenharmony_ci	int n;
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_ci	if (*temp_len < lws_base64_size((int)in_len))
219d4afb5ceSopenharmony_ci		return -1;
220d4afb5ceSopenharmony_ci
221d4afb5ceSopenharmony_ci	n = lws_jws_base64_enc(in, in_len, temp, (size_t)*temp_len);
222d4afb5ceSopenharmony_ci	if (n < 0)
223d4afb5ceSopenharmony_ci		return -1;
224d4afb5ceSopenharmony_ci
225d4afb5ceSopenharmony_ci	map->len[idx] = (unsigned int)n;
226d4afb5ceSopenharmony_ci	map->buf[idx] = temp;
227d4afb5ceSopenharmony_ci
228d4afb5ceSopenharmony_ci	*temp_len -= n;
229d4afb5ceSopenharmony_ci
230d4afb5ceSopenharmony_ci	return 0;
231d4afb5ceSopenharmony_ci}
232d4afb5ceSopenharmony_ci
233d4afb5ceSopenharmony_ciint
234d4afb5ceSopenharmony_cilws_jws_randomize_element(struct lws_context *context, struct lws_jws_map *map,
235d4afb5ceSopenharmony_ci			  int idx, char *temp, int *temp_len, size_t random_len,
236d4afb5ceSopenharmony_ci			  size_t actual_alloc)
237d4afb5ceSopenharmony_ci{
238d4afb5ceSopenharmony_ci	if (!actual_alloc)
239d4afb5ceSopenharmony_ci		actual_alloc = random_len;
240d4afb5ceSopenharmony_ci
241d4afb5ceSopenharmony_ci	if ((size_t)*temp_len < actual_alloc)
242d4afb5ceSopenharmony_ci		return -1;
243d4afb5ceSopenharmony_ci
244d4afb5ceSopenharmony_ci	map->len[idx] = (uint32_t)random_len;
245d4afb5ceSopenharmony_ci	map->buf[idx] = temp;
246d4afb5ceSopenharmony_ci
247d4afb5ceSopenharmony_ci	if (lws_get_random(context, temp, random_len) != random_len) {
248d4afb5ceSopenharmony_ci		lwsl_err("Problem getting random\n");
249d4afb5ceSopenharmony_ci		return -1;
250d4afb5ceSopenharmony_ci	}
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci	*temp_len -= (int)actual_alloc;
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ci	return 0;
255d4afb5ceSopenharmony_ci}
256d4afb5ceSopenharmony_ci
257d4afb5ceSopenharmony_ciint
258d4afb5ceSopenharmony_cilws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp,
259d4afb5ceSopenharmony_ci		      int *temp_len, size_t len, size_t actual_alloc)
260d4afb5ceSopenharmony_ci{
261d4afb5ceSopenharmony_ci	if (!actual_alloc)
262d4afb5ceSopenharmony_ci		actual_alloc = len;
263d4afb5ceSopenharmony_ci
264d4afb5ceSopenharmony_ci	if ((size_t)*temp_len < actual_alloc)
265d4afb5ceSopenharmony_ci		return -1;
266d4afb5ceSopenharmony_ci
267d4afb5ceSopenharmony_ci	map->len[idx] = (uint32_t)len;
268d4afb5ceSopenharmony_ci	map->buf[idx] = temp;
269d4afb5ceSopenharmony_ci	*temp_len -= (int)actual_alloc;
270d4afb5ceSopenharmony_ci
271d4afb5ceSopenharmony_ci	return 0;
272d4afb5ceSopenharmony_ci}
273d4afb5ceSopenharmony_ci
274d4afb5ceSopenharmony_ciint
275d4afb5ceSopenharmony_cilws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max)
276d4afb5ceSopenharmony_ci{
277d4afb5ceSopenharmony_ci	int n;
278d4afb5ceSopenharmony_ci
279d4afb5ceSopenharmony_ci	n = lws_b64_encode_string_url(in, (int)in_len, out, (int)out_max - 1);
280d4afb5ceSopenharmony_ci	if (n < 0) {
281d4afb5ceSopenharmony_ci		lwsl_notice("%s: in len %d too large for %d out buf\n",
282d4afb5ceSopenharmony_ci				__func__, (int)in_len, (int)out_max);
283d4afb5ceSopenharmony_ci		return n; /* too large for output buffer */
284d4afb5ceSopenharmony_ci	}
285d4afb5ceSopenharmony_ci
286d4afb5ceSopenharmony_ci	/* trim the terminal = */
287d4afb5ceSopenharmony_ci	while (n && out[n - 1] == '=')
288d4afb5ceSopenharmony_ci		n--;
289d4afb5ceSopenharmony_ci
290d4afb5ceSopenharmony_ci	out[n] = '\0';
291d4afb5ceSopenharmony_ci
292d4afb5ceSopenharmony_ci	return n;
293d4afb5ceSopenharmony_ci}
294d4afb5ceSopenharmony_ci
295d4afb5ceSopenharmony_ciint
296d4afb5ceSopenharmony_cilws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map)
297d4afb5ceSopenharmony_ci{
298d4afb5ceSopenharmony_ci	int me = 0;
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci	memset(map, 0, sizeof(*map));
301d4afb5ceSopenharmony_ci
302d4afb5ceSopenharmony_ci	map->buf[me] = (char *)in;
303d4afb5ceSopenharmony_ci	map->len[me] = 0;
304d4afb5ceSopenharmony_ci
305d4afb5ceSopenharmony_ci	while (len--) {
306d4afb5ceSopenharmony_ci		if (*in++ == '.') {
307d4afb5ceSopenharmony_ci			if (++me == LWS_JWS_MAX_COMPACT_BLOCKS)
308d4afb5ceSopenharmony_ci				return -1;
309d4afb5ceSopenharmony_ci			map->buf[me] = (char *)in;
310d4afb5ceSopenharmony_ci			map->len[me] = 0;
311d4afb5ceSopenharmony_ci			continue;
312d4afb5ceSopenharmony_ci		}
313d4afb5ceSopenharmony_ci		map->len[me]++;
314d4afb5ceSopenharmony_ci	}
315d4afb5ceSopenharmony_ci
316d4afb5ceSopenharmony_ci	return me + 1;
317d4afb5ceSopenharmony_ci}
318d4afb5ceSopenharmony_ci
319d4afb5ceSopenharmony_ci/* b64 in, map contains decoded elements, if non-NULL,
320d4afb5ceSopenharmony_ci * map_b64 set to b64 elements
321d4afb5ceSopenharmony_ci */
322d4afb5ceSopenharmony_ci
323d4afb5ceSopenharmony_ciint
324d4afb5ceSopenharmony_cilws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
325d4afb5ceSopenharmony_ci		       struct lws_jws_map *map_b64, char *out,
326d4afb5ceSopenharmony_ci		       int *out_len)
327d4afb5ceSopenharmony_ci{
328d4afb5ceSopenharmony_ci	int blocks, n, m = 0;
329d4afb5ceSopenharmony_ci
330d4afb5ceSopenharmony_ci	if (!map_b64)
331d4afb5ceSopenharmony_ci		map_b64 = map;
332d4afb5ceSopenharmony_ci
333d4afb5ceSopenharmony_ci	memset(map_b64, 0, sizeof(*map_b64));
334d4afb5ceSopenharmony_ci	memset(map, 0, sizeof(*map));
335d4afb5ceSopenharmony_ci
336d4afb5ceSopenharmony_ci	blocks = lws_jws_b64_compact_map(in, len, map_b64);
337d4afb5ceSopenharmony_ci
338d4afb5ceSopenharmony_ci	if (blocks > LWS_JWS_MAX_COMPACT_BLOCKS)
339d4afb5ceSopenharmony_ci		return -1;
340d4afb5ceSopenharmony_ci
341d4afb5ceSopenharmony_ci	while (m < blocks) {
342d4afb5ceSopenharmony_ci		n = lws_b64_decode_string_len(map_b64->buf[m], (int)map_b64->len[m],
343d4afb5ceSopenharmony_ci					      out, *out_len);
344d4afb5ceSopenharmony_ci		if (n < 0) {
345d4afb5ceSopenharmony_ci			lwsl_err("%s: b64 decode failed\n", __func__);
346d4afb5ceSopenharmony_ci			return -1;
347d4afb5ceSopenharmony_ci		}
348d4afb5ceSopenharmony_ci		/* replace the map entry with the decoded content */
349d4afb5ceSopenharmony_ci		if (n)
350d4afb5ceSopenharmony_ci			map->buf[m] = out;
351d4afb5ceSopenharmony_ci		else
352d4afb5ceSopenharmony_ci			map->buf[m] = NULL;
353d4afb5ceSopenharmony_ci		map->len[m++] = (unsigned int)n;
354d4afb5ceSopenharmony_ci		out += n;
355d4afb5ceSopenharmony_ci		*out_len -= n;
356d4afb5ceSopenharmony_ci
357d4afb5ceSopenharmony_ci		if (*out_len < 1)
358d4afb5ceSopenharmony_ci			return -1;
359d4afb5ceSopenharmony_ci	}
360d4afb5ceSopenharmony_ci
361d4afb5ceSopenharmony_ci	return blocks;
362d4afb5ceSopenharmony_ci}
363d4afb5ceSopenharmony_ci
364d4afb5ceSopenharmony_cistatic int
365d4afb5ceSopenharmony_cilws_jws_compact_decode_map(struct lws_jws_map *map_b64, struct lws_jws_map *map,
366d4afb5ceSopenharmony_ci			   char *out, int *out_len)
367d4afb5ceSopenharmony_ci{
368d4afb5ceSopenharmony_ci	int n, m = 0;
369d4afb5ceSopenharmony_ci
370d4afb5ceSopenharmony_ci	for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) {
371d4afb5ceSopenharmony_ci		n = lws_b64_decode_string_len(map_b64->buf[m], (int)map_b64->len[m],
372d4afb5ceSopenharmony_ci					      out, *out_len);
373d4afb5ceSopenharmony_ci		if (n < 0) {
374d4afb5ceSopenharmony_ci			lwsl_err("%s: b64 decode failed\n", __func__);
375d4afb5ceSopenharmony_ci			return -1;
376d4afb5ceSopenharmony_ci		}
377d4afb5ceSopenharmony_ci		/* replace the map entry with the decoded content */
378d4afb5ceSopenharmony_ci		map->buf[m] = out;
379d4afb5ceSopenharmony_ci		map->len[m++] = (unsigned int)n;
380d4afb5ceSopenharmony_ci		out += n;
381d4afb5ceSopenharmony_ci		*out_len -= n;
382d4afb5ceSopenharmony_ci
383d4afb5ceSopenharmony_ci		if (*out_len < 1)
384d4afb5ceSopenharmony_ci			return -1;
385d4afb5ceSopenharmony_ci	}
386d4afb5ceSopenharmony_ci
387d4afb5ceSopenharmony_ci	return 0;
388d4afb5ceSopenharmony_ci}
389d4afb5ceSopenharmony_ci
390d4afb5ceSopenharmony_ciint
391d4afb5ceSopenharmony_cilws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
392d4afb5ceSopenharmony_ci		       char *end)
393d4afb5ceSopenharmony_ci{
394d4afb5ceSopenharmony_ci	int n, len = lws_ptr_diff(end, (*p)) - 1;
395d4afb5ceSopenharmony_ci	char *p_entry = *p;
396d4afb5ceSopenharmony_ci
397d4afb5ceSopenharmony_ci	if (len < 3)
398d4afb5ceSopenharmony_ci		return -1;
399d4afb5ceSopenharmony_ci
400d4afb5ceSopenharmony_ci	if (!first)
401d4afb5ceSopenharmony_ci		*(*p)++ = '.';
402d4afb5ceSopenharmony_ci
403d4afb5ceSopenharmony_ci	n = lws_jws_base64_enc(in, in_len, *p, (unsigned int)len - 1);
404d4afb5ceSopenharmony_ci	if (n < 0)
405d4afb5ceSopenharmony_ci		return -1;
406d4afb5ceSopenharmony_ci
407d4afb5ceSopenharmony_ci	*p += n;
408d4afb5ceSopenharmony_ci
409d4afb5ceSopenharmony_ci	return lws_ptr_diff((*p), p_entry);
410d4afb5ceSopenharmony_ci}
411d4afb5ceSopenharmony_ci
412d4afb5ceSopenharmony_ciint
413d4afb5ceSopenharmony_cilws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
414d4afb5ceSopenharmony_ci		       const struct lws_jws_map *map,	/* non-b64 */
415d4afb5ceSopenharmony_ci		       char *buf, int *len)
416d4afb5ceSopenharmony_ci{
417d4afb5ceSopenharmony_ci	int n, m;
418d4afb5ceSopenharmony_ci
419d4afb5ceSopenharmony_ci	for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) {
420d4afb5ceSopenharmony_ci		if (!map->buf[n]) {
421d4afb5ceSopenharmony_ci			map_b64->buf[n] = NULL;
422d4afb5ceSopenharmony_ci			map_b64->len[n] = 0;
423d4afb5ceSopenharmony_ci			continue;
424d4afb5ceSopenharmony_ci		}
425d4afb5ceSopenharmony_ci		m = lws_jws_base64_enc(map->buf[n], map->len[n], buf, (size_t)*len);
426d4afb5ceSopenharmony_ci		if (m < 0)
427d4afb5ceSopenharmony_ci			return -1;
428d4afb5ceSopenharmony_ci		buf += m;
429d4afb5ceSopenharmony_ci		*len -= m;
430d4afb5ceSopenharmony_ci		if (*len < 1)
431d4afb5ceSopenharmony_ci			return -1;
432d4afb5ceSopenharmony_ci	}
433d4afb5ceSopenharmony_ci
434d4afb5ceSopenharmony_ci	return 0;
435d4afb5ceSopenharmony_ci}
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_ci/*
438d4afb5ceSopenharmony_ci * This takes both a base64 -encoded map and a plaintext map.
439d4afb5ceSopenharmony_ci *
440d4afb5ceSopenharmony_ci * JWS demands base-64 encoded elements for hash computation and at least for
441d4afb5ceSopenharmony_ci * the JOSE header and signature, decoded versions too.
442d4afb5ceSopenharmony_ci */
443d4afb5ceSopenharmony_ci
444d4afb5ceSopenharmony_ciint
445d4afb5ceSopenharmony_cilws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
446d4afb5ceSopenharmony_ci		    struct lws_jwk *jwk, struct lws_context *context)
447d4afb5ceSopenharmony_ci{
448d4afb5ceSopenharmony_ci	enum enum_genrsa_mode padding = LGRSAM_PKCS1_1_5;
449d4afb5ceSopenharmony_ci	char temp[256];
450d4afb5ceSopenharmony_ci	int n, h_len, b = 3, temp_len = sizeof(temp);
451d4afb5ceSopenharmony_ci	uint8_t digest[LWS_GENHASH_LARGEST];
452d4afb5ceSopenharmony_ci	struct lws_genhash_ctx hash_ctx;
453d4afb5ceSopenharmony_ci	struct lws_genec_ctx ecdsactx;
454d4afb5ceSopenharmony_ci	struct lws_genrsa_ctx rsactx;
455d4afb5ceSopenharmony_ci	struct lws_genhmac_ctx ctx;
456d4afb5ceSopenharmony_ci	struct lws_jose jose;
457d4afb5ceSopenharmony_ci
458d4afb5ceSopenharmony_ci	lws_jose_init(&jose);
459d4afb5ceSopenharmony_ci
460d4afb5ceSopenharmony_ci	/* only valid if no signature or key */
461d4afb5ceSopenharmony_ci	if (!map_b64->buf[LJWS_SIG] && !map->buf[LJWS_UHDR])
462d4afb5ceSopenharmony_ci		b = 2;
463d4afb5ceSopenharmony_ci
464d4afb5ceSopenharmony_ci	if (lws_jws_parse_jose(&jose, map->buf[LJWS_JOSE], (int)map->len[LJWS_JOSE],
465d4afb5ceSopenharmony_ci			       temp, &temp_len) < 0 || !jose.alg) {
466d4afb5ceSopenharmony_ci		lwsl_notice("%s: parse failed\n", __func__);
467d4afb5ceSopenharmony_ci		return -1;
468d4afb5ceSopenharmony_ci	}
469d4afb5ceSopenharmony_ci
470d4afb5ceSopenharmony_ci	if (!strcmp(jose.alg->alg, "none")) {
471d4afb5ceSopenharmony_ci		/* "none" compact serialization has 2 blocks: jose.payload */
472d4afb5ceSopenharmony_ci		if (b != 2 || jwk)
473d4afb5ceSopenharmony_ci			return -1;
474d4afb5ceSopenharmony_ci
475d4afb5ceSopenharmony_ci		/* the lack of a key matches the lack of a signature */
476d4afb5ceSopenharmony_ci		return 0;
477d4afb5ceSopenharmony_ci	}
478d4afb5ceSopenharmony_ci
479d4afb5ceSopenharmony_ci	/* all other have 3 blocks: jose.payload.sig */
480d4afb5ceSopenharmony_ci	if (b != 3 || !jwk) {
481d4afb5ceSopenharmony_ci		lwsl_notice("%s: %d blocks\n", __func__, b);
482d4afb5ceSopenharmony_ci		return -1;
483d4afb5ceSopenharmony_ci	}
484d4afb5ceSopenharmony_ci
485d4afb5ceSopenharmony_ci	switch (jose.alg->algtype_signing) {
486d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS:
487d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP:
488d4afb5ceSopenharmony_ci		padding = LGRSAM_PKCS1_OAEP_PSS;
489d4afb5ceSopenharmony_ci		/* fallthru */
490d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5:
491d4afb5ceSopenharmony_ci
492d4afb5ceSopenharmony_ci		/* RSASSA-PKCS1-v1_5 or OAEP using SHA-256/384/512 */
493d4afb5ceSopenharmony_ci
494d4afb5ceSopenharmony_ci		if (jwk->kty != LWS_GENCRYPTO_KTY_RSA)
495d4afb5ceSopenharmony_ci			return -1;
496d4afb5ceSopenharmony_ci
497d4afb5ceSopenharmony_ci		/* 6(RSA): compute the hash of the payload into "digest" */
498d4afb5ceSopenharmony_ci
499d4afb5ceSopenharmony_ci		if (lws_genhash_init(&hash_ctx, jose.alg->hash_type))
500d4afb5ceSopenharmony_ci			return -1;
501d4afb5ceSopenharmony_ci
502d4afb5ceSopenharmony_ci		/*
503d4afb5ceSopenharmony_ci		 * JWS Signing Input value:
504d4afb5ceSopenharmony_ci		 *
505d4afb5ceSopenharmony_ci		 * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
506d4afb5ceSopenharmony_ci		 * 	BASE64URL(JWS Payload)
507d4afb5ceSopenharmony_ci		 */
508d4afb5ceSopenharmony_ci
509d4afb5ceSopenharmony_ci		if (lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE],
510d4afb5ceSopenharmony_ci						  map_b64->len[LJWS_JOSE]) ||
511d4afb5ceSopenharmony_ci		    lws_genhash_update(&hash_ctx, ".", 1) ||
512d4afb5ceSopenharmony_ci		    lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD],
513d4afb5ceSopenharmony_ci						  map_b64->len[LJWS_PYLD]) ||
514d4afb5ceSopenharmony_ci		    lws_genhash_destroy(&hash_ctx, digest)) {
515d4afb5ceSopenharmony_ci			lws_genhash_destroy(&hash_ctx, NULL);
516d4afb5ceSopenharmony_ci
517d4afb5ceSopenharmony_ci			return -1;
518d4afb5ceSopenharmony_ci		}
519d4afb5ceSopenharmony_ci		// h_len = lws_genhash_size(jose.alg->hash_type);
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci		if (lws_genrsa_create(&rsactx, jwk->e, context, padding,
522d4afb5ceSopenharmony_ci				LWS_GENHASH_TYPE_UNKNOWN)) {
523d4afb5ceSopenharmony_ci			lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
524d4afb5ceSopenharmony_ci				    __func__);
525d4afb5ceSopenharmony_ci			return -1;
526d4afb5ceSopenharmony_ci		}
527d4afb5ceSopenharmony_ci
528d4afb5ceSopenharmony_ci		n = lws_genrsa_hash_sig_verify(&rsactx, digest,
529d4afb5ceSopenharmony_ci					       jose.alg->hash_type,
530d4afb5ceSopenharmony_ci					       (uint8_t *)map->buf[LJWS_SIG],
531d4afb5ceSopenharmony_ci					       map->len[LJWS_SIG]);
532d4afb5ceSopenharmony_ci
533d4afb5ceSopenharmony_ci		lws_genrsa_destroy(&rsactx);
534d4afb5ceSopenharmony_ci		if (n < 0) {
535d4afb5ceSopenharmony_ci			lwsl_notice("%s: decrypt fail\n", __func__);
536d4afb5ceSopenharmony_ci			return -1;
537d4afb5ceSopenharmony_ci		}
538d4afb5ceSopenharmony_ci
539d4afb5ceSopenharmony_ci		break;
540d4afb5ceSopenharmony_ci
541d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_NONE: /* HSxxx */
542d4afb5ceSopenharmony_ci
543d4afb5ceSopenharmony_ci		/* SHA256/384/512 HMAC */
544d4afb5ceSopenharmony_ci
545d4afb5ceSopenharmony_ci		h_len = (int)lws_genhmac_size(jose.alg->hmac_type);
546d4afb5ceSopenharmony_ci
547d4afb5ceSopenharmony_ci		/* 6) compute HMAC over payload */
548d4afb5ceSopenharmony_ci
549d4afb5ceSopenharmony_ci		if (lws_genhmac_init(&ctx, jose.alg->hmac_type,
550d4afb5ceSopenharmony_ci				     jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf,
551d4afb5ceSopenharmony_ci				     jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len))
552d4afb5ceSopenharmony_ci			return -1;
553d4afb5ceSopenharmony_ci
554d4afb5ceSopenharmony_ci		/*
555d4afb5ceSopenharmony_ci		 * JWS Signing Input value:
556d4afb5ceSopenharmony_ci		 *
557d4afb5ceSopenharmony_ci		 * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
558d4afb5ceSopenharmony_ci		 *   BASE64URL(JWS Payload)
559d4afb5ceSopenharmony_ci		 */
560d4afb5ceSopenharmony_ci
561d4afb5ceSopenharmony_ci		if (lws_genhmac_update(&ctx, map_b64->buf[LJWS_JOSE],
562d4afb5ceSopenharmony_ci					     map_b64->len[LJWS_JOSE]) ||
563d4afb5ceSopenharmony_ci		    lws_genhmac_update(&ctx, ".", 1) ||
564d4afb5ceSopenharmony_ci		    lws_genhmac_update(&ctx, map_b64->buf[LJWS_PYLD],
565d4afb5ceSopenharmony_ci					     map_b64->len[LJWS_PYLD]) ||
566d4afb5ceSopenharmony_ci		    lws_genhmac_destroy(&ctx, digest)) {
567d4afb5ceSopenharmony_ci			lws_genhmac_destroy(&ctx, NULL);
568d4afb5ceSopenharmony_ci
569d4afb5ceSopenharmony_ci			return -1;
570d4afb5ceSopenharmony_ci		}
571d4afb5ceSopenharmony_ci
572d4afb5ceSopenharmony_ci		/* 7) Compare the computed and decoded hashes */
573d4afb5ceSopenharmony_ci
574d4afb5ceSopenharmony_ci		if (lws_timingsafe_bcmp(digest, map->buf[2], (uint32_t)h_len)) {
575d4afb5ceSopenharmony_ci			lwsl_notice("digest mismatch\n");
576d4afb5ceSopenharmony_ci
577d4afb5ceSopenharmony_ci			return -1;
578d4afb5ceSopenharmony_ci		}
579d4afb5ceSopenharmony_ci
580d4afb5ceSopenharmony_ci		break;
581d4afb5ceSopenharmony_ci
582d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_ECDSA:
583d4afb5ceSopenharmony_ci
584d4afb5ceSopenharmony_ci		/* ECDSA using SHA-256/384/512 */
585d4afb5ceSopenharmony_ci
586d4afb5ceSopenharmony_ci		/* Confirm the key coming in with this makes sense */
587d4afb5ceSopenharmony_ci
588d4afb5ceSopenharmony_ci		/* has to be an EC key :-) */
589d4afb5ceSopenharmony_ci		if (jwk->kty != LWS_GENCRYPTO_KTY_EC)
590d4afb5ceSopenharmony_ci			return -1;
591d4afb5ceSopenharmony_ci
592d4afb5ceSopenharmony_ci		/* key must state its curve */
593d4afb5ceSopenharmony_ci		if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
594d4afb5ceSopenharmony_ci			return -1;
595d4afb5ceSopenharmony_ci
596d4afb5ceSopenharmony_ci		/* key must match the selected alg curve */
597d4afb5ceSopenharmony_ci		if (strcmp((const char *)jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
598d4afb5ceSopenharmony_ci				jose.alg->curve_name))
599d4afb5ceSopenharmony_ci			return -1;
600d4afb5ceSopenharmony_ci
601d4afb5ceSopenharmony_ci		/*
602d4afb5ceSopenharmony_ci		 * JWS Signing Input value:
603d4afb5ceSopenharmony_ci		 *
604d4afb5ceSopenharmony_ci		 * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
605d4afb5ceSopenharmony_ci		 * 	BASE64URL(JWS Payload)
606d4afb5ceSopenharmony_ci		 *
607d4afb5ceSopenharmony_ci		 * Validating the JWS Signature is a bit different from the
608d4afb5ceSopenharmony_ci		 * previous examples.  We need to split the 64 member octet
609d4afb5ceSopenharmony_ci		 * sequence of the JWS Signature (which is base64url decoded
610d4afb5ceSopenharmony_ci		 * from the value encoded in the JWS representation) into two
611d4afb5ceSopenharmony_ci		 * 32 octet sequences, the first representing R and the second
612d4afb5ceSopenharmony_ci		 * S.  We then pass the public key (x, y), the signature (R, S),
613d4afb5ceSopenharmony_ci		 * and the JWS Signing Input (which is the initial substring of
614d4afb5ceSopenharmony_ci		 * the JWS Compact Serialization representation up until but not
615d4afb5ceSopenharmony_ci		 * including the second period character) to an ECDSA signature
616d4afb5ceSopenharmony_ci		 * verifier that has been configured to use the P-256 curve with
617d4afb5ceSopenharmony_ci		 * the SHA-256 hash function.
618d4afb5ceSopenharmony_ci		 */
619d4afb5ceSopenharmony_ci
620d4afb5ceSopenharmony_ci		if (lws_genhash_init(&hash_ctx, jose.alg->hash_type) ||
621d4afb5ceSopenharmony_ci		    lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE],
622d4afb5ceSopenharmony_ci						  map_b64->len[LJWS_JOSE]) ||
623d4afb5ceSopenharmony_ci		    lws_genhash_update(&hash_ctx, ".", 1) ||
624d4afb5ceSopenharmony_ci		    lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD],
625d4afb5ceSopenharmony_ci						  map_b64->len[LJWS_PYLD]) ||
626d4afb5ceSopenharmony_ci		    lws_genhash_destroy(&hash_ctx, digest)) {
627d4afb5ceSopenharmony_ci			lws_genhash_destroy(&hash_ctx, NULL);
628d4afb5ceSopenharmony_ci
629d4afb5ceSopenharmony_ci			return -1;
630d4afb5ceSopenharmony_ci		}
631d4afb5ceSopenharmony_ci
632d4afb5ceSopenharmony_ci		h_len = (int)lws_genhash_size(jose.alg->hash_type);
633d4afb5ceSopenharmony_ci
634d4afb5ceSopenharmony_ci		if (lws_genecdsa_create(&ecdsactx, context, NULL)) {
635d4afb5ceSopenharmony_ci			lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
636d4afb5ceSopenharmony_ci				    __func__);
637d4afb5ceSopenharmony_ci			return -1;
638d4afb5ceSopenharmony_ci		}
639d4afb5ceSopenharmony_ci
640d4afb5ceSopenharmony_ci		if (lws_genecdsa_set_key(&ecdsactx, jwk->e)) {
641d4afb5ceSopenharmony_ci			lws_genec_destroy(&ecdsactx);
642d4afb5ceSopenharmony_ci			lwsl_notice("%s: ec key import fail\n", __func__);
643d4afb5ceSopenharmony_ci			return -1;
644d4afb5ceSopenharmony_ci		}
645d4afb5ceSopenharmony_ci
646d4afb5ceSopenharmony_ci		n = lws_genecdsa_hash_sig_verify_jws(&ecdsactx, digest,
647d4afb5ceSopenharmony_ci						     jose.alg->hash_type,
648d4afb5ceSopenharmony_ci						     jose.alg->keybits_fixed,
649d4afb5ceSopenharmony_ci						  (uint8_t *)map->buf[LJWS_SIG],
650d4afb5ceSopenharmony_ci						     map->len[LJWS_SIG]);
651d4afb5ceSopenharmony_ci		lws_genec_destroy(&ecdsactx);
652d4afb5ceSopenharmony_ci		if (n < 0) {
653d4afb5ceSopenharmony_ci			lwsl_notice("%s: verify fail\n", __func__);
654d4afb5ceSopenharmony_ci			return -1;
655d4afb5ceSopenharmony_ci		}
656d4afb5ceSopenharmony_ci
657d4afb5ceSopenharmony_ci		break;
658d4afb5ceSopenharmony_ci
659d4afb5ceSopenharmony_ci	default:
660d4afb5ceSopenharmony_ci		lwsl_err("%s: unknown alg from jose\n", __func__);
661d4afb5ceSopenharmony_ci		return -1;
662d4afb5ceSopenharmony_ci	}
663d4afb5ceSopenharmony_ci
664d4afb5ceSopenharmony_ci	return 0;
665d4afb5ceSopenharmony_ci}
666d4afb5ceSopenharmony_ci
667d4afb5ceSopenharmony_ci/* it's already a b64 map, we will make a temp plain version */
668d4afb5ceSopenharmony_ci
669d4afb5ceSopenharmony_ciint
670d4afb5ceSopenharmony_cilws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
671d4afb5ceSopenharmony_ci				    struct lws_jwk *jwk,
672d4afb5ceSopenharmony_ci			            struct lws_context *context,
673d4afb5ceSopenharmony_ci			            char *temp, int *temp_len)
674d4afb5ceSopenharmony_ci{
675d4afb5ceSopenharmony_ci	struct lws_jws_map map;
676d4afb5ceSopenharmony_ci	int n;
677d4afb5ceSopenharmony_ci
678d4afb5ceSopenharmony_ci	n = lws_jws_compact_decode_map(map_b64, &map, temp, temp_len);
679d4afb5ceSopenharmony_ci	if (n > 3 || n < 0)
680d4afb5ceSopenharmony_ci		return -1;
681d4afb5ceSopenharmony_ci
682d4afb5ceSopenharmony_ci	return lws_jws_sig_confirm(map_b64, &map, jwk, context);
683d4afb5ceSopenharmony_ci}
684d4afb5ceSopenharmony_ci
685d4afb5ceSopenharmony_ci/*
686d4afb5ceSopenharmony_ci * it's already a compact / concatenated b64 string, we will make a temp
687d4afb5ceSopenharmony_ci * plain version
688d4afb5ceSopenharmony_ci */
689d4afb5ceSopenharmony_ci
690d4afb5ceSopenharmony_ciint
691d4afb5ceSopenharmony_cilws_jws_sig_confirm_compact_b64(const char *in, size_t len,
692d4afb5ceSopenharmony_ci				struct lws_jws_map *map, struct lws_jwk *jwk,
693d4afb5ceSopenharmony_ci				struct lws_context *context,
694d4afb5ceSopenharmony_ci				char *temp, int *temp_len)
695d4afb5ceSopenharmony_ci{
696d4afb5ceSopenharmony_ci	struct lws_jws_map map_b64;
697d4afb5ceSopenharmony_ci	int n;
698d4afb5ceSopenharmony_ci
699d4afb5ceSopenharmony_ci	if (lws_jws_b64_compact_map(in, (int)len, &map_b64) < 0)
700d4afb5ceSopenharmony_ci		return -1;
701d4afb5ceSopenharmony_ci
702d4afb5ceSopenharmony_ci	n = lws_jws_compact_decode(in, (int)len, map, &map_b64, temp, temp_len);
703d4afb5ceSopenharmony_ci	if (n > 3 || n < 0)
704d4afb5ceSopenharmony_ci		return -1;
705d4afb5ceSopenharmony_ci
706d4afb5ceSopenharmony_ci	return lws_jws_sig_confirm(&map_b64, map, jwk, context);
707d4afb5ceSopenharmony_ci}
708d4afb5ceSopenharmony_ci
709d4afb5ceSopenharmony_ci/* it's already plain, we will make a temp b64 version */
710d4afb5ceSopenharmony_ci
711d4afb5ceSopenharmony_ciint
712d4afb5ceSopenharmony_cilws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk,
713d4afb5ceSopenharmony_ci			    struct lws_context *context, char *temp,
714d4afb5ceSopenharmony_ci			    int *temp_len)
715d4afb5ceSopenharmony_ci{
716d4afb5ceSopenharmony_ci	struct lws_jws_map map_b64;
717d4afb5ceSopenharmony_ci
718d4afb5ceSopenharmony_ci	if (lws_jws_compact_encode(&map_b64, map, temp, temp_len) < 0)
719d4afb5ceSopenharmony_ci		return -1;
720d4afb5ceSopenharmony_ci
721d4afb5ceSopenharmony_ci	return lws_jws_sig_confirm(&map_b64, map, jwk, context);
722d4afb5ceSopenharmony_ci}
723d4afb5ceSopenharmony_ci
724d4afb5ceSopenharmony_ciint
725d4afb5ceSopenharmony_cilws_jws_sig_confirm_json(const char *in, size_t len,
726d4afb5ceSopenharmony_ci			 struct lws_jws *jws, struct lws_jwk *jwk,
727d4afb5ceSopenharmony_ci			 struct lws_context *context,
728d4afb5ceSopenharmony_ci			 char *temp, int *temp_len)
729d4afb5ceSopenharmony_ci{
730d4afb5ceSopenharmony_ci	if (lws_jws_json_parse(jws, (const uint8_t *)in,
731d4afb5ceSopenharmony_ci			       (int)len, temp, temp_len)) {
732d4afb5ceSopenharmony_ci		lwsl_err("%s: lws_jws_json_parse failed\n", __func__);
733d4afb5ceSopenharmony_ci
734d4afb5ceSopenharmony_ci		return -1;
735d4afb5ceSopenharmony_ci	}
736d4afb5ceSopenharmony_ci	return lws_jws_sig_confirm(&jws->map_b64, &jws->map, jwk, context);
737d4afb5ceSopenharmony_ci}
738d4afb5ceSopenharmony_ci
739d4afb5ceSopenharmony_ci
740d4afb5ceSopenharmony_ciint
741d4afb5ceSopenharmony_cilws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws,
742d4afb5ceSopenharmony_ci		      char *b64_sig, size_t sig_len)
743d4afb5ceSopenharmony_ci{
744d4afb5ceSopenharmony_ci	enum enum_genrsa_mode pad = LGRSAM_PKCS1_1_5;
745d4afb5ceSopenharmony_ci	uint8_t digest[LWS_GENHASH_LARGEST];
746d4afb5ceSopenharmony_ci	struct lws_genhash_ctx hash_ctx;
747d4afb5ceSopenharmony_ci	struct lws_genec_ctx ecdsactx;
748d4afb5ceSopenharmony_ci	struct lws_genrsa_ctx rsactx;
749d4afb5ceSopenharmony_ci	uint8_t *buf;
750d4afb5ceSopenharmony_ci	int n, m;
751d4afb5ceSopenharmony_ci
752d4afb5ceSopenharmony_ci	if (jose->alg->hash_type == LWS_GENHASH_TYPE_UNKNOWN &&
753d4afb5ceSopenharmony_ci	    jose->alg->hmac_type == LWS_GENHMAC_TYPE_UNKNOWN &&
754d4afb5ceSopenharmony_ci	    !strcmp(jose->alg->alg, "none"))
755d4afb5ceSopenharmony_ci		return 0;
756d4afb5ceSopenharmony_ci
757d4afb5ceSopenharmony_ci	if (lws_genhash_init(&hash_ctx, jose->alg->hash_type) ||
758d4afb5ceSopenharmony_ci	    lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_JOSE],
759d4afb5ceSopenharmony_ci					  jws->map_b64.len[LJWS_JOSE]) ||
760d4afb5ceSopenharmony_ci	    lws_genhash_update(&hash_ctx, ".", 1) ||
761d4afb5ceSopenharmony_ci	    lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_PYLD],
762d4afb5ceSopenharmony_ci					  jws->map_b64.len[LJWS_PYLD]) ||
763d4afb5ceSopenharmony_ci	    lws_genhash_destroy(&hash_ctx, digest)) {
764d4afb5ceSopenharmony_ci		lws_genhash_destroy(&hash_ctx, NULL);
765d4afb5ceSopenharmony_ci
766d4afb5ceSopenharmony_ci		return -1;
767d4afb5ceSopenharmony_ci	}
768d4afb5ceSopenharmony_ci
769d4afb5ceSopenharmony_ci	switch (jose->alg->algtype_signing) {
770d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS:
771d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP:
772d4afb5ceSopenharmony_ci		pad = LGRSAM_PKCS1_OAEP_PSS;
773d4afb5ceSopenharmony_ci		/* fallthru */
774d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5:
775d4afb5ceSopenharmony_ci
776d4afb5ceSopenharmony_ci		if (jws->jwk->kty != LWS_GENCRYPTO_KTY_RSA)
777d4afb5ceSopenharmony_ci			return -1;
778d4afb5ceSopenharmony_ci
779d4afb5ceSopenharmony_ci		if (lws_genrsa_create(&rsactx, jws->jwk->e, jws->context,
780d4afb5ceSopenharmony_ci				      pad, LWS_GENHASH_TYPE_UNKNOWN)) {
781d4afb5ceSopenharmony_ci			lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
782d4afb5ceSopenharmony_ci				    __func__);
783d4afb5ceSopenharmony_ci			return -1;
784d4afb5ceSopenharmony_ci		}
785d4afb5ceSopenharmony_ci
786d4afb5ceSopenharmony_ci		n = (int)jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len;
787d4afb5ceSopenharmony_ci		buf = lws_malloc((unsigned int)lws_base64_size(n), "jws sign");
788d4afb5ceSopenharmony_ci		if (!buf)
789d4afb5ceSopenharmony_ci			return -1;
790d4afb5ceSopenharmony_ci
791d4afb5ceSopenharmony_ci		n = lws_genrsa_hash_sign(&rsactx, digest, jose->alg->hash_type,
792d4afb5ceSopenharmony_ci					 buf, (unsigned int)n);
793d4afb5ceSopenharmony_ci		lws_genrsa_destroy(&rsactx);
794d4afb5ceSopenharmony_ci		if (n < 0) {
795d4afb5ceSopenharmony_ci			lwsl_err("%s: lws_genrsa_hash_sign failed\n", __func__);
796d4afb5ceSopenharmony_ci			lws_free(buf);
797d4afb5ceSopenharmony_ci
798d4afb5ceSopenharmony_ci			return -1;
799d4afb5ceSopenharmony_ci		}
800d4afb5ceSopenharmony_ci
801d4afb5ceSopenharmony_ci		n = lws_jws_base64_enc((char *)buf, (unsigned int)n, b64_sig, sig_len);
802d4afb5ceSopenharmony_ci		lws_free(buf);
803d4afb5ceSopenharmony_ci		if (n < 0) {
804d4afb5ceSopenharmony_ci			lwsl_err("%s: lws_jws_base64_enc failed\n", __func__);
805d4afb5ceSopenharmony_ci		}
806d4afb5ceSopenharmony_ci
807d4afb5ceSopenharmony_ci		return n;
808d4afb5ceSopenharmony_ci
809d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_NONE:
810d4afb5ceSopenharmony_ci		return lws_jws_base64_enc((char *)digest,
811d4afb5ceSopenharmony_ci					 lws_genhash_size(jose->alg->hash_type),
812d4afb5ceSopenharmony_ci					  b64_sig, sig_len);
813d4afb5ceSopenharmony_ci	case LWS_JOSE_ENCTYPE_ECDSA:
814d4afb5ceSopenharmony_ci		/* ECDSA using SHA-256/384/512 */
815d4afb5ceSopenharmony_ci
816d4afb5ceSopenharmony_ci		/* the key coming in with this makes sense, right? */
817d4afb5ceSopenharmony_ci
818d4afb5ceSopenharmony_ci		/* has to be an EC key :-) */
819d4afb5ceSopenharmony_ci		if (jws->jwk->kty != LWS_GENCRYPTO_KTY_EC)
820d4afb5ceSopenharmony_ci			return -1;
821d4afb5ceSopenharmony_ci
822d4afb5ceSopenharmony_ci		/* key must state its curve */
823d4afb5ceSopenharmony_ci		if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
824d4afb5ceSopenharmony_ci			return -1;
825d4afb5ceSopenharmony_ci
826d4afb5ceSopenharmony_ci		/* must have all his pieces for a private key */
827d4afb5ceSopenharmony_ci		if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_X].buf ||
828d4afb5ceSopenharmony_ci		    !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf ||
829d4afb5ceSopenharmony_ci		    !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf)
830d4afb5ceSopenharmony_ci			return -1;
831d4afb5ceSopenharmony_ci
832d4afb5ceSopenharmony_ci		/* key must match the selected alg curve */
833d4afb5ceSopenharmony_ci		if (strcmp((const char *)
834d4afb5ceSopenharmony_ci				jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
835d4afb5ceSopenharmony_ci			    jose->alg->curve_name))
836d4afb5ceSopenharmony_ci			return -1;
837d4afb5ceSopenharmony_ci
838d4afb5ceSopenharmony_ci		if (lws_genecdsa_create(&ecdsactx, jws->context, NULL)) {
839d4afb5ceSopenharmony_ci			lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
840d4afb5ceSopenharmony_ci				    __func__);
841d4afb5ceSopenharmony_ci			return -1;
842d4afb5ceSopenharmony_ci		}
843d4afb5ceSopenharmony_ci
844d4afb5ceSopenharmony_ci		if (lws_genecdsa_set_key(&ecdsactx, jws->jwk->e)) {
845d4afb5ceSopenharmony_ci			lws_genec_destroy(&ecdsactx);
846d4afb5ceSopenharmony_ci			lwsl_notice("%s: ec key import fail\n", __func__);
847d4afb5ceSopenharmony_ci			return -1;
848d4afb5ceSopenharmony_ci		}
849d4afb5ceSopenharmony_ci		m = lws_gencrypto_bits_to_bytes(jose->alg->keybits_fixed) * 2;
850d4afb5ceSopenharmony_ci		buf = lws_malloc((unsigned int)m, "jws sign");
851d4afb5ceSopenharmony_ci		if (!buf)
852d4afb5ceSopenharmony_ci			return -1;
853d4afb5ceSopenharmony_ci
854d4afb5ceSopenharmony_ci		n = lws_genecdsa_hash_sign_jws(&ecdsactx, digest,
855d4afb5ceSopenharmony_ci					       jose->alg->hash_type,
856d4afb5ceSopenharmony_ci					       jose->alg->keybits_fixed,
857d4afb5ceSopenharmony_ci					       (uint8_t *)buf, (unsigned int)m);
858d4afb5ceSopenharmony_ci		lws_genec_destroy(&ecdsactx);
859d4afb5ceSopenharmony_ci		if (n < 0) {
860d4afb5ceSopenharmony_ci			lws_free(buf);
861d4afb5ceSopenharmony_ci			lwsl_notice("%s: lws_genecdsa_hash_sign_jws fail\n",
862d4afb5ceSopenharmony_ci					__func__);
863d4afb5ceSopenharmony_ci			return -1;
864d4afb5ceSopenharmony_ci		}
865d4afb5ceSopenharmony_ci
866d4afb5ceSopenharmony_ci		n = lws_jws_base64_enc((char *)buf, (unsigned int)m, b64_sig, sig_len);
867d4afb5ceSopenharmony_ci		lws_free(buf);
868d4afb5ceSopenharmony_ci
869d4afb5ceSopenharmony_ci		return n;
870d4afb5ceSopenharmony_ci
871d4afb5ceSopenharmony_ci	default:
872d4afb5ceSopenharmony_ci		break;
873d4afb5ceSopenharmony_ci	}
874d4afb5ceSopenharmony_ci
875d4afb5ceSopenharmony_ci	/* unknown key type */
876d4afb5ceSopenharmony_ci
877d4afb5ceSopenharmony_ci	return -1;
878d4afb5ceSopenharmony_ci}
879d4afb5ceSopenharmony_ci
880d4afb5ceSopenharmony_ci/*
881d4afb5ceSopenharmony_ci * Flattened JWS JSON:
882d4afb5ceSopenharmony_ci *
883d4afb5ceSopenharmony_ci *  {
884d4afb5ceSopenharmony_ci *    "payload":   "<payload contents>",
885d4afb5ceSopenharmony_ci *    "protected": "<integrity-protected header contents>",
886d4afb5ceSopenharmony_ci *    "header":    <non-integrity-protected header contents>,
887d4afb5ceSopenharmony_ci *    "signature": "<signature contents>"
888d4afb5ceSopenharmony_ci *   }
889d4afb5ceSopenharmony_ci */
890d4afb5ceSopenharmony_ci
891d4afb5ceSopenharmony_ciint
892d4afb5ceSopenharmony_cilws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len)
893d4afb5ceSopenharmony_ci{
894d4afb5ceSopenharmony_ci	size_t n = 0;
895d4afb5ceSopenharmony_ci
896d4afb5ceSopenharmony_ci	if (len < 1)
897d4afb5ceSopenharmony_ci		return 1;
898d4afb5ceSopenharmony_ci
899d4afb5ceSopenharmony_ci	n += (unsigned int)lws_snprintf(flattened + n, len - n , "{\"payload\": \"");
900d4afb5ceSopenharmony_ci	lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_PYLD],
901d4afb5ceSopenharmony_ci			jws->map_b64.len[LJWS_PYLD], len - n);
902d4afb5ceSopenharmony_ci	n = n + strlen(flattened + n);
903d4afb5ceSopenharmony_ci
904d4afb5ceSopenharmony_ci	n += (unsigned int)lws_snprintf(flattened + n, len - n , "\",\n \"protected\": \"");
905d4afb5ceSopenharmony_ci	lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_JOSE],
906d4afb5ceSopenharmony_ci			jws->map_b64.len[LJWS_JOSE], len - n);
907d4afb5ceSopenharmony_ci	n = n + strlen(flattened + n);
908d4afb5ceSopenharmony_ci
909d4afb5ceSopenharmony_ci	if (jws->map_b64.buf[LJWS_UHDR]) {
910d4afb5ceSopenharmony_ci		n += (unsigned int)lws_snprintf(flattened + n, len - n , "\",\n \"header\": ");
911d4afb5ceSopenharmony_ci		lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_UHDR],
912d4afb5ceSopenharmony_ci				jws->map_b64.len[LJWS_UHDR], len - n);
913d4afb5ceSopenharmony_ci		n = n + strlen(flattened + n);
914d4afb5ceSopenharmony_ci	}
915d4afb5ceSopenharmony_ci
916d4afb5ceSopenharmony_ci	n += (unsigned int)lws_snprintf(flattened + n, len - n , "\",\n \"signature\": \"");
917d4afb5ceSopenharmony_ci	lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_SIG],
918d4afb5ceSopenharmony_ci			jws->map_b64.len[LJWS_SIG], len - n);
919d4afb5ceSopenharmony_ci	n = n + strlen(flattened + n);
920d4afb5ceSopenharmony_ci
921d4afb5ceSopenharmony_ci	n += (unsigned int)lws_snprintf(flattened + n, len - n , "\"}\n");
922d4afb5ceSopenharmony_ci
923d4afb5ceSopenharmony_ci	return (n >= len - 1);
924d4afb5ceSopenharmony_ci}
925d4afb5ceSopenharmony_ci
926d4afb5ceSopenharmony_ciint
927d4afb5ceSopenharmony_cilws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len)
928d4afb5ceSopenharmony_ci{
929d4afb5ceSopenharmony_ci	size_t n = 0;
930d4afb5ceSopenharmony_ci
931d4afb5ceSopenharmony_ci	if (len < 1)
932d4afb5ceSopenharmony_ci		return 1;
933d4afb5ceSopenharmony_ci
934d4afb5ceSopenharmony_ci	lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_JOSE],
935d4afb5ceSopenharmony_ci		     jws->map_b64.len[LJWS_JOSE], len - n);
936d4afb5ceSopenharmony_ci	n += strlen(compact + n);
937d4afb5ceSopenharmony_ci	if (n >= len - 1)
938d4afb5ceSopenharmony_ci		return 1;
939d4afb5ceSopenharmony_ci	compact[n++] = '.';
940d4afb5ceSopenharmony_ci	lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_PYLD],
941d4afb5ceSopenharmony_ci		     jws->map_b64.len[LJWS_PYLD], len - n);
942d4afb5ceSopenharmony_ci	n += strlen(compact + n);
943d4afb5ceSopenharmony_ci	if (n >= len - 1)
944d4afb5ceSopenharmony_ci		return 1;
945d4afb5ceSopenharmony_ci	compact[n++] = '.';
946d4afb5ceSopenharmony_ci	lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_SIG],
947d4afb5ceSopenharmony_ci		     jws->map_b64.len[LJWS_SIG], len - n);
948d4afb5ceSopenharmony_ci	n += strlen(compact + n);
949d4afb5ceSopenharmony_ci
950d4afb5ceSopenharmony_ci	return n >= len - 1;
951d4afb5ceSopenharmony_ci}
952d4afb5ceSopenharmony_ci
953d4afb5ceSopenharmony_ciint
954d4afb5ceSopenharmony_cilws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
955d4afb5ceSopenharmony_ci			const char *alg_list, const char *com, size_t len,
956d4afb5ceSopenharmony_ci			char *temp, int tl, char *out, size_t *out_len)
957d4afb5ceSopenharmony_ci{
958d4afb5ceSopenharmony_ci	struct lws_tokenize ts;
959d4afb5ceSopenharmony_ci	struct lws_jose jose;
960d4afb5ceSopenharmony_ci	int otl = tl, r = 1;
961d4afb5ceSopenharmony_ci	struct lws_jws jws;
962d4afb5ceSopenharmony_ci	size_t n;
963d4afb5ceSopenharmony_ci
964d4afb5ceSopenharmony_ci	memset(&jws, 0, sizeof(jws));
965d4afb5ceSopenharmony_ci	lws_jose_init(&jose);
966d4afb5ceSopenharmony_ci
967d4afb5ceSopenharmony_ci	/*
968d4afb5ceSopenharmony_ci	 * Decode the b64.b64[.b64] compact serialization
969d4afb5ceSopenharmony_ci	 * blocks
970d4afb5ceSopenharmony_ci	 */
971d4afb5ceSopenharmony_ci
972d4afb5ceSopenharmony_ci	n = (size_t)lws_jws_compact_decode(com, (int)len, &jws.map, &jws.map_b64,
973d4afb5ceSopenharmony_ci				   temp, &tl);
974d4afb5ceSopenharmony_ci	if (n != 3) {
975d4afb5ceSopenharmony_ci		lwsl_err("%s: concat_map failed: %d\n", __func__, (int)n);
976d4afb5ceSopenharmony_ci		goto bail;
977d4afb5ceSopenharmony_ci	}
978d4afb5ceSopenharmony_ci
979d4afb5ceSopenharmony_ci	temp += otl - tl;
980d4afb5ceSopenharmony_ci	otl = tl;
981d4afb5ceSopenharmony_ci
982d4afb5ceSopenharmony_ci	/*
983d4afb5ceSopenharmony_ci	 * Parse the JOSE header
984d4afb5ceSopenharmony_ci	 */
985d4afb5ceSopenharmony_ci
986d4afb5ceSopenharmony_ci	if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE],
987d4afb5ceSopenharmony_ci			       (int)jws.map.len[LJWS_JOSE], temp, &tl) < 0) {
988d4afb5ceSopenharmony_ci		lwsl_err("%s: JOSE parse failed\n", __func__);
989d4afb5ceSopenharmony_ci		goto bail;
990d4afb5ceSopenharmony_ci	}
991d4afb5ceSopenharmony_ci
992d4afb5ceSopenharmony_ci	/*
993d4afb5ceSopenharmony_ci	 * Insist to see an alg in there that we list as acceptable
994d4afb5ceSopenharmony_ci	 */
995d4afb5ceSopenharmony_ci
996d4afb5ceSopenharmony_ci	lws_tokenize_init(&ts, alg_list, LWS_TOKENIZE_F_COMMA_SEP_LIST |
997d4afb5ceSopenharmony_ci					 LWS_TOKENIZE_F_RFC7230_DELIMS);
998d4afb5ceSopenharmony_ci	n = strlen(jose.alg->alg);
999d4afb5ceSopenharmony_ci
1000d4afb5ceSopenharmony_ci	do {
1001d4afb5ceSopenharmony_ci		ts.e = (int8_t)lws_tokenize(&ts);
1002d4afb5ceSopenharmony_ci		if (ts.e == LWS_TOKZE_TOKEN && ts.token_len == n &&
1003d4afb5ceSopenharmony_ci		    !strncmp(jose.alg->alg, ts.token, ts.token_len))
1004d4afb5ceSopenharmony_ci			break;
1005d4afb5ceSopenharmony_ci	} while (ts.e != LWS_TOKZE_ENDED);
1006d4afb5ceSopenharmony_ci
1007d4afb5ceSopenharmony_ci	if (ts.e != LWS_TOKZE_TOKEN) {
1008d4afb5ceSopenharmony_ci		lwsl_err("%s: JOSE using alg %s (accepted: %s)\n", __func__,
1009d4afb5ceSopenharmony_ci			 jose.alg->alg, alg_list);
1010d4afb5ceSopenharmony_ci		goto bail;
1011d4afb5ceSopenharmony_ci	}
1012d4afb5ceSopenharmony_ci
1013d4afb5ceSopenharmony_ci	/* we liked the alg... now how about the crypto? */
1014d4afb5ceSopenharmony_ci
1015d4afb5ceSopenharmony_ci	if (lws_jws_sig_confirm(&jws.map_b64, &jws.map, jwk, ctx) < 0) {
1016d4afb5ceSopenharmony_ci		lwsl_notice("%s: confirm JWT sig failed\n",
1017d4afb5ceSopenharmony_ci			    __func__);
1018d4afb5ceSopenharmony_ci		goto bail;
1019d4afb5ceSopenharmony_ci	}
1020d4afb5ceSopenharmony_ci
1021d4afb5ceSopenharmony_ci	/* yeah, it's validated... see about copying it out */
1022d4afb5ceSopenharmony_ci
1023d4afb5ceSopenharmony_ci	if (*out_len < jws.map.len[LJWS_PYLD] + 1) {
1024d4afb5ceSopenharmony_ci		/* we don't have enough room */
1025d4afb5ceSopenharmony_ci		r = 2;
1026d4afb5ceSopenharmony_ci		goto bail;
1027d4afb5ceSopenharmony_ci	}
1028d4afb5ceSopenharmony_ci
1029d4afb5ceSopenharmony_ci	memcpy(out, jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]);
1030d4afb5ceSopenharmony_ci	*out_len = jws.map.len[LJWS_PYLD];
1031d4afb5ceSopenharmony_ci	out[jws.map.len[LJWS_PYLD]] = '\0';
1032d4afb5ceSopenharmony_ci
1033d4afb5ceSopenharmony_ci	r = 0;
1034d4afb5ceSopenharmony_ci
1035d4afb5ceSopenharmony_cibail:
1036d4afb5ceSopenharmony_ci	lws_jws_destroy(&jws);
1037d4afb5ceSopenharmony_ci	lws_jose_destroy(&jose);
1038d4afb5ceSopenharmony_ci
1039d4afb5ceSopenharmony_ci	return r;
1040d4afb5ceSopenharmony_ci}
1041d4afb5ceSopenharmony_ci
1042d4afb5ceSopenharmony_cistatic int lws_jwt_vsign_via_info(struct lws_context *ctx, struct lws_jwk *jwk,
1043d4afb5ceSopenharmony_ci    const struct lws_jwt_sign_info *info, const char *format, va_list ap)
1044d4afb5ceSopenharmony_ci{
1045d4afb5ceSopenharmony_ci	size_t actual_hdr_len;
1046d4afb5ceSopenharmony_ci	struct lws_jose jose;
1047d4afb5ceSopenharmony_ci	struct lws_jws jws;
1048d4afb5ceSopenharmony_ci	va_list ap_cpy;
1049d4afb5ceSopenharmony_ci	int n, r = 1;
1050d4afb5ceSopenharmony_ci	int otl, tlr;
1051d4afb5ceSopenharmony_ci	char *p, *q;
1052d4afb5ceSopenharmony_ci
1053d4afb5ceSopenharmony_ci	lws_jws_init(&jws, jwk, ctx);
1054d4afb5ceSopenharmony_ci	lws_jose_init(&jose);
1055d4afb5ceSopenharmony_ci
1056d4afb5ceSopenharmony_ci	otl = tlr = info->tl;
1057d4afb5ceSopenharmony_ci	p = info->temp;
1058d4afb5ceSopenharmony_ci
1059d4afb5ceSopenharmony_ci	/*
1060d4afb5ceSopenharmony_ci	 * We either just use the provided info->jose_hdr, or build a
1061d4afb5ceSopenharmony_ci	 * minimal header from info->alg
1062d4afb5ceSopenharmony_ci	 */
1063d4afb5ceSopenharmony_ci	actual_hdr_len = info->jose_hdr ? info->jose_hdr_len :
1064d4afb5ceSopenharmony_ci					  10 + strlen(info->alg);
1065d4afb5ceSopenharmony_ci
1066d4afb5ceSopenharmony_ci	if (actual_hdr_len > INT_MAX) {
1067d4afb5ceSopenharmony_ci	  goto bail;
1068d4afb5ceSopenharmony_ci	}
1069d4afb5ceSopenharmony_ci
1070d4afb5ceSopenharmony_ci	if (lws_jws_alloc_element(&jws.map, LJWS_JOSE, info->temp, &tlr,
1071d4afb5ceSopenharmony_ci				  actual_hdr_len, 0)) {
1072d4afb5ceSopenharmony_ci		lwsl_err("%s: temp space too small\n", __func__);
1073d4afb5ceSopenharmony_ci		goto bail;
1074d4afb5ceSopenharmony_ci	}
1075d4afb5ceSopenharmony_ci
1076d4afb5ceSopenharmony_ci	if (!info->jose_hdr) {
1077d4afb5ceSopenharmony_ci
1078d4afb5ceSopenharmony_ci		/* get algorithm from 'alg' string and write minimal JOSE header */
1079d4afb5ceSopenharmony_ci		if (lws_gencrypto_jws_alg_to_definition(info->alg, &jose.alg)) {
1080d4afb5ceSopenharmony_ci			lwsl_err("%s: unknown alg %s\n", __func__, info->alg);
1081d4afb5ceSopenharmony_ci
1082d4afb5ceSopenharmony_ci			goto bail;
1083d4afb5ceSopenharmony_ci		}
1084d4afb5ceSopenharmony_ci		jws.map.len[LJWS_JOSE] = (uint32_t)lws_snprintf(
1085d4afb5ceSopenharmony_ci				(char *)jws.map.buf[LJWS_JOSE], (size_t)otl,
1086d4afb5ceSopenharmony_ci						"{\"alg\":\"%s\"}", info->alg);
1087d4afb5ceSopenharmony_ci	} else {
1088d4afb5ceSopenharmony_ci
1089d4afb5ceSopenharmony_ci		/*
1090d4afb5ceSopenharmony_ci		 * Get algorithm by parsing the given JOSE header and copy it,
1091d4afb5ceSopenharmony_ci		 * if it's ok
1092d4afb5ceSopenharmony_ci		 */
1093d4afb5ceSopenharmony_ci		if (lws_jws_parse_jose(&jose, info->jose_hdr,
1094d4afb5ceSopenharmony_ci				       (int)actual_hdr_len, info->temp, &tlr)) {
1095d4afb5ceSopenharmony_ci			lwsl_err("%s: invalid jose header\n", __func__);
1096d4afb5ceSopenharmony_ci			goto bail;
1097d4afb5ceSopenharmony_ci		}
1098d4afb5ceSopenharmony_ci		tlr = otl;
1099d4afb5ceSopenharmony_ci		memcpy((char *)jws.map.buf[LJWS_JOSE], info->jose_hdr,
1100d4afb5ceSopenharmony_ci								actual_hdr_len);
1101d4afb5ceSopenharmony_ci		jws.map.len[LJWS_JOSE] = (uint32_t)actual_hdr_len;
1102d4afb5ceSopenharmony_ci		tlr -= (int)actual_hdr_len;
1103d4afb5ceSopenharmony_ci	}
1104d4afb5ceSopenharmony_ci
1105d4afb5ceSopenharmony_ci	p += otl - tlr;
1106d4afb5ceSopenharmony_ci	otl = tlr;
1107d4afb5ceSopenharmony_ci
1108d4afb5ceSopenharmony_ci	va_copy(ap_cpy, ap);
1109d4afb5ceSopenharmony_ci	n = vsnprintf(NULL, 0, format, ap_cpy);
1110d4afb5ceSopenharmony_ci	va_end(ap_cpy);
1111d4afb5ceSopenharmony_ci	if (n + 2 >= tlr)
1112d4afb5ceSopenharmony_ci		goto bail;
1113d4afb5ceSopenharmony_ci
1114d4afb5ceSopenharmony_ci	q = lws_malloc((unsigned int)n + 2, __func__);
1115d4afb5ceSopenharmony_ci	if (!q)
1116d4afb5ceSopenharmony_ci		goto bail;
1117d4afb5ceSopenharmony_ci
1118d4afb5ceSopenharmony_ci	vsnprintf(q, (unsigned int)n + 2, format, ap);
1119d4afb5ceSopenharmony_ci
1120d4afb5ceSopenharmony_ci	/* add the plaintext from stdin to the map and a b64 version */
1121d4afb5ceSopenharmony_ci
1122d4afb5ceSopenharmony_ci	jws.map.buf[LJWS_PYLD] = q;
1123d4afb5ceSopenharmony_ci	jws.map.len[LJWS_PYLD] = (uint32_t)n;
1124d4afb5ceSopenharmony_ci
1125d4afb5ceSopenharmony_ci	if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_PYLD, p, &tlr,
1126d4afb5ceSopenharmony_ci				       jws.map.buf[LJWS_PYLD],
1127d4afb5ceSopenharmony_ci				       jws.map.len[LJWS_PYLD]))
1128d4afb5ceSopenharmony_ci		goto bail1;
1129d4afb5ceSopenharmony_ci
1130d4afb5ceSopenharmony_ci	p += otl - tlr;
1131d4afb5ceSopenharmony_ci	otl = tlr;
1132d4afb5ceSopenharmony_ci
1133d4afb5ceSopenharmony_ci	/* add the b64 JOSE header to the b64 map */
1134d4afb5ceSopenharmony_ci
1135d4afb5ceSopenharmony_ci	if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_JOSE, p, &tlr,
1136d4afb5ceSopenharmony_ci				       jws.map.buf[LJWS_JOSE],
1137d4afb5ceSopenharmony_ci				       jws.map.len[LJWS_JOSE]))
1138d4afb5ceSopenharmony_ci		goto bail1;
1139d4afb5ceSopenharmony_ci
1140d4afb5ceSopenharmony_ci	p += otl - tlr;
1141d4afb5ceSopenharmony_ci	otl = tlr;
1142d4afb5ceSopenharmony_ci
1143d4afb5ceSopenharmony_ci	/* prepare the space for the b64 signature in the map */
1144d4afb5ceSopenharmony_ci
1145d4afb5ceSopenharmony_ci	if (lws_jws_alloc_element(&jws.map_b64, LJWS_SIG, p, &tlr,
1146d4afb5ceSopenharmony_ci				  (size_t)lws_base64_size(LWS_JWE_LIMIT_KEY_ELEMENT_BYTES),
1147d4afb5ceSopenharmony_ci				  0))
1148d4afb5ceSopenharmony_ci		goto bail1;
1149d4afb5ceSopenharmony_ci
1150d4afb5ceSopenharmony_ci	/* sign the plaintext */
1151d4afb5ceSopenharmony_ci
1152d4afb5ceSopenharmony_ci	n = lws_jws_sign_from_b64(&jose, &jws,
1153d4afb5ceSopenharmony_ci				  (char *)jws.map_b64.buf[LJWS_SIG],
1154d4afb5ceSopenharmony_ci				  jws.map_b64.len[LJWS_SIG]);
1155d4afb5ceSopenharmony_ci	if (n < 0)
1156d4afb5ceSopenharmony_ci		goto bail1;
1157d4afb5ceSopenharmony_ci
1158d4afb5ceSopenharmony_ci	/* set the actual b64 signature size */
1159d4afb5ceSopenharmony_ci	jws.map_b64.len[LJWS_SIG] = (uint32_t)n;
1160d4afb5ceSopenharmony_ci
1161d4afb5ceSopenharmony_ci	/* create the compact JWS representation */
1162d4afb5ceSopenharmony_ci	if (lws_jws_write_compact(&jws, info->out, *info->out_len))
1163d4afb5ceSopenharmony_ci		goto bail1;
1164d4afb5ceSopenharmony_ci
1165d4afb5ceSopenharmony_ci	*info->out_len = strlen(info->out);
1166d4afb5ceSopenharmony_ci
1167d4afb5ceSopenharmony_ci	r = 0;
1168d4afb5ceSopenharmony_ci
1169d4afb5ceSopenharmony_cibail1:
1170d4afb5ceSopenharmony_ci	lws_free(q);
1171d4afb5ceSopenharmony_ci
1172d4afb5ceSopenharmony_cibail:
1173d4afb5ceSopenharmony_ci	jws.map.buf[LJWS_PYLD] = NULL;
1174d4afb5ceSopenharmony_ci	jws.map.len[LJWS_PYLD] = 0;
1175d4afb5ceSopenharmony_ci	lws_jws_destroy(&jws);
1176d4afb5ceSopenharmony_ci	lws_jose_destroy(&jose);
1177d4afb5ceSopenharmony_ci
1178d4afb5ceSopenharmony_ci	return r;
1179d4afb5ceSopenharmony_ci}
1180d4afb5ceSopenharmony_ci
1181d4afb5ceSopenharmony_ciint
1182d4afb5ceSopenharmony_cilws_jwt_sign_via_info(struct lws_context *ctx, struct lws_jwk *jwk,
1183d4afb5ceSopenharmony_ci		     const struct lws_jwt_sign_info *info, const char *format,
1184d4afb5ceSopenharmony_ci		     ...)
1185d4afb5ceSopenharmony_ci{
1186d4afb5ceSopenharmony_ci	int ret;
1187d4afb5ceSopenharmony_ci	va_list ap;
1188d4afb5ceSopenharmony_ci
1189d4afb5ceSopenharmony_ci	va_start(ap, format);
1190d4afb5ceSopenharmony_ci	ret = lws_jwt_vsign_via_info(ctx, jwk, info, format, ap);
1191d4afb5ceSopenharmony_ci	va_end(ap);
1192d4afb5ceSopenharmony_ci
1193d4afb5ceSopenharmony_ci	return ret;
1194d4afb5ceSopenharmony_ci}
1195d4afb5ceSopenharmony_ci
1196d4afb5ceSopenharmony_ciint
1197d4afb5ceSopenharmony_cilws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
1198d4afb5ceSopenharmony_ci		     const char *alg, char *out, size_t *out_len, char *temp,
1199d4afb5ceSopenharmony_ci		     int tl, const char *format, ...)
1200d4afb5ceSopenharmony_ci{
1201d4afb5ceSopenharmony_ci	struct lws_jwt_sign_info info = {
1202d4afb5ceSopenharmony_ci		.alg		= alg,
1203d4afb5ceSopenharmony_ci		.jose_hdr	= NULL,
1204d4afb5ceSopenharmony_ci		.out		= out,
1205d4afb5ceSopenharmony_ci		.out_len	= out_len,
1206d4afb5ceSopenharmony_ci		.temp		= temp,
1207d4afb5ceSopenharmony_ci		.tl		= tl
1208d4afb5ceSopenharmony_ci	};
1209d4afb5ceSopenharmony_ci	int r = 1;
1210d4afb5ceSopenharmony_ci	va_list ap;
1211d4afb5ceSopenharmony_ci
1212d4afb5ceSopenharmony_ci	va_start(ap, format);
1213d4afb5ceSopenharmony_ci
1214d4afb5ceSopenharmony_ci	r = lws_jwt_vsign_via_info(ctx, jwk, &info, format, ap);
1215d4afb5ceSopenharmony_ci
1216d4afb5ceSopenharmony_ci	va_end(ap);
1217d4afb5ceSopenharmony_ci	return r;
1218d4afb5ceSopenharmony_ci}
1219d4afb5ceSopenharmony_ci
1220d4afb5ceSopenharmony_ciint
1221d4afb5ceSopenharmony_cilws_jwt_token_sanity(const char *in, size_t in_len,
1222d4afb5ceSopenharmony_ci		     const char *iss, const char *aud,
1223d4afb5ceSopenharmony_ci		     const char *csrf_in,
1224d4afb5ceSopenharmony_ci		     char *sub, size_t sub_len, unsigned long *expiry_unix_time)
1225d4afb5ceSopenharmony_ci{
1226d4afb5ceSopenharmony_ci	unsigned long now = lws_now_secs(), exp;
1227d4afb5ceSopenharmony_ci	const char *cp;
1228d4afb5ceSopenharmony_ci	size_t len;
1229d4afb5ceSopenharmony_ci
1230d4afb5ceSopenharmony_ci	/*
1231d4afb5ceSopenharmony_ci	 * It has our issuer?
1232d4afb5ceSopenharmony_ci	 */
1233d4afb5ceSopenharmony_ci
1234d4afb5ceSopenharmony_ci	if (lws_json_simple_strcmp(in, in_len, "\"iss\":", iss)) {
1235d4afb5ceSopenharmony_ci		lwsl_notice("%s: iss mismatch\n", __func__);
1236d4afb5ceSopenharmony_ci		return 1;
1237d4afb5ceSopenharmony_ci	}
1238d4afb5ceSopenharmony_ci
1239d4afb5ceSopenharmony_ci	/*
1240d4afb5ceSopenharmony_ci	 * ... it is indended for us to consume? (this is set
1241d4afb5ceSopenharmony_ci	 * to the public base url for this sai instance)
1242d4afb5ceSopenharmony_ci	 */
1243d4afb5ceSopenharmony_ci	if (lws_json_simple_strcmp(in, in_len, "\"aud\":", aud)) {
1244d4afb5ceSopenharmony_ci		lwsl_notice("%s: aud mismatch\n", __func__);
1245d4afb5ceSopenharmony_ci		return 1;
1246d4afb5ceSopenharmony_ci	}
1247d4afb5ceSopenharmony_ci
1248d4afb5ceSopenharmony_ci	/*
1249d4afb5ceSopenharmony_ci	 * ...it's not too early for it?
1250d4afb5ceSopenharmony_ci	 */
1251d4afb5ceSopenharmony_ci	cp = lws_json_simple_find(in, in_len, "\"nbf\":", &len);
1252d4afb5ceSopenharmony_ci	if (!cp || (unsigned long)atol(cp) > now) {
1253d4afb5ceSopenharmony_ci		lwsl_notice("%s: nbf fail\n", __func__);
1254d4afb5ceSopenharmony_ci		return 1;
1255d4afb5ceSopenharmony_ci	}
1256d4afb5ceSopenharmony_ci
1257d4afb5ceSopenharmony_ci	/*
1258d4afb5ceSopenharmony_ci	 * ... and not too late for it?
1259d4afb5ceSopenharmony_ci	 */
1260d4afb5ceSopenharmony_ci	cp = lws_json_simple_find(in, in_len, "\"exp\":", &len);
1261d4afb5ceSopenharmony_ci	exp = (unsigned long)atol(cp);
1262d4afb5ceSopenharmony_ci	if (!cp || (unsigned long)atol(cp) < now) {
1263d4afb5ceSopenharmony_ci		lwsl_notice("%s: exp fail %lu vs %lu\n", __func__,
1264d4afb5ceSopenharmony_ci				cp ? (unsigned long)atol(cp) : 0, now);
1265d4afb5ceSopenharmony_ci		return 1;
1266d4afb5ceSopenharmony_ci	}
1267d4afb5ceSopenharmony_ci
1268d4afb5ceSopenharmony_ci	/*
1269d4afb5ceSopenharmony_ci	 * Caller cares about subject?  Then we must have it, and it can't be
1270d4afb5ceSopenharmony_ci	 * empty.
1271d4afb5ceSopenharmony_ci	 */
1272d4afb5ceSopenharmony_ci
1273d4afb5ceSopenharmony_ci	if (sub) {
1274d4afb5ceSopenharmony_ci		cp = lws_json_simple_find(in, in_len, "\"sub\":", &len);
1275d4afb5ceSopenharmony_ci		if (!cp || !len) {
1276d4afb5ceSopenharmony_ci			lwsl_notice("%s: missing subject\n", __func__);
1277d4afb5ceSopenharmony_ci			return 1;
1278d4afb5ceSopenharmony_ci		}
1279d4afb5ceSopenharmony_ci		lws_strnncpy(sub, cp, len, sub_len);
1280d4afb5ceSopenharmony_ci	}
1281d4afb5ceSopenharmony_ci
1282d4afb5ceSopenharmony_ci	/*
1283d4afb5ceSopenharmony_ci	 * If caller has been told a Cross Site Request Forgery (CSRF) nonce,
1284d4afb5ceSopenharmony_ci	 * require this JWT to express the same CSRF... this makes generated
1285d4afb5ceSopenharmony_ci	 * links for dangerous privileged auth'd actions expire with the JWT
1286d4afb5ceSopenharmony_ci	 * that was accessing the site when the links were generated.  And it
1287d4afb5ceSopenharmony_ci	 * leaves an attacker not knowing what links to synthesize unless he
1288d4afb5ceSopenharmony_ci	 * can read the token or pages generated with it.
1289d4afb5ceSopenharmony_ci	 *
1290d4afb5ceSopenharmony_ci	 * Using this is very good for security, but it implies you must refresh
1291d4afb5ceSopenharmony_ci	 * generated pages still when the auth token is expiring (and the user
1292d4afb5ceSopenharmony_ci	 * must log in again).
1293d4afb5ceSopenharmony_ci	 */
1294d4afb5ceSopenharmony_ci
1295d4afb5ceSopenharmony_ci	if (csrf_in &&
1296d4afb5ceSopenharmony_ci	    lws_json_simple_strcmp(in, in_len, "\"csrf\":", csrf_in)) {
1297d4afb5ceSopenharmony_ci		lwsl_notice("%s: csrf mismatch\n", __func__);
1298d4afb5ceSopenharmony_ci		return 1;
1299d4afb5ceSopenharmony_ci	}
1300d4afb5ceSopenharmony_ci
1301d4afb5ceSopenharmony_ci	if (expiry_unix_time)
1302d4afb5ceSopenharmony_ci		*expiry_unix_time = exp;
1303d4afb5ceSopenharmony_ci
1304d4afb5ceSopenharmony_ci	return 0;
1305d4afb5ceSopenharmony_ci}
1306