xref: /third_party/libwebsockets/lib/jose/jwe/jwe.c (revision d4afb5ce)
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