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 
25 #include "private-lib-core.h"
26 #include "private-lib-cose.h"
27 
28 struct lws_cose_sign_context *
lws_cose_sign_create(const lws_cose_sign_create_info_t *info)29 lws_cose_sign_create(const lws_cose_sign_create_info_t *info)
30 {
31 	struct lws_cose_sign_context *csc;
32 
33 	/* you have to have prepared a cbor output context for us to use */
34 	assert(info->lec);
35 	/* you have to provide at least one key in a cose_keyset */
36 	assert(info->keyset);
37 	/* you have to provide an lws_context (for crypto random) */
38 	assert(info->cx);
39 
40 	if (info->sigtype == SIGTYPE_MAC) {
41 		lwsl_err("%s: only mac0 supported for signing\n", __func__);
42 		return NULL;
43 	}
44 
45 	csc = lws_zalloc(sizeof(*csc), __func__);
46 	if (!csc)
47 		return NULL;
48 
49 	csc->info = *info;
50 
51 	return csc;
52 }
53 
54 int
lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg, const lws_cose_key_t *ck)55 lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
56 		  const lws_cose_key_t *ck)
57 {
58 	lws_cose_sig_alg_t *si = lws_cose_sign_alg_create(csc->info.cx, ck, alg,
59 							  LWSCOSE_WKKO_SIGN);
60 
61 	if (!si)
62 		return 1;
63 
64 	lws_dll2_add_tail(&si->list, &csc->algs);
65 
66 	return 0;
67 }
68 
69 static signed char cose_tags[] = {
70 	0,
71 	LWSCOAP_CONTENTFORMAT_COSE_SIGN,
72 	LWSCOAP_CONTENTFORMAT_COSE_SIGN1,
73 	LWSCOAP_CONTENTFORMAT_COSE_SIGN,
74 	LWSCOAP_CONTENTFORMAT_COSE_MAC,
75 	LWSCOAP_CONTENTFORMAT_COSE_MAC0
76 };
77 
78 static void
lws_cose_sign_hashing(struct lws_cose_sign_context *csc, const uint8_t *in, size_t in_len)79 lws_cose_sign_hashing(struct lws_cose_sign_context *csc,
80 		      const uint8_t *in, size_t in_len)
81 {
82 	//lwsl_hexdump_warn(in, in_len);
83 
84 	assert(in_len);
85 
86 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
87 				   lws_dll2_get_head(&csc->algs)) {
88 		lws_cose_sig_alg_t *alg = lws_container_of(p,
89 						lws_cose_sig_alg_t, list);
90 
91 		if (lws_cose_sign_alg_hash(alg, in, in_len))
92 			alg->failed = 1;
93 	} lws_end_foreach_dll_safe(p, tp);
94 }
95 
96 /*
97  * These chunks may be payload or application AAD being emitted into the
98  * signed object somewhere else.  But we do not emit them ourselves here
99  * (since other non-emitted things are also hashed by us) and so can always
100  * deal with the whole in_len in one step.
101  */
102 
103 enum lws_lec_pctx_ret
lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc, const uint8_t *in, size_t in_len)104 lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
105 			    const uint8_t *in, size_t in_len)
106 {
107 	uint8_t lbuf[MAX_BLOBBED_PARAMS], lb[9];
108 	const struct lws_gencrypto_keyelem *ke;
109 	enum lws_lec_pctx_ret ret;
110 	lws_lec_pctx_t lec, lec1;
111 	lws_cose_sig_alg_t *alg;
112 	uint8_t c;
113 	size_t s;
114 
115 	switch (csc->tli) {
116 	case ST_UNKNOWN:
117 		/*
118 		 * We need to figure out what signing structure we need to use,
119 		 * given the algorithms that are in it.  So let's have a look
120 		 * and decide.
121 		 */
122 
123 		if (!csc->algs.count) {
124 			lwsl_err("%s: must add at least one signature\n", __func__);
125 			return 1;
126 		}
127 
128 		csc->type = SIGTYPE_MULTI;
129 		alg = lws_container_of(csc->algs.head, lws_cose_sig_alg_t, list);
130 
131 		switch (alg->cose_alg) {
132 		case LWSCOSE_WKAHMAC_256_64:
133 		case LWSCOSE_WKAHMAC_256_256:
134 		case LWSCOSE_WKAHMAC_384_384:
135 		case LWSCOSE_WKAHMAC_512_512:
136 //			if (csc->info.sigtype == SIGTYPE_MAC0)
137 				csc->type = SIGTYPE_MAC0;
138 //			else
139 //				csc->type = SIGTYPE_MAC;
140 			break;
141 		}
142 
143 		if (csc->algs.count == 1) {
144 			if (!csc->info.sigtype && csc->type == SIGTYPE_MAC) {
145 			    if (csc->info.flags & LCSC_FL_ADD_CBOR_PREFER_MAC0)
146 				csc->type = SIGTYPE_MAC0;
147 			} else
148 				if (!csc->info.sigtype ||
149 				    csc->info.sigtype == SIGTYPE_SINGLE) /* ie, if no hint */
150 					csc->type = SIGTYPE_SINGLE;
151 		}
152 
153 		lwsl_notice("%s: decided on type %d\n", __func__, csc->type);
154 
155 		/*
156 		 * Start emitting the appropriate tag if that's requested
157 		 */
158 
159 		if (csc->info.flags & LCSC_FL_ADD_CBOR_TAG) {
160 			ret = lws_lec_printf(csc->info.lec, "%t(",
161 					       cose_tags[csc->type]);
162 
163 			if (ret != LWS_LECPCTX_RET_FINISHED)
164 				return ret;
165 		}
166 
167 		/* The */
168 		c = 0;
169 		switch (csc->type) {
170 		case SIGTYPE_MAC0:
171 		case SIGTYPE_MULTI:
172 		case SIGTYPE_SINGLE:
173 			c = 0x84;
174 			break;
175 		case SIGTYPE_MAC:
176 			c = 0x85;
177 			break;
178 		default:
179 			break;
180 		}
181 
182 		/* The outer array */
183 		csc->info.lec->scratch[csc->info.lec->scratch_len++] = c;
184 
185 		/*
186 		 * Then, let's start hashing with the sigtype constant part
187 		 */
188 
189 		lws_cose_sign_hashing(csc, sig_mctx[csc->type],
190 					   sig_mctx_len[csc->type]);
191 
192 		csc->tli = ST_OUTER_PROTECTED;
193 		csc->subsequent = 0;
194 
195 		/* fallthru */
196 
197 	case ST_OUTER_PROTECTED:
198 
199 		/*
200 		 * We need to list and emit any outer protected data as a map
201 		 * into its own buffer, then emit that into the output as a bstr
202 		 */
203 
204 		switch (csc->type) {
205 		case SIGTYPE_SINGLE:
206 		case SIGTYPE_MAC0:
207 			alg = lws_container_of(csc->algs.head,
208 					       lws_cose_sig_alg_t, list);
209 
210 			lws_lec_init(&lec, lbuf, sizeof(lbuf));
211 
212 			/* we know it will fit... but coverity doesn't */
213 			ret = lws_lec_printf(&lec, "{1:%lld}",
214 					     (long long)alg->cose_alg);
215 		       if (ret != LWS_LECPCTX_RET_FINISHED)
216 			       return ret;
217 
218 			lws_lec_scratch(&lec);
219 
220 			if (!csc->subsequent) {
221 				lws_lec_init(&lec1, lb, sizeof(lb));
222 				lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
223 						lec.used);
224 				lws_cose_sign_hashing(csc, lec1.scratch,
225 							   lec1.scratch_len);
226 				lws_cose_sign_hashing(csc, lec.start, lec.used);
227 				ret = lws_lec_printf(csc->info.lec, "%.*b",
228 						     (int)lec.used, lec.start);
229 
230 				if (ret != LWS_LECPCTX_RET_FINISHED)
231 					return ret;
232 				csc->subsequent = 1;
233 			}
234 			break;
235 		case SIGTYPE_MAC:
236 		case SIGTYPE_MULTI:
237 			lws_lec_init(&lec, lbuf, sizeof(lbuf));
238 			lws_lec_int(&lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
239 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
240 			lws_lec_scratch(&lec);
241 			lec.used = lws_ptr_diff_size_t(lec.buf, lec.start);
242 			lws_cose_sign_hashing(csc, lec.start,
243 						   lec.used);
244 			break;
245 		default:
246 			lec.used = 0;
247 			break;
248 		}
249 
250 		csc->tli = ST_OUTER_UNPROTECTED;
251 
252 		/* fallthru */
253 
254 	case ST_OUTER_UNPROTECTED:
255 
256 		/*
257 		 * We need to list and emit any outer unprotected data, as
258 		 * an inline cbor map
259 		 */
260 
261 		switch (csc->type) {
262 		case SIGTYPE_SINGLE:
263 		case SIGTYPE_MAC0:
264 			alg = lws_container_of(csc->algs.head,
265 					       lws_cose_sig_alg_t, list);
266 			ke = &alg->cose_key->meta[COSEKEY_META_KID];
267 			if (ke->len) {
268 				ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
269 						     LWSCOSE_WKL_KID,
270 						     (int)ke->len, ke->buf);
271 
272 				if (ret != LWS_LECPCTX_RET_FINISHED)
273 					return ret;
274 			}
275 			/* hack for no extra data */
276 
277 			lws_lec_init(&lec1, lb, sizeof(lb));
278 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
279 			lws_cose_sign_hashing(csc, lec1.scratch,
280 						   lec1.scratch_len);
281 			break;
282 		case SIGTYPE_MAC:
283 		case SIGTYPE_MULTI:
284 
285 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
286 
287 			/*
288 			 * For cose-sign, we need to feed each sig alg its alg-
289 			 * specific protected data into the hash before letting
290 			 * all the hashes see the payload
291 			 */
292 
293 			lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
294 						   lws_dll2_get_head(&csc->algs)) {
295 				alg = lws_container_of(p, lws_cose_sig_alg_t, list);
296 
297 				lws_lec_init(&lec, lbuf, sizeof(lbuf));
298 
299 				/* we know it will fit... but coverity doesn't... */
300 				ret = lws_lec_printf(&lec, "{1:%lld}",
301 						     (long long)alg->cose_alg);
302 			       if (ret != LWS_LECPCTX_RET_FINISHED)
303 				       return ret;
304 
305 				lws_lec_init(&lec1, lb, sizeof(lb));
306 				lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
307 						lec.used);
308 
309 				// lwsl_hexdump_warn(lec1.scratch, lec1.scratch_len);
310 				// lwsl_hexdump_warn(lec.start, lec.used);
311 				if (lws_cose_sign_alg_hash(alg, lec1.scratch,
312 							   lec1.scratch_len))
313 					alg->failed = 1;
314 				if (lws_cose_sign_alg_hash(alg, lec.start,
315 							   lec.used))
316 					alg->failed = 1;
317 
318 			} lws_end_foreach_dll_safe(p, tp);
319 
320 			lws_lec_init(&lec1, lb, sizeof(lb));
321 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
322 			lws_cose_sign_hashing(csc, lec1.scratch,
323 						   lec1.scratch_len);
324 
325 			break;
326 		default:
327 			ret = lws_lec_printf(csc->info.lec, "{}");
328 			if (ret != LWS_LECPCTX_RET_FINISHED)
329 				return ret;
330 			break;
331 		}
332 
333 		csc->tli = ST_OUTER_PAYLOAD;
334 		csc->subsequent = 0;
335 
336 		/* Prepare the payload BSTR */
337 
338 		lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0,
339 					   csc->info.inline_payload_len);
340 
341 		lws_lec_init(&lec1, lb, sizeof(lb));
342 		lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
343 			    csc->info.inline_payload_len);
344 		lws_cose_sign_hashing(csc, lec1.scratch,
345 					   lec1.scratch_len);
346 
347 		lws_lec_scratch(csc->info.lec);
348 
349 		csc->rem_pay = csc->info.inline_payload_len;
350 
351 		/* fallthru */
352 
353 	case ST_OUTER_PAYLOAD:
354 
355 		if (csc->along) {
356 			in += csc->along;
357 			in_len -= csc->along;
358 		}
359 
360 		lws_lec_scratch(csc->info.lec);
361 
362 		if (csc->rem_pay) {
363 
364 			lws_cose_sign_hashing(csc, in, in_len);
365 
366 			/*
367 			 * in / in_len is the payload chunk
368 			 */
369 
370 			s = lws_ptr_diff_size_t(csc->info.lec->end,
371 						csc->info.lec->buf);
372 			if (s > (size_t)csc->rem_pay)
373 				s = (size_t)csc->rem_pay;
374 			if (s > in_len)
375 				s = in_len;
376 
377 			memcpy(csc->info.lec->buf, in, s);
378 			csc->info.lec->buf += s;
379 			csc->info.lec->used = lws_ptr_diff_size_t(
380 					csc->info.lec->buf,
381 					csc->info.lec->start);
382 			csc->rem_pay -= s;
383 
384 			csc->along = s;
385 
386 			return LWS_LECPCTX_RET_AGAIN;
387 		}
388 
389 		/* finished with rem_pay */
390 
391 		if (csc->type == SIGTYPE_MULTI) {
392 
393 			csc->alg = lws_container_of(csc->algs.head,
394 						lws_cose_sig_alg_t, list);
395 			lws_lec_init(&lec1, lb, sizeof(lb));
396 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
397 				    csc->algs.count);
398 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
399 					csc->algs.count);
400 			csc->tli = ST_INNER_PROTECTED;
401 			goto inner_protected;
402 		}
403 		csc->tli = ST_OUTER_SIGN1_SIGNATURE;
404 		csc->along = 0;
405 
406 		/* fallthru */
407 
408 	case ST_OUTER_SIGN1_SIGNATURE:
409 
410 		alg = lws_container_of(lws_dll2_get_head(&csc->algs),
411 				       lws_cose_sig_alg_t, list);
412 
413 		if (!alg->completed)
414 			lws_cose_sign_alg_complete(alg);
415 		if (alg->failed)
416 			return LWS_LECPCTX_RET_FAIL;
417 
418 		ret = lws_lec_printf(csc->info.lec, "%.*b",
419 				     (int)alg->rhash_len, alg->rhash);
420 		if (ret != LWS_LECPCTX_RET_FINISHED)
421 				return ret;
422 
423 		if (csc->type == SIGTYPE_MAC) {
424 			csc->alg = lws_container_of(csc->algs.head,
425 						lws_cose_sig_alg_t, list);
426 			lws_lec_init(&lec1, lb, sizeof(lb));
427 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
428 				    csc->algs.count);
429 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
430 					csc->algs.count);
431 			csc->tli = ST_INNER_PROTECTED;
432 			goto inner_protected;
433 		}
434 
435 		break;
436 
437 	case ST_INNER_PROTECTED:
438 inner_protected:
439 
440 		/*
441 		 * We need to list and emit any outer protected data as a map
442 		 * into its own buffer, then emit that into the output as a bstr
443 		 */
444 
445 		switch (csc->type) {
446 		case SIGTYPE_MAC:
447 		case SIGTYPE_MULTI:
448 			lws_lec_init(&lec1, lb, sizeof(lb));
449 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
450 
451 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
452 
453 			lws_lec_init(&lec, lbuf, sizeof(lbuf));
454 
455 			/* we know it will fit */
456 			lws_lec_printf(&lec, "{1:%lld}",
457 					     (long long)csc->alg->cose_alg);
458 
459 			lws_lec_init(&lec1, lb, sizeof(lb));
460 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
461 					lec.used);
462 			if (lws_lec_printf(csc->info.lec, "{1:%lld}",
463 					     (long long)csc->alg->cose_alg) != LWS_LECPCTX_RET_FINISHED)
464 				/* coverity */
465 				return 0;
466 			break;
467 		default:
468 			lec.used = 0;
469 			break;
470 		}
471 
472 
473 		csc->tli = ST_INNER_UNPROTECTED;
474 
475 		/* fallthru */
476 
477 	case ST_INNER_UNPROTECTED:
478 
479 		switch (csc->type) {
480 		case SIGTYPE_MULTI:
481 			alg = lws_container_of(csc->algs.head,
482 					       lws_cose_sig_alg_t, list);
483 			ke = &alg->cose_key->meta[COSEKEY_META_KID];
484 			if (ke->len) {
485 				ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
486 						     LWSCOSE_WKL_KID,
487 						     (int)ke->len, ke->buf);
488 
489 				if (ret != LWS_LECPCTX_RET_FINISHED)
490 					return ret;
491 			}
492 			break;
493 		default:
494 			ret = lws_lec_printf(csc->info.lec, "{}");
495 			if (ret != LWS_LECPCTX_RET_FINISHED)
496 				return ret;
497 			break;
498 		}
499 
500 		lws_cose_sign_alg_complete(csc->alg);
501 		if (csc->alg->failed)
502 			return LWS_LECPCTX_RET_FAIL;
503 		csc->tli = ST_INNER_SIGNATURE;
504 
505 		/* fallthru */
506 
507 	case ST_INNER_SIGNATURE:
508 
509 		ret = lws_lec_printf(csc->info.lec, "%.*b",
510 				     (int)csc->alg->rhash_len, csc->alg->rhash);
511 		if (ret != LWS_LECPCTX_RET_FINISHED)
512 			return ret;
513 
514 		if (csc->alg->list.next) {
515 			csc->alg = (lws_cose_sig_alg_t *)csc->alg->list.next;
516 			csc->tli = ST_INNER_PROTECTED;
517 		}
518 		break;
519 
520 	}
521 
522 	return 0;
523 }
524 
525 void
lws_cose_sign_destroy(struct lws_cose_sign_context **_csc)526 lws_cose_sign_destroy(struct lws_cose_sign_context **_csc)
527 {
528 	struct lws_cose_sign_context *csc = *_csc;
529 
530 	if (!csc)
531 		return;
532 
533 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
534 				   lws_dll2_get_head(&csc->algs)) {
535 		lws_cose_sig_alg_t *alg = lws_container_of(p,
536 						lws_cose_sig_alg_t, list);
537 
538 		lws_dll2_remove(p);
539 		lws_cose_sign_alg_destroy(&alg);
540 	} lws_end_foreach_dll_safe(p, tp);
541 
542 	lws_free_set_NULL(*_csc);
543 }
544