1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26 #include "private-lib-jose-jws.h"
27
28 /*
29 * Currently only support flattened or compact (implicitly single signature)
30 */
31
32 static const char * const jws_json[] = {
33 "protected", /* base64u */
34 "header", /* JSON */
35 "payload", /* base64u payload */
36 "signature", /* base64u signature */
37
38 //"signatures[].protected",
39 //"signatures[].header",
40 //"signatures[].signature"
41 };
42
43 enum lws_jws_json_tok {
44 LJWSJT_PROTECTED,
45 LJWSJT_HEADER,
46 LJWSJT_PAYLOAD,
47 LJWSJT_SIGNATURE,
48
49 // LJWSJT_SIGNATURES_PROTECTED,
50 // LJWSJT_SIGNATURES_HEADER,
51 // LJWSJT_SIGNATURES_SIGNATURE,
52 };
53
54 /* parse a JWS complete or flattened JSON object */
55
56 struct jws_cb_args {
57 struct lws_jws *jws;
58
59 char *temp;
60 int *temp_len;
61 };
62
63 static signed char
lws_jws_json_cb(struct lejp_ctx * ctx,char reason)64 lws_jws_json_cb(struct lejp_ctx *ctx, char reason)
65 {
66 struct jws_cb_args *args = (struct jws_cb_args *)ctx->user;
67 int n, m;
68
69 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
70 return 0;
71
72 switch (ctx->path_match - 1) {
73
74 /* strings */
75
76 case LJWSJT_PROTECTED: /* base64u: JOSE: must contain 'alg' */
77 m = LJWS_JOSE;
78 goto append_string;
79 case LJWSJT_PAYLOAD: /* base64u */
80 m = LJWS_PYLD;
81 goto append_string;
82 case LJWSJT_SIGNATURE: /* base64u */
83 m = LJWS_SIG;
84 goto append_string;
85
86 case LJWSJT_HEADER: /* unprotected freeform JSON */
87 break;
88
89 default:
90 return -1;
91 }
92
93 return 0;
94
95 append_string:
96
97 if (*args->temp_len < ctx->npos) {
98 lwsl_err("%s: out of parsing space\n", __func__);
99 return -1;
100 }
101
102 /*
103 * We keep both b64u and decoded in temp mapped using map / map_b64,
104 * the jws signature is actually over the b64 content not the plaintext,
105 * and we can't do it until we see the protected alg.
106 */
107
108 if (!args->jws->map_b64.buf[m]) {
109 args->jws->map_b64.buf[m] = args->temp;
110 args->jws->map_b64.len[m] = 0;
111 }
112
113 memcpy(args->temp, ctx->buf, ctx->npos);
114 args->temp += ctx->npos;
115 *args->temp_len -= ctx->npos;
116 args->jws->map_b64.len[m] += ctx->npos;
117
118 if (reason == LEJPCB_VAL_STR_END) {
119 args->jws->map.buf[m] = args->temp;
120
121 n = lws_b64_decode_string_len(
122 (const char *)args->jws->map_b64.buf[m],
123 args->jws->map_b64.len[m],
124 (char *)args->temp, *args->temp_len);
125 if (n < 0) {
126 lwsl_err("%s: b64 decode failed: in len %d, m %d\n", __func__, (int)args->jws->map_b64.len[m], m);
127 return -1;
128 }
129
130 args->temp += n;
131 *args->temp_len -= n;
132 args->jws->map.len[m] = n;
133 }
134
135 return 0;
136 }
137
138 static int
lws_jws_json_parse(struct lws_jws * jws,const uint8_t * buf,int len,char * temp,int * temp_len)139 lws_jws_json_parse(struct lws_jws *jws, const uint8_t *buf, int len,
140 char *temp, int *temp_len)
141 {
142 struct jws_cb_args args;
143 struct lejp_ctx jctx;
144 int m = 0;
145
146 args.jws = jws;
147 args.temp = temp;
148 args.temp_len = temp_len;
149
150 lejp_construct(&jctx, lws_jws_json_cb, &args, jws_json,
151 LWS_ARRAY_SIZE(jws_json));
152
153 m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)buf, len);
154 lejp_destruct(&jctx);
155 if (m < 0) {
156 lwsl_notice("%s: parse returned %d\n", __func__, m);
157 return -1;
158 }
159
160 return 0;
161 }
162
163 void
lws_jws_init(struct lws_jws * jws,struct lws_jwk * jwk,struct lws_context * context)164 lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk,
165 struct lws_context *context)
166 {
167 memset(jws, 0, sizeof(*jws));
168 jws->context = context;
169 jws->jwk = jwk;
170 }
171
172 static void
lws_jws_map_bzero(struct lws_jws_map * map)173 lws_jws_map_bzero(struct lws_jws_map *map)
174 {
175 int n;
176
177 /* no need to scrub first jose header element (it can be canned then) */
178
179 for (n = 1; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++)
180 if (map->buf[n])
181 lws_explicit_bzero((void *)map->buf[n], map->len[n]);
182 }
183
184 void
lws_jws_destroy(struct lws_jws * jws)185 lws_jws_destroy(struct lws_jws *jws)
186 {
187 lws_jws_map_bzero(&jws->map);
188 jws->jwk = NULL;
189 }
190
191 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 lws_jws_dup_element(struct lws_jws_map *map, int idx, char *temp, int *temp_len,
193 const void *in, size_t in_len, size_t actual_alloc)
194 {
195 if (!actual_alloc)
196 actual_alloc = in_len;
197
198 if ((size_t)*temp_len < actual_alloc)
199 return -1;
200
201 memcpy(temp, in, in_len);
202
203 map->len[idx] = in_len;
204 map->buf[idx] = temp;
205
206 *temp_len -= actual_alloc;
207
208 return 0;
209 }
210
211 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 lws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
213 char *temp, int *temp_len, const void *in,
214 size_t in_len)
215 {
216 int n;
217
218 if (*temp_len < lws_base64_size((int)in_len))
219 return -1;
220
221 n = lws_jws_base64_enc(in, in_len, temp, *temp_len);
222 if (n < 0)
223 return -1;
224
225 map->len[idx] = n;
226 map->buf[idx] = temp;
227
228 *temp_len -= n;
229
230 return 0;
231 }
232
233 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 lws_jws_randomize_element(struct lws_context *context, struct lws_jws_map *map,
235 int idx, char *temp, int *temp_len, size_t random_len,
236 size_t actual_alloc)
237 {
238 if (!actual_alloc)
239 actual_alloc = random_len;
240
241 if ((size_t)*temp_len < actual_alloc)
242 return -1;
243
244 map->len[idx] = random_len;
245 map->buf[idx] = temp;
246
247 if (lws_get_random(context, temp, random_len) != random_len) {
248 lwsl_err("Problem getting random\n");
249 return -1;
250 }
251
252 *temp_len -= actual_alloc;
253
254 return 0;
255 }
256
257 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 lws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp,
259 int *temp_len, size_t len, size_t actual_alloc)
260 {
261 if (!actual_alloc)
262 actual_alloc = len;
263
264 if ((size_t)*temp_len < actual_alloc)
265 return -1;
266
267 map->len[idx] = len;
268 map->buf[idx] = temp;
269 *temp_len -= actual_alloc;
270
271 return 0;
272 }
273
274 int
lws_jws_base64_enc(const char * in,size_t in_len,char * out,size_t out_max)275 lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max)
276 {
277 int n;
278
279 n = lws_b64_encode_string_url(in, in_len, out, out_max - 1);
280 if (n < 0) {
281 lwsl_notice("%s: in len %d too large for %d out buf\n",
282 __func__, (int)in_len, (int)out_max);
283 return n; /* too large for output buffer */
284 }
285
286 /* trim the terminal = */
287 while (n && out[n - 1] == '=')
288 n--;
289
290 out[n] = '\0';
291
292 return n;
293 }
294
295 int
lws_jws_b64_compact_map(const char * in,int len,struct lws_jws_map * map)296 lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map)
297 {
298 int me = 0;
299
300 memset(map, 0, sizeof(*map));
301
302 map->buf[me] = (char *)in;
303 map->len[me] = 0;
304
305 while (len--) {
306 if (*in++ == '.') {
307 if (++me == LWS_JWS_MAX_COMPACT_BLOCKS)
308 return -1;
309 map->buf[me] = (char *)in;
310 map->len[me] = 0;
311 continue;
312 }
313 map->len[me]++;
314 }
315
316 return me + 1;
317 }
318
319 /* b64 in, map contains decoded elements, if non-NULL,
320 * map_b64 set to b64 elements
321 */
322
323 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 lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
325 struct lws_jws_map *map_b64, char *out,
326 int *out_len)
327 {
328 int blocks, n, m = 0;
329
330 if (!map_b64)
331 map_b64 = map;
332
333 memset(map_b64, 0, sizeof(*map_b64));
334 memset(map, 0, sizeof(*map));
335
336 blocks = lws_jws_b64_compact_map(in, len, map_b64);
337
338 if (blocks > LWS_JWS_MAX_COMPACT_BLOCKS)
339 return -1;
340
341 while (m < blocks) {
342 n = lws_b64_decode_string_len(map_b64->buf[m], map_b64->len[m],
343 out, *out_len);
344 if (n < 0) {
345 lwsl_err("%s: b64 decode failed\n", __func__);
346 return -1;
347 }
348 /* replace the map entry with the decoded content */
349 if (n)
350 map->buf[m] = out;
351 else
352 map->buf[m] = NULL;
353 map->len[m++] = n;
354 out += n;
355 *out_len -= n;
356
357 if (*out_len < 1)
358 return -1;
359 }
360
361 return blocks;
362 }
363
364 static int
lws_jws_compact_decode_map(struct lws_jws_map * map_b64,struct lws_jws_map * map,char * out,int * out_len)365 lws_jws_compact_decode_map(struct lws_jws_map *map_b64, struct lws_jws_map *map,
366 char *out, int *out_len)
367 {
368 int n, m = 0;
369
370 for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) {
371 n = lws_b64_decode_string_len(map_b64->buf[m], map_b64->len[m],
372 out, *out_len);
373 if (n < 0) {
374 lwsl_err("%s: b64 decode failed\n", __func__);
375 return -1;
376 }
377 /* replace the map entry with the decoded content */
378 map->buf[m] = out;
379 map->len[m++] = n;
380 out += n;
381 *out_len -= n;
382
383 if (*out_len < 1)
384 return -1;
385 }
386
387 return 0;
388 }
389
390 int
lws_jws_encode_section(const char * in,size_t in_len,int first,char ** p,char * end)391 lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
392 char *end)
393 {
394 int n, len = (end - *p) - 1;
395 char *p_entry = *p;
396
397 if (len < 3)
398 return -1;
399
400 if (!first)
401 *(*p)++ = '.';
402
403 n = lws_jws_base64_enc(in, in_len, *p, len - 1);
404 if (n < 0)
405 return -1;
406
407 *p += n;
408
409 return (*p) - p_entry;
410 }
411
412 int
lws_jws_compact_encode(struct lws_jws_map * map_b64,const struct lws_jws_map * map,char * buf,int * len)413 lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
414 const struct lws_jws_map *map, /* non-b64 */
415 char *buf, int *len)
416 {
417 int n, m;
418
419 for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) {
420 if (!map->buf[n]) {
421 map_b64->buf[n] = NULL;
422 map_b64->len[n] = 0;
423 continue;
424 }
425 m = lws_jws_base64_enc(map->buf[n], map->len[n], buf, *len);
426 if (m < 0)
427 return -1;
428 buf += m;
429 *len -= m;
430 if (*len < 1)
431 return -1;
432 }
433
434 return 0;
435 }
436
437 /*
438 * This takes both a base64 -encoded map and a plaintext map.
439 *
440 * JWS demands base-64 encoded elements for hash computation and at least for
441 * the JOSE header and signature, decoded versions too.
442 */
443
444 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 lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
446 struct lws_jwk *jwk, struct lws_context *context)
447 {
448 enum enum_genrsa_mode padding = LGRSAM_PKCS1_1_5;
449 char temp[256];
450 int n, h_len, b = 3, temp_len = sizeof(temp);
451 uint8_t digest[LWS_GENHASH_LARGEST];
452 struct lws_genhash_ctx hash_ctx;
453 struct lws_genec_ctx ecdsactx;
454 struct lws_genrsa_ctx rsactx;
455 struct lws_genhmac_ctx ctx;
456 struct lws_jose jose;
457
458 lws_jose_init(&jose);
459
460 /* only valid if no signature or key */
461 if (!map_b64->buf[LJWS_SIG] && !map->buf[LJWS_UHDR])
462 b = 2;
463
464 if (lws_jws_parse_jose(&jose, map->buf[LJWS_JOSE], map->len[LJWS_JOSE],
465 temp, &temp_len) < 0 || !jose.alg) {
466 lwsl_notice("%s: parse failed\n", __func__);
467 return -1;
468 }
469
470 if (!strcmp(jose.alg->alg, "none")) {
471 /* "none" compact serialization has 2 blocks: jose.payload */
472 if (b != 2 || jwk)
473 return -1;
474
475 /* the lack of a key matches the lack of a signature */
476 return 0;
477 }
478
479 /* all other have 3 blocks: jose.payload.sig */
480 if (b != 3 || !jwk) {
481 lwsl_notice("%s: %d blocks\n", __func__, b);
482 return -1;
483 }
484
485 switch (jose.alg->algtype_signing) {
486 case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS:
487 case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP:
488 padding = LGRSAM_PKCS1_OAEP_PSS;
489 /* fallthru */
490 case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5:
491
492 /* RSASSA-PKCS1-v1_5 or OAEP using SHA-256/384/512 */
493
494 if (jwk->kty != LWS_GENCRYPTO_KTY_RSA)
495 return -1;
496
497 /* 6(RSA): compute the hash of the payload into "digest" */
498
499 if (lws_genhash_init(&hash_ctx, jose.alg->hash_type))
500 return -1;
501
502 /*
503 * JWS Signing Input value:
504 *
505 * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
506 * BASE64URL(JWS Payload)
507 */
508
509 if (lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE],
510 map_b64->len[LJWS_JOSE]) ||
511 lws_genhash_update(&hash_ctx, ".", 1) ||
512 lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD],
513 map_b64->len[LJWS_PYLD]) ||
514 lws_genhash_destroy(&hash_ctx, digest)) {
515 lws_genhash_destroy(&hash_ctx, NULL);
516
517 return -1;
518 }
519 // h_len = lws_genhash_size(jose.alg->hash_type);
520
521 if (lws_genrsa_create(&rsactx, jwk->e, context, padding,
522 LWS_GENHASH_TYPE_UNKNOWN)) {
523 lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
524 __func__);
525 return -1;
526 }
527
528 n = lws_genrsa_hash_sig_verify(&rsactx, digest,
529 jose.alg->hash_type,
530 (uint8_t *)map->buf[LJWS_SIG],
531 map->len[LJWS_SIG]);
532
533 lws_genrsa_destroy(&rsactx);
534 if (n < 0) {
535 lwsl_notice("%s: decrypt fail\n", __func__);
536 return -1;
537 }
538
539 break;
540
541 case LWS_JOSE_ENCTYPE_NONE: /* HSxxx */
542
543 /* SHA256/384/512 HMAC */
544
545 h_len = lws_genhmac_size(jose.alg->hmac_type);
546
547 /* 6) compute HMAC over payload */
548
549 if (lws_genhmac_init(&ctx, jose.alg->hmac_type,
550 jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf,
551 jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len))
552 return -1;
553
554 /*
555 * JWS Signing Input value:
556 *
557 * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
558 * BASE64URL(JWS Payload)
559 */
560
561 if (lws_genhmac_update(&ctx, map_b64->buf[LJWS_JOSE],
562 map_b64->len[LJWS_JOSE]) ||
563 lws_genhmac_update(&ctx, ".", 1) ||
564 lws_genhmac_update(&ctx, map_b64->buf[LJWS_PYLD],
565 map_b64->len[LJWS_PYLD]) ||
566 lws_genhmac_destroy(&ctx, digest)) {
567 lws_genhmac_destroy(&ctx, NULL);
568
569 return -1;
570 }
571
572 /* 7) Compare the computed and decoded hashes */
573
574 if (lws_timingsafe_bcmp(digest, map->buf[2], h_len)) {
575 lwsl_notice("digest mismatch\n");
576
577 return -1;
578 }
579
580 break;
581
582 case LWS_JOSE_ENCTYPE_ECDSA:
583
584 /* ECDSA using SHA-256/384/512 */
585
586 /* Confirm the key coming in with this makes sense */
587
588 /* has to be an EC key :-) */
589 if (jwk->kty != LWS_GENCRYPTO_KTY_EC)
590 return -1;
591
592 /* key must state its curve */
593 if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
594 return -1;
595
596 /* key must match the selected alg curve */
597 if (strcmp((const char *)jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
598 jose.alg->curve_name))
599 return -1;
600
601 /*
602 * JWS Signing Input value:
603 *
604 * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
605 * BASE64URL(JWS Payload)
606 *
607 * Validating the JWS Signature is a bit different from the
608 * previous examples. We need to split the 64 member octet
609 * sequence of the JWS Signature (which is base64url decoded
610 * from the value encoded in the JWS representation) into two
611 * 32 octet sequences, the first representing R and the second
612 * S. We then pass the public key (x, y), the signature (R, S),
613 * and the JWS Signing Input (which is the initial substring of
614 * the JWS Compact Serialization representation up until but not
615 * including the second period character) to an ECDSA signature
616 * verifier that has been configured to use the P-256 curve with
617 * the SHA-256 hash function.
618 */
619
620 if (lws_genhash_init(&hash_ctx, jose.alg->hash_type) ||
621 lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE],
622 map_b64->len[LJWS_JOSE]) ||
623 lws_genhash_update(&hash_ctx, ".", 1) ||
624 lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD],
625 map_b64->len[LJWS_PYLD]) ||
626 lws_genhash_destroy(&hash_ctx, digest)) {
627 lws_genhash_destroy(&hash_ctx, NULL);
628
629 return -1;
630 }
631
632 h_len = lws_genhash_size(jose.alg->hash_type);
633
634 if (lws_genecdsa_create(&ecdsactx, context, NULL)) {
635 lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
636 __func__);
637 return -1;
638 }
639
640 if (lws_genecdsa_set_key(&ecdsactx, jwk->e)) {
641 lws_genec_destroy(&ecdsactx);
642 lwsl_notice("%s: ec key import fail\n", __func__);
643 return -1;
644 }
645
646 n = lws_genecdsa_hash_sig_verify_jws(&ecdsactx, digest,
647 jose.alg->hash_type,
648 jose.alg->keybits_fixed,
649 (uint8_t *)map->buf[LJWS_SIG],
650 map->len[LJWS_SIG]);
651 lws_genec_destroy(&ecdsactx);
652 if (n < 0) {
653 lwsl_notice("%s: verify fail\n", __func__);
654 return -1;
655 }
656
657 break;
658
659 default:
660 lwsl_err("%s: unknown alg from jose\n", __func__);
661 return -1;
662 }
663
664 return 0;
665 }
666
667 /* it's already a b64 map, we will make a temp plain version */
668
669 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 lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
671 struct lws_jwk *jwk,
672 struct lws_context *context,
673 char *temp, int *temp_len)
674 {
675 struct lws_jws_map map;
676 int n;
677
678 n = lws_jws_compact_decode_map(map_b64, &map, temp, temp_len);
679 if (n > 3 || n < 0)
680 return -1;
681
682 return lws_jws_sig_confirm(map_b64, &map, jwk, context);
683 }
684
685 /*
686 * it's already a compact / concatenated b64 string, we will make a temp
687 * plain version
688 */
689
690 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 lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
692 struct lws_jws_map *map, struct lws_jwk *jwk,
693 struct lws_context *context,
694 char *temp, int *temp_len)
695 {
696 struct lws_jws_map map_b64;
697 int n;
698
699 if (lws_jws_b64_compact_map(in, len, &map_b64) < 0)
700 return -1;
701
702 n = lws_jws_compact_decode(in, len, map, &map_b64, temp, temp_len);
703 if (n > 3 || n < 0)
704 return -1;
705
706 return lws_jws_sig_confirm(&map_b64, map, jwk, context);
707 }
708
709 /* it's already plain, we will make a temp b64 version */
710
711 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 lws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk,
713 struct lws_context *context, char *temp,
714 int *temp_len)
715 {
716 struct lws_jws_map map_b64;
717
718 if (lws_jws_compact_encode(&map_b64, map, temp, temp_len) < 0)
719 return -1;
720
721 return lws_jws_sig_confirm(&map_b64, map, jwk, context);
722 }
723
724 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 lws_jws_sig_confirm_json(const char *in, size_t len,
726 struct lws_jws *jws, struct lws_jwk *jwk,
727 struct lws_context *context,
728 char *temp, int *temp_len)
729 {
730 if (lws_jws_json_parse(jws, (const uint8_t *)in, len, temp, temp_len)) {
731 lwsl_err("%s: lws_jws_json_parse failed\n", __func__);
732
733 return -1;
734 }
735 return lws_jws_sig_confirm(&jws->map_b64, &jws->map, jwk, context);
736 }
737
738
739 int
lws_jws_sign_from_b64(struct lws_jose * jose,struct lws_jws * jws,char * b64_sig,size_t sig_len)740 lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws,
741 char *b64_sig, size_t sig_len)
742 {
743 enum enum_genrsa_mode pad = LGRSAM_PKCS1_1_5;
744 uint8_t digest[LWS_GENHASH_LARGEST];
745 struct lws_genhash_ctx hash_ctx;
746 struct lws_genec_ctx ecdsactx;
747 struct lws_genrsa_ctx rsactx;
748 uint8_t *buf;
749 int n, m;
750
751 if (jose->alg->hash_type == LWS_GENHASH_TYPE_UNKNOWN &&
752 jose->alg->hmac_type == LWS_GENHMAC_TYPE_UNKNOWN &&
753 !strcmp(jose->alg->alg, "none"))
754 return 0;
755
756 if (lws_genhash_init(&hash_ctx, jose->alg->hash_type) ||
757 lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_JOSE],
758 jws->map_b64.len[LJWS_JOSE]) ||
759 lws_genhash_update(&hash_ctx, ".", 1) ||
760 lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_PYLD],
761 jws->map_b64.len[LJWS_PYLD]) ||
762 lws_genhash_destroy(&hash_ctx, digest)) {
763 lws_genhash_destroy(&hash_ctx, NULL);
764
765 return -1;
766 }
767
768 switch (jose->alg->algtype_signing) {
769 case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS:
770 case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP:
771 pad = LGRSAM_PKCS1_OAEP_PSS;
772 /* fallthru */
773 case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5:
774
775 if (jws->jwk->kty != LWS_GENCRYPTO_KTY_RSA)
776 return -1;
777
778 if (lws_genrsa_create(&rsactx, jws->jwk->e, jws->context,
779 pad, LWS_GENHASH_TYPE_UNKNOWN)) {
780 lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
781 __func__);
782 return -1;
783 }
784
785 n = jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len;
786 buf = lws_malloc(lws_base64_size(n), "jws sign");
787 if (!buf)
788 return -1;
789
790 n = lws_genrsa_hash_sign(&rsactx, digest, jose->alg->hash_type,
791 buf, n);
792 lws_genrsa_destroy(&rsactx);
793 if (n < 0) {
794 lwsl_err("%s: lws_genrsa_hash_sign failed\n", __func__);
795 lws_free(buf);
796
797 return -1;
798 }
799
800 n = lws_jws_base64_enc((char *)buf, n, b64_sig, sig_len);
801 lws_free(buf);
802 if (n < 0) {
803 lwsl_err("%s: lws_jws_base64_enc failed\n", __func__);
804 }
805
806 return n;
807
808 case LWS_JOSE_ENCTYPE_NONE:
809 return lws_jws_base64_enc((char *)digest,
810 lws_genhash_size(jose->alg->hash_type),
811 b64_sig, sig_len);
812 case LWS_JOSE_ENCTYPE_ECDSA:
813 /* ECDSA using SHA-256/384/512 */
814
815 /* the key coming in with this makes sense, right? */
816
817 /* has to be an EC key :-) */
818 if (jws->jwk->kty != LWS_GENCRYPTO_KTY_EC)
819 return -1;
820
821 /* key must state its curve */
822 if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
823 return -1;
824
825 /* must have all his pieces for a private key */
826 if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_X].buf ||
827 !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf ||
828 !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf)
829 return -1;
830
831 /* key must match the selected alg curve */
832 if (strcmp((const char *)
833 jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
834 jose->alg->curve_name))
835 return -1;
836
837 if (lws_genecdsa_create(&ecdsactx, jws->context, NULL)) {
838 lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
839 __func__);
840 return -1;
841 }
842
843 if (lws_genecdsa_set_key(&ecdsactx, jws->jwk->e)) {
844 lws_genec_destroy(&ecdsactx);
845 lwsl_notice("%s: ec key import fail\n", __func__);
846 return -1;
847 }
848 m = lws_gencrypto_bits_to_bytes(jose->alg->keybits_fixed) * 2;
849 buf = lws_malloc(m, "jws sign");
850 if (!buf)
851 return -1;
852
853 n = lws_genecdsa_hash_sign_jws(&ecdsactx, digest,
854 jose->alg->hash_type,
855 jose->alg->keybits_fixed,
856 (uint8_t *)buf, m);
857 lws_genec_destroy(&ecdsactx);
858 if (n < 0) {
859 lws_free(buf);
860 lwsl_notice("%s: lws_genecdsa_hash_sign_jws fail\n",
861 __func__);
862 return -1;
863 }
864
865 n = lws_jws_base64_enc((char *)buf, m, b64_sig, sig_len);
866 lws_free(buf);
867
868 return n;
869
870 default:
871 break;
872 }
873
874 /* unknown key type */
875
876 return -1;
877 }
878
879 /*
880 * Flattened JWS JSON:
881 *
882 * {
883 * "payload": "<payload contents>",
884 * "protected": "<integrity-protected header contents>",
885 * "header": <non-integrity-protected header contents>,
886 * "signature": "<signature contents>"
887 * }
888 */
889
890 int
lws_jws_write_flattened_json(struct lws_jws * jws,char * flattened,size_t len)891 lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len)
892 {
893 size_t n = 0;
894
895 if (len < 1)
896 return 1;
897
898 n += lws_snprintf(flattened + n, len - n , "{\"payload\": \"");
899 lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_PYLD],
900 jws->map_b64.len[LJWS_PYLD], len - n);
901 n += strlen(flattened + n);
902
903 n += lws_snprintf(flattened + n, len - n , "\",\n \"protected\": \"");
904 lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_JOSE],
905 jws->map_b64.len[LJWS_JOSE], len - n);
906 n += strlen(flattened + n);
907
908 if (jws->map_b64.buf[LJWS_UHDR]) {
909 n += lws_snprintf(flattened + n, len - n , "\",\n \"header\": ");
910 lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_UHDR],
911 jws->map_b64.len[LJWS_UHDR], len - n);
912 n += strlen(flattened + n);
913 }
914
915 n += lws_snprintf(flattened + n, len - n , "\",\n \"signature\": \"");
916 lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_SIG],
917 jws->map_b64.len[LJWS_SIG], len - n);
918 n += strlen(flattened + n);
919
920 n += lws_snprintf(flattened + n, len - n , "\"}\n");
921
922 return (n >= len - 1);
923 }
924
925 int
lws_jws_write_compact(struct lws_jws * jws,char * compact,size_t len)926 lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len)
927 {
928 size_t n = 0;
929
930 if (len < 1)
931 return 1;
932
933 lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_JOSE],
934 jws->map_b64.len[LJWS_JOSE], len - n);
935 n += strlen(compact + n);
936 lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_PYLD],
937 jws->map_b64.len[LJWS_PYLD], len - n);
938 n += strlen(compact + n);
939 lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_SIG],
940 jws->map_b64.len[LJWS_SIG], len - n);
941 n += strlen(compact + n);
942
943 return n >= len - 1;
944 }
945