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.h"
27 #include "private-lib-jose-jwe.h"
28
29 /*
30 * Currently only support flattened or compact (implicitly single signature)
31 */
32
33 static const char * const jwe_json[] = {
34 "protected",
35 "iv",
36 "ciphertext",
37 "tag",
38 "encrypted_key"
39 };
40
41 enum enum_jwe_complete_tokens {
42 LWS_EJCT_PROTECTED,
43 LWS_EJCT_IV,
44 LWS_EJCT_CIPHERTEXT,
45 LWS_EJCT_TAG,
46 LWS_EJCT_RECIP_ENC_KEY,
47 };
48
49 /* parse a JWS complete or flattened JSON object */
50
51 struct jwe_cb_args {
52 struct lws_jws *jws;
53
54 char *temp;
55 int *temp_len;
56 };
57
58 static signed char
lws_jwe_json_cb(struct lejp_ctx * ctx,char reason)59 lws_jwe_json_cb(struct lejp_ctx *ctx, char reason)
60 {
61 struct jwe_cb_args *args = (struct jwe_cb_args *)ctx->user;
62 int n, m;
63
64 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
65 return 0;
66
67 switch (ctx->path_match - 1) {
68
69 /* strings */
70
71 case LWS_EJCT_PROTECTED: /* base64u: JOSE: must contain 'alg' */
72 m = LJWS_JOSE;
73 goto append_string;
74 case LWS_EJCT_IV: /* base64u */
75 m = LJWE_IV;
76 goto append_string;
77 case LWS_EJCT_CIPHERTEXT: /* base64u */
78 m = LJWE_CTXT;
79 goto append_string;
80 case LWS_EJCT_TAG: /* base64u */
81 m = LJWE_ATAG;
82 goto append_string;
83 case LWS_EJCT_RECIP_ENC_KEY: /* base64u */
84 m = LJWE_EKEY;
85 goto append_string;
86
87 default:
88 return -1;
89 }
90
91 return 0;
92
93 append_string:
94
95 if (*args->temp_len < ctx->npos) {
96 lwsl_err("%s: out of parsing space\n", __func__);
97 return -1;
98 }
99
100 /*
101 * We keep both b64u and decoded in temp mapped using map / map_b64,
102 * the jws signature is actually over the b64 content not the plaintext,
103 * and we can't do it until we see the protected alg.
104 */
105
106 if (!args->jws->map_b64.buf[m]) {
107 args->jws->map_b64.buf[m] = args->temp;
108 args->jws->map_b64.len[m] = 0;
109 }
110
111 memcpy(args->temp, ctx->buf, ctx->npos);
112 args->temp += ctx->npos;
113 *args->temp_len -= ctx->npos;
114 args->jws->map_b64.len[m] += ctx->npos;
115
116 if (reason == LEJPCB_VAL_STR_END) {
117 args->jws->map.buf[m] = args->temp;
118
119 n = lws_b64_decode_string_len(
120 (const char *)args->jws->map_b64.buf[m],
121 args->jws->map_b64.len[m],
122 (char *)args->temp, *args->temp_len);
123 if (n < 0) {
124 lwsl_err("%s: b64 decode failed\n", __func__);
125 return -1;
126 }
127
128 args->temp += n;
129 *args->temp_len -= n;
130 args->jws->map.len[m] = n;
131 }
132
133 return 0;
134 }
135
136 int
lws_jwe_json_parse(struct lws_jwe * jwe,const uint8_t * buf,int len,char * temp,int * temp_len)137 lws_jwe_json_parse(struct lws_jwe *jwe, const uint8_t *buf, int len,
138 char *temp, int *temp_len)
139 {
140 struct jwe_cb_args args;
141 struct lejp_ctx jctx;
142 int m = 0;
143
144 args.jws = &jwe->jws;
145 args.temp = temp;
146 args.temp_len = temp_len;
147
148 lejp_construct(&jctx, lws_jwe_json_cb, &args, jwe_json,
149 LWS_ARRAY_SIZE(jwe_json));
150
151 m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)buf, len);
152 lejp_destruct(&jctx);
153 if (m < 0) {
154 lwsl_notice("%s: parse returned %d\n", __func__, m);
155 return -1;
156 }
157
158 return 0;
159 }
160
161 void
lws_jwe_init(struct lws_jwe * jwe,struct lws_context * context)162 lws_jwe_init(struct lws_jwe *jwe, struct lws_context *context)
163 {
164 lws_jose_init(&jwe->jose);
165 lws_jws_init(&jwe->jws, &jwe->jwk, context);
166 memset(&jwe->jwk, 0, sizeof(jwe->jwk));
167 jwe->recip = 0;
168 jwe->cek_valid = 0;
169 }
170
171 void
lws_jwe_destroy(struct lws_jwe * jwe)172 lws_jwe_destroy(struct lws_jwe *jwe)
173 {
174 lws_jws_destroy(&jwe->jws);
175 lws_jose_destroy(&jwe->jose);
176 lws_jwk_destroy(&jwe->jwk);
177 /* cleanse the CEK we held on to in case of further encryptions of it */
178 lws_explicit_bzero(jwe->cek, sizeof(jwe->cek));
179 jwe->cek_valid = 0;
180 }
181
182 static uint8_t *
be32(uint32_t i,uint32_t * p32)183 be32(uint32_t i, uint32_t *p32)
184 {
185 uint8_t *p = (uint8_t *)p32;
186
187 *p++ = (i >> 24) & 0xff;
188 *p++ = (i >> 16) & 0xff;
189 *p++ = (i >> 8) & 0xff;
190 *p++ = i & 0xff;
191
192 return (uint8_t *)p32;
193 }
194
195 /*
196 * The key derivation process derives the agreed-upon key from the
197 * shared secret Z established through the ECDH algorithm, per
198 * Section 6.2.2.2 of [NIST.800-56A].
199 *
200 *
201 * Key derivation is performed using the Concat KDF, as defined in
202 * Section 5.8.1 of [NIST.800-56A], where the Digest Method is SHA-256.
203 *
204 * out must be prepared to take at least 32 bytes or the encrypted key size,
205 * whichever is larger.
206 */
207
208 int
lws_jwa_concat_kdf(struct lws_jwe * jwe,int direct,uint8_t * out,const uint8_t * shared_secret,int sslen)209 lws_jwa_concat_kdf(struct lws_jwe *jwe, int direct, uint8_t *out,
210 const uint8_t *shared_secret, int sslen)
211 {
212 int hlen = lws_genhash_size(LWS_GENHASH_TYPE_SHA256), aidlen;
213 struct lws_genhash_ctx hash_ctx;
214 uint32_t ctr = 1, t;
215 const char *aid;
216
217 if (!jwe->jose.enc_alg || !jwe->jose.alg)
218 return -1;
219
220 /*
221 * Hash
222 *
223 * AlgorithmID || PartyUInfo || PartyVInfo
224 * {|| SuppPubInfo }{|| SuppPrivInfo }
225 *
226 * AlgorithmID
227 *
228 * The AlgorithmID value is of the form Datalen || Data, where Data
229 * is a variable-length string of zero or more octets, and Datalen is
230 * a fixed-length, big-endian 32-bit counter that indicates the
231 * length (in octets) of Data. In the Direct Key Agreement case,
232 * Data is set to the octets of the ASCII representation of the "enc"
233 * Header Parameter value. In the Key Agreement with Key Wrapping
234 * case, Data is set to the octets of the ASCII representation of the
235 * "alg" (algorithm) Header Parameter value.
236 */
237
238 aid = direct ? jwe->jose.enc_alg->alg : jwe->jose.alg->alg;
239 aidlen = strlen(aid);
240
241 /*
242 * PartyUInfo (PartyVInfo is the same deal)
243 *
244 * The PartyUInfo value is of the form Datalen || Data, where Data is
245 * a variable-length string of zero or more octets, and Datalen is a
246 * fixed-length, big-endian 32-bit counter that indicates the length
247 * (in octets) of Data. If an "apu" (agreement PartyUInfo) Header
248 * Parameter is present, Data is set to the result of base64url
249 * decoding the "apu" value and Datalen is set to the number of
250 * octets in Data. Otherwise, Datalen is set to 0 and Data is set to
251 * the empty octet sequence
252 *
253 * SuppPubInfo
254 *
255 * This is set to the keydatalen represented as a 32-bit big-endian
256 * integer.
257 *
258 * keydatalen
259 *
260 * This is set to the number of bits in the desired output key. For
261 * "ECDH-ES", this is length of the key used by the "enc" algorithm.
262 * For "ECDH-ES+A128KW", "ECDH-ES+A192KW", and "ECDH-ES+A256KW", this
263 * is 128, 192, and 256, respectively.
264 *
265 * Compute Hash i = H(counter || Z || OtherInfo).
266 *
267 * We must iteratively hash over key material that's larger than
268 * one hash output size (256b for SHA-256)
269 */
270
271 while (ctr <= (uint32_t)((jwe->jose.enc_alg->keybits_fixed + (hlen - 1)) / hlen)) {
272
273 /*
274 * Key derivation is performed using the Concat KDF, as defined
275 * in Section 5.8.1 of [NIST.800-56A], where the Digest Method
276 * is SHA-256.
277 */
278
279 if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256))
280 return -1;
281
282 if (/* counter */
283 lws_genhash_update(&hash_ctx, be32(ctr++, &t), 4) ||
284 /* Z */
285 lws_genhash_update(&hash_ctx, shared_secret, sslen) ||
286 /* other info */
287 lws_genhash_update(&hash_ctx, be32(strlen(aid), &t), 4) ||
288 lws_genhash_update(&hash_ctx, aid, aidlen) ||
289 lws_genhash_update(&hash_ctx,
290 be32(jwe->jose.e[LJJHI_APU].len, &t), 4) ||
291 lws_genhash_update(&hash_ctx, jwe->jose.e[LJJHI_APU].buf,
292 jwe->jose.e[LJJHI_APU].len) ||
293 lws_genhash_update(&hash_ctx,
294 be32(jwe->jose.e[LJJHI_APV].len, &t), 4) ||
295 lws_genhash_update(&hash_ctx, jwe->jose.e[LJJHI_APV].buf,
296 jwe->jose.e[LJJHI_APV].len) ||
297 lws_genhash_update(&hash_ctx,
298 be32(jwe->jose.enc_alg->keybits_fixed, &t),
299 4) ||
300 lws_genhash_destroy(&hash_ctx, out)) {
301 lwsl_err("%s: fail\n", __func__);
302 lws_genhash_destroy(&hash_ctx, NULL);
303
304 return -1;
305 }
306
307 out += hlen;
308 }
309
310 return 0;
311 }
312
313 void
lws_jwe_be64(uint64_t c,uint8_t * p8)314 lws_jwe_be64(uint64_t c, uint8_t *p8)
315 {
316 int n;
317
318 for (n = 56; n >= 0; n -= 8)
319 *p8++ = (uint8_t)((c >> n) & 0xff);
320 }
321
322 int
lws_jwe_auth_and_decrypt(struct lws_jwe * jwe,char * temp,int * temp_len)323 lws_jwe_auth_and_decrypt(struct lws_jwe *jwe, char *temp, int *temp_len)
324 {
325 int valid_aescbc_hmac, valid_aesgcm;
326 char dotstar[96];
327
328 if (lws_jwe_parse_jose(&jwe->jose, jwe->jws.map.buf[LJWS_JOSE],
329 jwe->jws.map.len[LJWS_JOSE],
330 temp, temp_len) < 0) {
331 lws_strnncpy(dotstar, jwe->jws.map.buf[LJWS_JOSE],
332 jwe->jws.map.len[LJWS_JOSE], sizeof(dotstar));
333 lwsl_err("%s: JOSE parse '%s' failed\n", __func__, dotstar);
334 return -1;
335 }
336
337 if (!jwe->jose.alg) {
338 lws_strnncpy(dotstar, jwe->jws.map.buf[LJWS_JOSE],
339 jwe->jws.map.len[LJWS_JOSE], sizeof(dotstar));
340 lwsl_err("%s: no jose.alg: %s\n", __func__, dotstar);
341
342 return -1;
343 }
344
345 valid_aescbc_hmac = jwe->jose.enc_alg &&
346 jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_CBC &&
347 (jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA256 ||
348 jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA384 ||
349 jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA512);
350
351 valid_aesgcm = jwe->jose.enc_alg &&
352 jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_GCM;
353
354 if ((jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5 ||
355 jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP)) {
356 /* RSA + AESCBC */
357 if (valid_aescbc_hmac)
358 return lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(jwe);
359 /* RSA + AESGCM */
360 if (valid_aesgcm)
361 return lws_jwe_auth_and_decrypt_rsa_aes_gcm(jwe);
362 }
363
364 /* AESKW */
365
366 if (jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_AES_ECB &&
367 valid_aescbc_hmac)
368 return lws_jwe_auth_and_decrypt_aeskw_cbc_hs(jwe);
369
370 /* ECDH-ES + AESKW */
371
372 if (jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_ECDHES &&
373 valid_aescbc_hmac)
374 return lws_jwe_auth_and_decrypt_ecdh_cbc_hs(jwe,
375 temp, temp_len);
376
377 lwsl_err("%s: unknown cipher alg combo %s / %s\n", __func__,
378 jwe->jose.alg->alg, jwe->jose.enc_alg ?
379 jwe->jose.enc_alg->alg : "NULL");
380
381 return -1;
382 }
383 int
lws_jwe_encrypt(struct lws_jwe * jwe,char * temp,int * temp_len)384 lws_jwe_encrypt(struct lws_jwe *jwe, char *temp, int *temp_len)
385 {
386 int valid_aescbc_hmac, valid_aesgcm, ot = *temp_len, ret = -1;
387
388 if (jwe->jose.recipients >= (int)LWS_ARRAY_SIZE(jwe->jose.recipient)) {
389 lwsl_err("%s: max recipients reached\n", __func__);
390
391 return -1;
392 }
393
394 valid_aesgcm = jwe->jose.enc_alg &&
395 jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_GCM;
396
397 if (lws_jwe_parse_jose(&jwe->jose, jwe->jws.map.buf[LJWS_JOSE],
398 jwe->jws.map.len[LJWS_JOSE], temp, temp_len) < 0) {
399 lwsl_err("%s: JOSE parse failed\n", __func__);
400 goto bail;
401 }
402
403 temp += ot - *temp_len;
404
405 valid_aescbc_hmac = jwe->jose.enc_alg &&
406 jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_CBC &&
407 (jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA256 ||
408 jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA384 ||
409 jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA512);
410
411 if ((jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5 ||
412 jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP)) {
413 /* RSA + AESCBC */
414 if (valid_aescbc_hmac) {
415 ret = lws_jwe_encrypt_rsa_aes_cbc_hs(jwe, temp, temp_len);
416 goto bail;
417 }
418 /* RSA + AESGCM */
419 if (valid_aesgcm) {
420 ret = lws_jwe_encrypt_rsa_aes_gcm(jwe, temp, temp_len);
421 goto bail;
422 }
423 }
424
425 /* AESKW */
426
427 if (jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_AES_ECB &&
428 valid_aescbc_hmac) {
429 ret = lws_jwe_encrypt_aeskw_cbc_hs(jwe, temp, temp_len);
430 goto bail;
431 }
432
433 /* ECDH-ES + AESKW */
434
435 if (jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_ECDHES &&
436 valid_aescbc_hmac) {
437 ret = lws_jwe_encrypt_ecdh_cbc_hs(jwe, temp, temp_len);
438 goto bail;
439 }
440
441 lwsl_err("%s: unknown cipher alg combo %s / %s\n", __func__,
442 jwe->jose.alg->alg, jwe->jose.enc_alg ?
443 jwe->jose.enc_alg->alg : "NULL");
444
445 bail:
446 if (ret)
447 memset(&jwe->jose.recipient[jwe->jose.recipients], 0,
448 sizeof(jwe->jose.recipient[0]));
449 else
450 jwe->jose.recipients++;
451
452 return ret;
453 }
454
455 /*
456 * JWE Compact Serialization consists of
457 *
458 * BASE64URL(UTF8(JWE Protected Header)) || '.' ||
459 * BASE64URL(JWE Encrypted Key) || '.' ||
460 * BASE64URL(JWE Initialization Vector) || '.' ||
461 * BASE64URL(JWE Ciphertext) || '.' ||
462 * BASE64URL(JWE Authentication Tag)
463 *
464 *
465 * In the JWE Compact Serialization, no JWE Shared Unprotected Header or
466 * JWE Per-Recipient Unprotected Header are used. In this case, the
467 * JOSE Header and the JWE Protected Header are the same.
468 *
469 * Therefore:
470 *
471 * - Everything needed in the header part must go in the protected header
472 * (it's the only part emitted). We expect the caller did this.
473 *
474 * - You can't emit Compact representation if there are multiple recipients
475 */
476
477 int
lws_jwe_render_compact(struct lws_jwe * jwe,char * out,size_t out_len)478 lws_jwe_render_compact(struct lws_jwe *jwe, char *out, size_t out_len)
479 {
480 size_t orig = out_len;
481 int n;
482
483 if (jwe->jose.recipients > 1) {
484 lwsl_notice("%s: can't issue compact representation for"
485 " multiple recipients (%d)\n", __func__,
486 jwe->jose.recipients);
487
488 return -1;
489 }
490
491 n = lws_jws_base64_enc(jwe->jws.map.buf[LJWS_JOSE],
492 jwe->jws.map.len[LJWS_JOSE], out, out_len);
493 if (n < 0 || (int)out_len == n) {
494 lwsl_info("%s: unable to encode JOSE\n", __func__);
495 return -1;
496 }
497
498 out += n;
499 *out++ = '.';
500 out_len -= n + 1;
501
502 n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_EKEY],
503 jwe->jws.map.len[LJWE_EKEY], out, out_len);
504 if (n < 0 || (int)out_len == n) {
505 lwsl_info("%s: unable to encode EKEY\n", __func__);
506 return -1;
507 }
508
509 out += n;
510 *out++ = '.';
511 out_len -= n + 1;
512 n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_IV],
513 jwe->jws.map.len[LJWE_IV], out, out_len);
514 if (n < 0 || (int)out_len == n) {
515 lwsl_info("%s: unable to encode IV\n", __func__);
516 return -1;
517 }
518
519 out += n;
520 *out++ = '.';
521 out_len -= n + 1;
522
523 n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_CTXT],
524 jwe->jws.map.len[LJWE_CTXT], out, out_len);
525 if (n < 0 || (int)out_len == n) {
526 lwsl_info("%s: unable to encode CTXT\n", __func__);
527 return -1;
528 }
529
530 out += n;
531 *out++ = '.';
532 out_len -= n + 1;
533 n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_ATAG],
534 jwe->jws.map.len[LJWE_ATAG], out, out_len);
535 if (n < 0 || (int)out_len == n) {
536 lwsl_info("%s: unable to encode ATAG\n", __func__);
537 return -1;
538 }
539
540 out += n;
541 *out++ = '\0';
542 out_len -= n;
543
544 return orig - out_len;
545 }
546
547 int
lws_jwe_create_packet(struct lws_jwe * jwe,const char * payload,size_t len,const char * nonce,char * out,size_t out_len,struct lws_context * context)548 lws_jwe_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,
549 const char *nonce, char *out, size_t out_len,
550 struct lws_context *context)
551 {
552 char *buf, *start, *p, *end, *p1, *end1;
553 struct lws_jws jws;
554 int n, m;
555
556 lws_jws_init(&jws, &jwe->jwk, context);
557
558 /*
559 * This buffer is local to the function, the actual output is prepared
560 * into out. Only the plaintext protected header
561 * (which contains the public key, 512 bytes for 4096b) goes in
562 * here temporarily.
563 */
564 n = LWS_PRE + 2048;
565 buf = malloc(n);
566 if (!buf) {
567 lwsl_notice("%s: malloc %d failed\n", __func__, n);
568 return -1;
569 }
570
571 p = start = buf + LWS_PRE;
572 end = buf + n - LWS_PRE - 1;
573
574 /*
575 * temporary JWS protected header plaintext
576 */
577
578 if (!jwe->jose.alg || !jwe->jose.alg->alg)
579 goto bail;
580
581 p += lws_snprintf(p, end - p, "{\"alg\":\"%s\",\"jwk\":",
582 jwe->jose.alg->alg);
583 m = end - p;
584 n = lws_jwk_export(&jwe->jwk, 0, p, &m);
585 if (n < 0) {
586 lwsl_notice("failed to export jwk\n");
587
588 goto bail;
589 }
590 p += n;
591 p += lws_snprintf(p, end - p, ",\"nonce\":\"%s\"}", nonce);
592
593 /*
594 * prepare the signed outer JSON with all the parts in
595 */
596
597 p1 = out;
598 end1 = out + out_len - 1;
599
600 p1 += lws_snprintf(p1, end1 - p1, "{\"protected\":\"");
601 jws.map_b64.buf[LJWS_JOSE] = p1;
602 n = lws_jws_base64_enc(start, p - start, p1, end1 - p1);
603 if (n < 0) {
604 lwsl_notice("%s: failed to encode protected\n", __func__);
605 goto bail;
606 }
607 jws.map_b64.len[LJWS_JOSE] = n;
608 p1 += n;
609
610 p1 += lws_snprintf(p1, end1 - p1, "\",\"payload\":\"");
611 jws.map_b64.buf[LJWS_PYLD] = p1;
612 n = lws_jws_base64_enc(payload, len, p1, end1 - p1);
613 if (n < 0) {
614 lwsl_notice("%s: failed to encode payload\n", __func__);
615 goto bail;
616 }
617 jws.map_b64.len[LJWS_PYLD] = n;
618 p1 += n;
619
620 p1 += lws_snprintf(p1, end1 - p1, "\",\"header\":\"");
621 jws.map_b64.buf[LJWS_UHDR] = p1;
622 n = lws_jws_base64_enc(payload, len, p1, end1 - p1);
623 if (n < 0) {
624 lwsl_notice("%s: failed to encode payload\n", __func__);
625 goto bail;
626 }
627 jws.map_b64.len[LJWS_UHDR] = n;
628
629 p1 += n;
630 p1 += lws_snprintf(p1, end1 - p1, "\",\"signature\":\"");
631
632 /*
633 * taking the b64 protected header and the b64 payload, sign them
634 * and place the signature into the packet
635 */
636 n = lws_jws_sign_from_b64(&jwe->jose, &jws, p1, end1 - p1);
637 if (n < 0) {
638 lwsl_notice("sig gen failed\n");
639
640 goto bail;
641 }
642 jws.map_b64.buf[LJWS_SIG] = p1;
643 jws.map_b64.len[LJWS_SIG] = n;
644
645 p1 += n;
646 p1 += lws_snprintf(p1, end1 - p1, "\"}");
647
648 free(buf);
649
650 return p1 - out;
651
652 bail:
653 lws_jws_destroy(&jws);
654 free(buf);
655
656 return -1;
657 }
658
659 static const char *protected_en[] = {
660 "encrypted_key", "aad", "iv", "ciphertext", "tag"
661 };
662
663 static int protected_idx[] = {
664 LJWE_EKEY, LJWE_AAD, LJWE_IV, LJWE_CTXT, LJWE_ATAG
665 };
666
667 /*
668 * The complete JWE may look something like this:
669 *
670 * {
671 * "protected":
672 * "eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
673 * "unprotected":
674 * {"jku":"https://server.example.com/keys.jwks"},
675 * "recipients":[
676 * {"header":
677 * {"alg":"RSA1_5","kid":"2011-04-29"},
678 * "encrypted_key":
679 * "UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-
680 * kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKx
681 * GHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3
682 * YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPh
683 * cCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPg
684 * wCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A"},
685 * {"header":
686 * {"alg":"A128KW","kid":"7"},
687 * "encrypted_key":
688 * "6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ"}],
689 * "iv":
690 * "AxY8DCtDaGlsbGljb3RoZQ",
691 * "ciphertext":
692 * "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY",
693 * "tag":
694 * "Mz-VPPyU4RlcuYv1IwIvzw"
695 * }
696 *
697 * The flattened JWE ends up like this
698 *
699 * {
700 * "protected": "eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
701 * "unprotected": {"jku":"https://server.example.com/keys.jwks"},
702 * "header": {"alg":"A128KW","kid":"7"},
703 * "encrypted_key": "6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ",
704 * "iv": "AxY8DCtDaGlsbGljb3RoZQ",
705 * "ciphertext": "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY",
706 * "tag": "Mz-VPPyU4RlcuYv1IwIvzw"
707 * }
708 *
709 * {
710 * "protected":"<integrity-protected header contents>",
711 * "unprotected":<non-integrity-protected header contents>,
712 * "header":<more non-integrity-protected header contents>,
713 * "encrypted_key":"<encrypted key contents>",
714 * "aad":"<additional authenticated data contents>",
715 * "iv":"<initialization vector contents>",
716 * "ciphertext":"<ciphertext contents>",
717 * "tag":"<authentication tag contents>"
718 * }
719 */
720
721 int
lws_jwe_render_flattened(struct lws_jwe * jwe,char * out,size_t out_len)722 lws_jwe_render_flattened(struct lws_jwe *jwe, char *out, size_t out_len)
723 {
724 char buf[3072], *p1, *end1, protected[128];
725 int m, n, jlen, plen;
726
727 jlen = lws_jose_render(&jwe->jose, jwe->jws.jwk, buf, sizeof(buf));
728 if (jlen < 0) {
729 lwsl_err("%s: lws_jose_render failed\n", __func__);
730
731 return -1;
732 }
733
734 /*
735 * prepare the JWE JSON with all the parts in
736 */
737
738 p1 = out;
739 end1 = out + out_len - 1;
740
741 /*
742 * The protected header is b64url encoding of the JOSE header part
743 */
744
745 plen = lws_snprintf(protected, sizeof(protected),
746 "{\"alg\":\"%s\",\"enc\":\"%s\"}",
747 jwe->jose.alg->alg, jwe->jose.enc_alg->alg);
748
749 p1 += lws_snprintf(p1, end1 - p1, "{\"protected\":\"");
750 jwe->jws.map_b64.buf[LJWS_JOSE] = p1;
751 n = lws_jws_base64_enc(protected, plen, p1, end1 - p1);
752 if (n < 0) {
753 lwsl_notice("%s: failed to encode protected\n", __func__);
754 goto bail;
755 }
756 jwe->jws.map_b64.len[LJWS_JOSE] = n;
757 p1 += n;
758
759 /* unprotected not supported atm */
760
761 p1 += lws_snprintf(p1, end1 - p1, "\",\n\"header\":");
762 lws_strnncpy(p1, buf, jlen, end1 - p1);
763 p1 += strlen(p1);
764
765 for (m = 0; m < (int)LWS_ARRAY_SIZE(protected_en); m++)
766 if (jwe->jws.map.buf[protected_idx[m]]) {
767 p1 += lws_snprintf(p1, end1 - p1, ",\n\"%s\":\"",
768 protected_en[m]);
769 //jwe->jws.map_b64.buf[protected_idx[m]] = p1;
770 n = lws_jws_base64_enc(jwe->jws.map.buf[protected_idx[m]],
771 jwe->jws.map.len[protected_idx[m]],
772 p1, end1 - p1);
773 if (n < 0) {
774 lwsl_notice("%s: failed to encode %s\n",
775 __func__, protected_en[m]);
776 goto bail;
777 }
778 //jwe->jws.map_b64.len[protected_idx[m]] = n;
779 p1 += n;
780 p1 += lws_snprintf(p1, end1 - p1, "\"");
781 }
782
783 p1 += lws_snprintf(p1, end1 - p1, "\n}\n");
784
785 return p1 - out;
786
787 bail:
788 lws_jws_destroy(&jwe->jws);
789
790 return -1;
791 }
792