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