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 * JOSE-specific JWK code
25d4afb5ceSopenharmony_ci */
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci#include "private-lib-core.h"
28d4afb5ceSopenharmony_ci#include "private-lib-jose.h"
29d4afb5ceSopenharmony_ci
30d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
31d4afb5ceSopenharmony_ci#include <fcntl.h>
32d4afb5ceSopenharmony_ci#endif
33d4afb5ceSopenharmony_ci
34d4afb5ceSopenharmony_cistatic const char * const kty_names[] = {
35d4afb5ceSopenharmony_ci	"unknown",	/* LWS_GENCRYPTO_KTY_UNKNOWN */
36d4afb5ceSopenharmony_ci	"oct",		/* LWS_GENCRYPTO_KTY_OCT */
37d4afb5ceSopenharmony_ci	"RSA",		/* LWS_GENCRYPTO_KTY_RSA */
38d4afb5ceSopenharmony_ci	"EC"		/* LWS_GENCRYPTO_KTY_EC */
39d4afb5ceSopenharmony_ci};
40d4afb5ceSopenharmony_ci
41d4afb5ceSopenharmony_ci/*
42d4afb5ceSopenharmony_ci * These are the entire legal token set for names in jwk.
43d4afb5ceSopenharmony_ci *
44d4afb5ceSopenharmony_ci * The first version is used to parse a detached single jwk that don't have any
45d4afb5ceSopenharmony_ci * parent JSON context.  The second version is used to parse full jwk objects
46d4afb5ceSopenharmony_ci * that has a "keys": [ ] array containing the keys.
47d4afb5ceSopenharmony_ci */
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ciconst char * const jwk_tok[] = {
50d4afb5ceSopenharmony_ci	"keys[]",			/* dummy */
51d4afb5ceSopenharmony_ci	"e", "n", "d", "p", "q", "dp", "dq", "qi", /* RSA */
52d4afb5ceSopenharmony_ci	"kty",				/* generic */
53d4afb5ceSopenharmony_ci	"k",				/* symmetric key data */
54d4afb5ceSopenharmony_ci	"crv", "x", "y",		/* EC (also "D") */
55d4afb5ceSopenharmony_ci	"kid",				/* generic */
56d4afb5ceSopenharmony_ci	"use"				/* mutually exclusive with "key_ops" */,
57d4afb5ceSopenharmony_ci	"key_ops"			/* mutually exclusive with "use" */,
58d4afb5ceSopenharmony_ci	"x5c",				/* generic */
59d4afb5ceSopenharmony_ci	"alg"				/* generic */
60d4afb5ceSopenharmony_ci}, * const jwk_outer_tok[] = {
61d4afb5ceSopenharmony_ci	"keys[]",
62d4afb5ceSopenharmony_ci	"keys[].e", "keys[].n", "keys[].d", "keys[].p", "keys[].q", "keys[].dp",
63d4afb5ceSopenharmony_ci	"keys[].dq", "keys[].qi",
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ci	"keys[].kty", "keys[].k",		/* generic */
66d4afb5ceSopenharmony_ci	"keys[].crv", "keys[].x", "keys[].y",	/* EC (also "D") */
67d4afb5ceSopenharmony_ci	"keys[].kid", "keys[].use"	/* mutually exclusive with "key_ops" */,
68d4afb5ceSopenharmony_ci	"keys[].key_ops",		/* mutually exclusive with "use" */
69d4afb5ceSopenharmony_ci	"keys[].x5c", "keys[].alg"
70d4afb5ceSopenharmony_ci};
71d4afb5ceSopenharmony_ci
72d4afb5ceSopenharmony_cistatic unsigned short tok_map[] = {
73d4afb5ceSopenharmony_ci	F_RSA | F_EC | F_OCT | F_META |		 0xff,
74d4afb5ceSopenharmony_ci	F_RSA |				F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_E,
75d4afb5ceSopenharmony_ci	F_RSA |				F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_N,
76d4afb5ceSopenharmony_ci	F_RSA | F_EC |			F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_D,
77d4afb5ceSopenharmony_ci	F_RSA |				F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_P,
78d4afb5ceSopenharmony_ci	F_RSA |				F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_Q,
79d4afb5ceSopenharmony_ci	F_RSA |				F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_DP,
80d4afb5ceSopenharmony_ci	F_RSA |				F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_DQ,
81d4afb5ceSopenharmony_ci	F_RSA |				F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_QI,
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ci	F_RSA | F_EC | F_OCT | F_META |		 F_M | JWK_META_KTY,
84d4afb5ceSopenharmony_ci		       F_OCT |		F_B64U | F_M | LWS_GENCRYPTO_OCT_KEYEL_K,
85d4afb5ceSopenharmony_ci
86d4afb5ceSopenharmony_ci		F_EC |				 F_M | LWS_GENCRYPTO_EC_KEYEL_CRV,
87d4afb5ceSopenharmony_ci		F_EC |			F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_X,
88d4afb5ceSopenharmony_ci		F_EC |			F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_Y,
89d4afb5ceSopenharmony_ci
90d4afb5ceSopenharmony_ci	F_RSA | F_EC | F_OCT | F_META |		       JWK_META_KID,
91d4afb5ceSopenharmony_ci	F_RSA | F_EC | F_OCT | F_META |		       JWK_META_USE,
92d4afb5ceSopenharmony_ci
93d4afb5ceSopenharmony_ci	F_RSA | F_EC | F_OCT | F_META |		       JWK_META_KEY_OPS,
94d4afb5ceSopenharmony_ci	F_RSA | F_EC | F_OCT | F_META | F_B64 |	       JWK_META_X5C,
95d4afb5ceSopenharmony_ci	F_RSA | F_EC | F_OCT | F_META |		       JWK_META_ALG,
96d4afb5ceSopenharmony_ci};
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_cistruct lexico {
99d4afb5ceSopenharmony_ci	const char *name;
100d4afb5ceSopenharmony_ci	int idx;
101d4afb5ceSopenharmony_ci	char meta;
102d4afb5ceSopenharmony_ci} lexico_ec[] =  {
103d4afb5ceSopenharmony_ci	{ "alg",	JWK_META_ALG,			1 },
104d4afb5ceSopenharmony_ci	{ "crv",	LWS_GENCRYPTO_EC_KEYEL_CRV,	0 },
105d4afb5ceSopenharmony_ci	{ "d",		LWS_GENCRYPTO_EC_KEYEL_D,	2 | 0 },
106d4afb5ceSopenharmony_ci	{ "key_ops",	JWK_META_KEY_OPS,		1 },
107d4afb5ceSopenharmony_ci	{ "kid",	JWK_META_KID,			1 },
108d4afb5ceSopenharmony_ci	{ "kty",	JWK_META_KTY,			1 },
109d4afb5ceSopenharmony_ci	{ "use",	JWK_META_USE,			1 },
110d4afb5ceSopenharmony_ci	{ "x",		LWS_GENCRYPTO_EC_KEYEL_X,	0 },
111d4afb5ceSopenharmony_ci	{ "x5c",	JWK_META_X5C,			1 },
112d4afb5ceSopenharmony_ci	{ "y",		LWS_GENCRYPTO_EC_KEYEL_Y,	0 }
113d4afb5ceSopenharmony_ci}, lexico_oct[] =  {
114d4afb5ceSopenharmony_ci	{ "alg",	JWK_META_ALG,			1 },
115d4afb5ceSopenharmony_ci	{ "k",		LWS_GENCRYPTO_OCT_KEYEL_K,	0 },
116d4afb5ceSopenharmony_ci	{ "key_ops",	JWK_META_KEY_OPS,		1 },
117d4afb5ceSopenharmony_ci	{ "kid",	JWK_META_KID,			1 },
118d4afb5ceSopenharmony_ci	{ "kty",	JWK_META_KTY,			1 },
119d4afb5ceSopenharmony_ci	{ "use",	JWK_META_USE,			1 },
120d4afb5ceSopenharmony_ci	{ "x5c",	JWK_META_X5C,			1 }
121d4afb5ceSopenharmony_ci}, lexico_rsa[] =  {
122d4afb5ceSopenharmony_ci	{ "alg",	JWK_META_ALG,			1 },
123d4afb5ceSopenharmony_ci	{ "d",		LWS_GENCRYPTO_RSA_KEYEL_D,	2 | 0 },
124d4afb5ceSopenharmony_ci	{ "dp",		LWS_GENCRYPTO_RSA_KEYEL_DP,	2 | 0 },
125d4afb5ceSopenharmony_ci	{ "dq",		LWS_GENCRYPTO_RSA_KEYEL_DQ,	2 | 0 },
126d4afb5ceSopenharmony_ci	{ "e",		LWS_GENCRYPTO_RSA_KEYEL_E,	0 },
127d4afb5ceSopenharmony_ci	{ "key_ops",	JWK_META_KEY_OPS,		1 },
128d4afb5ceSopenharmony_ci	{ "kid",	JWK_META_KID,			1 },
129d4afb5ceSopenharmony_ci	{ "kty",	JWK_META_KTY,			1 },
130d4afb5ceSopenharmony_ci	{ "n",		LWS_GENCRYPTO_RSA_KEYEL_N,	0 },
131d4afb5ceSopenharmony_ci	{ "p",		LWS_GENCRYPTO_RSA_KEYEL_P,	2 | 0 },
132d4afb5ceSopenharmony_ci	{ "q",		LWS_GENCRYPTO_RSA_KEYEL_Q,	2 | 0 },
133d4afb5ceSopenharmony_ci	{ "qi",		LWS_GENCRYPTO_RSA_KEYEL_QI,	2 | 0 },
134d4afb5ceSopenharmony_ci	{ "use",	JWK_META_USE,			1 },
135d4afb5ceSopenharmony_ci	{ "x5c",	JWK_META_X5C,			1 }
136d4afb5ceSopenharmony_ci};
137d4afb5ceSopenharmony_ci
138d4afb5ceSopenharmony_cistatic int
139d4afb5ceSopenharmony_ci_lws_jwk_set_el_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len)
140d4afb5ceSopenharmony_ci{
141d4afb5ceSopenharmony_ci	size_t dec_size = (unsigned int)lws_base64_size(len);
142d4afb5ceSopenharmony_ci	int n;
143d4afb5ceSopenharmony_ci
144d4afb5ceSopenharmony_ci	e->buf = lws_malloc(dec_size, "jwk");
145d4afb5ceSopenharmony_ci	if (!e->buf)
146d4afb5ceSopenharmony_ci		return -1;
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_ci	/* same decoder accepts both url or original styles */
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci	n = lws_b64_decode_string_len(in, len, (char *)e->buf, (int)dec_size - 1);
151d4afb5ceSopenharmony_ci	if (n < 0)
152d4afb5ceSopenharmony_ci		return -1;
153d4afb5ceSopenharmony_ci	e->len = (uint32_t)n;
154d4afb5ceSopenharmony_ci
155d4afb5ceSopenharmony_ci	return 0;
156d4afb5ceSopenharmony_ci}
157d4afb5ceSopenharmony_ci
158d4afb5ceSopenharmony_cistatic int
159d4afb5ceSopenharmony_ci_lws_jwk_set_el_jwk_b64u(struct lws_gencrypto_keyelem *e, char *in, int len)
160d4afb5ceSopenharmony_ci{
161d4afb5ceSopenharmony_ci	size_t dec_size = (size_t)lws_base64_size(len);
162d4afb5ceSopenharmony_ci	int n;
163d4afb5ceSopenharmony_ci
164d4afb5ceSopenharmony_ci	e->buf = lws_malloc(dec_size, "jwk");
165d4afb5ceSopenharmony_ci	if (!e->buf)
166d4afb5ceSopenharmony_ci		return -1;
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci	/* same decoder accepts both url or original styles */
169d4afb5ceSopenharmony_ci
170d4afb5ceSopenharmony_ci	n = lws_b64_decode_string_len(in, len, (char *)e->buf, (int)dec_size - 1);
171d4afb5ceSopenharmony_ci	if (n < 0)
172d4afb5ceSopenharmony_ci		return -1;
173d4afb5ceSopenharmony_ci	e->len = (uint32_t)n;
174d4afb5ceSopenharmony_ci
175d4afb5ceSopenharmony_ci	return 0;
176d4afb5ceSopenharmony_ci}
177d4afb5ceSopenharmony_ci
178d4afb5ceSopenharmony_ci
179d4afb5ceSopenharmony_cisigned char
180d4afb5ceSopenharmony_cicb_jwk(struct lejp_ctx *ctx, char reason)
181d4afb5ceSopenharmony_ci{
182d4afb5ceSopenharmony_ci	struct lws_jwk_parse_state *jps = (struct lws_jwk_parse_state *)ctx->user;
183d4afb5ceSopenharmony_ci	struct lws_jwk *jwk = jps->jwk;
184d4afb5ceSopenharmony_ci	unsigned int idx, n;
185d4afb5ceSopenharmony_ci	unsigned short poss;
186d4afb5ceSopenharmony_ci	char dotstar[64];
187d4afb5ceSopenharmony_ci
188d4afb5ceSopenharmony_ci	if (reason == LEJPCB_VAL_STR_START)
189d4afb5ceSopenharmony_ci		jps->pos = 0;
190d4afb5ceSopenharmony_ci
191d4afb5ceSopenharmony_ci	if (reason == LEJPCB_OBJECT_START && ctx->path_match == 0 + 1)
192d4afb5ceSopenharmony_ci		/*
193d4afb5ceSopenharmony_ci		 * new keys[] member is starting
194d4afb5ceSopenharmony_ci		 *
195d4afb5ceSopenharmony_ci		 * Until we see some JSON names, it could be anything...
196d4afb5ceSopenharmony_ci		 * there is no requirement for kty to be given first and eg,
197d4afb5ceSopenharmony_ci		 * ACME specifies the keys must be ordered in lexographic
198d4afb5ceSopenharmony_ci		 * order - where kty is not first.
199d4afb5ceSopenharmony_ci		 */
200d4afb5ceSopenharmony_ci		jps->possible = F_RSA | F_EC | F_OCT;
201d4afb5ceSopenharmony_ci
202d4afb5ceSopenharmony_ci	if (reason == LEJPCB_OBJECT_END && ctx->path_match == 0 + 1) {
203d4afb5ceSopenharmony_ci		/* we completed parsing a key */
204d4afb5ceSopenharmony_ci		if (jps->per_key_cb && jps->possible) {
205d4afb5ceSopenharmony_ci			if (jps->per_key_cb(jps->jwk, jps->user)) {
206d4afb5ceSopenharmony_ci
207d4afb5ceSopenharmony_ci				lwsl_notice("%s: user cb halts import\n",
208d4afb5ceSopenharmony_ci					    __func__);
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_ci				return -2;
211d4afb5ceSopenharmony_ci			}
212d4afb5ceSopenharmony_ci
213d4afb5ceSopenharmony_ci			/* clear it down */
214d4afb5ceSopenharmony_ci			lws_jwk_destroy(jps->jwk);
215d4afb5ceSopenharmony_ci			jps->possible = 0;
216d4afb5ceSopenharmony_ci		}
217d4afb5ceSopenharmony_ci	}
218d4afb5ceSopenharmony_ci
219d4afb5ceSopenharmony_ci	if (reason == LEJPCB_COMPLETE) {
220d4afb5ceSopenharmony_ci
221d4afb5ceSopenharmony_ci		/*
222d4afb5ceSopenharmony_ci		 * Now we saw the whole jwk and know the key type, let'jwk insist
223d4afb5ceSopenharmony_ci		 * that as a whole, it must be consistent and complete.
224d4afb5ceSopenharmony_ci		 *
225d4afb5ceSopenharmony_ci		 * The tracking of ->possible bits from even before we know the
226d4afb5ceSopenharmony_ci		 * kty already makes certain we cannot have key element members
227d4afb5ceSopenharmony_ci		 * defined that are inconsistent with the key type.
228d4afb5ceSopenharmony_ci		 */
229d4afb5ceSopenharmony_ci
230d4afb5ceSopenharmony_ci		for (n = 0; n < LWS_ARRAY_SIZE(tok_map); n++)
231d4afb5ceSopenharmony_ci			/*
232d4afb5ceSopenharmony_ci			 * All mandataory elements for the key type
233d4afb5ceSopenharmony_ci			 * must be present
234d4afb5ceSopenharmony_ci			 */
235d4afb5ceSopenharmony_ci			if ((tok_map[n] & jps->possible) && (
236d4afb5ceSopenharmony_ci			    ((tok_map[n] & (F_M | F_META)) == (F_M | F_META) &&
237d4afb5ceSopenharmony_ci			     !jwk->meta[tok_map[n] & 0xff].buf) ||
238d4afb5ceSopenharmony_ci			    ((tok_map[n] & (F_M | F_META)) == F_M &&
239d4afb5ceSopenharmony_ci			     !jwk->e[tok_map[n] & 0xff].buf))) {
240d4afb5ceSopenharmony_ci				lwsl_notice("%s: missing %s\n", __func__,
241d4afb5ceSopenharmony_ci					    jwk_tok[n]);
242d4afb5ceSopenharmony_ci					return -3;
243d4afb5ceSopenharmony_ci				}
244d4afb5ceSopenharmony_ci
245d4afb5ceSopenharmony_ci		/*
246d4afb5ceSopenharmony_ci		 * When the key may be public or public + private, ensure the
247d4afb5ceSopenharmony_ci		 * intra-key members related to that are consistent.
248d4afb5ceSopenharmony_ci		 *
249d4afb5ceSopenharmony_ci		 * Only RSA keys need extra care, since EC keys are already
250d4afb5ceSopenharmony_ci		 * confirmed by making CRV, X and Y mandatory and only D
251d4afb5ceSopenharmony_ci		 * (the singular private part) optional.  For RSA, N and E are
252d4afb5ceSopenharmony_ci		 * also already known to be present using mandatory checking.
253d4afb5ceSopenharmony_ci		 */
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_ci		/*
256d4afb5ceSopenharmony_ci		 * If a private key, it must have all D, P and Q.  Public key
257d4afb5ceSopenharmony_ci		 * must have none of them.
258d4afb5ceSopenharmony_ci		 */
259d4afb5ceSopenharmony_ci		if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
260d4afb5ceSopenharmony_ci		    !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) &&
261d4afb5ceSopenharmony_ci		      (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) &&
262d4afb5ceSopenharmony_ci		      (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) ||
263d4afb5ceSopenharmony_ci		      (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
264d4afb5ceSopenharmony_ci		       jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf &&
265d4afb5ceSopenharmony_ci		       jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf))
266d4afb5ceSopenharmony_ci		      ) {
267d4afb5ceSopenharmony_ci			lwsl_notice("%s: RSA requires D, P and Q for private\n",
268d4afb5ceSopenharmony_ci				    __func__);
269d4afb5ceSopenharmony_ci			return -3;
270d4afb5ceSopenharmony_ci		}
271d4afb5ceSopenharmony_ci
272d4afb5ceSopenharmony_ci		/*
273d4afb5ceSopenharmony_ci		 * If the precomputed private key terms appear, they must all
274d4afb5ceSopenharmony_ci		 * appear together.
275d4afb5ceSopenharmony_ci		 */
276d4afb5ceSopenharmony_ci		if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
277d4afb5ceSopenharmony_ci		    !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf) &&
278d4afb5ceSopenharmony_ci		      (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) &&
279d4afb5ceSopenharmony_ci		      (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf)) ||
280d4afb5ceSopenharmony_ci		      (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf &&
281d4afb5ceSopenharmony_ci		       jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf &&
282d4afb5ceSopenharmony_ci		       jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf))
283d4afb5ceSopenharmony_ci		      ) {
284d4afb5ceSopenharmony_ci			lwsl_notice("%s: RSA DP, DQ, QI must all appear "
285d4afb5ceSopenharmony_ci				    "or none\n", __func__);
286d4afb5ceSopenharmony_ci			return -3;
287d4afb5ceSopenharmony_ci		}
288d4afb5ceSopenharmony_ci
289d4afb5ceSopenharmony_ci		/*
290d4afb5ceSopenharmony_ci		 * The precomputed private key terms must not appear without
291d4afb5ceSopenharmony_ci		 * the private key itself also appearing.
292d4afb5ceSopenharmony_ci		 */
293d4afb5ceSopenharmony_ci		if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
294d4afb5ceSopenharmony_ci		    !jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
295d4afb5ceSopenharmony_ci		     jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) {
296d4afb5ceSopenharmony_ci			lwsl_notice("%s: RSA DP, DQ, QI can appear only with "
297d4afb5ceSopenharmony_ci				    "private key\n", __func__);
298d4afb5ceSopenharmony_ci			return -3;
299d4afb5ceSopenharmony_ci		}
300d4afb5ceSopenharmony_ci
301d4afb5ceSopenharmony_ci		if ((jwk->kty == LWS_GENCRYPTO_KTY_RSA ||
302d4afb5ceSopenharmony_ci		     jwk->kty == LWS_GENCRYPTO_KTY_EC) &&
303d4afb5ceSopenharmony_ci		    jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf)
304d4afb5ceSopenharmony_ci		jwk->private_key = 1;
305d4afb5ceSopenharmony_ci	}
306d4afb5ceSopenharmony_ci
307d4afb5ceSopenharmony_ci	if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
308d4afb5ceSopenharmony_ci		return 0;
309d4afb5ceSopenharmony_ci
310d4afb5ceSopenharmony_ci	if (ctx->path_match == 0 + 1)
311d4afb5ceSopenharmony_ci		return 0;
312d4afb5ceSopenharmony_ci
313d4afb5ceSopenharmony_ci	idx = tok_map[ctx->path_match - 1];
314d4afb5ceSopenharmony_ci	if ((idx & 0xff) == 0xff)
315d4afb5ceSopenharmony_ci		return 0;
316d4afb5ceSopenharmony_ci
317d4afb5ceSopenharmony_ci	switch (idx) {
318d4afb5ceSopenharmony_ci	/* note: kty is not necessarily first... we have to keep track of
319d4afb5ceSopenharmony_ci	 * what could match given which element names have already been
320d4afb5ceSopenharmony_ci	 * seen.  Once kty comes, we confirm it'jwk still possible (ie, it'jwk
321d4afb5ceSopenharmony_ci	 * not trying to tell us that it'jwk RSA now when we saw a "crv"
322d4afb5ceSopenharmony_ci	 * earlier) and then reduce the possibilities to just the one that
323d4afb5ceSopenharmony_ci	 * kty told. */
324d4afb5ceSopenharmony_ci	case F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY:
325d4afb5ceSopenharmony_ci
326d4afb5ceSopenharmony_ci		if (ctx->npos == 3 && !strncmp(ctx->buf, "oct", 3)) {
327d4afb5ceSopenharmony_ci			if (!(jps->possible & F_OCT))
328d4afb5ceSopenharmony_ci				goto elements_mismatch;
329d4afb5ceSopenharmony_ci			jwk->kty = LWS_GENCRYPTO_KTY_OCT;
330d4afb5ceSopenharmony_ci			jps->possible = F_OCT;
331d4afb5ceSopenharmony_ci			goto cont;
332d4afb5ceSopenharmony_ci		}
333d4afb5ceSopenharmony_ci		if (ctx->npos == 3 && !strncmp(ctx->buf, "RSA", 3)) {
334d4afb5ceSopenharmony_ci			if (!(jps->possible & F_RSA))
335d4afb5ceSopenharmony_ci				goto elements_mismatch;
336d4afb5ceSopenharmony_ci			jwk->kty = LWS_GENCRYPTO_KTY_RSA;
337d4afb5ceSopenharmony_ci			jps->possible = F_RSA;
338d4afb5ceSopenharmony_ci			goto cont;
339d4afb5ceSopenharmony_ci		}
340d4afb5ceSopenharmony_ci		if (ctx->npos == 2 && !strncmp(ctx->buf, "EC", 2)) {
341d4afb5ceSopenharmony_ci			if (!(jps->possible & F_EC))
342d4afb5ceSopenharmony_ci				goto elements_mismatch;
343d4afb5ceSopenharmony_ci			jwk->kty = LWS_GENCRYPTO_KTY_EC;
344d4afb5ceSopenharmony_ci			jps->possible = F_EC;
345d4afb5ceSopenharmony_ci			goto cont;
346d4afb5ceSopenharmony_ci		}
347d4afb5ceSopenharmony_ci		lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
348d4afb5ceSopenharmony_ci		lwsl_err("%s: Unknown KTY '%s'\n", __func__, dotstar);
349d4afb5ceSopenharmony_ci		return -1;
350d4afb5ceSopenharmony_ci
351d4afb5ceSopenharmony_ci	default:
352d4afb5ceSopenharmony_cicont:
353d4afb5ceSopenharmony_ci		if (jps->pos + ctx->npos >= (int)sizeof(jps->b64))
354d4afb5ceSopenharmony_ci			goto bail;
355d4afb5ceSopenharmony_ci
356d4afb5ceSopenharmony_ci		memcpy(jps->b64 + jps->pos, ctx->buf, ctx->npos);
357d4afb5ceSopenharmony_ci		jps->pos += ctx->npos;
358d4afb5ceSopenharmony_ci
359d4afb5ceSopenharmony_ci		if (reason == LEJPCB_VAL_STR_CHUNK)
360d4afb5ceSopenharmony_ci			return 0;
361d4afb5ceSopenharmony_ci
362d4afb5ceSopenharmony_ci		/* chunking has been collated */
363d4afb5ceSopenharmony_ci
364d4afb5ceSopenharmony_ci		poss = idx & (F_RSA | F_EC | F_OCT);
365d4afb5ceSopenharmony_ci		jps->possible &= poss;
366d4afb5ceSopenharmony_ci		if (!jps->possible)
367d4afb5ceSopenharmony_ci			goto elements_mismatch;
368d4afb5ceSopenharmony_ci
369d4afb5ceSopenharmony_ci		if (idx & F_META) {
370d4afb5ceSopenharmony_ci			if (_lws_jwk_set_el_jwk(&jwk->meta[idx & 0x7f],
371d4afb5ceSopenharmony_ci						jps->b64, (unsigned int)jps->pos) < 0)
372d4afb5ceSopenharmony_ci				goto bail;
373d4afb5ceSopenharmony_ci
374d4afb5ceSopenharmony_ci			break;
375d4afb5ceSopenharmony_ci		}
376d4afb5ceSopenharmony_ci
377d4afb5ceSopenharmony_ci		if (idx & F_B64U) {
378d4afb5ceSopenharmony_ci			/* key data... do the base64 decode as needed */
379d4afb5ceSopenharmony_ci			if (_lws_jwk_set_el_jwk_b64u(&jwk->e[idx & 0x7f],
380d4afb5ceSopenharmony_ci						     jps->b64, jps->pos) < 0)
381d4afb5ceSopenharmony_ci				goto bail;
382d4afb5ceSopenharmony_ci
383d4afb5ceSopenharmony_ci			if (jwk->e[idx & 0x7f].len >
384d4afb5ceSopenharmony_ci					LWS_JWE_LIMIT_KEY_ELEMENT_BYTES) {
385d4afb5ceSopenharmony_ci				lwsl_notice("%s: oversize keydata\n", __func__);
386d4afb5ceSopenharmony_ci				goto bail;
387d4afb5ceSopenharmony_ci			}
388d4afb5ceSopenharmony_ci
389d4afb5ceSopenharmony_ci			return 0;
390d4afb5ceSopenharmony_ci		}
391d4afb5ceSopenharmony_ci
392d4afb5ceSopenharmony_ci		if (idx & F_B64) {
393d4afb5ceSopenharmony_ci
394d4afb5ceSopenharmony_ci			/* cert data... do non-urlcoded base64 decode */
395d4afb5ceSopenharmony_ci			if (_lws_jwk_set_el_jwk_b64(&jwk->e[idx & 0x7f],
396d4afb5ceSopenharmony_ci						    jps->b64, jps->pos) < 0)
397d4afb5ceSopenharmony_ci				goto bail;
398d4afb5ceSopenharmony_ci			return 0;
399d4afb5ceSopenharmony_ci		}
400d4afb5ceSopenharmony_ci
401d4afb5ceSopenharmony_ci			if (_lws_jwk_set_el_jwk(&jwk->e[idx & 0x7f],
402d4afb5ceSopenharmony_ci						jps->b64, (unsigned int)jps->pos) < 0)
403d4afb5ceSopenharmony_ci				goto bail;
404d4afb5ceSopenharmony_ci		break;
405d4afb5ceSopenharmony_ci	}
406d4afb5ceSopenharmony_ci
407d4afb5ceSopenharmony_ci	return 0;
408d4afb5ceSopenharmony_ci
409d4afb5ceSopenharmony_cielements_mismatch:
410d4afb5ceSopenharmony_ci	lwsl_err("%s: jwk elements mismatch\n", __func__);
411d4afb5ceSopenharmony_ci
412d4afb5ceSopenharmony_cibail:
413d4afb5ceSopenharmony_ci	lwsl_err("%s: element failed\n", __func__);
414d4afb5ceSopenharmony_ci
415d4afb5ceSopenharmony_ci	return -1;
416d4afb5ceSopenharmony_ci}
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_ciint
419d4afb5ceSopenharmony_cilws_jwk_import(struct lws_jwk *jwk, lws_jwk_key_import_callback cb, void *user,
420d4afb5ceSopenharmony_ci	       const char *in, size_t len)
421d4afb5ceSopenharmony_ci{
422d4afb5ceSopenharmony_ci	struct lejp_ctx jctx;
423d4afb5ceSopenharmony_ci	struct lws_jwk_parse_state jps;
424d4afb5ceSopenharmony_ci	int m;
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci	lws_jwk_init_jps(&jps, jwk, cb, user);
427d4afb5ceSopenharmony_ci
428d4afb5ceSopenharmony_ci	lejp_construct(&jctx, cb_jwk, &jps, cb ? jwk_outer_tok: jwk_tok,
429d4afb5ceSopenharmony_ci		       LWS_ARRAY_SIZE(jwk_tok));
430d4afb5ceSopenharmony_ci
431d4afb5ceSopenharmony_ci	m = lejp_parse(&jctx, (uint8_t *)in, (int)len);
432d4afb5ceSopenharmony_ci	lejp_destruct(&jctx);
433d4afb5ceSopenharmony_ci
434d4afb5ceSopenharmony_ci	if (m < 0) {
435d4afb5ceSopenharmony_ci		lwsl_notice("%s: parse got %d\n", __func__, m);
436d4afb5ceSopenharmony_ci		lws_jwk_destroy(jwk);
437d4afb5ceSopenharmony_ci		return -1;
438d4afb5ceSopenharmony_ci	}
439d4afb5ceSopenharmony_ci
440d4afb5ceSopenharmony_ci	switch (jwk->kty) {
441d4afb5ceSopenharmony_ci	case LWS_GENCRYPTO_KTY_UNKNOWN:
442d4afb5ceSopenharmony_ci		lwsl_notice("%s: missing or unknown kty\n", __func__);
443d4afb5ceSopenharmony_ci		lws_jwk_destroy(jwk);
444d4afb5ceSopenharmony_ci		return -1;
445d4afb5ceSopenharmony_ci	default:
446d4afb5ceSopenharmony_ci		break;
447d4afb5ceSopenharmony_ci	}
448d4afb5ceSopenharmony_ci
449d4afb5ceSopenharmony_ci	return 0;
450d4afb5ceSopenharmony_ci}
451d4afb5ceSopenharmony_ci
452d4afb5ceSopenharmony_ci
453d4afb5ceSopenharmony_ciint
454d4afb5ceSopenharmony_cilws_jwk_export(struct lws_jwk *jwk, int flags, char *p, int *len)
455d4afb5ceSopenharmony_ci{
456d4afb5ceSopenharmony_ci	char *start = p, *end = &p[*len - 1];
457d4afb5ceSopenharmony_ci	int n, m, limit, first = 1, asym = 0;
458d4afb5ceSopenharmony_ci	struct lexico *l;
459d4afb5ceSopenharmony_ci
460d4afb5ceSopenharmony_ci	/* RFC7638 lexicographic order requires
461d4afb5ceSopenharmony_ci	 *  RSA: e -> kty -> n
462d4afb5ceSopenharmony_ci	 *  oct: k -> kty
463d4afb5ceSopenharmony_ci	 *
464d4afb5ceSopenharmony_ci	 * ie, meta and key data elements appear interleaved in name alpha order
465d4afb5ceSopenharmony_ci	 */
466d4afb5ceSopenharmony_ci
467d4afb5ceSopenharmony_ci	p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{");
468d4afb5ceSopenharmony_ci
469d4afb5ceSopenharmony_ci	switch (jwk->kty) {
470d4afb5ceSopenharmony_ci	case LWS_GENCRYPTO_KTY_OCT:
471d4afb5ceSopenharmony_ci		l = lexico_oct;
472d4afb5ceSopenharmony_ci		limit = LWS_ARRAY_SIZE(lexico_oct);
473d4afb5ceSopenharmony_ci		break;
474d4afb5ceSopenharmony_ci	case LWS_GENCRYPTO_KTY_RSA:
475d4afb5ceSopenharmony_ci		l = lexico_rsa;
476d4afb5ceSopenharmony_ci		limit = LWS_ARRAY_SIZE(lexico_rsa);
477d4afb5ceSopenharmony_ci		asym = 1;
478d4afb5ceSopenharmony_ci		break;
479d4afb5ceSopenharmony_ci	case LWS_GENCRYPTO_KTY_EC:
480d4afb5ceSopenharmony_ci		l = lexico_ec;
481d4afb5ceSopenharmony_ci		limit = LWS_ARRAY_SIZE(lexico_ec);
482d4afb5ceSopenharmony_ci		asym = 1;
483d4afb5ceSopenharmony_ci		break;
484d4afb5ceSopenharmony_ci	default:
485d4afb5ceSopenharmony_ci		return -1;
486d4afb5ceSopenharmony_ci	}
487d4afb5ceSopenharmony_ci
488d4afb5ceSopenharmony_ci	for (n = 0; n < limit; n++) {
489d4afb5ceSopenharmony_ci		const char *q, *q_end;
490d4afb5ceSopenharmony_ci		char tok[12];
491d4afb5ceSopenharmony_ci		int pos = 0, f = 1;
492d4afb5ceSopenharmony_ci
493d4afb5ceSopenharmony_ci		if ((l->meta & 1) && (jwk->meta[l->idx].buf ||
494d4afb5ceSopenharmony_ci				      l->idx == (int)JWK_META_KTY)) {
495d4afb5ceSopenharmony_ci
496d4afb5ceSopenharmony_ci			switch (l->idx) {
497d4afb5ceSopenharmony_ci			case JWK_META_KTY:
498d4afb5ceSopenharmony_ci				if (!first)
499d4afb5ceSopenharmony_ci					*p++ = ',';
500d4afb5ceSopenharmony_ci				first = 0;
501d4afb5ceSopenharmony_ci				p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"%s\"",
502d4afb5ceSopenharmony_ci						  l->name, kty_names[jwk->kty]);
503d4afb5ceSopenharmony_ci				break;
504d4afb5ceSopenharmony_ci			case JWK_META_KEY_OPS:
505d4afb5ceSopenharmony_ci				if (!first)
506d4afb5ceSopenharmony_ci					*p++ = ',';
507d4afb5ceSopenharmony_ci				first = 0;
508d4afb5ceSopenharmony_ci				q = (const char *)jwk->meta[l->idx].buf;
509d4afb5ceSopenharmony_ci				q_end = q + jwk->meta[l->idx].len;
510d4afb5ceSopenharmony_ci
511d4afb5ceSopenharmony_ci				p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
512d4afb5ceSopenharmony_ci						  "\"%s\":[", l->name);
513d4afb5ceSopenharmony_ci				/*
514d4afb5ceSopenharmony_ci				 * For the public version, usages that
515d4afb5ceSopenharmony_ci				 * require the private part must be
516d4afb5ceSopenharmony_ci				 * snipped
517d4afb5ceSopenharmony_ci				 */
518d4afb5ceSopenharmony_ci
519d4afb5ceSopenharmony_ci				while (q < q_end) {
520d4afb5ceSopenharmony_ci					if (*q != ' ' && pos < (int)sizeof(tok) - 1) {
521d4afb5ceSopenharmony_ci						tok[pos++] = *q++;
522d4afb5ceSopenharmony_ci						if (q != q_end)
523d4afb5ceSopenharmony_ci							continue;
524d4afb5ceSopenharmony_ci					}
525d4afb5ceSopenharmony_ci					tok[pos] = '\0';
526d4afb5ceSopenharmony_ci					pos = 0;
527d4afb5ceSopenharmony_ci					if ((flags & LWSJWKF_EXPORT_PRIVATE) ||
528d4afb5ceSopenharmony_ci					    !asym || (strcmp(tok, "sign") &&
529d4afb5ceSopenharmony_ci						      strcmp(tok, "encrypt"))) {
530d4afb5ceSopenharmony_ci						if (!f)
531d4afb5ceSopenharmony_ci							*p++ = ',';
532d4afb5ceSopenharmony_ci						f = 0;
533d4afb5ceSopenharmony_ci						p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
534d4afb5ceSopenharmony_ci							"\"%s\"", tok);
535d4afb5ceSopenharmony_ci					}
536d4afb5ceSopenharmony_ci					q++;
537d4afb5ceSopenharmony_ci				}
538d4afb5ceSopenharmony_ci
539d4afb5ceSopenharmony_ci				*p++ = ']';
540d4afb5ceSopenharmony_ci
541d4afb5ceSopenharmony_ci				break;
542d4afb5ceSopenharmony_ci
543d4afb5ceSopenharmony_ci			default:
544d4afb5ceSopenharmony_ci				/* both sig and enc require asym private key */
545d4afb5ceSopenharmony_ci				if (!(flags & LWSJWKF_EXPORT_PRIVATE) &&
546d4afb5ceSopenharmony_ci				    asym && l->idx == (int)JWK_META_USE)
547d4afb5ceSopenharmony_ci					break;
548d4afb5ceSopenharmony_ci				if (!first)
549d4afb5ceSopenharmony_ci					*p++ = ',';
550d4afb5ceSopenharmony_ci				first = 0;
551d4afb5ceSopenharmony_ci				p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"",
552d4afb5ceSopenharmony_ci						  l->name);
553d4afb5ceSopenharmony_ci				lws_strnncpy(p, (const char *)jwk->meta[l->idx].buf,
554d4afb5ceSopenharmony_ci					     jwk->meta[l->idx].len, end - p);
555d4afb5ceSopenharmony_ci				p += strlen(p);
556d4afb5ceSopenharmony_ci				p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"");
557d4afb5ceSopenharmony_ci				break;
558d4afb5ceSopenharmony_ci			}
559d4afb5ceSopenharmony_ci		}
560d4afb5ceSopenharmony_ci
561d4afb5ceSopenharmony_ci		if ((!(l->meta & 1)) && jwk->e[l->idx].buf &&
562d4afb5ceSopenharmony_ci		    ((flags & LWSJWKF_EXPORT_PRIVATE) || !(l->meta & 2))) {
563d4afb5ceSopenharmony_ci			if (!first)
564d4afb5ceSopenharmony_ci				*p++ = ',';
565d4afb5ceSopenharmony_ci			first = 0;
566d4afb5ceSopenharmony_ci
567d4afb5ceSopenharmony_ci			p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"", l->name);
568d4afb5ceSopenharmony_ci
569d4afb5ceSopenharmony_ci			if (jwk->kty == LWS_GENCRYPTO_KTY_EC &&
570d4afb5ceSopenharmony_ci			    l->idx == (int)LWS_GENCRYPTO_EC_KEYEL_CRV) {
571d4afb5ceSopenharmony_ci				lws_strnncpy(p,
572d4afb5ceSopenharmony_ci					     (const char *)jwk->e[l->idx].buf,
573d4afb5ceSopenharmony_ci					     jwk->e[l->idx].len, end - p);
574d4afb5ceSopenharmony_ci				m = (int)strlen(p);
575d4afb5ceSopenharmony_ci			} else
576d4afb5ceSopenharmony_ci				m = lws_jws_base64_enc(
577d4afb5ceSopenharmony_ci					(const char *)jwk->e[l->idx].buf,
578d4afb5ceSopenharmony_ci					jwk->e[l->idx].len, p, lws_ptr_diff_size_t(end, p) - 4);
579d4afb5ceSopenharmony_ci			if (m < 0) {
580d4afb5ceSopenharmony_ci				lwsl_notice("%s: enc failed\n", __func__);
581d4afb5ceSopenharmony_ci				return -1;
582d4afb5ceSopenharmony_ci			}
583d4afb5ceSopenharmony_ci			p += m;
584d4afb5ceSopenharmony_ci			p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"");
585d4afb5ceSopenharmony_ci		}
586d4afb5ceSopenharmony_ci
587d4afb5ceSopenharmony_ci		l++;
588d4afb5ceSopenharmony_ci	}
589d4afb5ceSopenharmony_ci
590d4afb5ceSopenharmony_ci	p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
591d4afb5ceSopenharmony_ci			  (flags & LWSJWKF_EXPORT_NOCRLF) ? "}" : "}\n");
592d4afb5ceSopenharmony_ci
593d4afb5ceSopenharmony_ci	*len -= lws_ptr_diff(p, start);
594d4afb5ceSopenharmony_ci
595d4afb5ceSopenharmony_ci	return lws_ptr_diff(p, start);
596d4afb5ceSopenharmony_ci}
597d4afb5ceSopenharmony_ci
598d4afb5ceSopenharmony_ciint
599d4afb5ceSopenharmony_cilws_jwk_load(struct lws_jwk *jwk, const char *filename,
600d4afb5ceSopenharmony_ci	     lws_jwk_key_import_callback cb, void *user)
601d4afb5ceSopenharmony_ci{
602d4afb5ceSopenharmony_ci	unsigned int buflen = 4096;
603d4afb5ceSopenharmony_ci	char *buf = lws_malloc(buflen, "jwk-load");
604d4afb5ceSopenharmony_ci	int n;
605d4afb5ceSopenharmony_ci
606d4afb5ceSopenharmony_ci	if (!buf)
607d4afb5ceSopenharmony_ci		return -1;
608d4afb5ceSopenharmony_ci
609d4afb5ceSopenharmony_ci	n = lws_plat_read_file(filename, buf, buflen);
610d4afb5ceSopenharmony_ci	if (n < 0)
611d4afb5ceSopenharmony_ci		goto bail;
612d4afb5ceSopenharmony_ci
613d4afb5ceSopenharmony_ci	n = lws_jwk_import(jwk, cb, user, buf, (unsigned int)n);
614d4afb5ceSopenharmony_ci	lws_free(buf);
615d4afb5ceSopenharmony_ci
616d4afb5ceSopenharmony_ci	return n;
617d4afb5ceSopenharmony_cibail:
618d4afb5ceSopenharmony_ci	lws_free(buf);
619d4afb5ceSopenharmony_ci
620d4afb5ceSopenharmony_ci	return -1;
621d4afb5ceSopenharmony_ci}
622d4afb5ceSopenharmony_ci
623d4afb5ceSopenharmony_ciint
624d4afb5ceSopenharmony_cilws_jwk_save(struct lws_jwk *jwk, const char *filename)
625d4afb5ceSopenharmony_ci{
626d4afb5ceSopenharmony_ci	int buflen = 4096;
627d4afb5ceSopenharmony_ci	char *buf = lws_malloc((unsigned int)buflen, "jwk-save");
628d4afb5ceSopenharmony_ci	int n, m;
629d4afb5ceSopenharmony_ci
630d4afb5ceSopenharmony_ci	if (!buf)
631d4afb5ceSopenharmony_ci		return -1;
632d4afb5ceSopenharmony_ci
633d4afb5ceSopenharmony_ci	n = lws_jwk_export(jwk, LWSJWKF_EXPORT_PRIVATE, buf, &buflen);
634d4afb5ceSopenharmony_ci	if (n < 0)
635d4afb5ceSopenharmony_ci		goto bail;
636d4afb5ceSopenharmony_ci
637d4afb5ceSopenharmony_ci	m = lws_plat_write_file(filename, buf, (size_t)n);
638d4afb5ceSopenharmony_ci
639d4afb5ceSopenharmony_ci	lws_free(buf);
640d4afb5ceSopenharmony_ci	if (m)
641d4afb5ceSopenharmony_ci		return -1;
642d4afb5ceSopenharmony_ci
643d4afb5ceSopenharmony_ci	return 0;
644d4afb5ceSopenharmony_ci
645d4afb5ceSopenharmony_cibail:
646d4afb5ceSopenharmony_ci	lws_free(buf);
647d4afb5ceSopenharmony_ci
648d4afb5ceSopenharmony_ci	return -1;
649d4afb5ceSopenharmony_ci}
650