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