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