• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * cose_key code
25  */
26 
27 #include "private-lib-core.h"
28 //#include "private-lib-jose.h"
29 
30 #define lwsl_cose lwsl_notice
31 #define lwsl_hexdump_cose lwsl_hexdump_notice
32 
33 // #define VERBOSE 1
34 
35 struct lws_cose_key_parse_state {
36 	struct lws_cose_key		*ck;
37 	/**< single key created here if pkey_set is NULL */
38 	char				buf[(8192 / 8) + 1];
39 	/**< enough for 8Kb key, only needed during parse */
40 	lws_cose_key_import_callback	per_key_cb;
41 	lws_dll2_owner_t		*pkey_set;
42 	/**< if non-NULL, expects a [ key set ], else single key */
43 	void				*user;
44 	size_t				pos;
45 	int				cose_state;
46 	cose_param_t			seen[16];
47 	int				seen_count;
48 	int				gencrypto_eidx;
49 	int				meta_idx;
50 	unsigned short			possible;
51 };
52 
53 /*
54  * A COSE key representation is a CBOR map with a specified structure.  The
55  * keys are
56  *
57  * 	LWSCOSE_WKK_KTY			MUST	  int / tstr
58  *	LWSCOSE_WKK_KID			OPT       bstr
59  *	LWSCOSE_WKK_ALG			OPT	  int / tstr
60  *	LWSCOSE_WKK_KEY_OPS		OPT	  [ + (int / tstr) ]
61  *	LWSCOSE_WKK_BASE_IV		OPT	  bstr
62  */
63 
64 #if defined(_DEBUG)
65 
66 static const char *meta_names[] = {
67 	"kty", "kid", "use", "key_ops", "base_iv", "alg"
68 };
69 
70 static const char *oct_names[] = {
71 	"k"
72 };
73 
74 static const char *rsa_names[] = {
75 	"e", "n", "d", "p", "q", "dp", "dq", "qi", "other", "ri", "di", "ti"
76 };
77 
78 static const char *ec_names[] = {
79 	"crv", "x", "d", "y",
80 };
81 
82 void
lws_cose_key_dump(const struct lws_cose_key * ck)83 lws_cose_key_dump(const struct lws_cose_key *ck)
84 {
85 	const char **enames;
86 	char hex[2048];
87 	int elems;
88 	int n;
89 
90 	(void)enames;
91 	(void)meta_names;
92 
93 	switch (ck->gencrypto_kty) {
94 
95 	case LWS_GENCRYPTO_KTY_OCT:
96 		elems = LWS_GENCRYPTO_OCT_KEYEL_COUNT;
97 		enames = oct_names;
98 		break;
99 	case LWS_GENCRYPTO_KTY_RSA:
100 		elems = LWS_GENCRYPTO_RSA_KEYEL_COUNT;
101 		enames = rsa_names;
102 		break;
103 	case LWS_GENCRYPTO_KTY_EC:
104 		elems = LWS_GENCRYPTO_EC_KEYEL_COUNT;
105 		enames = ec_names;
106 		break;
107 
108 	default:
109 		lwsl_err("%s: jwk %p: unknown type\n", __func__, ck);
110 
111 		return;
112 	}
113 
114 	lwsl_cose("%s: cose_key %p, kty: %lld (gc %d)\n", __func__, ck,
115 			(long long)ck->kty, ck->gencrypto_kty);
116 
117 	for (n = 0; n < LWS_COUNT_COSE_KEY_ELEMENTS; n++) {
118 		if (ck->meta[n].buf) {
119 			lws_hex_from_byte_array(ck->meta[n].buf, ck->meta[n].len,
120 						hex, sizeof(hex));
121 			lwsl_cose("  meta: %s: %s\n", meta_names[n], hex);
122 		}
123 	}
124 
125 	for (n = 0; n < elems; n++) {
126 		if (ck->e[n].buf) {
127 			lws_hex_from_byte_array(ck->e[n].buf, ck->e[n].len,
128 						hex, sizeof(hex));
129 			lwsl_cose("  e: %s: %s\n", enames[n], hex);
130 		}
131 	}
132 }
133 #endif
134 
135 static const char * const kty_strings[] = { NULL,
136 	"OKP", "EC2", "RSA", "SYMMETRIC", "HSS_LMS", "WALNUTDSA"
137 };
138 
139 int
lws_cose_key_checks(const lws_cose_key_t * key,int64_t kty,cose_param_t alg,int key_op,const char * crv)140 lws_cose_key_checks(const lws_cose_key_t *key, int64_t kty, cose_param_t alg,
141 		    int key_op, const char *crv)
142 {
143 	const struct lws_gencrypto_keyelem *ke;
144 
145 	/*
146 	 * we ourselves have to have a very clear idea what we need, even if
147 	 * matches are optional in the key itself
148 	 */
149 	assert(key);
150 	assert(kty);
151 	assert(alg);
152 	assert(key_op);
153 	assert((kty != LWSCOSE_WKKTV_OKP && kty != LWSCOSE_WKKTV_EC2) || crv);
154 
155 	/* RFC8152 8.1:
156 	 *
157 	 * The 'kty' field MUST be present, and it MUST be '...'.
158 	 *
159 	 * But kty can come as an int or a string, but we convert well-known
160 	 * kty ints to the corresponding string representation at key import
161 	 */
162 	if (!kty || kty >= (int)LWS_ARRAY_SIZE(kty_strings)) {
163 		/* we don't understand it */
164 		lwsl_notice("%s: unknown kty %d\n", __func__, (int)kty);
165 		goto bail;
166 	}
167 
168 	ke = &key->meta[COSEKEY_META_KTY];
169 	if (ke->buf && (strlen(kty_strings[kty]) != ke->len ||
170 			memcmp(kty_strings[kty], ke->buf, ke->len))) {
171 		lwsl_notice("%s: key is of wrong kty\n", __func__);
172 		lwsl_hexdump_notice(ke->buf, ke->len);
173 		goto bail;
174 	}
175 
176 	/* ...
177 	 * If the 'alg' field is present, it MUST match the ... signature
178 	 * algorithm being used.
179 	 *
180 	 * We attempt to convert key alg text representations to a well-known
181 	 * index, if we can't, then we don't know the alg anyway and should fail
182 	 * it
183 	 */
184 
185 	if (!key->cose_alg && key->meta[COSEKEY_META_ALG].buf) {
186 		lwsl_notice("%s: alg fail 1\n", __func__);
187 		goto bail;
188 	}
189 
190 	if (key->cose_alg && /* accept it being absent altogether */
191 	    key->cose_alg != alg) {
192 		lwsl_notice("%s: alg fail 2\n", __func__);
193 
194 		goto bail;
195 	}
196 
197 	/* ...
198 	 * If the 'key_ops' field is present, it MUST include 'sign' / 'verify'
199 	 * when creating /verifying an ... signature.
200 	 */
201 
202 	ke = &key->meta[COSEKEY_META_KEY_OPS];
203 	if (ke->buf && ke->len) {
204 		uint32_t n;
205 
206 		for (n = 0; n < ke->len; n++)
207 			if (ke->buf[n] == key_op)
208 				break;
209 
210 		if (n == ke->len)
211 			goto bail;
212 	}
213 
214 	/*
215 	 * If it's related to EC, check there is a curve associated with the
216 	 * key, and check it is what we expect
217 	 */
218 
219 	if (kty == LWSCOSE_WKKTV_OKP || kty == LWSCOSE_WKKTV_EC2) {
220 		ke = &key->e[LWS_GENCRYPTO_EC_KEYEL_CRV];
221 
222 		if (!ke->buf)
223 			goto bail;
224 		if (ke->len != strlen(crv))
225 			goto bail;
226 		if (memcmp(ke->buf, crv, ke->len))
227 			goto bail;
228 	}
229 
230 	/* We're willing to use this key for this operation */
231 
232 	return 0;
233 
234 bail:
235 	lwsl_notice("%s: key rejected\n", __func__);
236 
237 	return 1;
238 }
239 
240 
241 static int
lws_ck_set_el(struct lws_gencrypto_keyelem * e,char * in,size_t len)242 lws_ck_set_el(struct lws_gencrypto_keyelem *e, char *in, size_t len)
243 {
244 	e->buf = lws_malloc(len + 1, "ck");
245 	if (!e->buf)
246 		return -1;
247 
248 	memcpy(e->buf, in, len);
249 	e->buf[len] = '\0';
250 	e->len = (uint32_t)len;
251 
252 	return 0;
253 }
254 
255 static struct {
256 	const char *curve;
257 	cose_param_t cose_id;
258 } cose_curves[] = {
259 	{ "P-256",	LWSCOSE_WKEC_P256 },
260 	{ "P-384",	LWSCOSE_WKEC_P384 },
261 	{ "P-521",	LWSCOSE_WKEC_P521 },
262 	{ "X25519",	LWSCOSE_WKEC_X25519 },
263 	{ "X448",	LWSCOSE_WKEC_X448 },
264 	{ "ED25519",	LWSCOSE_WKEC_ED25519 },
265 	{ "ED448",	LWSCOSE_WKEC_ED448 },
266 	{ "SECP256K1",	LWSCOSE_WKEC_SECP256K1 },
267 };
268 
269 /* 0 means failed */
270 
271 static cose_param_t
lws_cose_curve_name_to_id(const char * curve)272 lws_cose_curve_name_to_id(const char *curve)
273 {
274 	int n;
275 
276 	for (n = 0; n < (int)LWS_ARRAY_SIZE(cose_curves); n++)
277 		if (!strcmp(cose_curves[n].curve, curve))
278 			return cose_curves[n].cose_id;
279 
280 	return 0;
281 }
282 
283 static const char *
lws_cose_curve_id_to_name(cose_param_t id)284 lws_cose_curve_id_to_name(cose_param_t id)
285 {
286 	int n;
287 
288 	for (n = 0; n < (int)LWS_ARRAY_SIZE(cose_curves); n++)
289 		if (cose_curves[n].cose_id == id)
290 			return cose_curves[n].curve;
291 
292 	return 0;
293 }
294 
295 static const char * const wk_algs[] = {
296 	"ES256", "ES384", "ES512"
297 };
298 static signed char wk_alg_indexes[] = {
299 	LWSCOSE_WKAECDSA_ALG_ES256,
300 	LWSCOSE_WKAECDSA_ALG_ES384,
301 	LWSCOSE_WKAECDSA_ALG_ES512,
302 };
303 
304 static signed char
cb_cose_key(struct lecp_ctx * ctx,char reason)305 cb_cose_key(struct lecp_ctx *ctx, char reason)
306 {
307 	struct lws_cose_key_parse_state *cps =
308 			(struct lws_cose_key_parse_state *)ctx->user;
309 	struct lws_gencrypto_keyelem *ke = NULL;
310 	const char *p;
311 	int n;
312 
313 #if defined(VERBOSE)
314 	lwsl_notice("%s: reason %d, path %s, ord %u, ppos %d\n", __func__,
315 			reason & 0x3f,
316 			ctx->path, ctx->st[ctx->sp - 1].ordinal,
317 			ctx->pst[ctx->pst_sp].ppos);
318 #endif
319 
320 	switch (reason) {
321 	case LECPCB_OBJECT_START:
322 		if (cps->ck)
323 			break;
324 		goto ak;
325 	case LECPCB_ARRAY_ITEM_START:
326 		if (cps->pkey_set && ctx->pst[ctx->pst_sp].ppos == 2) {
327 			ak:
328 			cps->ck = lws_zalloc(sizeof(*cps->ck), __func__);
329 			if (!cps->ck)
330 				goto bail;
331 			cps->cose_state = 0;
332 			cps->meta_idx = -1;
333 			cps->gencrypto_eidx = -1;
334 			cps->seen_count = 0;
335 
336 			if (cps->pkey_set)
337 				lws_dll2_add_tail(&cps->ck->list, cps->pkey_set);
338 		}
339 		break;
340 	case LECPCB_ARRAY_ITEM_END:
341 		if (cps->pkey_set && ctx->pst[ctx->pst_sp].ppos == 2) {
342 			if (cps->per_key_cb)
343 				cps->per_key_cb(cps->ck, cps->user);
344 		}
345 		break;
346 	case LECPCB_TAG_START:
347 		if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_KEY) {
348 			lwsl_warn("%s: unexpected tag\n", __func__);
349 			goto bail;
350 		}
351 		break;
352 
353 	case LECPCB_VAL_NUM_INT:
354 	case LECPCB_VAL_NUM_UINT:
355 		if (!ctx->sp) {
356 			lwsl_warn("%s: unexpected uint %d, ppos %d\n",
357 				  __func__, ctx->sp, ctx->pst[ctx->sp].ppos);
358 			goto bail;
359 		}
360 
361 		if (!lecp_parse_map_is_key(ctx)) {
362 			const char *kty_str;
363 
364 			/* value part of map */
365 
366 			switch (cps->cose_state) {
367 			case LWSCOSE_WKK_KTY:
368 				assert(cps->ck);
369 				cps->ck->kty = (int)ctx->item.u.u64;
370 
371 				/* convert the cose key type to gencrypto one */
372 				switch (ctx->item.u.u64) {
373 				case LWSCOSE_WKKTV_OKP:
374 					cps->ck->gencrypto_kty =
375 							LWS_GENCRYPTO_KTY_EC;
376 					kty_str = "OKP";
377 					break;
378 				case LWSCOSE_WKKTV_EC2:
379 					kty_str = "EC2";
380 					cps->ck->gencrypto_kty =
381 							LWS_GENCRYPTO_KTY_EC;
382 					break;
383 				case LWSCOSE_WKKTV_RSA:
384 					kty_str = "RSA";
385 					cps->ck->gencrypto_kty =
386 							LWS_GENCRYPTO_KTY_RSA;
387 					break;
388 				case LWSCOSE_WKKTV_SYMMETRIC:
389 					kty_str = "SYMMETRIC";
390 					cps->ck->gencrypto_kty =
391 							LWS_GENCRYPTO_KTY_OCT;
392 					break;
393 				// case LWSCOSE_WKKTV_HSS_LMS:
394 				// case LWSCOSE_WKKTV_WALNUTDSA:
395 				default:
396 					lwsl_warn("%s: unknown kty\n", __func__);
397 					goto bail;
398 				}
399 
400 				/* store the string version of the key type */
401 
402 				ke = &cps->ck->meta[COSEKEY_META_KTY];
403 				ke->len = (uint32_t)strlen(kty_str);
404 				ke->buf = lws_malloc(ke->len + 1, __func__);
405 				if (!ke->buf)
406 					goto bail;
407 				memcpy(ke->buf, kty_str, ke->len + 1);
408 				break;
409 			case LWSCOSE_WKK_ALG:
410 				/*
411 				 * He can tie the key to a cose alg code
412 				 */
413 				cps->ck->cose_alg = (int)ctx->item.u.u64;
414 				break;
415 			case LWSCOSE_WKK_KEY_OPS:
416 				if (!cps->pkey_set &&
417 				    (ctx->pst[ctx->sp].ppos != 3 ||
418 				     strcmp(ctx->path, ".[]"))) {
419 					lwsl_warn("%s: unexpected kops\n",
420 								__func__);
421 					goto bail;
422 				}
423 				if (cps->pkey_set &&
424 				    (ctx->pst[ctx->sp].ppos != 5 ||
425 				     strcmp(ctx->path, "[].[]"))) {
426 					lwsl_warn("%s: unexpected kops\n",
427 								__func__);
428 					goto bail;
429 				}
430 				break;
431 			case LWSCOSE_WKOKP_CRV:
432 				cps->ck->cose_curve = (int)ctx->item.u.u64;
433 				p = lws_cose_curve_id_to_name(cps->ck->cose_curve);
434 				if (p) {
435 					ke = &cps->ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV];
436 					ke->len = (uint32_t)strlen(p);
437 					ke->buf = lws_malloc(ke->len + 1, __func__);
438 					if (!ke->buf)
439 						goto bail;
440 					memcpy(ke->buf, p, ke->len);
441 					ke->buf[ke->len] = '\0';
442 				}
443 				break;
444 			default:
445 				lwsl_warn("%s: uint not allowed in state %d\n",
446 						__func__, cps->cose_state);
447 				/* int not allowed in this state */
448 				goto bail;
449 			}
450 
451 			cps->cose_state = 0;
452 			break;
453 		}
454 
455 		/* key part of map pair */
456 
457 		/*
458 		 * Disallow any of these coming more than once
459 		 */
460 		cps->cose_state = (int)ctx->item.u.u64;
461 		for (n = 0 ; n < cps->seen_count; n++)
462 			if (cps->seen[n] == cps->cose_state) {
463 				/* dupe */
464 				lwsl_warn("%s: duplicate map name %d\n",
465 						__func__, cps->cose_state);
466 				goto bail;
467 			}
468 
469 		if (cps->seen_count >= (int)LWS_ARRAY_SIZE(cps->seen))
470 			goto bail;
471 		cps->seen[cps->seen_count++] = cps->cose_state;
472 
473 		cps->meta_idx = -1;
474 		switch ((int)ctx->item.u.u64) {
475 		case LWSCOSE_WKK_KTY:
476 			cps->meta_idx = COSEKEY_META_KTY;
477 			break;
478 		case LWSCOSE_WKK_KID:
479 			cps->meta_idx = COSEKEY_META_KID;
480 			break;
481 		case LWSCOSE_WKK_ALG:
482 			cps->meta_idx = COSEKEY_META_ALG;
483 			break;
484 		case LWSCOSE_WKK_KEY_OPS:
485 			cps->meta_idx = COSEKEY_META_KEY_OPS;
486 			break;
487 		case LWSCOSE_WKK_BASE_IV:
488 			cps->meta_idx = COSEKEY_META_BASE_IV;
489 			break;
490 
491 		default:
492 			cps->gencrypto_eidx = -1;
493 
494 			switch (cps->ck->kty) {
495 			case LWSCOSE_WKKTV_OKP:
496 				switch ((int)ctx->item.u.u64) {
497 				case LWSCOSE_WKOKP_CRV:
498 					cps->cose_state = LWSCOSE_WKOKP_CRV;
499 					break;
500 				case LWSCOSE_WKOKP_X:
501 					cps->gencrypto_eidx =
502 						LWS_GENCRYPTO_EC_KEYEL_X;
503 					break;
504 				case LWSCOSE_WKOKP_D:
505 					cps->gencrypto_eidx =
506 						LWS_GENCRYPTO_EC_KEYEL_D;
507 					break;
508 				default:
509 					goto bail;
510 				}
511 				break;
512 			case LWSCOSE_WKKTV_EC2:
513 				switch ((int)ctx->item.u.u64) {
514 				case LWSCOSE_WKECKP_CRV:
515 					cps->cose_state = LWSCOSE_WKOKP_CRV;
516 					break;
517 				case LWSCOSE_WKECKP_X:
518 					cps->gencrypto_eidx =
519 						LWS_GENCRYPTO_EC_KEYEL_X;
520 					break;
521 				case LWSCOSE_WKECKP_Y:
522 					cps->gencrypto_eidx =
523 						LWS_GENCRYPTO_EC_KEYEL_Y;
524 					break;
525 				case LWSCOSE_WKECKP_D:
526 					cps->gencrypto_eidx =
527 						LWS_GENCRYPTO_EC_KEYEL_D;
528 					break;
529 				default:
530 					goto bail;
531 				}
532 				break;
533 			case LWSCOSE_WKKTV_RSA:
534 				switch ((int)ctx->item.u.u64) {
535 				case LWSCOSE_WKKPRSA_N:
536 					cps->gencrypto_eidx =
537 						LWS_GENCRYPTO_RSA_KEYEL_N;
538 					break;
539 				case LWSCOSE_WKKPRSA_E:
540 					cps->gencrypto_eidx =
541 						LWS_GENCRYPTO_RSA_KEYEL_E;
542 					break;
543 				case LWSCOSE_WKKPRSA_D:
544 					cps->gencrypto_eidx =
545 						LWS_GENCRYPTO_RSA_KEYEL_D;
546 					break;
547 				case LWSCOSE_WKKPRSA_P:
548 					cps->gencrypto_eidx =
549 						LWS_GENCRYPTO_RSA_KEYEL_P;
550 					break;
551 				case LWSCOSE_WKKPRSA_Q:
552 					cps->gencrypto_eidx =
553 						LWS_GENCRYPTO_RSA_KEYEL_Q;
554 					break;
555 				case LWSCOSE_WKKPRSA_DP:
556 					cps->gencrypto_eidx =
557 						LWS_GENCRYPTO_RSA_KEYEL_DP;
558 					break;
559 				case LWSCOSE_WKKPRSA_DQ:
560 					cps->gencrypto_eidx =
561 						LWS_GENCRYPTO_RSA_KEYEL_DQ;
562 					break;
563 				case LWSCOSE_WKKPRSA_QINV:
564 					cps->gencrypto_eidx =
565 						LWS_GENCRYPTO_RSA_KEYEL_QI;
566 					break;
567 				case LWSCOSE_WKKPRSA_OTHER:
568 					cps->gencrypto_eidx =
569 						LWS_GENCRYPTO_RSA_KEYEL_OTHER;
570 					break;
571 				case LWSCOSE_WKKPRSA_RI:
572 					cps->gencrypto_eidx =
573 						LWS_GENCRYPTO_RSA_KEYEL_RI;
574 					break;
575 				case LWSCOSE_WKKPRSA_DI:
576 					cps->gencrypto_eidx =
577 						LWS_GENCRYPTO_RSA_KEYEL_DI;
578 					break;
579 				case LWSCOSE_WKKPRSA_TI:
580 					cps->gencrypto_eidx =
581 						LWS_GENCRYPTO_RSA_KEYEL_TI;
582 					break;
583 				default:
584 					goto bail;
585 				}
586 				break;
587 			case LWSCOSE_WKKTV_SYMMETRIC:
588 				if (ctx->item.u.i64 != -1 &&
589 				    ctx->item.u.u64 != LWSCOSE_WKSYMKP_KEY_VALUE)
590 					goto bail;
591 
592 				cps->gencrypto_eidx = LWS_GENCRYPTO_OCT_KEYEL_K;
593 				break;
594 			default:
595 				lwsl_warn("%s: unknown kty\n", __func__);
596 				goto bail;
597 			}
598 			break;
599 		}
600 		break;
601 
602 	case LECPCB_VAL_BLOB_START:
603 		if (!ctx->sp || !(ctx->st[ctx->sp - 1].ordinal & 1)) {
604 			lwsl_warn("%s: unexpected blob\n", __func__);
605 			goto bail;
606 		}
607 
608 		if (cps->cose_state == COSEKEY_META_KID)
609 			break;
610 
611 		/*
612 		 * Validate the association of the blob now, collect it into
613 		 * the temp buf in cps and then alloc and copy it into the
614 		 * related key element when it's at the end and the size known
615 		 */
616 
617 		cps->pos = 0;
618 		if (cps->gencrypto_eidx >= 0) {
619 			if (cps->ck->e[cps->gencrypto_eidx].buf) {
620 				lwsl_warn("%s: e[%d] set twice %d\n", __func__,
621 						cps->gencrypto_eidx,
622 						cps->ck->e[cps->gencrypto_eidx].len);
623 				/* key elements must only come at most once */
624 				goto bail;
625 			}
626 			break;
627 		}
628 		if (cps->meta_idx >= 0)
629 			break;
630 
631 		goto bail;
632 
633 	case LECPCB_VAL_BLOB_CHUNK:
634 	case LECPCB_VAL_BLOB_END:
635 		if (cps->pos + ctx->npos > sizeof(cps->buf)) {
636 			lwsl_warn("%s: oversize blob\n", __func__);
637 			goto bail;
638 		}
639 		memcpy(cps->buf + cps->pos, ctx->buf, ctx->npos);
640 		cps->pos += ctx->npos;
641 
642 		if (reason == LECPCB_VAL_BLOB_CHUNK)
643 			break;
644 
645 		/* we have the key element data, let's make the ck element */
646 		if (cps->gencrypto_eidx >= 0) {
647 
648 			if (cps->ck->e[cps->gencrypto_eidx].buf)
649 				break;
650 
651 			lws_ck_set_el(&cps->ck->e[cps->gencrypto_eidx],
652 					(char *)cps->buf, cps->pos);
653 			cps->gencrypto_eidx = -1;
654 			break;
655 		}
656 
657 
658 		if (cps->meta_idx >= 0) {
659 			lws_ck_set_el(&cps->ck->meta[cps->meta_idx],
660 					(char *)cps->buf, cps->pos);
661 			cps->meta_idx = -1;
662 		}
663 		cps->pos = 0;
664 		break;
665 	case LECPCB_VAL_STR_END:
666 		if (cps->cose_state == LWSCOSE_WKOKP_CRV) {
667 			cps->ck->cose_curve = lws_cose_curve_name_to_id(ctx->buf);
668 			ke = &cps->ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV];
669 			ke->len = ctx->npos;
670 			ke->buf = lws_malloc(ctx->npos, __func__);
671 			if (!ke->buf)
672 				goto bail;
673 			memcpy(ke->buf, ctx->buf, ctx->npos);
674 		}
675 
676 		if (!lecp_parse_map_is_key(ctx) &&
677 		    cps->cose_state == LWSCOSE_WKK_ALG) {
678 			size_t n;
679 
680 			for (n = 0; n < LWS_ARRAY_SIZE(wk_algs); n++)
681 				if (ctx->npos == strlen(wk_algs[n]) &&
682 				    !memcmp(ctx->buf, wk_algs[n], ctx->npos)) {
683 					cps->ck->cose_alg = wk_alg_indexes[n];
684 					break;
685 				}
686 
687 			if (n == LWS_ARRAY_SIZE(wk_algs))
688 				/* key is for an alg we don't understand */
689 				lwsl_warn("%s: key for unknown alg %.*s\n",
690 					  __func__, (int)ctx->npos, ctx->buf);
691 
692 			ke = &cps->ck->meta[COSEKEY_META_ALG];
693 			ke->len = ctx->npos;
694 			ke->buf = lws_malloc(ctx->npos, __func__);
695 			if (!ke->buf)
696 				goto bail;
697 			memcpy(ke->buf, ctx->buf, ctx->npos);
698 		}
699 
700 		break;
701 	}
702 
703 	return 0;
704 
705 bail:
706 	lwsl_warn("%s: bail\n", __func__);
707 	lws_cose_key_destroy(&cps->ck);
708 
709 	if (cps->pkey_set) {
710 		lws_cose_key_set_destroy(cps->pkey_set);
711 		cps->pkey_set = NULL;
712 	}
713 
714 	return -1;
715 }
716 
717 void
lws_cose_key_destroy_elements(struct lws_gencrypto_keyelem * el,int m)718 lws_cose_key_destroy_elements(struct lws_gencrypto_keyelem *el, int m)
719 {
720 	int n;
721 
722 	if (!el)
723 		return;
724 
725 	for (n = 0; n < m; n++)
726 		if (el[n].buf) {
727 			/* wipe all key material when it goes out of scope */
728 			lws_explicit_bzero(el[n].buf, el[n].len);
729 			lws_free_set_NULL(el[n].buf);
730 			el[n].len = 0;
731 		}
732 }
733 
734 void
lws_cose_key_destroy(struct lws_cose_key ** pck)735 lws_cose_key_destroy(struct lws_cose_key **pck)
736 {
737 	struct lws_cose_key *ck = *pck;
738 
739 	if (!ck)
740 		return;
741 
742 	lws_dll2_remove(&ck->list);
743 
744 	lws_cose_key_destroy_elements(ck->e, LWS_ARRAY_SIZE(ck->e));
745 	lws_cose_key_destroy_elements(ck->meta, LWS_ARRAY_SIZE(ck->meta));
746 
747 	lws_free_set_NULL(*pck);
748 }
749 
750 static int
lws_cose_key_set_memb_remove(struct lws_dll2 * d,void * user)751 lws_cose_key_set_memb_remove(struct lws_dll2 *d, void *user)
752 {
753 	lws_cose_key_t *ck = lws_container_of(d, lws_cose_key_t, list);
754 
755 	lws_dll2_remove(d);
756 	lws_cose_key_destroy(&ck);
757 
758 	return 0;
759 }
760 
761 void
lws_cose_key_set_destroy(lws_dll2_owner_t * o)762 lws_cose_key_set_destroy(lws_dll2_owner_t *o)
763 {
764 	lws_dll2_foreach_safe(o, NULL, lws_cose_key_set_memb_remove);
765 }
766 
767 lws_cose_key_t *
lws_cose_key_from_set(lws_dll2_owner_t * set,const uint8_t * kid,size_t kl)768 lws_cose_key_from_set(lws_dll2_owner_t *set, const uint8_t *kid, size_t kl)
769 {
770 	lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(set)) {
771 		lws_cose_key_t *ck = lws_container_of(p, lws_cose_key_t, list);
772 		struct lws_gencrypto_keyelem *ke = &ck->meta[COSEKEY_META_KID];
773 
774 		if (!kid) /* always the first then */
775 			return ck;
776 
777 		if (ke->buf && ke->len == (uint32_t)kl &&
778 		    !memcmp(ke->buf, kid, ke->len))
779 			return ck;
780 
781 	} lws_end_foreach_dll(p);
782 
783 	return NULL;
784 }
785 
786 lws_cose_key_t *
lws_cose_key_generate(struct lws_context * context,cose_param_t cose_kty,int use_mask,int bits,const char * curve,const uint8_t * kid,size_t kl)787 lws_cose_key_generate(struct lws_context *context, cose_param_t cose_kty,
788 		      int use_mask, int bits, const char *curve,
789 		      const uint8_t *kid, size_t kl)
790 {
791 	struct lws_gencrypto_keyelem *ke;
792 	lws_cose_key_t *ck;
793 	size_t sn;
794 	int n;
795 
796 	ck = lws_zalloc(sizeof(*ck), __func__);
797 	if (!ck)
798 		return NULL;
799 
800 	ck->kty = cose_kty;
801 	ck->private_key = 1;
802 
803 	if (use_mask & 0xfffe) {
804 		int count = 0;
805 
806 		for (n = 1; n < 15; n++)
807 			if (use_mask & (1 << n))
808 				count++;
809 		ke = &ck->meta[COSEKEY_META_KEY_OPS];
810 		ke->buf = lws_malloc((size_t)count, __func__);
811 		if (!ke->buf)
812 			goto fail;
813 		ke->len = (uint32_t)count;
814 		count = 0;
815 		for (n = 1; n < 15; n++)
816 			if (use_mask & (1 << n))
817 				ke->buf[count++] = (uint8_t)n;
818 	}
819 
820 	if (kid) {
821 		ke = &ck->meta[COSEKEY_META_KID];
822 		ke->buf = lws_malloc(kl, __func__);
823 		ke->len = (uint32_t)kl;
824 		memcpy(ke->buf, kid, ke->len);
825 	}
826 
827 	switch (cose_kty) {
828 	case LWSCOSE_WKKTV_RSA:
829 		{
830 			struct lws_genrsa_ctx ctx;
831 
832 			memset(&ctx, 0, sizeof(ctx));
833 			ck->gencrypto_kty = LWS_GENCRYPTO_KTY_RSA;
834 
835 			lwsl_notice("%s: generating %d bit RSA key\n",
836 					__func__, bits);
837 			n = lws_genrsa_new_keypair(context, &ctx,
838 						   LGRSAM_PKCS1_1_5,
839 						   ck->e, bits);
840 			lws_genrsa_destroy(&ctx);
841 			if (n) {
842 				lwsl_err("%s: problem generating RSA key\n",
843 						__func__);
844 				goto fail;
845 			}
846 		}
847 		break;
848 	case LWSCOSE_WKKTV_SYMMETRIC:
849 
850 		ck->gencrypto_kty = LWS_GENCRYPTO_KTY_OCT;
851 		sn = (unsigned int)lws_gencrypto_bits_to_bytes(bits);
852 		ke = &ck->e[LWS_GENCRYPTO_OCT_KEYEL_K];
853 		ke->buf = lws_malloc(sn, "oct");
854 		if (!ke->buf)
855 			goto fail;
856 		ke->len = (uint32_t)sn;
857 		if (lws_get_random(context, ke->buf, sn) != sn) {
858 			lwsl_err("%s: problem getting random\n", __func__);
859 			goto fail;
860 		}
861 		break;
862 
863 	case LWSCOSE_WKKTV_OKP:
864 	case LWSCOSE_WKKTV_EC2:
865 	{
866 		struct lws_genec_ctx ctx;
867 
868 		ck->gencrypto_kty = LWS_GENCRYPTO_KTY_EC;
869 
870 		if (!curve) {
871 			lwsl_err("%s: must have a named curve\n", __func__);
872 
873 			goto fail;
874 		}
875 
876 		if (lws_genecdsa_create(&ctx, context, NULL))
877 			goto fail;
878 
879 		ctx.genec_alg = LEGENEC_ECDSA;
880 		lwsl_notice("%s: generating ECDSA key on curve %s\n", __func__,
881 				curve);
882 
883 		n = lws_genecdsa_new_keypair(&ctx, curve, ck->e);
884 		lws_genec_destroy(&ctx);
885 		if (n) {
886 			lwsl_err("%s: problem generating ECDSA key\n", __func__);
887 			goto fail;
888 		}
889 		/* trim the trailing NUL */
890 		ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV].len = (uint32_t)strlen(curve);
891 	}
892 		break;
893 
894 	default:
895 		lwsl_err("%s: unknown kty\n", __func__);
896 		goto fail;
897 	}
898 
899 	return ck;
900 
901 fail:
902 	lws_free_set_NULL(ck);
903 
904 	return NULL;
905 }
906 
907 struct lws_cose_key *
lws_cose_key_import(lws_dll2_owner_t * pkey_set,lws_cose_key_import_callback cb,void * user,const uint8_t * in,size_t len)908 lws_cose_key_import(lws_dll2_owner_t *pkey_set, lws_cose_key_import_callback cb,
909 		    void *user, const uint8_t *in, size_t len)
910 {
911 	struct lws_cose_key_parse_state cps;
912 	struct lecp_ctx ctx;
913 	int m;
914 
915 	memset(&cps, 0, sizeof(cps));
916 
917 	cps.per_key_cb		= cb;
918 	cps.user		= user;
919 	cps.pkey_set		= pkey_set;
920 	cps.gencrypto_eidx	= -1;
921 
922 	lecp_construct(&ctx, cb_cose_key, &cps, NULL, 0);
923 	m = lecp_parse(&ctx, in, len);
924 	lecp_destruct(&ctx);
925 
926 	if (m < 0) {
927 		lwsl_notice("%s: parse got %d\n", __func__, m);
928 		if (cps.pkey_set)
929 			lws_cose_key_set_destroy(cps.pkey_set);
930 
931 		return NULL;
932 	}
933 
934 	switch (cps.ck->gencrypto_kty) {
935 	case LWS_GENCRYPTO_KTY_UNKNOWN:
936 		lwsl_notice("%s: missing or unknown ktys\n", __func__);
937 		goto bail;
938 	default:
939 		break;
940 	}
941 
942 	return cps.ck;
943 
944 bail:
945 	lws_cose_key_destroy(&cps.ck);
946 	return NULL;
947 }
948 
949 /* gencrypto element orering -> cose key parameters */
950 
951 static const signed char ckp[3][12] = {
952 	{ /* LWS_GENCRYPTO_KTY_OCT (1) */
953 		/* LWS_GENCRYPTO_OCT_KEYEL_K */ LWSCOSE_WKSYMKP_KEY_VALUE,
954 	},
955 	{ /* LWS_GENCRYPTO_KTY_RSA (2) */
956 		/* LWS_GENCRYPTO_RSA_KEYEL_E */       LWSCOSE_WKKPRSA_E,
957 		/* LWS_GENCRYPTO_RSA_KEYEL_N */       LWSCOSE_WKKPRSA_N,
958 		/* LWS_GENCRYPTO_RSA_KEYEL_D */       LWSCOSE_WKKPRSA_D,
959 		/* LWS_GENCRYPTO_RSA_KEYEL_P */       LWSCOSE_WKKPRSA_P,
960 		/* LWS_GENCRYPTO_RSA_KEYEL_Q */       LWSCOSE_WKKPRSA_Q,
961 		/* LWS_GENCRYPTO_RSA_KEYEL_DP */      LWSCOSE_WKKPRSA_DP,
962 		/* LWS_GENCRYPTO_RSA_KEYEL_DQ */      LWSCOSE_WKKPRSA_DQ,
963 		/* LWS_GENCRYPTO_RSA_KEYEL_QT */      LWSCOSE_WKKPRSA_QINV,
964 		/* LWS_GENCRYPTO_RSA_KEYEL_OTHER */   LWSCOSE_WKKPRSA_OTHER,
965 		/* LWS_GENCRYPTO_RSA_KEYEL_RI */      LWSCOSE_WKKPRSA_RI,
966 		/* LWS_GENCRYPTO_RSA_KEYEL_DI */      LWSCOSE_WKKPRSA_DI,
967 		/* LWS_GENCRYPTO_RSA_KEYEL_TI */      LWSCOSE_WKKPRSA_TI,
968 	},
969 	{ /* LWS_GENCRYPTO_KTY_EC (3) */
970 		/* LWS_GENCRYPTO_EC_KEYEL_CRV */ LWSCOSE_WKECKP_CRV,
971 		/* LWS_GENCRYPTO_EC_KEYEL_X */   LWSCOSE_WKECKP_X,
972 		/* LWS_GENCRYPTO_EC_KEYEL_D */   LWSCOSE_WKECKP_D,
973 		/* LWS_GENCRYPTO_EC_KEYEL_Y */   LWSCOSE_WKECKP_Y,
974 	}
975 };
976 
977 enum lws_lec_pctx_ret
lws_cose_key_export(lws_cose_key_t * ck,lws_lec_pctx_t * ctx,int flags)978 lws_cose_key_export(lws_cose_key_t *ck, lws_lec_pctx_t *ctx, int flags)
979 {
980 	cose_param_t pa = 0;
981 	int n;
982 
983 	if (!ctx->opaque[0]) {
984 
985 		ctx->opaque[0] = 1; /* map pair count */
986 		ctx->opaque[1] = 1; /* element index */
987 		ctx->opaque[2] = 0; /* public mask */
988 		ctx->opaque[3] = 0; /* doing AGAIN */
989 
990 		switch (ck->gencrypto_kty) {
991 		case LWS_GENCRYPTO_KTY_OCT:
992 			/* nothing to differentiate */
993 			ctx->opaque[2] = 1 << LWS_GENCRYPTO_OCT_KEYEL_K;
994 			break;
995 		case LWS_GENCRYPTO_KTY_RSA:
996 			ctx->opaque[2] = 1 << LWS_GENCRYPTO_RSA_KEYEL_E;
997 			break;
998 		case LWS_GENCRYPTO_KTY_EC:
999 			ctx->opaque[2] = (1 << LWS_GENCRYPTO_EC_KEYEL_X) |
1000 					 (1 << LWS_GENCRYPTO_EC_KEYEL_Y);
1001 			break;
1002 		default:
1003 			goto fail;
1004 		}
1005 
1006 		if (flags & LWSJWKF_EXPORT_PRIVATE)
1007 			ctx->opaque[2] = 0xffff;
1008 
1009 		/*
1010 		 * We first need to find out how many CBOR map pairs we are
1011 		 * planning to create, so we can set a fixed length map of the
1012 		 * right size.
1013 		 */
1014 
1015 		for (n = 0; n < (int)LWS_ARRAY_SIZE(ck->e); n++)
1016 			if ((ctx->opaque[2] & (1 << n)) && ck->e[n].buf)
1017 				ctx->opaque[0]++;
1018 
1019 		/*
1020 		 * We always issue kty, others may be
1021 		 *
1022 		 * KID / ALG / KEY_OPS / BASE_IV
1023 		 */
1024 
1025 		if (ck->meta[COSEKEY_META_KID].buf)
1026 			ctx->opaque[0]++;
1027 		if (ck->meta[COSEKEY_META_ALG].buf)
1028 			ctx->opaque[0]++;
1029 		if (ck->meta[COSEKEY_META_KEY_OPS].buf)
1030 			ctx->opaque[0]++;
1031 		if (ck->meta[COSEKEY_META_BASE_IV].buf)
1032 			ctx->opaque[0]++;
1033 
1034 		lws_lec_int(ctx, LWS_CBOR_MAJTYP_MAP, 0, (uint64_t)ctx->opaque[0]);
1035 		lws_lec_signed(ctx, LWSCOSE_WKK_KTY);
1036 		lws_lec_signed(ctx, (int64_t)ck->kty);
1037 
1038 		if (ck->gencrypto_kty == LWS_GENCRYPTO_KTY_EC) {
1039 			struct lws_gencrypto_keyelem *ke =
1040 					&ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV];
1041 
1042 			if (!ke->buf ||
1043 			    ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV].len > 10) {
1044 				lwsl_err("%s: no curve type\n", __func__);
1045 				goto fail;
1046 			}
1047 
1048 			pa = lws_cose_curve_name_to_id((const char *)ke->buf);
1049 			lws_lec_signed(ctx, LWSCOSE_WKECKP_CRV);
1050 			if (pa)
1051 				lws_lec_signed(ctx, pa);
1052 			else
1053 				lws_lec_printf(ctx, "%.*s",
1054 						(int)ke->len, ke->buf);
1055 		}
1056 
1057 
1058 		ctx->opaque[1] = COSEKEY_META_KID;
1059 	}
1060 
1061 	/*
1062 	 * Start from the second key meta, then do any elements that are set
1063 	 */
1064 
1065 	while (ctx->buf != ctx->end) {
1066 		struct lws_gencrypto_keyelem *ke = NULL;
1067 		int cose_key_param = 0;
1068 
1069 		if (lws_lec_scratch(ctx))
1070 			break;
1071 
1072 		if (ctx->opaque[1] == LWS_ARRAY_SIZE(ck->e) +
1073 				      LWS_COUNT_COSE_KEY_ELEMENTS)
1074 			break;
1075 
1076 		if (ctx->opaque[1] >= LWS_COUNT_COSE_KEY_ELEMENTS) {
1077 			n = ctx->opaque[1] - LWS_COUNT_COSE_KEY_ELEMENTS;
1078 
1079 			if (ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
1080 			    n != LWS_GENCRYPTO_EC_KEYEL_CRV) {
1081 				/* we didn't already encode his curve */
1082 
1083 				if ((ctx->opaque[2] & (1 << n)) &&
1084 				     ck->e[n].buf && ck->e[n].len) {
1085 					ke = &ck->e[n];
1086 					cose_key_param = ckp[ck->gencrypto_kty - 1][n];
1087 				}
1088 			}
1089 		} else
1090 
1091 			switch (ctx->opaque[1]) {
1092 
1093 			case COSEKEY_META_KID: /* bstr */
1094 				if (ck->meta[COSEKEY_META_KID].buf) {
1095 					ke = &ck->meta[COSEKEY_META_KID];
1096 					cose_key_param = LWSCOSE_WKK_KID;
1097 					// lwsl_hexdump_notice(ke->buf, ke->len);
1098 				}
1099 				break;
1100 
1101 			case COSEKEY_META_ALG: /* int, tstr */
1102 				if (ck->meta[COSEKEY_META_ALG].buf) {
1103 					ke = &ck->meta[COSEKEY_META_ALG];
1104 					cose_key_param = LWSCOSE_WKK_ALG;
1105 				}
1106 				break;
1107 
1108 			case COSEKEY_META_KEY_OPS: /* [ int ] */
1109 				if (!ck->meta[COSEKEY_META_KEY_OPS].buf)
1110 					break;
1111 				ke = &ck->meta[COSEKEY_META_KEY_OPS];
1112 
1113 				n = (int)ke->len;
1114 				if (n > 10)
1115 					n = 10;
1116 
1117 				/*
1118 				 * We copy this array into scratch by hand now we
1119 				 * made sure it will fit, we will never need AGAIN
1120 				 */
1121 
1122 				lws_lec_signed(ctx, LWSCOSE_WKK_KEY_OPS);
1123 				lws_lec_int(ctx, LWS_CBOR_MAJTYP_ARRAY, 0, (uint64_t)n);
1124 				memcpy(&ctx->scratch[ctx->scratch_len], ke->buf,
1125 						(size_t)n);
1126 				ctx->scratch_len = (uint8_t)(ctx->scratch_len + (uint8_t)n);
1127 				ke = NULL;
1128 				break;
1129 
1130 			case COSEKEY_META_BASE_IV: /* bstr */
1131 				if (ck->meta[COSEKEY_META_BASE_IV].buf) {
1132 					ke = &ck->meta[COSEKEY_META_BASE_IV];
1133 					cose_key_param = LWSCOSE_WKK_BASE_IV;
1134 				}
1135 				break;
1136 
1137 			default:
1138 				break;
1139 			}
1140 
1141 		if (ke && ke->buf && ke->len) {
1142 
1143 			if (!ctx->opaque[3])
1144 				lws_lec_signed(ctx, cose_key_param);
1145 
1146 			/* binary string or text string? */
1147 			if (ctx->opaque[1] == COSEKEY_META_KID ||
1148 			    ctx->opaque[1] == COSEKEY_META_BASE_IV ||
1149 			    ctx->opaque[1] >= LWS_COUNT_COSE_KEY_ELEMENTS)
1150 				n = (int)lws_lec_printf(ctx, "%.*b",
1151 							(int)ke->len, ke->buf);
1152 			else
1153 				n = (int)lws_lec_printf(ctx, "%.*s",
1154 							(int)ke->len, ke->buf);
1155 
1156 			switch (n) {
1157 			case LWS_LECPCTX_RET_AGAIN:
1158 				ctx->opaque[3] = 1;
1159 				/* dump what we have and come back */
1160 				continue;
1161 			case LWS_LECPCTX_RET_FAIL:
1162 				goto fail;
1163 			case LWS_LECPCTX_RET_FINISHED:
1164 				break;
1165 			}
1166 		}
1167 
1168 		/* move on if we finished that guy */
1169 		ctx->opaque[1]++;
1170 		ctx->opaque[3] = 0;
1171 	}
1172 
1173 	ctx->used = lws_ptr_diff_size_t(ctx->buf, ctx->start);
1174 
1175 	if (ctx->buf == ctx->end || ctx->scratch_len)
1176 		return LWS_LECPCTX_RET_AGAIN;
1177 
1178 	ctx->opaque[0] = 0;
1179 
1180 	return LWS_LECPCTX_RET_FINISHED;
1181 
1182 fail:
1183 	lwsl_notice("%s: failed\n", __func__);
1184 
1185 	ctx->opaque[0] = 0;
1186 
1187 	return LWS_LECPCTX_RET_FAIL;
1188 }
1189