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