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