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