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