• 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_sign handling
25  *
26  * Validation:
27  *
28  *  - we put all our pieces and results in an lwsac in the parse state object
29  *
30  *  - we collect pieces needed for sig validation into lwsac elements
31  *
32  *  - we go through each signature making discrete results in the lwsac for
33  *    the user code to assess
34  */
35 
36 #include "private-lib-core.h"
37 #include "private-lib-cose.h"
38 
39 const uint8_t *sig_mctx[] = { (uint8_t *)"",
40 				    (uint8_t *)"\x85\x69""Signature",
41 				    (uint8_t *)"\x84\x6a""Signature1",
42 				    (uint8_t *)"\x85\x6f""CounterSignature",
43 				    (uint8_t *)"\x84\x63""MAC",
44 				    (uint8_t *)"\x84\x64""MAC0",
45 };
46 uint8_t sig_mctx_len[] = { 0, 11, 12, 17, 5, 6 };
47 
48 struct alg_names {
49 	const char	*name;
50 	cose_param_t	alg;
51 } alg_names[] = {
52 	{ "ES256",	LWSCOSE_WKAECDSA_ALG_ES256 },
53 	{ "ES384", 	LWSCOSE_WKAECDSA_ALG_ES384 },
54 	{ "ES512",	LWSCOSE_WKAECDSA_ALG_ES512 },
55 	{ "HS256_64", 	LWSCOSE_WKAHMAC_256_64 },
56 	{ "HS256", 	LWSCOSE_WKAHMAC_256_256 },
57 	{ "HS384", 	LWSCOSE_WKAHMAC_384_384 },
58 	{ "HS512", 	LWSCOSE_WKAHMAC_512_512 },
59 	{ "RS256", 	LWSCOSE_WKARSA_ALG_RS256 },
60 	{ "RS384", 	LWSCOSE_WKARSA_ALG_RS384 },
61 	{ "RS512", 	LWSCOSE_WKARSA_ALG_RS512 },
62 };
63 
64 /*
65  * The Sig_structure plaintext is new temp CBOR made up from pieces from the
66  * cose_sign, cose_signature, and payload in a specific order
67  *
68  *  tstr     context string
69  *  bstr     0-len or protected body headers
70  *  bstr     (Missing for sign1) 0-len or protected signer headers
71  *  bstr     0-len or protected application part
72  *  bstr     the payload
73  *
74  * We are getting CBOR with an optional outer tag and then an array of exactly
75  * 4 items in a fixed order
76  *
77  * [
78  *   protected headers: bstr containing a map (captured as CBOR in cps->ph[])
79  *   unprotected: map: for sign1, eg, the alg (!?), the kid
80  *   payload: bstr
81  *   if sign: signatures: [ cose_signature struct array,
82  *   			    each is a 3-element array
83  *     [
84  *       protected: bstr containing a map: (eg, the alg) (captured as CBOR)
85  *       unprotected: map: (eg, the kid)
86  *       signature:  bstr
87  *     ]
88  *   if sign1: bstr containing signature
89  * ]
90  *
91  * The last signatures field may be an array of signatures, or a single
92  * cose_signature object for cose_sign1.
93  *
94  * For cose_sign1, we know the signature alg before the payload and can do it
95  * in a single pass.  But for sign, we do not know the signature algs until
96  * after the payload, which is an unfortunate oversight in cose_sign, meaning we
97  * cannot hash the payload one or more ways in a single pass.
98  */
99 
100 #if defined(VERBOSE)
101 const char *cose_sections[] = {
102 	"ST_UNKNOWN",
103 
104 	"ST_OUTER_PROTECTED",
105 	"ST_OUTER_UNPROTECTED",
106 	"ST_OUTER_PAYLOAD",
107 	"ST_OUTER_SIGN1_SIGNATURE",
108 
109 	"ST_OUTER_SIGN_SIGARRAY",
110 
111 	"ST_OUTER_MACTAG",
112 
113 	"ST_INNER_PROTECTED",
114 	"ST_INNER_UNPROTECTED",
115 	"ST_INNER_SIGNATURE",
116 
117 	"ST_INNER_EXCESS",
118 };
119 #endif
120 
121 const char *
lws_cose_alg_to_name(cose_param_t alg)122 lws_cose_alg_to_name(cose_param_t alg)
123 {
124 	size_t n;
125 
126 	for (n = 0; n < LWS_ARRAY_SIZE(alg_names); n++)
127 		if (alg_names[n].alg == alg)
128 			return alg_names[n].name;
129 
130 	return "unknown_alg";
131 }
132 
133 cose_param_t
lws_cose_name_to_alg(const char * name)134 lws_cose_name_to_alg(const char *name)
135 {
136 	size_t n;
137 
138 	for (n = 0; n < LWS_ARRAY_SIZE(alg_names); n++)
139 		if (!strcmp(alg_names[n].name, name))
140 			return alg_names[n].alg;
141 
142 	return 0;
143 }
144 
145 static size_t
bstr_len(uint8_t * t,size_t buflen,uint8_t opcode,uint64_t len)146 bstr_len(uint8_t *t, size_t buflen, uint8_t opcode, uint64_t len)
147 {
148 	uint8_t *ot = t;
149 
150 	if (buflen < 9)
151 		return 0;
152 
153 	if (len < 24) {
154 		*t = (uint8_t)(opcode | len);
155 
156 		return 1;
157 	}
158 	if (len < 256) {
159 		*t++ = opcode | LWS_CBOR_1;
160 		goto b;
161 	}
162 	if (len < 65536) {
163 		*t++ = opcode | LWS_CBOR_2;
164 		goto b1;
165 	}
166 	if (len < 0xffffffffu) {
167 		*t++ = opcode | LWS_CBOR_4;
168 		goto b2;
169 	}
170 
171 	*t++ = opcode | LWS_CBOR_8;
172 
173 	*t++ = (uint8_t)(len >> 56);
174 	*t++ = (uint8_t)(len >> 48);
175 	*t++ = (uint8_t)(len >> 40);
176 	*t++ = (uint8_t)(len >> 32);
177 
178 b2:
179 	*t++ = (uint8_t)(len >> 24);
180 	*t++ = (uint8_t)(len >> 16);
181 b1:
182 	*t++ = (uint8_t)(len >> 8);
183 b:
184 	*t++ = (uint8_t)len;
185 
186 	return lws_ptr_diff_size_t(t, ot);
187 }
188 
189 static int
apply_external(struct lws_cose_validate_context * cps)190 apply_external(struct lws_cose_validate_context *cps)
191 {
192 	lws_cose_sig_alg_t *alg;
193 	uint8_t t[9];
194 
195 	alg = lws_container_of(cps->algs.head, lws_cose_sig_alg_t, list);
196 	if (!alg)
197 		/* expected if no key */
198 		return 0;
199 
200 	/* get the external payload first, if any indicated */
201 
202 	if (cps->info.ext_len) {
203 		lws_cose_sig_ext_pay_t ex;
204 		size_t s;
205 
206 		s = bstr_len(t, sizeof(t), LWS_CBOR_MAJTYP_BSTR,
207 			     cps->info.ext_len);
208 		if (lws_cose_val_alg_hash(alg, t, s))
209 			return 1;
210 
211 		memset(&ex, 0, sizeof(ex));
212 		ex.cps = cps;
213 
214 		do {
215 			int n;
216 
217 			ex.xl = 0;
218 			n = cps->info.ext_cb(&ex);
219 
220 			if (ex.xl &&
221 			    lws_cose_val_alg_hash(alg, ex.ext, ex.xl))
222 				return 1;
223 
224 			if (n == LCOSESIGEXTCB_RET_ERROR)
225 				return 1;
226 
227 			if (n == LCOSESIGEXTCB_RET_FINISHED)
228 				break;
229 		} while (1);
230 	}
231 
232 	return 0;
233 }
234 
235 static int
create_alg(struct lecp_ctx * ctx,struct lws_cose_validate_context * cps)236 create_alg(struct lecp_ctx *ctx, struct lws_cose_validate_context *cps)
237 {
238 	lws_cose_validate_param_stack_t *sl = &cps->st[cps->sp], *sl0 = &cps->st[0];
239 	lws_cose_validate_res_t *res;
240 	lws_cose_sig_alg_t *alg;
241 	lws_cose_key_t *ck;
242 	uint8_t *p;
243 	size_t s;
244 
245 	/* with sign1, we can hash the payload in a
246 	 * single pass */
247 
248 	ck = lws_cose_key_from_set(cps->info.keyset, sl->kid.buf, sl->kid.len);
249 	if (!ck) {
250 		lwsl_notice("%s: no key\n", __func__);
251 		lwsl_hexdump_notice(sl->kid.buf, sl->kid.len);
252 		goto no_key_or_alg;
253 	}
254 
255 	// lwsl_notice("%s: cps->alg %d\n", __func__, (int)cps->alg);
256 
257 	alg = lws_cose_val_alg_create(cps->info.cx, ck, cps->st[0].alg,
258 				      LWSCOSE_WKKO_VERIFY);
259 	if (!alg) {
260 		lwsl_info("%s: no alg\n", __func__);
261 
262 no_key_or_alg:
263 		/*
264 		 * We can't create the alg then, so we can't normally
265 		 * create a result object.  Create one especially for this
266 		 * case and continue on
267 		 */
268 
269 		res = lws_zalloc(sizeof(*res), __func__);
270 		if (res) {
271 			res->result = -1001;
272 
273 			lws_dll2_add_tail(&res->list, &cps->results);
274 		}
275 
276 		return 0;
277 	}
278 
279 	lws_dll2_add_tail(&alg->list, &cps->algs);
280 
281 	/*
282 	 * Hash step 1: The first hash content depends on
283 	 *              sign/sign1/csign/mac/mac0 constant bstr
284 	 */
285 
286 	if (lws_cose_val_alg_hash(alg, sig_mctx[cps->info.sigtype],
287 			       sig_mctx_len[cps->info.sigtype]))
288 		goto bail;
289 
290 	/*
291 	 * Hash step 2: A zero-length bstr, or a copy of the
292 	 *              OUTER protected headers
293 	 *
294 	 *              A zero-entry map alone becomes a zero-
295 	 *              length bstr
296 	 */
297 
298 	if (sl0->ph_pos[0] < 2) {
299 		/* nothing to speak of */
300 		sl0->ph[0][0] = LWS_CBOR_MAJTYP_BSTR;
301 		p = &sl0->ph[0][0];
302 		s = 1;
303 	} else {
304 		if (sl0->ph_pos[0] < 24) {
305 			sl0->ph[0][2] = (uint8_t)
306 			   (LWS_CBOR_MAJTYP_BSTR | sl0->ph_pos[0]);
307 			p = &sl0->ph[0][2];
308 			s = (size_t)sl0->ph_pos[0] + 1;
309 		} else {
310 			sl0->ph[0][1] = LWS_CBOR_MAJTYP_BSTR |
311 					LWS_CBOR_1;
312 			sl0->ph[0][2] = (uint8_t)sl0->ph_pos[0];
313 			p = &sl0->ph[0][1];
314 			s = (size_t)sl0->ph_pos[0] + 2;
315 		}
316 	}
317 
318 	if (lws_cose_val_alg_hash(alg, p, s))
319 		goto bail;
320 
321 	/*
322 	 * Hash step 3: Protected signer headers (Elided for sign1)
323 	 */
324 
325 	if (cps->info.sigtype == SIGTYPE_MULTI) {
326 		if (sl->ph_pos[2] < 2) {
327 			/* nothing to speak of */
328 			sl->ph[2][0] = LWS_CBOR_MAJTYP_BSTR;
329 			p = &sl->ph[2][0];
330 			s = 1;
331 		} else {
332 			if (sl->ph_pos[2] < 24) {
333 				sl->ph[2][2] = (uint8_t)
334 				   (LWS_CBOR_MAJTYP_BSTR | sl->ph_pos[2]);
335 				p = &sl->ph[2][2];
336 				s = (size_t)sl->ph_pos[2] + 1;
337 			} else {
338 				sl->ph[2][1] = LWS_CBOR_MAJTYP_BSTR |
339 						LWS_CBOR_1;
340 				sl->ph[2][2] = (uint8_t)sl->ph_pos[2];
341 				p = &sl->ph[2][1];
342 				s = (size_t)sl->ph_pos[2] + 2;
343 			}
344 		}
345 
346 		if (lws_cose_val_alg_hash(alg, p, s))
347 			goto bail;
348 	}
349 
350 	/* Hash step 4: bstr for applictation protected pieces
351 	 *              empty for now
352 	 */
353 
354 	if (!cps->info.ext_len) { /* ie, if no app data */
355 		uint8_t u = LWS_CBOR_MAJTYP_BSTR;
356 		if (lws_cose_val_alg_hash(alg, &u, 1))
357 			goto bail;
358 	}
359 
360 	/*
361 	 * The final part is the payload in its own bstr, as
362 	 * we get it if sign1, else replayed from a cache in heap
363 	 */
364 
365 	if (cps->info.sigtype == SIGTYPE_SINGLE)
366 		return 0;
367 
368 	if (!cps->payload_stash) {
369 		lwsl_notice("%s: no payload stash\n", __func__);
370 		goto bail;
371 	}
372 
373 	apply_external(cps);
374 
375 	if (lws_cose_val_alg_hash(alg, cps->payload_stash, cps->payload_pos))
376 		goto bail;
377 lwsl_notice("a %d\n", (int)cps->sig_agg_pos);
378 
379 	lws_cose_val_alg_destroy(cps, &alg, (const uint8_t *)cps->sig_agg,
380 				 cps->sig_agg_pos);
381 
382 	return 0;
383 
384 bail:
385 	return 1;
386 }
387 
388 #if defined(VERBOSE)
389 static const char * const reason_names[] = {
390 	"LECPCB_CONSTRUCTED",
391 	"LECPCB_DESTRUCTED",
392 	"LECPCB_START",
393 	"LECPCB_COMPLETE",
394 	"LECPCB_FAILED",
395 	"LECPCB_PAIR_NAME",
396 	"LECPCB_VAL_TRUE",
397 	"LECPCB_VAL_FALSE",
398 	"LECPCB_VAL_NULL",
399 	"LECPCB_VAL_NUM_INT",
400 	"LECPCB_VAL_RESERVED", /* float in lejp */
401 	"LECPCB_VAL_STR_START",
402 	"LECPCB_VAL_STR_CHUNK",
403 	"LECPCB_VAL_STR_END",
404 	"LECPCB_ARRAY_START",
405 	"LECPCB_ARRAY_END",
406 	"LECPCB_OBJECT_START",
407 	"LECPCB_OBJECT_END",
408 	"LECPCB_TAG_START",
409 	"LECPCB_TAG_END",
410 	"LECPCB_VAL_NUM_UINT",
411 	"LECPCB_VAL_UNDEFINED",
412 	"LECPCB_VAL_FLOAT16",
413 	"LECPCB_VAL_FLOAT32",
414 	"LECPCB_VAL_FLOAT64",
415 	"LECPCB_VAL_SIMPLE",
416 	"LECPCB_VAL_BLOB_START",
417 	"LECPCB_VAL_BLOB_CHUNK",
418 	"LECPCB_VAL_BLOB_END",
419 	"LECPCB_ARRAY_ITEM_START",
420 	"LECPCB_ARRAY_ITEM_END",
421 	"LECPCB_LITERAL_CBOR"
422 };
423 #endif
424 
425 static int
ph_index(struct lws_cose_validate_context * cps)426 ph_index(struct lws_cose_validate_context *cps)
427 {
428 	switch (cps->tli) {
429 	case ST_OUTER_PROTECTED:
430 		return 0;
431 	case ST_OUTER_UNPROTECTED:
432 		return 1;
433 	case ST_INNER_PROTECTED:
434 		return 2;
435 	case ST_INNER_UNPROTECTED:
436 		return 3;
437 	}
438 
439 	assert(0);
440 	return 0;
441 }
442 
443 static signed char
cb_cose_sig(struct lecp_ctx * ctx,char reason)444 cb_cose_sig(struct lecp_ctx *ctx, char reason)
445 {
446 	struct lws_cose_validate_context *cps =
447 			(struct lws_cose_validate_context *)ctx->user;
448 	lws_cose_validate_param_stack_t *sl;
449 	struct lws_gencrypto_keyelem *ke;
450 	lws_cose_sig_alg_t *alg;
451 	uint8_t t[9];
452 	size_t s;
453 	int hi;
454 
455 #if defined(VERBOSE)
456 	lwsl_notice("%s: %s, tli %s, sub %d, ppos %d, sp %d\n", __func__,
457 			reason_names[reason & 0x1f], cose_sections[cps->tli],
458 			cps->sub, ctx->pst[ctx->pst_sp].ppos, cps->sp);
459 #endif
460 
461 	switch (reason) {
462 	case LECPCB_CONSTRUCTED:
463 		break;
464 
465 	case LECPCB_TAG_START:
466 
467 		lwsl_notice("%s: tag sigtype %d\n", __func__, cps->info.sigtype);
468 
469 		switch (cps->info.sigtype) {
470 		default:
471 			assert(0);
472 			break;
473 		case SIGTYPE_UNKNOWN:
474 			/* it means use the tag value to set the type */
475 			switch (ctx->item.u.u64) {
476 			case LWSCOAP_CONTENTFORMAT_COSE_SIGN:
477 				cps->info.sigtype = SIGTYPE_MULTI;
478 				break;
479 			case LWSCOAP_CONTENTFORMAT_COSE_SIGN1:
480 				cps->info.sigtype = SIGTYPE_SINGLE;
481 				break;
482 //			case LWSCOAP_CONTENTFORMAT_COSE_SIGN__:
483 //				cps->info.sigtype = SIGTYPE_COUNTERSIGNED;
484 //				break;
485 			case LWSCOAP_CONTENTFORMAT_COSE_MAC0:
486 				cps->info.sigtype = SIGTYPE_MAC0;
487 				break;
488 			case LWSCOAP_CONTENTFORMAT_COSE_MAC:
489 				cps->info.sigtype = SIGTYPE_MAC;
490 				break;
491 			default:
492 				goto unexpected_tag;
493 			}
494 			break;
495 		case SIGTYPE_MULTI:
496 			if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_SIGN)
497 				goto unexpected_tag;
498 			break;
499 		case SIGTYPE_SINGLE:
500 			if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_SIGN1)
501 				goto unexpected_tag;
502 			break;
503 		case SIGTYPE_COUNTERSIGNED:
504 			if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_SIGN)
505 				goto unexpected_tag;
506 			break;
507 		case SIGTYPE_MAC0:
508 			if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_MAC0)
509 				goto unexpected_tag;
510 			break;
511 		case SIGTYPE_MAC:
512 			if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_MAC) {
513 unexpected_tag:
514 				lwsl_warn("%s: unexpected tag %d\n", __func__,
515 						(int)ctx->item.u.u64);
516 				goto bail;
517 			}
518 			break;
519 		}
520 
521 		cps->depth++;
522 		break;
523 
524 	case LECPCB_ARRAY_ITEM_START:
525 
526 		if (cps->sub)
527 			break;
528 
529 		if (ctx->pst[ctx->pst_sp].ppos == 4 ||
530 		    ctx->pst[ctx->pst_sp].ppos == 6) {
531 			switch (cps->tli) {
532 			case ST_INNER_UNPROTECTED:
533 			case ST_INNER_PROTECTED:
534 				hi = ph_index(cps);
535 				sl = &cps->st[cps->sp];
536 				sl->ph_pos[hi] = 0;
537 				lecp_parse_report_raw(ctx, 1);
538 				break;
539 			default:
540 				break;
541 			}
542 			break;
543 		}
544 
545 		if (ctx->pst[ctx->pst_sp].ppos != 2)
546 			break;
547 
548 		switch (cps->tli) {
549 		case ST_OUTER_UNPROTECTED:
550 		case ST_OUTER_PROTECTED:
551 			/*
552 			 * Holy type confusion, Batman... this is a CBOR bstr
553 			 * containing valid CBOR that must also be parsed as
554 			 * part of the containing array... we need to collect
555 			 * it anyway since it is part of the signing plaintext
556 			 * in bstr form, let's get it and then parse it at the
557 			 * END of the bstr.
558 			 */
559 			lecp_parse_report_raw(ctx, 1);
560 			break;
561 
562 		case ST_OUTER_PAYLOAD:
563 			if (cps->info.sigtype != SIGTYPE_SINGLE)
564 				break;
565 
566 			if (create_alg(ctx, cps))
567 				goto bail;
568 
569 			break;
570 
571 		case ST_OUTER_SIGN_SIGARRAY:
572 			cps->tli = ST_INNER_PROTECTED;
573 			break;
574 		}
575 		break;
576 
577 	case LECPCB_ARRAY_ITEM_END:
578 
579 		if (cps->sub)
580 			break;
581 
582 		if (ctx->pst[ctx->pst_sp].ppos == 2) {
583 			sl = &cps->st[cps->sp];
584 			switch (cps->tli) {
585 			case ST_OUTER_UNPROTECTED:
586 				break;
587 				/* fallthru */
588 			case ST_OUTER_PROTECTED:
589 				lecp_parse_report_raw(ctx, 0);
590 
591 				hi = ph_index(cps);
592 
593 				if (!sl->ph_pos[hi] || cps->sub)
594 					break;
595 
596 				cps->sub = 1;
597 				s = (size_t)sl->ph_pos[hi];
598 
599 				if (lecp_parse_subtree(&cps->ctx,
600 						       sl->ph[hi] + 3, s) !=
601 							      LECP_CONTINUE)
602 					goto bail;
603 				cps->sub = 0;
604 				break;
605 
606 			case ST_OUTER_PAYLOAD:
607 				switch (cps->info.sigtype) {
608 				case SIGTYPE_MULTI:
609 					cps->tli = ST_OUTER_SIGN_SIGARRAY - 1;
610 					break;
611 				case SIGTYPE_MAC:
612 				case SIGTYPE_MAC0:
613 					cps->tli = ST_OUTER_MACTAG - 1;
614 					break;
615 				case SIGTYPE_COUNTERSIGNED:
616 					break;
617 				default:
618 					break;
619 				}
620 				break;
621 
622 			case ST_OUTER_SIGN1_SIGNATURE:
623 			case ST_OUTER_MACTAG:
624 				cps->sp++;
625 				cps->tli = ST_INNER_PROTECTED - 1;
626 				break;
627 
628 			case ST_INNER_UNPROTECTED:
629 				lwsl_notice("ST_INNER_UNPROTECTED end\n");
630 				break;
631 			case ST_INNER_PROTECTED:
632 				lwsl_notice("ST_INNER_PROTECTED end\n");
633 				break;
634 
635 			case ST_INNER_EXCESS:
636 			case ST_OUTER_SIGN_SIGARRAY:
637 				cps->tli--; /* so no change */
638 				break;
639 			}
640 			if (!cps->sub)
641 				cps->tli++;
642 		}
643 
644 		if (ctx->pst[ctx->pst_sp].ppos >= 4) {
645 			uint8_t *p;
646 			uint8_t u;
647 			size_t s1;
648 
649 			switch (cps->tli) {
650 			case ST_INNER_UNPROTECTED:
651 			case ST_INNER_PROTECTED:
652 
653 				hi = ph_index(cps);
654 				sl = &cps->st[cps->sp];
655 				p = sl->ph[hi] + 3;
656 				lecp_parse_report_raw(ctx, 0);
657 
658 				if (!sl->ph_pos[hi] || cps->sub) {
659 					if (!cps->sub)
660 						cps->tli++;
661 					break;
662 				}
663 
664 				cps->sub = 1;
665 				s = (size_t)sl->ph_pos[hi];
666 
667 				/*
668 				 * somehow the raw captures the
669 				 * initial BSTR container length,
670 				 * let's strip it
671 				 */
672 
673 				u = (*p) & LWS_CBOR_SUBMASK;
674 				if (((*p) & LWS_CBOR_MAJTYP_MASK) ==
675 							LWS_CBOR_MAJTYP_BSTR) {
676 					s1 = 1;
677 					if (u == LWS_CBOR_1)
678 						s1 = 2;
679 					else if (u == LWS_CBOR_2)
680 						s1 = 3;
681 					else if (u == LWS_CBOR_4)
682 						s1 = 5;
683 					else if (u == LWS_CBOR_8)
684 						s1 = 9;
685 
686 					if (s1 > s)
687 						goto bail;
688 
689 					sl->ph_pos[hi] = (int)
690 						(sl->ph_pos[hi] - (ssize_t)s1);
691 					s = s - s1;
692 					memmove(p, p + s1, s);
693 				}
694 
695 				if (lecp_parse_subtree(&cps->ctx, p, s) !=
696 								LECP_CONTINUE)
697 					goto bail;
698 
699 				cps->sub = 0;
700 
701 				if (!cps->sub)
702 					cps->tli++;
703 				break;
704 
705 			case ST_INNER_SIGNATURE:
706 				if (cps->info.sigtype == SIGTYPE_MAC) {
707 					// lwsl_err("Y: alg %d\n", (int)cps->alg);
708 					if (create_alg(ctx, cps))
709 						goto bail;
710 				}
711 				cps->tli++;
712 				break;
713 			default:
714 				break;
715 			}
716 		}
717 
718 		break;
719 
720 	case LECPCB_VAL_NUM_INT:
721 	case LECPCB_VAL_NUM_UINT:
722 		switch (cps->tli) {
723 		case ST_INNER_PROTECTED:
724 		case ST_INNER_UNPROTECTED:
725 		case ST_INNER_SIGNATURE:
726 		case ST_OUTER_PROTECTED:
727 		case ST_OUTER_UNPROTECTED:
728 			if (lecp_parse_map_is_key(ctx)) {
729 				cps->map_key = ctx->item.u.i64;
730 				// lwsl_notice("%s: key %d\n", __func__, (int)cps->map_key);
731 				break;
732 			}
733 
734 			// lwsl_notice("%s: key %d val %d\n", __func__, (int)cps->map_key, (int)ctx->item.u.i64);
735 
736 			if (cps->map_key == LWSCOSE_WKL_ALG) {
737 				sl = &cps->st[cps->sp];
738 				cps->map_key = 0;
739 				if (cps->tli == ST_INNER_PROTECTED ||
740 				     cps->tli == ST_INNER_UNPROTECTED ||
741 				     cps->tli == ST_INNER_SIGNATURE) {
742 					sl->alg = ctx->item.u.i64;
743 					if (!cps->st[0].alg)
744 						cps->st[0].alg = sl->alg;
745 				} else
746 					sl->alg = ctx->item.u.i64;
747 				break;
748 			}
749 			break;
750 		}
751 		break;
752 
753 	case LECPCB_VAL_STR_END:
754 		switch (cps->tli) {
755 		case ST_OUTER_UNPROTECTED:
756 			break;
757 		}
758 		break;
759 
760 	case LECPCB_VAL_BLOB_START:
761 
762 		lwsl_notice("%s: blob size %d\n", __func__, (int)ctx->item.u.u64);
763 
764 		if (cps->tli == ST_OUTER_SIGN1_SIGNATURE ||
765 		    cps->tli == ST_INNER_SIGNATURE) {
766 			if (ctx->item.u.u64 > sizeof(cps->sig_agg))
767 				goto bail;
768 			cps->sig_agg_pos = 0;
769 			break;
770 		}
771 
772 		if (cps->tli != ST_OUTER_PAYLOAD)
773 			break;
774 
775 		if (apply_external(cps)) {
776 			lwsl_notice("%s: ext\n", __func__);
777 			goto bail;
778 		}
779 
780 		s = bstr_len(t, sizeof(t), LWS_CBOR_MAJTYP_BSTR,
781 			     ctx->item.u.u64);
782 
783 		if (cps->info.sigtype == SIGTYPE_SINGLE) {
784 			alg = lws_container_of(cps->algs.head,
785 					       lws_cose_sig_alg_t, list);
786 			if (!alg)
787 				/* expected if no key */
788 				break;
789 			if (lws_cose_val_alg_hash(alg, t, s)) {
790 				lwsl_notice("%s: hash failed\n", __func__);
791 				goto bail;
792 			}
793 
794 			break;
795 		}
796 
797 		cps->payload_stash_size = (size_t)(ctx->item.u.u64 + s);
798 		cps->payload_stash = lws_malloc(cps->payload_stash_size,
799 							__func__);
800 		if (!cps->payload_stash) {
801 			lwsl_notice("%s: oom\n", __func__);
802 			goto bail;
803 		}
804 
805 		memcpy(cps->payload_stash, t, s);
806 		cps->payload_pos = s;
807 
808 		break;
809 
810 	case LECPCB_VAL_BLOB_CHUNK:
811 		switch (cps->tli) {
812 		case ST_OUTER_PAYLOAD:
813 
814 			if (cps->info.pay_cb && ctx->npos)
815 				cps->info.pay_cb(cps, cps->info.pay_opaque,
816 						 (uint8_t *)ctx->buf, ctx->npos);
817 
818 			if (cps->payload_stash) {
819 				if (cps->payload_pos + ctx->npos >
820 					cps->payload_stash_size)
821 					goto bail;
822 				memcpy(cps->payload_stash + cps->payload_pos,
823 						ctx->buf, ctx->npos);
824 				cps->payload_pos += ctx->npos;
825 				break;
826 			}
827 			alg = lws_container_of(cps->algs.head,
828 					       lws_cose_sig_alg_t, list);
829 			if (!alg)
830 				/* expected if no key */
831 				break;
832 			if (ctx->npos &&
833 			    lws_cose_val_alg_hash(alg, (uint8_t *)ctx->buf,
834 					      ctx->npos)) {
835 				lwsl_notice("%s: chunk fail\n", __func__);
836 				goto bail;
837 			}
838 			break;
839 		case ST_INNER_SIGNATURE:
840 		case ST_OUTER_SIGN1_SIGNATURE:
841 			/* the sig is big compared to ctx->buf... we need to
842 			 * stash it then */
843 			memcpy(cps->sig_agg + cps->sig_agg_pos, ctx->buf,
844 				ctx->npos);
845 			cps->sig_agg_pos = cps->sig_agg_pos + ctx->npos;
846 			break;
847 		}
848 		break;
849 
850 	case LECPCB_VAL_BLOB_END:
851 		switch (cps->tli) {
852 
853 		case ST_INNER_SIGNATURE:
854 			if (cps->info.sigtype == SIGTYPE_MULTI) {
855 				memcpy(cps->sig_agg + cps->sig_agg_pos, ctx->buf,
856 					ctx->npos);
857 				cps->sig_agg_pos = cps->sig_agg_pos + ctx->npos;
858 				// lwsl_err("Y: alg %d\n", (int)cps->alg);
859 				if (create_alg(ctx, cps))
860 					goto bail;
861 				break;
862 			}
863 			if (cps->info.sigtype != SIGTYPE_MAC)
864 				break;
865 			/* fallthru */
866 		case ST_OUTER_PROTECTED:
867 		case ST_OUTER_UNPROTECTED:
868 		case ST_INNER_PROTECTED:
869 		case ST_INNER_UNPROTECTED:
870 			if (cps->map_key == LWSCOSE_WKL_KID) {
871 				sl = &cps->st[cps->sp];
872 				ke = &sl->kid;
873 				if (ke->buf)
874 					lws_free(ke->buf);
875 				ke->buf = lws_malloc(ctx->npos, __func__);
876 				if (!ke->buf)
877 					goto bail;
878 				ke->len = ctx->npos;
879 				memcpy(ke->buf, ctx->buf, ctx->npos);
880 				cps->map_key = 0;
881 			}
882 			break;
883 
884 		case ST_OUTER_PAYLOAD:
885 			if (cps->info.pay_cb && ctx->npos)
886 				cps->info.pay_cb(cps, cps->info.pay_opaque,
887 						 (uint8_t *)ctx->buf, ctx->npos);
888 			if (cps->payload_stash) {
889 				if (cps->payload_pos + ctx->npos >
890 					cps->payload_stash_size)
891 					goto bail;
892 				memcpy(cps->payload_stash + cps->payload_pos,
893 						ctx->buf, ctx->npos);
894 				cps->payload_pos += ctx->npos;
895 				break;
896 			}
897 			alg = lws_container_of(cps->algs.head,
898 					       lws_cose_sig_alg_t, list);
899 			if (!alg)
900 				/* expected if no key */
901 				break;
902 
903 			if (ctx->npos &&
904 			    lws_cose_val_alg_hash(alg, (uint8_t *)ctx->buf,
905 					      ctx->npos))
906 				goto bail;
907 			break;
908 
909 		case ST_OUTER_SIGN1_SIGNATURE:
910 			if (cps->info.sigtype == SIGTYPE_MULTI)
911 				break;
912 
913 			memcpy(cps->sig_agg + cps->sig_agg_pos, ctx->buf,
914 				ctx->npos);
915 			cps->sig_agg_pos += ctx->npos;
916 
917 			alg = lws_container_of(cps->algs.head,
918 					lws_cose_sig_alg_t, list);
919 			lwsl_notice("b\n");
920 			if (alg)
921 				lws_cose_val_alg_destroy(cps, &alg,
922 							 cps->sig_agg,
923 							 cps->sig_agg_pos);
924 			break;
925 
926 		case ST_OUTER_MACTAG:
927 			if (cps->mac_pos + ctx->npos > sizeof(cps->mac))
928 				goto bail;
929 			memcpy(cps->mac + cps->mac_pos, ctx->buf, ctx->npos);
930 			cps->mac_pos += ctx->npos;
931 
932 			if (cps->info.sigtype == SIGTYPE_MAC0) {
933 				if (create_alg(ctx, cps))
934 					goto bail;
935 			}
936 
937 			break;
938 		}
939 		break;
940 
941 	case LECPCB_LITERAL_CBOR:
942 		/* only used for protected headers */
943 		switch (cps->tli) {
944 		case ST_INNER_PROTECTED:
945 		case ST_OUTER_PROTECTED:
946 		case ST_INNER_UNPROTECTED:
947 		case ST_OUTER_UNPROTECTED:
948 			sl = &cps->st[cps->sp];
949 			hi = ph_index(cps);
950 			if (sl->ph_pos[hi] + 3 + ctx->cbor_pos >
951 					(int)sizeof(sl->ph[hi]) - 3)
952 				/* more protected cbor than we can handle */
953 				goto bail;
954 			memcpy(sl->ph[hi] + 3 + sl->ph_pos[hi], ctx->cbor,
955 			       ctx->cbor_pos);
956 			sl->ph_pos[hi] += ctx->cbor_pos;
957 			break;
958 		}
959 	}
960 
961 	return 0;
962 
963 bail:
964 
965 	return -1;
966 }
967 
968 struct lws_cose_validate_context *
lws_cose_validate_create(const lws_cose_validate_create_info_t * info)969 lws_cose_validate_create(const lws_cose_validate_create_info_t *info)
970 {
971 	struct lws_cose_validate_context *cps;
972 
973 	/* you have to provide at least one key in a cose_keyset */
974 	assert(info->keyset);
975 	/* you have to provide an lws_context (for crypto random) */
976 	assert(info->cx);
977 
978 	cps = lws_zalloc(sizeof(*cps), __func__);
979 	if (!cps)
980 		return NULL;
981 
982 	cps->info			= *info;
983 	cps->tli			= ST_OUTER_PROTECTED;
984 
985 	lecp_construct(&cps->ctx, cb_cose_sig, cps, NULL, 0);
986 
987 	return cps;
988 }
989 
990 int
lws_cose_validate_chunk(struct lws_cose_validate_context * cps,const uint8_t * in,size_t in_len,size_t * used_in)991 lws_cose_validate_chunk(struct lws_cose_validate_context *cps,
992 			const uint8_t *in, size_t in_len, size_t *used_in)
993 {
994 	int n;
995 
996 	n = lecp_parse(&cps->ctx, in, in_len);
997 	if (used_in)
998 		*used_in = cps->ctx.used_in;
999 
1000 	if (n == LECP_CONTINUE)
1001 		return LECP_CONTINUE;
1002 
1003 	lecp_destruct(&cps->ctx);
1004 
1005 	return n;
1006 }
1007 
1008 lws_dll2_owner_t *
lws_cose_validate_results(struct lws_cose_validate_context * cps)1009 lws_cose_validate_results(struct lws_cose_validate_context *cps)
1010 {
1011 	return &cps->results;
1012 }
1013 
1014 void
lws_cose_validate_destroy(struct lws_cose_validate_context ** _cps)1015 lws_cose_validate_destroy(struct lws_cose_validate_context **_cps)
1016 {
1017 	struct lws_cose_validate_context *cps = *_cps;
1018 
1019 	if (!cps)
1020 		return;
1021 
1022 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
1023 				   lws_dll2_get_head(&cps->algs)) {
1024 		lws_cose_sig_alg_t *alg = lws_container_of(p,
1025 						lws_cose_sig_alg_t, list);
1026 
1027 		lws_dll2_remove(p);
1028 		lws_cose_val_alg_destroy(cps, &alg, NULL, 0);
1029 	} lws_end_foreach_dll_safe(p, tp);
1030 
1031 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
1032 				   lws_dll2_get_head(&cps->results)) {
1033 		lws_cose_validate_res_t *res = lws_container_of(p,
1034 					lws_cose_validate_res_t, list);
1035 
1036 		lws_dll2_remove(p);
1037 		lws_free(res);
1038 	} lws_end_foreach_dll_safe(p, tp);
1039 
1040 	lws_free_set_NULL(cps->payload_stash);
1041 
1042 	lwsac_free(&cps->ac);
1043 
1044 	while (cps->sp >= 0) {
1045 		if (cps->st[cps->sp].kid.buf)
1046 			lws_free(cps->st[cps->sp].kid.buf);
1047 		cps->sp--;
1048 	}
1049 
1050 	lws_free_set_NULL(*_cps);
1051 }
1052