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