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