• 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 
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 */
213 			lws_lec_printf(&lec, "{1:%lld}",
214 					     (long long)alg->cose_alg);
215 			lws_lec_scratch(&lec);
216 
217 			if (!csc->subsequent) {
218 				lws_lec_init(&lec1, lb, sizeof(lb));
219 				lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
220 						lec.used);
221 				lws_cose_sign_hashing(csc, lec1.scratch,
222 							   lec1.scratch_len);
223 				lws_cose_sign_hashing(csc, lec.start, lec.used);
224 				ret = lws_lec_printf(csc->info.lec, "%.*b",
225 						     (int)lec.used, lec.start);
226 
227 				if (ret != LWS_LECPCTX_RET_FINISHED)
228 					return ret;
229 				csc->subsequent = 1;
230 			}
231 			break;
232 		case SIGTYPE_MAC:
233 		case SIGTYPE_MULTI:
234 			lws_lec_init(&lec, lbuf, sizeof(lbuf));
235 			lws_lec_int(&lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
236 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
237 			lws_lec_scratch(&lec);
238 			lec.used = lws_ptr_diff_size_t(lec.buf, lec.start);
239 			lws_cose_sign_hashing(csc, lec.start,
240 						   lec.used);
241 			break;
242 		default:
243 			lec.used = 0;
244 			break;
245 		}
246 
247 		csc->tli = ST_OUTER_UNPROTECTED;
248 
249 		/* fallthru */
250 
251 	case ST_OUTER_UNPROTECTED:
252 
253 		/*
254 		 * We need to list and emit any outer unprotected data, as
255 		 * an inline cbor map
256 		 */
257 
258 		switch (csc->type) {
259 		case SIGTYPE_SINGLE:
260 		case SIGTYPE_MAC0:
261 			alg = lws_container_of(csc->algs.head,
262 					       lws_cose_sig_alg_t, list);
263 			ke = &alg->cose_key->meta[COSEKEY_META_KID];
264 			if (ke->len) {
265 				ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
266 						     LWSCOSE_WKL_KID,
267 						     (int)ke->len, ke->buf);
268 
269 				if (ret != LWS_LECPCTX_RET_FINISHED)
270 					return ret;
271 			}
272 			/* hack for no extra data */
273 
274 			lws_lec_init(&lec1, lb, sizeof(lb));
275 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
276 			lws_cose_sign_hashing(csc, lec1.scratch,
277 						   lec1.scratch_len);
278 			break;
279 		case SIGTYPE_MAC:
280 		case SIGTYPE_MULTI:
281 
282 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
283 
284 			/*
285 			 * For cose-sign, we need to feed each sig alg its alg-
286 			 * specific protected data into the hash before letting
287 			 * all the hashes see the payload
288 			 */
289 
290 			lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
291 						   lws_dll2_get_head(&csc->algs)) {
292 				alg = lws_container_of(p, lws_cose_sig_alg_t, list);
293 
294 				lws_lec_init(&lec, lbuf, sizeof(lbuf));
295 
296 				/* we know it will fit */
297 				lws_lec_printf(&lec, "{1:%lld}",
298 						     (long long)alg->cose_alg);
299 
300 				lws_lec_init(&lec1, lb, sizeof(lb));
301 				lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
302 						lec.used);
303 
304 				// lwsl_hexdump_warn(lec1.scratch, lec1.scratch_len);
305 				// lwsl_hexdump_warn(lec.start, lec.used);
306 				if (lws_cose_sign_alg_hash(alg, lec1.scratch,
307 							   lec1.scratch_len))
308 					alg->failed = 1;
309 				if (lws_cose_sign_alg_hash(alg, lec.start,
310 							   lec.used))
311 					alg->failed = 1;
312 
313 			} lws_end_foreach_dll_safe(p, tp);
314 
315 			lws_lec_init(&lec1, lb, sizeof(lb));
316 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
317 			lws_cose_sign_hashing(csc, lec1.scratch,
318 						   lec1.scratch_len);
319 
320 			break;
321 		default:
322 			ret = lws_lec_printf(csc->info.lec, "{}");
323 			if (ret != LWS_LECPCTX_RET_FINISHED)
324 				return ret;
325 			break;
326 		}
327 
328 		csc->tli = ST_OUTER_PAYLOAD;
329 		csc->subsequent = 0;
330 
331 		/* Prepare the payload BSTR */
332 
333 		lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0,
334 					   csc->info.inline_payload_len);
335 
336 		lws_lec_init(&lec1, lb, sizeof(lb));
337 		lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
338 			    csc->info.inline_payload_len);
339 		lws_cose_sign_hashing(csc, lec1.scratch,
340 					   lec1.scratch_len);
341 
342 		lws_lec_scratch(csc->info.lec);
343 
344 		csc->rem_pay = csc->info.inline_payload_len;
345 
346 		/* fallthru */
347 
348 	case ST_OUTER_PAYLOAD:
349 
350 		if (csc->along) {
351 			in += csc->along;
352 			in_len -= csc->along;
353 		}
354 
355 		lws_lec_scratch(csc->info.lec);
356 
357 		if (csc->rem_pay) {
358 
359 			lws_cose_sign_hashing(csc, in, in_len);
360 
361 			/*
362 			 * in / in_len is the payload chunk
363 			 */
364 
365 			s = lws_ptr_diff_size_t(csc->info.lec->end,
366 						csc->info.lec->buf);
367 			if (s > (size_t)csc->rem_pay)
368 				s = (size_t)csc->rem_pay;
369 			if (s > in_len)
370 				s = in_len;
371 
372 			memcpy(csc->info.lec->buf, in, s);
373 			csc->info.lec->buf += s;
374 			csc->info.lec->used = lws_ptr_diff_size_t(
375 					csc->info.lec->buf,
376 					csc->info.lec->start);
377 			csc->rem_pay -= s;
378 
379 			csc->along = s;
380 
381 			return LWS_LECPCTX_RET_AGAIN;
382 		}
383 
384 		/* finished with rem_pay */
385 
386 		if (csc->type == SIGTYPE_MULTI) {
387 
388 			csc->alg = lws_container_of(csc->algs.head,
389 						lws_cose_sig_alg_t, list);
390 			lws_lec_init(&lec1, lb, sizeof(lb));
391 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
392 				    csc->algs.count);
393 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
394 					csc->algs.count);
395 			csc->tli = ST_INNER_PROTECTED;
396 			goto inner_protected;
397 		}
398 		csc->tli = ST_OUTER_SIGN1_SIGNATURE;
399 		csc->along = 0;
400 
401 		/* fallthru */
402 
403 	case ST_OUTER_SIGN1_SIGNATURE:
404 
405 		alg = lws_container_of(lws_dll2_get_head(&csc->algs),
406 				       lws_cose_sig_alg_t, list);
407 
408 		if (!alg->completed)
409 			lws_cose_sign_alg_complete(alg);
410 		if (alg->failed)
411 			return LWS_LECPCTX_RET_FAIL;
412 
413 		ret = lws_lec_printf(csc->info.lec, "%.*b",
414 				     (int)alg->rhash_len, alg->rhash);
415 		if (ret != LWS_LECPCTX_RET_FINISHED)
416 				return ret;
417 
418 		if (csc->type == SIGTYPE_MAC) {
419 			csc->alg = lws_container_of(csc->algs.head,
420 						lws_cose_sig_alg_t, list);
421 			lws_lec_init(&lec1, lb, sizeof(lb));
422 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
423 				    csc->algs.count);
424 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
425 					csc->algs.count);
426 			csc->tli = ST_INNER_PROTECTED;
427 			goto inner_protected;
428 		}
429 
430 		break;
431 
432 	case ST_INNER_PROTECTED:
433 inner_protected:
434 
435 		/*
436 		 * We need to list and emit any outer protected data as a map
437 		 * into its own buffer, then emit that into the output as a bstr
438 		 */
439 
440 		switch (csc->type) {
441 		case SIGTYPE_MAC:
442 		case SIGTYPE_MULTI:
443 			lws_lec_init(&lec1, lb, sizeof(lb));
444 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
445 
446 			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
447 
448 			lws_lec_init(&lec, lbuf, sizeof(lbuf));
449 
450 			/* we know it will fit */
451 			lws_lec_printf(&lec, "{1:%lld}",
452 					     (long long)csc->alg->cose_alg);
453 
454 			lws_lec_init(&lec1, lb, sizeof(lb));
455 			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
456 					lec.used);
457 			lws_lec_printf(csc->info.lec, "{1:%lld}",
458 					     (long long)csc->alg->cose_alg);
459 			break;
460 		default:
461 			lec.used = 0;
462 			break;
463 		}
464 
465 
466 		csc->tli = ST_INNER_UNPROTECTED;
467 
468 		/* fallthru */
469 
470 	case ST_INNER_UNPROTECTED:
471 
472 		switch (csc->type) {
473 		case SIGTYPE_MULTI:
474 			alg = lws_container_of(csc->algs.head,
475 					       lws_cose_sig_alg_t, list);
476 			ke = &alg->cose_key->meta[COSEKEY_META_KID];
477 			if (ke->len) {
478 				ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
479 						     LWSCOSE_WKL_KID,
480 						     (int)ke->len, ke->buf);
481 
482 				if (ret != LWS_LECPCTX_RET_FINISHED)
483 					return ret;
484 			}
485 			break;
486 		default:
487 			ret = lws_lec_printf(csc->info.lec, "{}");
488 			if (ret != LWS_LECPCTX_RET_FINISHED)
489 				return ret;
490 			break;
491 		}
492 
493 		lws_cose_sign_alg_complete(csc->alg);
494 		if (csc->alg->failed)
495 			return LWS_LECPCTX_RET_FAIL;
496 		csc->tli = ST_INNER_SIGNATURE;
497 
498 		/* fallthru */
499 
500 	case ST_INNER_SIGNATURE:
501 
502 		ret = lws_lec_printf(csc->info.lec, "%.*b",
503 				     (int)csc->alg->rhash_len, csc->alg->rhash);
504 		if (ret != LWS_LECPCTX_RET_FINISHED)
505 			return ret;
506 
507 		if (csc->alg->list.next) {
508 			csc->alg = (lws_cose_sig_alg_t *)csc->alg->list.next;
509 			csc->tli = ST_INNER_PROTECTED;
510 		}
511 		break;
512 
513 	}
514 
515 	return 0;
516 }
517 
518 void
lws_cose_sign_destroy(struct lws_cose_sign_context ** _csc)519 lws_cose_sign_destroy(struct lws_cose_sign_context **_csc)
520 {
521 	struct lws_cose_sign_context *csc = *_csc;
522 
523 	if (!csc)
524 		return;
525 
526 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
527 				   lws_dll2_get_head(&csc->algs)) {
528 		lws_cose_sig_alg_t *alg = lws_container_of(p,
529 						lws_cose_sig_alg_t, list);
530 
531 		lws_dll2_remove(p);
532 		lws_cose_sign_alg_destroy(&alg);
533 	} lws_end_foreach_dll_safe(p, tp);
534 
535 	lws_free_set_NULL(*_csc);
536 }
537