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 * JOSE is actually specified as part of JWS RFC7515. JWE references RFC7515
25 * to specify its JOSE JSON object. So it lives in ./lib/jose/jws/jose.c.
26 */
27
28 #include "private-lib-core.h"
29 #include "jose/private-lib-jose.h"
30
31 #include <stdint.h>
32
33 static const char * const jws_jose[] = {
34 "alg", /* REQUIRED */
35 "jku",
36 "jwk",
37 "kid",
38 "x5u",
39 "x5c",
40 "x5t",
41 "x5t#S256",
42 "typ",
43 "cty",
44 "crit",
45
46 /* valid for JWE only below here */
47
48 "recipients[].header",
49 "recipients[].header.alg",
50 "recipients[].header.kid",
51 "recipients[].encrypted_key",
52
53 "enc",
54 "zip", /* ("DEF" = deflate) */
55
56 "epk", /* valid for JWE ECDH only */
57 "apu", /* valid for JWE ECDH only */
58 "apv", /* valid for JWE ECDH only */
59 "iv", /* valid for JWE AES only */
60 "tag", /* valid for JWE AES only */
61 "p2s", /* valid for JWE PBES2 only */
62 "p2c" /* valid for JWE PBES2 only */
63 };
64
65 struct jose_cb_args {
66 struct lws_jose *jose;
67
68 struct lejp_ctx jwk_jctx; /* fake lejp context used to parse epk */
69 struct lws_jwk_parse_state jps; /* fake jwk parse state */
70
71 char *temp;
72 int *temp_len;
73
74 unsigned int is_jwe;
75 unsigned int recipients_array;
76
77 int recip;
78 };
79
80 /*
81 * JWE A.4.7 Complete JWE JSON Serialization example
82 *
83 * LEJPCB_CONSTRUCTED
84 * LEJPCB_START
85 * LEJPCB_OBJECT_START
86 *
87 * protected LEJPCB_PAIR_NAME
88 * protected LEJPCB_VAL_STR_START
89 * protected LEJPCB_VAL_STR_END
90 *
91 * unprotected LEJPCB_PAIR_NAME
92 * unprotected LEJPCB_OBJECT_START
93 * unprotected.jku LEJPCB_PAIR_NAME
94 * unprotected.jku LEJPCB_VAL_STR_START
95 * unprotected.jku LEJPCB_VAL_STR_END
96 * unprotected.jku LEJPCB_OBJECT_END
97 *
98 * recipients LEJPCB_PAIR_NAME
99 * recipients[] LEJPCB_ARRAY_START
100 *
101 * recipients[] LEJPCB_OBJECT_START
102 * recipients[].header LEJPCB_PAIR_NAME
103 * recipients[].header LEJPCB_OBJECT_START
104 * recipients[].header.alg LEJPCB_PAIR_NAME
105 * recipients[].header.alg LEJPCB_VAL_STR_START
106 * recipients[].header.alg LEJPCB_VAL_STR_END
107 * recipients[].header.kid LEJPCB_PAIR_NAME
108 * recipients[].header.kid LEJPCB_VAL_STR_START
109 * recipients[].header.kid LEJPCB_VAL_STR_END
110 * recipients[] LEJPCB_OBJECT_END
111 * recipients[].encrypted_key LEJPCB_PAIR_NAME
112 * recipients[].encrypted_key LEJPCB_VAL_STR_START
113 * recipients[].encrypted_key LEJPCB_VAL_STR_CHUNK
114 * recipients[].encrypted_key LEJPCB_VAL_STR_END
115 * recipients[] LEJPCB_OBJECT_END (ctx->sp = 1)
116 *
117 * recipients[] LEJPCB_OBJECT_START
118 * recipients[].header LEJPCB_PAIR_NAME
119 * recipients[].header LEJPCB_OBJECT_START
120 * recipients[].header.alg LEJPCB_PAIR_NAME
121 * recipients[].header.alg LEJPCB_VAL_STR_START
122 * recipients[].header.alg LEJPCB_VAL_STR_END
123 * recipients[].header.kid LEJPCB_PAIR_NAME
124 * recipients[].header.kid LEJPCB_VAL_STR_START
125 * recipients[].header.kid LEJPCB_VAL_STR_END
126 * recipients[] LEJPCB_OBJECT_END
127 * recipients[].encrypted_key LEJPCB_PAIR_NAME
128 * recipients[].encrypted_key LEJPCB_VAL_STR_START
129 * recipients[].encrypted_key LEJPCB_VAL_STR_END
130 * recipients[] LEJPCB_OBJECT_END (ctx->sp = 1)
131 *
132 * recipients[] LEJPCB_ARRAY_END
133 *
134 * iv LEJPCB_PAIR_NAME
135 * iv LEJPCB_VAL_STR_START
136 * iv LEJPCB_VAL_STR_END
137 * ciphertext LEJPCB_PAIR_NAME
138 * ciphertext LEJPCB_VAL_STR_START
139 * ciphertext LEJPCB_VAL_STR_END
140 * tag LEJPCB_PAIR_NAME
141 * tag LEJPCB_VAL_STR_START
142 * tag LEJPCB_VAL_STR_END
143 *
144 * tag LEJPCB_OBJECT_END
145 * tag LEJPCB_COMPLETE
146 * tag LEJPCB_DESTRUCTED
147 *
148 */
149
150 /*
151 * RFC7516 7.2.2
152 *
153 * Note that when using the flattened syntax, just as when using the
154 * general syntax, any unprotected Header Parameter values can reside in
155 * either the "unprotected" member or the "header" member, or in both.
156 */
157
158 static signed char
lws_jws_jose_cb(struct lejp_ctx * ctx,char reason)159 lws_jws_jose_cb(struct lejp_ctx *ctx, char reason)
160 {
161 struct jose_cb_args *args = (struct jose_cb_args *)ctx->user;
162 int n; //, dest;
163
164 /*
165 * In JOSE JSON, the element "epk" contains a fully-formed JWK.
166 *
167 * For JOSE paths beginning "epk.", we pass them through to a JWK
168 * LEJP subcontext to parse using the JWK parser directly.
169 */
170
171 if (args->is_jwe && !strncmp(ctx->path, "epk.", 4)) {
172 memcpy(args->jwk_jctx.path, ctx->path + 4,
173 sizeof(ctx->path) - 4);
174 memcpy(args->jwk_jctx.buf, ctx->buf, ctx->npos);
175 args->jwk_jctx.npos = ctx->npos;
176
177 if (!ctx->path_match)
178 args->jwk_jctx.path_match = 0;
179 lejp_check_path_match(&args->jwk_jctx);
180
181 if (args->jwk_jctx.path_match)
182 args->jwk_jctx.pst[args->jwk_jctx.pst_sp].
183 callback(&args->jwk_jctx, reason);
184 }
185
186 // lwsl_notice("%s: %s %d (%d)\n", __func__, ctx->path, reason, ctx->sp);
187
188 /* at the end of each recipients[] entry, bump recipients count */
189
190 if (args->is_jwe && reason == LEJPCB_OBJECT_END && ctx->sp == 1 &&
191 !strcmp(ctx->path, "recipients[]"))
192 args->jose->recipients++;
193
194 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
195 return 0;
196
197 //dest = ctx->path_match - 1;
198
199 switch (ctx->path_match - 1) {
200
201 /* strings */
202
203 case LJJHI_ALG: /* REQUIRED */
204
205 /*
206 * look up whether we support this alg and point the caller at
207 * its definition if so
208 */
209
210 if (!args->is_jwe &&
211 lws_gencrypto_jws_alg_to_definition(ctx->buf,
212 &args->jose->alg)) {
213 lwsl_notice("%s: unknown alg '%s'\n", __func__,
214 ctx->buf);
215
216 return -1;
217 }
218
219 if (args->is_jwe &&
220 lws_gencrypto_jwe_alg_to_definition(ctx->buf,
221 &args->jose->alg)) {
222 lwsl_notice("%s: unknown JWE alg '%s'\n", __func__,
223 ctx->buf);
224
225 return -1;
226 }
227
228 return 0;
229
230 case LJJHI_TYP: /* Optional: string: media type */
231 lws_strnncpy(args->jose->typ, ctx->buf, ctx->npos,
232 sizeof(args->jose->typ));
233 break;
234
235 case LJJHI_JKU: /* Optional: string */
236 case LJJHI_KID: /* Optional: string */
237 case LJJHI_X5U: /* Optional: string: url of public key cert / chain */
238 case LJJHI_CTY: /* Optional: string: content media type */
239
240 /* base64 */
241
242 case LJJHI_X5C: /* Optional: base64 (NOT -url): actual cert */
243
244 /* base64-url */
245
246 case LJJHI_X5T: /* Optional: base64url: SHA-1 of actual cert */
247 case LJJHI_X5T_S256: /* Optional: base64url: SHA-256 of actual cert */
248
249 /* array of strings */
250
251 case LJJHI_CRIT: /* Optional for send, REQUIRED: array of strings:
252 * mustn't contain standardized strings or null set */
253 break;
254
255 /* jwk child */
256
257 case LJJHI_JWK: /* Optional: jwk JSON object: public key: */
258
259 /* past here, JWE only */
260
261 case LJJHI_RECIPS_HDR:
262 if (!args->is_jwe) {
263 lwsl_info("%s: recipients in jws\n", __func__);
264 return -1;
265 }
266 args->recipients_array = 1;
267 break;
268
269 case LJJHI_RECIPS_HDR_ALG:
270 case LJJHI_RECIPS_HDR_KID:
271 break;
272
273 case LJJHI_RECIPS_EKEY:
274 if (!args->is_jwe) {
275 lwsl_info("%s: recipients in jws\n", __func__);
276 return -1;
277 }
278 args->recipients_array = 1;
279 //dest = ;
280 goto append_string;
281
282 case LJJHI_ENC: /* JWE only: Mandatory: string */
283 if (!args->is_jwe) {
284 lwsl_info("%s: enc in jws\n", __func__);
285 return -1;
286 }
287 if (lws_gencrypto_jwe_enc_to_definition(ctx->buf,
288 &args->jose->enc_alg)) {
289 lwsl_notice("%s: unknown enc '%s'\n", __func__,
290 ctx->buf);
291
292 return -1;
293 }
294 break;
295
296 case LJJHI_ZIP: /* JWE only: Optional: string ("DEF" = deflate) */
297 if (!args->is_jwe)
298 return -1;
299 goto append_string;
300
301 case LJJHI_EPK: /* Additional arg for JWE ECDH */
302 if (!args->is_jwe)
303 return -1;
304 /* Ephemeral key... this JSON subsection is actually a JWK */
305 lwsl_err("LJJHI_EPK\n");
306 break;
307
308 case LJJHI_APU: /* Additional arg for JWE ECDH */
309 if (!args->is_jwe)
310 return -1;
311 /* Agreement Party U */
312 goto append_string;
313
314 case LJJHI_APV: /* Additional arg for JWE ECDH */
315 if (!args->is_jwe)
316 return -1;
317 /* Agreement Party V */
318 goto append_string;
319
320 case LJJHI_IV: /* Additional arg for JWE AES */
321 if (!args->is_jwe)
322 return -1;
323 goto append_string;
324
325 case LJJHI_TAG: /* Additional arg for JWE AES */
326 if (!args->is_jwe)
327 return -1;
328 goto append_string;
329
330 case LJJHI_P2S: /* Additional arg for JWE PBES2 */
331 if (!args->is_jwe)
332 return -1;
333 goto append_string;
334 case LJJHI_P2C: /* Additional arg for JWE PBES2 */
335 if (!args->is_jwe)
336 return -1;
337 goto append_string;
338
339 /* ignore what we don't understand */
340
341 default:
342 return 0;
343 }
344
345 return 0;
346
347 append_string:
348
349 if (*args->temp_len < ctx->npos) {
350 lwsl_err("%s: out of parsing space\n", __func__);
351 return -1;
352 }
353
354 if (!args->jose->e[ctx->path_match - 1].buf) {
355 args->jose->e[ctx->path_match - 1].buf = (uint8_t *)args->temp;
356 args->jose->e[ctx->path_match - 1].len = 0;
357 }
358
359 memcpy(args->temp, ctx->buf, ctx->npos);
360 args->temp += ctx->npos;
361 *args->temp_len -= ctx->npos;
362 args->jose->e[ctx->path_match - 1].len += ctx->npos;
363
364 if (reason == LEJPCB_VAL_STR_END) {
365 n = lws_b64_decode_string_len(
366 (const char *)args->jose->e[ctx->path_match - 1].buf,
367 (int)args->jose->e[ctx->path_match - 1].len,
368 (char *)args->jose->e[ctx->path_match - 1].buf,
369 (int)args->jose->e[ctx->path_match - 1].len + 1);
370 if (n < 0) {
371 lwsl_err("%s: b64 decode failed\n", __func__);
372 return -1;
373 }
374
375 args->temp -= (int)args->jose->e[ctx->path_match - 1].len - n - 1;
376 *args->temp_len +=
377 (int)args->jose->e[ctx->path_match - 1].len - n - 1;
378
379 args->jose->e[ctx->path_match - 1].len = (uint32_t)n;
380 }
381
382 return 0;
383 }
384
385 void
lws_jose_init(struct lws_jose * jose)386 lws_jose_init(struct lws_jose *jose)
387 {
388 memset(jose, 0, sizeof(*jose));
389 }
390
391 static void
lws_jose_recip_destroy(struct lws_jws_recpient * r)392 lws_jose_recip_destroy(struct lws_jws_recpient *r)
393 {
394 lws_jwk_destroy(&r->jwk_ephemeral);
395 lws_jwk_destroy(&r->jwk);
396 }
397
398 void
lws_jose_destroy(struct lws_jose * jose)399 lws_jose_destroy(struct lws_jose *jose)
400 {
401 int n;
402
403 for (n = 0; n < (int)LWS_ARRAY_SIZE(jose->recipient); n++)
404 lws_jose_recip_destroy(&jose->recipient[n]);
405 }
406
407 static int
lws_jose_parse(struct lws_jose * jose,const uint8_t * buf,int n,char * temp,int * temp_len,int is_jwe)408 lws_jose_parse(struct lws_jose *jose, const uint8_t *buf, int n,
409 char *temp, int *temp_len, int is_jwe)
410 {
411 struct lejp_ctx jctx;
412 struct jose_cb_args args;
413 int m;
414
415 if (is_jwe) {
416 /* prepare a context for JOSE epk ephemeral jwk parsing */
417 lws_jwk_init_jps(&args.jps,
418 &jose->recipient[jose->recipients].jwk_ephemeral,
419 NULL, NULL);
420 lejp_construct(&args.jwk_jctx, cb_jwk, &args.jps,
421 jwk_tok, LWS_ARRAY_SIZE(jwk_tok));
422 }
423
424 args.is_jwe = (unsigned int)is_jwe;
425 args.temp = temp;
426 args.temp_len = temp_len;
427 args.jose = jose;
428 args.recip = 0;
429 args.recipients_array = 0;
430 jose->recipients = 0;
431
432 lejp_construct(&jctx, lws_jws_jose_cb, &args, jws_jose,
433 LWS_ARRAY_SIZE(jws_jose));
434
435 m = lejp_parse(&jctx, (uint8_t *)buf, n);
436 lejp_destruct(&jctx);
437 if (m < 0) {
438 lwsl_notice("%s: parse returned %d\n", __func__, m);
439 return -1;
440 }
441
442 if (!args.recipients_array && jose->recipient[0].unprot[LJJHI_ALG].buf)
443 /* if no explicit recipients[], we got one */
444 jose->recipients++;
445
446 return 0;
447 }
448
449 int
lws_jws_parse_jose(struct lws_jose * jose,const char * buf,int len,char * temp,int * temp_len)450 lws_jws_parse_jose(struct lws_jose *jose,
451 const char *buf, int len, char *temp, int *temp_len)
452 {
453 return lws_jose_parse(jose, (const uint8_t *)buf, len,
454 temp, temp_len, 0);
455 }
456
457 int
lws_jwe_parse_jose(struct lws_jose * jose,const char * buf,int len,char * temp,int * temp_len)458 lws_jwe_parse_jose(struct lws_jose *jose,
459 const char *buf, int len, char *temp, int *temp_len)
460 {
461 return lws_jose_parse(jose,
462 (const uint8_t *)buf, len, temp, temp_len, 1);
463 }
464
465 int
lws_jose_render(struct lws_jose * jose,struct lws_jwk * aux_jwk,char * out,size_t out_len)466 lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
467 char *out, size_t out_len)
468 {
469 struct lws_jwk *jwk;
470 char *end = out + out_len - 1;
471 int n, m, f, sub = 0, vl;
472
473 /* JOSE requires an alg */
474 if (!jose->alg || !jose->alg->alg)
475 goto bail;
476
477 *out++ = '{';
478
479 for (n = 0; n < LWS_COUNT_JOSE_HDR_ELEMENTS; n++) {
480 switch (n) {
481
482 /* strings */
483
484 case LJJHI_ALG: /* REQUIRED */
485 case LJJHI_JKU: /* Optional: string */
486 case LJJHI_KID: /* Optional: string */
487 case LJJHI_TYP: /* Optional: string: media type */
488 case LJJHI_CTY: /* Optional: string: content media type */
489 case LJJHI_X5U: /* Optional: string: pubkey cert / chain URL */
490 case LJJHI_ENC: /* JWE only: Optional: string */
491 case LJJHI_ZIP: /* JWE only: Optional: string ("DEF"=deflate) */
492 if (jose->e[n].buf) {
493 out += lws_snprintf(out, lws_ptr_diff_size_t(end, out),
494 "%s\"%s\":\"%s\"", sub ? ",\n" : "",
495 jws_jose[n], jose->e[n].buf);
496 sub = 1;
497 }
498 break;
499
500 case LJJHI_X5T: /* Optional: base64url: SHA-1 of actual cert */
501 case LJJHI_X5T_S256: /* Optional: base64url: SHA-256 of cert */
502 case LJJHI_APU: /* Additional arg for JWE ECDH: b64url */
503 case LJJHI_APV: /* Additional arg for JWE ECDH: b64url */
504 case LJJHI_IV: /* Additional arg for JWE AES: b64url */
505 case LJJHI_TAG: /* Additional arg for JWE AES: b64url */
506 case LJJHI_P2S: /* Additional arg for JWE PBES2: b64url: salt */
507 if (jose->e[n].buf) {
508 out += lws_snprintf(out, lws_ptr_diff_size_t(end, out),
509 "%s\"%s\":\"", sub ? ",\n" : "",
510 jws_jose[n]);
511 sub = 1;
512 m = lws_b64_encode_string_url((const char *)
513 jose->e[n].buf, (int)jose->e[n].len,
514 out, lws_ptr_diff(end, out));
515 if (m < 0)
516 return -1;
517 out += m;
518 out += lws_snprintf(out, lws_ptr_diff_size_t(end, out), "\"");
519 }
520 break;
521
522 case LJJHI_P2C: /* Additional arg for JWE PBES2: int: count */
523 break; /* don't support atm */
524
525 case LJJHI_X5C: /* Optional: base64 (NOT -url): actual cert */
526 if (jose->e[n].buf) {
527 out += lws_snprintf(out, lws_ptr_diff_size_t(end, out),
528 "%s\"%s\":\"", sub ? ",\n" : "",
529 jws_jose[n]);
530 sub = 1;
531 m = lws_b64_encode_string((const char *)
532 jose->e[n].buf, (int)jose->e[n].len,
533 out, lws_ptr_diff(end, out));
534 if (m < 0)
535 return -1;
536 out += m;
537 out += lws_snprintf(out, lws_ptr_diff_size_t(end, out), "\"");
538 }
539 break;
540
541 case LJJHI_EPK: /* Additional arg for JWE ECDH: eph pubkey */
542 case LJJHI_JWK: /* Optional: jwk JSON object: public key: */
543
544 jwk = n == LJJHI_EPK ? &jose->recipient[0].jwk_ephemeral : aux_jwk;
545 if (!jwk || !jwk->kty)
546 break;
547
548 out += lws_snprintf(out, lws_ptr_diff_size_t(end, out), "%s\"%s\":",
549 sub ? ",\n" : "", jws_jose[n]);
550 sub = 1;
551 vl = lws_ptr_diff(end, out);
552 m = lws_jwk_export(jwk, 0, out, &vl);
553 if (m < 0) {
554 lwsl_notice("%s: failed to export key\n",
555 __func__);
556
557 return -1;
558 }
559 out += m;
560 break;
561
562 case LJJHI_CRIT:/* Optional for send, REQUIRED: array of strings:
563 * mustn't contain standardized strings or null set */
564 if (!jose->e[n].buf)
565 break;
566
567 out += lws_snprintf(out, lws_ptr_diff_size_t(end, out),
568 "%s\"%s\":[", sub ? ",\n" : "", jws_jose[n]);
569 sub = 1;
570
571 m = 0;
572 f = 1;
573 while ((unsigned int)m < jose->e[n].len && (end - out) > 1) {
574 if (jose->e[n].buf[m] == ' ') {
575 if (!f)
576 *out++ = '\"';
577
578 m++;
579 f = 1;
580 continue;
581 }
582
583 if (f) {
584 if (m)
585 *out++ = ',';
586 *out++ = '\"';
587 f = 0;
588 }
589
590 *out++ = (char)jose->e[n].buf[m];
591 m++;
592 }
593
594 break;
595 }
596 }
597
598 *out++ = '}';
599
600 if (out > end - 2)
601 return -1;
602
603 return lws_ptr_diff(out_len, (end - out)) - 1;
604
605 bail:
606 return -1;
607 }
608