summaryrefslogtreecommitdiff
path: root/src/cbor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cbor.c')
-rw-r--r--src/cbor.c1520
1 files changed, 1520 insertions, 0 deletions
diff --git a/src/cbor.c b/src/cbor.c
new file mode 100644
index 0000000..3e03592
--- /dev/null
+++ b/src/cbor.c
@@ -0,0 +1,1520 @@
1/*
2 * Copyright (c) 2018 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
5 */
6
7#include <openssl/evp.h>
8#include <openssl/hmac.h>
9#include <openssl/sha.h>
10
11#include <string.h>
12#include "fido.h"
13
14static int
15check_key_type(cbor_item_t *item)
16{
17 if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT ||
18 item->type == CBOR_TYPE_STRING)
19 return (0);
20
21 fido_log_debug("%s: invalid type: %d", __func__, item->type);
22
23 return (-1);
24}
25
26/*
27 * Validate CTAP2 canonical CBOR encoding rules for maps.
28 */
29static int
30ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr)
31{
32 size_t curr_len;
33 size_t prev_len;
34
35 if (check_key_type(prev) < 0 || check_key_type(curr) < 0)
36 return (-1);
37
38 if (prev->type != curr->type) {
39 if (prev->type < curr->type)
40 return (0);
41 fido_log_debug("%s: unsorted types", __func__);
42 return (-1);
43 }
44
45 if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) {
46 if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) &&
47 cbor_get_int(curr) > cbor_get_int(prev))
48 return (0);
49 } else {
50 curr_len = cbor_string_length(curr);
51 prev_len = cbor_string_length(prev);
52
53 if (curr_len > prev_len || (curr_len == prev_len &&
54 memcmp(cbor_string_handle(prev), cbor_string_handle(curr),
55 curr_len) < 0))
56 return (0);
57 }
58
59 fido_log_debug("%s: invalid cbor", __func__);
60
61 return (-1);
62}
63
64int
65cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
66 const cbor_item_t *, void *))
67{
68 struct cbor_pair *v;
69 size_t n;
70
71 if ((v = cbor_map_handle(item)) == NULL) {
72 fido_log_debug("%s: cbor_map_handle", __func__);
73 return (-1);
74 }
75
76 n = cbor_map_size(item);
77
78 for (size_t i = 0; i < n; i++) {
79 if (v[i].key == NULL || v[i].value == NULL) {
80 fido_log_debug("%s: key=%p, value=%p for i=%zu",
81 __func__, (void *)v[i].key, (void *)v[i].value, i);
82 return (-1);
83 }
84 if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) {
85 fido_log_debug("%s: ctap_check_cbor", __func__);
86 return (-1);
87 }
88 if (f(v[i].key, v[i].value, arg) < 0) {
89 fido_log_debug("%s: iterator < 0 on i=%zu", __func__,
90 i);
91 return (-1);
92 }
93 }
94
95 return (0);
96}
97
98int
99cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
100 void *))
101{
102 cbor_item_t **v;
103 size_t n;
104
105 if ((v = cbor_array_handle(item)) == NULL) {
106 fido_log_debug("%s: cbor_array_handle", __func__);
107 return (-1);
108 }
109
110 n = cbor_array_size(item);
111
112 for (size_t i = 0; i < n; i++)
113 if (v[i] == NULL || f(v[i], arg) < 0) {
114 fido_log_debug("%s: iterator < 0 on i=%zu,%p",
115 __func__, i, (void *)v[i]);
116 return (-1);
117 }
118
119 return (0);
120}
121
122int
123cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg,
124 int(*parser)(const cbor_item_t *, const cbor_item_t *, void *))
125{
126 cbor_item_t *item = NULL;
127 struct cbor_load_result cbor;
128 int r;
129
130 if (blob_len < 1) {
131 fido_log_debug("%s: blob_len=%zu", __func__, blob_len);
132 r = FIDO_ERR_RX;
133 goto fail;
134 }
135
136 if (blob[0] != FIDO_OK) {
137 fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]);
138 r = blob[0];
139 goto fail;
140 }
141
142 if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) {
143 fido_log_debug("%s: cbor_load", __func__);
144 r = FIDO_ERR_RX_NOT_CBOR;
145 goto fail;
146 }
147
148 if (cbor_isa_map(item) == false ||
149 cbor_map_is_definite(item) == false) {
150 fido_log_debug("%s: cbor type", __func__);
151 r = FIDO_ERR_RX_INVALID_CBOR;
152 goto fail;
153 }
154
155 if (cbor_map_iter(item, arg, parser) < 0) {
156 fido_log_debug("%s: cbor_map_iter", __func__);
157 r = FIDO_ERR_RX_INVALID_CBOR;
158 goto fail;
159 }
160
161 r = FIDO_OK;
162fail:
163 if (item != NULL)
164 cbor_decref(&item);
165
166 return (r);
167}
168
169void
170cbor_vector_free(cbor_item_t **item, size_t len)
171{
172 for (size_t i = 0; i < len; i++)
173 if (item[i] != NULL)
174 cbor_decref(&item[i]);
175}
176
177int
178cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len)
179{
180 if (*buf != NULL || *len != 0) {
181 fido_log_debug("%s: dup", __func__);
182 return (-1);
183 }
184
185 if (cbor_isa_bytestring(item) == false ||
186 cbor_bytestring_is_definite(item) == false) {
187 fido_log_debug("%s: cbor type", __func__);
188 return (-1);
189 }
190
191 *len = cbor_bytestring_length(item);
192 if ((*buf = malloc(*len)) == NULL) {
193 *len = 0;
194 return (-1);
195 }
196
197 memcpy(*buf, cbor_bytestring_handle(item), *len);
198
199 return (0);
200}
201
202int
203cbor_string_copy(const cbor_item_t *item, char **str)
204{
205 size_t len;
206
207 if (*str != NULL) {
208 fido_log_debug("%s: dup", __func__);
209 return (-1);
210 }
211
212 if (cbor_isa_string(item) == false ||
213 cbor_string_is_definite(item) == false) {
214 fido_log_debug("%s: cbor type", __func__);
215 return (-1);
216 }
217
218 if ((len = cbor_string_length(item)) == SIZE_MAX ||
219 (*str = malloc(len + 1)) == NULL)
220 return (-1);
221
222 memcpy(*str, cbor_string_handle(item), len);
223 (*str)[len] = '\0';
224
225 return (0);
226}
227
228int
229cbor_add_bytestring(cbor_item_t *item, const char *key,
230 const unsigned char *value, size_t value_len)
231{
232 struct cbor_pair pair;
233 int ok = -1;
234
235 memset(&pair, 0, sizeof(pair));
236
237 if ((pair.key = cbor_build_string(key)) == NULL ||
238 (pair.value = cbor_build_bytestring(value, value_len)) == NULL) {
239 fido_log_debug("%s: cbor_build", __func__);
240 goto fail;
241 }
242
243 if (!cbor_map_add(item, pair)) {
244 fido_log_debug("%s: cbor_map_add", __func__);
245 goto fail;
246 }
247
248 ok = 0;
249fail:
250 if (pair.key)
251 cbor_decref(&pair.key);
252 if (pair.value)
253 cbor_decref(&pair.value);
254
255 return (ok);
256}
257
258int
259cbor_add_string(cbor_item_t *item, const char *key, const char *value)
260{
261 struct cbor_pair pair;
262 int ok = -1;
263
264 memset(&pair, 0, sizeof(pair));
265
266 if ((pair.key = cbor_build_string(key)) == NULL ||
267 (pair.value = cbor_build_string(value)) == NULL) {
268 fido_log_debug("%s: cbor_build", __func__);
269 goto fail;
270 }
271
272 if (!cbor_map_add(item, pair)) {
273 fido_log_debug("%s: cbor_map_add", __func__);
274 goto fail;
275 }
276
277 ok = 0;
278fail:
279 if (pair.key)
280 cbor_decref(&pair.key);
281 if (pair.value)
282 cbor_decref(&pair.value);
283
284 return (ok);
285}
286
287int
288cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value)
289{
290 struct cbor_pair pair;
291 int ok = -1;
292
293 memset(&pair, 0, sizeof(pair));
294
295 if ((pair.key = cbor_build_string(key)) == NULL ||
296 (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) {
297 fido_log_debug("%s: cbor_build", __func__);
298 goto fail;
299 }
300
301 if (!cbor_map_add(item, pair)) {
302 fido_log_debug("%s: cbor_map_add", __func__);
303 goto fail;
304 }
305
306 ok = 0;
307fail:
308 if (pair.key)
309 cbor_decref(&pair.key);
310 if (pair.value)
311 cbor_decref(&pair.value);
312
313 return (ok);
314}
315
316static int
317cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg)
318{
319 struct cbor_pair pair;
320 int ok = -1;
321
322 memset(&pair, 0, sizeof(pair));
323
324 if (arg == NULL)
325 return (0); /* empty argument */
326
327 if ((pair.key = cbor_build_uint8(n)) == NULL) {
328 fido_log_debug("%s: cbor_build", __func__);
329 goto fail;
330 }
331
332 pair.value = arg;
333
334 if (!cbor_map_add(item, pair)) {
335 fido_log_debug("%s: cbor_map_add", __func__);
336 goto fail;
337 }
338
339 ok = 0;
340fail:
341 if (pair.key)
342 cbor_decref(&pair.key);
343
344 return (ok);
345}
346
347cbor_item_t *
348cbor_flatten_vector(cbor_item_t *argv[], size_t argc)
349{
350 cbor_item_t *map;
351 uint8_t i;
352
353 if (argc > UINT8_MAX - 1)
354 return (NULL);
355
356 if ((map = cbor_new_definite_map(argc)) == NULL)
357 return (NULL);
358
359 for (i = 0; i < argc; i++)
360 if (cbor_add_arg(map, i + 1, argv[i]) < 0)
361 break;
362
363 if (i != argc) {
364 cbor_decref(&map);
365 map = NULL;
366 }
367
368 return (map);
369}
370
371int
372cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f)
373{
374 cbor_item_t *flat = NULL;
375 unsigned char *cbor = NULL;
376 size_t cbor_len;
377 size_t cbor_alloc_len;
378 int ok = -1;
379
380 if ((flat = cbor_flatten_vector(argv, argc)) == NULL)
381 goto fail;
382
383 cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len);
384 if (cbor_len == 0 || cbor_len == SIZE_MAX) {
385 fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len);
386 goto fail;
387 }
388
389 if ((f->ptr = malloc(cbor_len + 1)) == NULL)
390 goto fail;
391
392 f->len = cbor_len + 1;
393 f->ptr[0] = cmd;
394 memcpy(f->ptr + 1, cbor, f->len - 1);
395
396 ok = 0;
397fail:
398 if (flat != NULL)
399 cbor_decref(&flat);
400
401 free(cbor);
402
403 return (ok);
404}
405
406cbor_item_t *
407cbor_encode_rp_entity(const fido_rp_t *rp)
408{
409 cbor_item_t *item = NULL;
410
411 if ((item = cbor_new_definite_map(2)) == NULL)
412 return (NULL);
413
414 if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) ||
415 (rp->name && cbor_add_string(item, "name", rp->name) < 0)) {
416 cbor_decref(&item);
417 return (NULL);
418 }
419
420 return (item);
421}
422
423cbor_item_t *
424cbor_encode_user_entity(const fido_user_t *user)
425{
426 cbor_item_t *item = NULL;
427 const fido_blob_t *id = &user->id;
428 const char *display = user->display_name;
429
430 if ((item = cbor_new_definite_map(4)) == NULL)
431 return (NULL);
432
433 if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) ||
434 (user->icon && cbor_add_string(item, "icon", user->icon) < 0) ||
435 (user->name && cbor_add_string(item, "name", user->name) < 0) ||
436 (display && cbor_add_string(item, "displayName", display) < 0)) {
437 cbor_decref(&item);
438 return (NULL);
439 }
440
441 return (item);
442}
443
444cbor_item_t *
445cbor_encode_pubkey_param(int cose_alg)
446{
447 cbor_item_t *item = NULL;
448 cbor_item_t *body = NULL;
449 struct cbor_pair alg;
450 int ok = -1;
451
452 memset(&alg, 0, sizeof(alg));
453
454 if ((item = cbor_new_definite_array(1)) == NULL ||
455 (body = cbor_new_definite_map(2)) == NULL ||
456 cose_alg > -1 || cose_alg < INT16_MIN)
457 goto fail;
458
459 alg.key = cbor_build_string("alg");
460
461 if (-cose_alg - 1 > UINT8_MAX)
462 alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1));
463 else
464 alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1));
465
466 if (alg.key == NULL || alg.value == NULL) {
467 fido_log_debug("%s: cbor_build", __func__);
468 goto fail;
469 }
470
471 if (cbor_map_add(body, alg) == false ||
472 cbor_add_string(body, "type", "public-key") < 0 ||
473 cbor_array_push(item, body) == false)
474 goto fail;
475
476 ok = 0;
477fail:
478 if (ok < 0) {
479 if (item != NULL) {
480 cbor_decref(&item);
481 item = NULL;
482 }
483 }
484
485 if (body != NULL)
486 cbor_decref(&body);
487 if (alg.key != NULL)
488 cbor_decref(&alg.key);
489 if (alg.value != NULL)
490 cbor_decref(&alg.value);
491
492 return (item);
493}
494
495cbor_item_t *
496cbor_encode_pubkey(const fido_blob_t *pubkey)
497{
498 cbor_item_t *cbor_key = NULL;
499
500 if ((cbor_key = cbor_new_definite_map(2)) == NULL ||
501 cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 ||
502 cbor_add_string(cbor_key, "type", "public-key") < 0) {
503 if (cbor_key)
504 cbor_decref(&cbor_key);
505 return (NULL);
506 }
507
508 return (cbor_key);
509}
510
511cbor_item_t *
512cbor_encode_pubkey_list(const fido_blob_array_t *list)
513{
514 cbor_item_t *array = NULL;
515 cbor_item_t *key = NULL;
516
517 if ((array = cbor_new_definite_array(list->len)) == NULL)
518 goto fail;
519
520 for (size_t i = 0; i < list->len; i++) {
521 if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL ||
522 cbor_array_push(array, key) == false)
523 goto fail;
524 cbor_decref(&key);
525 }
526
527 return (array);
528fail:
529 if (key != NULL)
530 cbor_decref(&key);
531 if (array != NULL)
532 cbor_decref(&array);
533
534 return (NULL);
535}
536
537cbor_item_t *
538cbor_encode_extensions(int ext)
539{
540 cbor_item_t *item = NULL;
541
542 if (ext == 0 || ext != FIDO_EXT_HMAC_SECRET)
543 return (NULL);
544
545 if ((item = cbor_new_definite_map(1)) == NULL)
546 return (NULL);
547
548 if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) {
549 cbor_decref(&item);
550 return (NULL);
551 }
552
553 return (item);
554}
555
556cbor_item_t *
557cbor_encode_options(fido_opt_t rk, fido_opt_t uv)
558{
559 cbor_item_t *item = NULL;
560
561 if ((item = cbor_new_definite_map(2)) == NULL)
562 return (NULL);
563
564 if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) ||
565 (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
566 cbor_decref(&item);
567 return (NULL);
568 }
569
570 return (item);
571}
572
573cbor_item_t *
574cbor_encode_assert_options(fido_opt_t up, fido_opt_t uv)
575{
576 cbor_item_t *item = NULL;
577
578 if ((item = cbor_new_definite_map(2)) == NULL)
579 return (NULL);
580
581 if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) ||
582 (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
583 cbor_decref(&item);
584 return (NULL);
585 }
586
587 return (item);
588}
589
590cbor_item_t *
591cbor_encode_pin_auth(const fido_blob_t *hmac_key, const fido_blob_t *data)
592{
593 const EVP_MD *md = NULL;
594 unsigned char dgst[SHA256_DIGEST_LENGTH];
595 unsigned int dgst_len;
596
597 if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr,
598 (int)hmac_key->len, data->ptr, (int)data->len, dgst,
599 &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH)
600 return (NULL);
601
602 return (cbor_build_bytestring(dgst, 16));
603}
604
605cbor_item_t *
606cbor_encode_pin_opt(void)
607{
608 return (cbor_build_uint8(1));
609}
610
611cbor_item_t *
612cbor_encode_pin_enc(const fido_blob_t *key, const fido_blob_t *pin)
613{
614 fido_blob_t pe;
615 cbor_item_t *item = NULL;
616
617 if (aes256_cbc_enc(key, pin, &pe) < 0)
618 return (NULL);
619
620 item = cbor_build_bytestring(pe.ptr, pe.len);
621 free(pe.ptr);
622
623 return (item);
624}
625
626static int
627sha256(const unsigned char *data, size_t data_len, fido_blob_t *digest)
628{
629 if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL)
630 return (-1);
631
632 digest->len = SHA256_DIGEST_LENGTH;
633
634 if (SHA256(data, data_len, digest->ptr) != digest->ptr) {
635 free(digest->ptr);
636 digest->ptr = NULL;
637 digest->len = 0;
638 return (-1);
639 }
640
641 return (0);
642}
643
644cbor_item_t *
645cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin,
646 const fido_blob_t *pin)
647{
648 unsigned char dgst[SHA256_DIGEST_LENGTH];
649 unsigned int dgst_len;
650 cbor_item_t *item = NULL;
651 const EVP_MD *md = NULL;
652#if OPENSSL_VERSION_NUMBER < 0x10100000L
653 HMAC_CTX ctx;
654#else
655 HMAC_CTX *ctx = NULL;
656#endif
657 fido_blob_t *npe = NULL; /* new pin, encrypted */
658 fido_blob_t *ph = NULL; /* pin hash */
659 fido_blob_t *phe = NULL; /* pin hash, encrypted */
660 int ok = -1;
661
662 if ((npe = fido_blob_new()) == NULL ||
663 (ph = fido_blob_new()) == NULL ||
664 (phe = fido_blob_new()) == NULL)
665 goto fail;
666
667 if (aes256_cbc_enc(key, new_pin, npe) < 0) {
668 fido_log_debug("%s: aes256_cbc_enc 1", __func__);
669 goto fail;
670 }
671
672 if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) {
673 fido_log_debug("%s: sha256", __func__);
674 goto fail;
675 }
676
677 ph->len = 16; /* first 16 bytes */
678
679 if (aes256_cbc_enc(key, ph, phe) < 0) {
680 fido_log_debug("%s: aes256_cbc_enc 2", __func__);
681 goto fail;
682 }
683
684#if OPENSSL_VERSION_NUMBER < 0x10100000L
685 HMAC_CTX_init(&ctx);
686
687 if ((md = EVP_sha256()) == NULL ||
688 HMAC_Init_ex(&ctx, key->ptr, (int)key->len, md, NULL) == 0 ||
689 HMAC_Update(&ctx, npe->ptr, (int)npe->len) == 0 ||
690 HMAC_Update(&ctx, phe->ptr, (int)phe->len) == 0 ||
691 HMAC_Final(&ctx, dgst, &dgst_len) == 0 || dgst_len != 32) {
692 fido_log_debug("%s: HMAC", __func__);
693 goto fail;
694 }
695#else
696 if ((ctx = HMAC_CTX_new()) == NULL ||
697 (md = EVP_sha256()) == NULL ||
698 HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 ||
699 HMAC_Update(ctx, npe->ptr, (int)npe->len) == 0 ||
700 HMAC_Update(ctx, phe->ptr, (int)phe->len) == 0 ||
701 HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) {
702 fido_log_debug("%s: HMAC", __func__);
703 goto fail;
704 }
705#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
706
707 if ((item = cbor_build_bytestring(dgst, 16)) == NULL) {
708 fido_log_debug("%s: cbor_build_bytestring", __func__);
709 goto fail;
710 }
711
712 ok = 0;
713fail:
714 fido_blob_free(&npe);
715 fido_blob_free(&ph);
716 fido_blob_free(&phe);
717
718#if OPENSSL_VERSION_NUMBER >= 0x10100000L
719 if (ctx != NULL)
720 HMAC_CTX_free(ctx);
721#endif
722
723 if (ok < 0) {
724 if (item != NULL) {
725 cbor_decref(&item);
726 item = NULL;
727 }
728 }
729
730 return (item);
731}
732
733cbor_item_t *
734cbor_encode_set_pin_auth(const fido_blob_t *key, const fido_blob_t *pin)
735{
736 const EVP_MD *md = NULL;
737 unsigned char dgst[SHA256_DIGEST_LENGTH];
738 unsigned int dgst_len;
739 cbor_item_t *item = NULL;
740 fido_blob_t *pe = NULL;
741
742 if ((pe = fido_blob_new()) == NULL)
743 goto fail;
744
745 if (aes256_cbc_enc(key, pin, pe) < 0) {
746 fido_log_debug("%s: aes256_cbc_enc", __func__);
747 goto fail;
748 }
749
750 if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr,
751 (int)key->len, pe->ptr, (int)pe->len, dgst, &dgst_len) == NULL ||
752 dgst_len != SHA256_DIGEST_LENGTH) {
753 fido_log_debug("%s: HMAC", __func__);
754 goto fail;
755 }
756
757 item = cbor_build_bytestring(dgst, 16);
758fail:
759 fido_blob_free(&pe);
760
761 return (item);
762}
763
764cbor_item_t *
765cbor_encode_pin_hash_enc(const fido_blob_t *shared, const fido_blob_t *pin)
766{
767 cbor_item_t *item = NULL;
768 fido_blob_t *ph = NULL;
769 fido_blob_t *phe = NULL;
770
771 if ((ph = fido_blob_new()) == NULL || (phe = fido_blob_new()) == NULL)
772 goto fail;
773
774 if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) {
775 fido_log_debug("%s: SHA256", __func__);
776 goto fail;
777 }
778
779 ph->len = 16; /* first 16 bytes */
780
781 if (aes256_cbc_enc(shared, ph, phe) < 0) {
782 fido_log_debug("%s: aes256_cbc_enc", __func__);
783 goto fail;
784 }
785
786 item = cbor_build_bytestring(phe->ptr, phe->len);
787fail:
788 fido_blob_free(&ph);
789 fido_blob_free(&phe);
790
791 return (item);
792}
793
794cbor_item_t *
795cbor_encode_hmac_secret_param(const fido_blob_t *ecdh, const es256_pk_t *pk,
796 const fido_blob_t *hmac_salt)
797{
798 cbor_item_t *item = NULL;
799 cbor_item_t *param = NULL;
800 cbor_item_t *argv[3];
801 struct cbor_pair pair;
802
803 memset(argv, 0, sizeof(argv));
804 memset(&pair, 0, sizeof(pair));
805
806 if (ecdh == NULL || pk == NULL || hmac_salt->ptr == NULL) {
807 fido_log_debug("%s: ecdh=%p, pk=%p, hmac_salt->ptr=%p",
808 __func__, (const void *)ecdh, (const void *)pk,
809 (const void *)hmac_salt->ptr);
810 goto fail;
811 }
812
813 if (hmac_salt->len != 32 && hmac_salt->len != 64) {
814 fido_log_debug("%s: hmac_salt->len=%zu", __func__,
815 hmac_salt->len);
816 goto fail;
817 }
818
819 /* XXX not pin, but salt */
820 if ((argv[0] = es256_pk_encode(pk, 1)) == NULL ||
821 (argv[1] = cbor_encode_pin_enc(ecdh, hmac_salt)) == NULL ||
822 (argv[2] = cbor_encode_set_pin_auth(ecdh, hmac_salt)) == NULL) {
823 fido_log_debug("%s: cbor encode", __func__);
824 goto fail;
825 }
826
827 if ((param = cbor_flatten_vector(argv, 3)) == NULL) {
828 fido_log_debug("%s: cbor_flatten_vector", __func__);
829 goto fail;
830 }
831
832 if ((item = cbor_new_definite_map(1)) == NULL) {
833 fido_log_debug("%s: cbor_new_definite_map", __func__);
834 goto fail;
835 }
836
837 if ((pair.key = cbor_build_string("hmac-secret")) == NULL) {
838 fido_log_debug("%s: cbor_build", __func__);
839 goto fail;
840 }
841
842 pair.value = param;
843
844 if (!cbor_map_add(item, pair)) {
845 fido_log_debug("%s: cbor_map_add", __func__);
846 cbor_decref(&item);
847 item = NULL;
848 goto fail;
849 }
850
851fail:
852 for (size_t i = 0; i < 3; i++)
853 if (argv[i] != NULL)
854 cbor_decref(&argv[i]);
855
856 if (param != NULL)
857 cbor_decref(&param);
858 if (pair.key != NULL)
859 cbor_decref(&pair.key);
860
861 return (item);
862}
863
864int
865cbor_decode_fmt(const cbor_item_t *item, char **fmt)
866{
867 char *type = NULL;
868
869 if (cbor_string_copy(item, &type) < 0) {
870 fido_log_debug("%s: cbor_string_copy", __func__);
871 return (-1);
872 }
873
874 if (strcmp(type, "packed") && strcmp(type, "fido-u2f")) {
875 fido_log_debug("%s: type=%s", __func__, type);
876 free(type);
877 return (-1);
878 }
879
880 *fmt = type;
881
882 return (0);
883}
884
885struct cose_key {
886 int kty;
887 int alg;
888 int crv;
889};
890
891static int
892find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg)
893{
894 struct cose_key *cose_key = arg;
895
896 if (cbor_isa_uint(key) == true &&
897 cbor_int_get_width(key) == CBOR_INT_8) {
898 switch (cbor_get_uint8(key)) {
899 case 1:
900 if (cbor_isa_uint(val) == false ||
901 cbor_get_int(val) > INT_MAX || cose_key->kty != 0) {
902 fido_log_debug("%s: kty", __func__);
903 return (-1);
904 }
905
906 cose_key->kty = (int)cbor_get_int(val);
907
908 break;
909 case 3:
910 if (cbor_isa_negint(val) == false ||
911 cbor_get_int(val) > INT_MAX || cose_key->alg != 0) {
912 fido_log_debug("%s: alg", __func__);
913 return (-1);
914 }
915
916 cose_key->alg = -(int)cbor_get_int(val) - 1;
917
918 break;
919 }
920 } else if (cbor_isa_negint(key) == true &&
921 cbor_int_get_width(key) == CBOR_INT_8) {
922 if (cbor_get_uint8(key) == 0) {
923 /* get crv if not rsa, otherwise ignore */
924 if (cbor_isa_uint(val) == true &&
925 cbor_get_int(val) <= INT_MAX &&
926 cose_key->crv == 0)
927 cose_key->crv = (int)cbor_get_int(val);
928 }
929 }
930
931 return (0);
932}
933
934static int
935get_cose_alg(const cbor_item_t *item, int *cose_alg)
936{
937 struct cose_key cose_key;
938
939 memset(&cose_key, 0, sizeof(cose_key));
940
941 *cose_alg = 0;
942
943 if (cbor_isa_map(item) == false ||
944 cbor_map_is_definite(item) == false ||
945 cbor_map_iter(item, &cose_key, find_cose_alg) < 0) {
946 fido_log_debug("%s: cbor type", __func__);
947 return (-1);
948 }
949
950 switch (cose_key.alg) {
951 case COSE_ES256:
952 if (cose_key.kty != COSE_KTY_EC2 ||
953 cose_key.crv != COSE_P256) {
954 fido_log_debug("%s: invalid kty/crv", __func__);
955 return (-1);
956 }
957
958 break;
959 case COSE_EDDSA:
960 if (cose_key.kty != COSE_KTY_OKP ||
961 cose_key.crv != COSE_ED25519) {
962 fido_log_debug("%s: invalid kty/crv", __func__);
963 return (-1);
964 }
965
966 break;
967 case COSE_RS256:
968 if (cose_key.kty != COSE_KTY_RSA) {
969 fido_log_debug("%s: invalid kty/crv", __func__);
970 return (-1);
971 }
972
973 break;
974 default:
975 fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg);
976
977 return (-1);
978 }
979
980 *cose_alg = cose_key.alg;
981
982 return (0);
983}
984
985int
986cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key)
987{
988 if (get_cose_alg(item, type) < 0) {
989 fido_log_debug("%s: get_cose_alg", __func__);
990 return (-1);
991 }
992
993 switch (*type) {
994 case COSE_ES256:
995 if (es256_pk_decode(item, key) < 0) {
996 fido_log_debug("%s: es256_pk_decode", __func__);
997 return (-1);
998 }
999 break;
1000 case COSE_RS256:
1001 if (rs256_pk_decode(item, key) < 0) {
1002 fido_log_debug("%s: rs256_pk_decode", __func__);
1003 return (-1);
1004 }
1005 break;
1006 case COSE_EDDSA:
1007 if (eddsa_pk_decode(item, key) < 0) {
1008 fido_log_debug("%s: eddsa_pk_decode", __func__);
1009 return (-1);
1010 }
1011 break;
1012 default:
1013 fido_log_debug("%s: invalid cose_alg %d", __func__, *type);
1014 return (-1);
1015 }
1016
1017 return (0);
1018}
1019
1020static int
1021decode_attcred(const unsigned char **buf, size_t *len, int cose_alg,
1022 fido_attcred_t *attcred)
1023{
1024 cbor_item_t *item = NULL;
1025 struct cbor_load_result cbor;
1026 uint16_t id_len;
1027 int ok = -1;
1028
1029 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf,
1030 *len);
1031
1032 if (fido_buf_read(buf, len, &attcred->aaguid,
1033 sizeof(attcred->aaguid)) < 0) {
1034 fido_log_debug("%s: fido_buf_read aaguid", __func__);
1035 return (-1);
1036 }
1037
1038 if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) {
1039 fido_log_debug("%s: fido_buf_read id_len", __func__);
1040 return (-1);
1041 }
1042
1043 attcred->id.len = (size_t)be16toh(id_len);
1044 if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL)
1045 return (-1);
1046
1047 fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len);
1048
1049 if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) {
1050 fido_log_debug("%s: fido_buf_read id", __func__);
1051 return (-1);
1052 }
1053
1054 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1055 fido_log_debug("%s: cbor_load", __func__);
1056 fido_log_xxd(*buf, *len);
1057 goto fail;
1058 }
1059
1060 if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) {
1061 fido_log_debug("%s: cbor_decode_pubkey", __func__);
1062 goto fail;
1063 }
1064
1065 if (attcred->type != cose_alg) {
1066 fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__,
1067 attcred->type, cose_alg);
1068 goto fail;
1069 }
1070
1071 *buf += cbor.read;
1072 *len -= cbor.read;
1073
1074 ok = 0;
1075fail:
1076 if (item != NULL)
1077 cbor_decref(&item);
1078
1079 return (ok);
1080}
1081
1082static int
1083decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1084{
1085 int *authdata_ext = arg;
1086 char *type = NULL;
1087 int ok = -1;
1088
1089 if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) {
1090 fido_log_debug("%s: cbor type", __func__);
1091 ok = 0; /* ignore */
1092 goto out;
1093 }
1094
1095 if (cbor_isa_float_ctrl(val) == false ||
1096 cbor_float_get_width(val) != CBOR_FLOAT_0 ||
1097 cbor_is_bool(val) == false || *authdata_ext != 0) {
1098 fido_log_debug("%s: cbor type", __func__);
1099 goto out;
1100 }
1101
1102 if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
1103 *authdata_ext |= FIDO_EXT_HMAC_SECRET;
1104
1105 ok = 0;
1106out:
1107 free(type);
1108
1109 return (ok);
1110}
1111
1112static int
1113decode_extensions(const unsigned char **buf, size_t *len, int *authdata_ext)
1114{
1115 cbor_item_t *item = NULL;
1116 struct cbor_load_result cbor;
1117 int ok = -1;
1118
1119 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf,
1120 *len);
1121
1122 *authdata_ext = 0;
1123
1124 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1125 fido_log_debug("%s: cbor_load", __func__);
1126 fido_log_xxd(*buf, *len);
1127 goto fail;
1128 }
1129
1130 if (cbor_isa_map(item) == false ||
1131 cbor_map_is_definite(item) == false ||
1132 cbor_map_size(item) != 1 ||
1133 cbor_map_iter(item, authdata_ext, decode_extension) < 0) {
1134 fido_log_debug("%s: cbor type", __func__);
1135 goto fail;
1136 }
1137
1138 *buf += cbor.read;
1139 *len -= cbor.read;
1140
1141 ok = 0;
1142fail:
1143 if (item != NULL)
1144 cbor_decref(&item);
1145
1146 return (ok);
1147}
1148
1149static int
1150decode_hmac_secret_aux(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1151{
1152 fido_blob_t *out = arg;
1153 char *type = NULL;
1154 int ok = -1;
1155
1156 if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) {
1157 fido_log_debug("%s: cbor type", __func__);
1158 ok = 0; /* ignore */
1159 goto out;
1160 }
1161
1162 ok = cbor_bytestring_copy(val, &out->ptr, &out->len);
1163out:
1164 free(type);
1165
1166 return (ok);
1167}
1168
1169static int
1170decode_hmac_secret(const unsigned char **buf, size_t *len, fido_blob_t *out)
1171{
1172 cbor_item_t *item = NULL;
1173 struct cbor_load_result cbor;
1174 int ok = -1;
1175
1176 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf,
1177 *len);
1178
1179 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1180 fido_log_debug("%s: cbor_load", __func__);
1181 fido_log_xxd(*buf, *len);
1182 goto fail;
1183 }
1184
1185 if (cbor_isa_map(item) == false ||
1186 cbor_map_is_definite(item) == false ||
1187 cbor_map_size(item) != 1 ||
1188 cbor_map_iter(item, out, decode_hmac_secret_aux) < 0) {
1189 fido_log_debug("%s: cbor type", __func__);
1190 goto fail;
1191 }
1192
1193 *buf += cbor.read;
1194 *len -= cbor.read;
1195
1196 ok = 0;
1197fail:
1198 if (item != NULL)
1199 cbor_decref(&item);
1200
1201 return (ok);
1202}
1203
1204int
1205cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
1206 fido_blob_t *authdata_cbor, fido_authdata_t *authdata,
1207 fido_attcred_t *attcred, int *authdata_ext)
1208{
1209 const unsigned char *buf = NULL;
1210 size_t len;
1211 size_t alloc_len;
1212
1213 if (cbor_isa_bytestring(item) == false ||
1214 cbor_bytestring_is_definite(item) == false) {
1215 fido_log_debug("%s: cbor type", __func__);
1216 return (-1);
1217 }
1218
1219 if (authdata_cbor->ptr != NULL ||
1220 (authdata_cbor->len = cbor_serialize_alloc(item,
1221 &authdata_cbor->ptr, &alloc_len)) == 0) {
1222 fido_log_debug("%s: cbor_serialize_alloc", __func__);
1223 return (-1);
1224 }
1225
1226 buf = cbor_bytestring_handle(item);
1227 len = cbor_bytestring_length(item);
1228
1229 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len);
1230
1231 if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
1232 fido_log_debug("%s: fido_buf_read", __func__);
1233 return (-1);
1234 }
1235
1236 authdata->sigcount = be32toh(authdata->sigcount);
1237
1238 if (attcred != NULL) {
1239 if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 ||
1240 decode_attcred(&buf, &len, cose_alg, attcred) < 0)
1241 return (-1);
1242 }
1243
1244 if (authdata_ext != NULL) {
1245 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 &&
1246 decode_extensions(&buf, &len, authdata_ext) < 0)
1247 return (-1);
1248 }
1249
1250 /* XXX we should probably ensure that len == 0 at this point */
1251
1252 return (FIDO_OK);
1253}
1254
1255int
1256cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor,
1257 fido_authdata_t *authdata, int *authdata_ext, fido_blob_t *hmac_secret_enc)
1258{
1259 const unsigned char *buf = NULL;
1260 size_t len;
1261 size_t alloc_len;
1262
1263 if (cbor_isa_bytestring(item) == false ||
1264 cbor_bytestring_is_definite(item) == false) {
1265 fido_log_debug("%s: cbor type", __func__);
1266 return (-1);
1267 }
1268
1269 if (authdata_cbor->ptr != NULL ||
1270 (authdata_cbor->len = cbor_serialize_alloc(item,
1271 &authdata_cbor->ptr, &alloc_len)) == 0) {
1272 fido_log_debug("%s: cbor_serialize_alloc", __func__);
1273 return (-1);
1274 }
1275
1276 buf = cbor_bytestring_handle(item);
1277 len = cbor_bytestring_length(item);
1278
1279 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len);
1280
1281 if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
1282 fido_log_debug("%s: fido_buf_read", __func__);
1283 return (-1);
1284 }
1285
1286 authdata->sigcount = be32toh(authdata->sigcount);
1287
1288 *authdata_ext = 0;
1289 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) {
1290 /* XXX semantic leap: extensions -> hmac_secret */
1291 if (decode_hmac_secret(&buf, &len, hmac_secret_enc) < 0) {
1292 fido_log_debug("%s: decode_hmac_secret", __func__);
1293 return (-1);
1294 }
1295 *authdata_ext = FIDO_EXT_HMAC_SECRET;
1296 }
1297
1298 /* XXX we should probably ensure that len == 0 at this point */
1299
1300 return (FIDO_OK);
1301}
1302
1303static int
1304decode_x5c(const cbor_item_t *item, void *arg)
1305{
1306 fido_blob_t *x5c = arg;
1307
1308 if (x5c->len)
1309 return (0); /* ignore */
1310
1311 return (cbor_bytestring_copy(item, &x5c->ptr, &x5c->len));
1312}
1313
1314static int
1315decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1316{
1317 fido_attstmt_t *attstmt = arg;
1318 char *name = NULL;
1319 int ok = -1;
1320
1321 if (cbor_string_copy(key, &name) < 0) {
1322 fido_log_debug("%s: cbor type", __func__);
1323 ok = 0; /* ignore */
1324 goto out;
1325 }
1326
1327 if (!strcmp(name, "alg")) {
1328 if (cbor_isa_negint(val) == false ||
1329 cbor_int_get_width(val) != CBOR_INT_8 ||
1330 cbor_get_uint8(val) != -COSE_ES256 - 1) {
1331 fido_log_debug("%s: alg", __func__);
1332 goto out;
1333 }
1334 } else if (!strcmp(name, "sig")) {
1335 if (cbor_bytestring_copy(val, &attstmt->sig.ptr,
1336 &attstmt->sig.len) < 0) {
1337 fido_log_debug("%s: sig", __func__);
1338 goto out;
1339 }
1340 } else if (!strcmp(name, "x5c")) {
1341 if (cbor_isa_array(val) == false ||
1342 cbor_array_is_definite(val) == false ||
1343 cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) {
1344 fido_log_debug("%s: x5c", __func__);
1345 goto out;
1346 }
1347 }
1348
1349 ok = 0;
1350out:
1351 free(name);
1352
1353 return (ok);
1354}
1355
1356int
1357cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt)
1358{
1359 if (cbor_isa_map(item) == false ||
1360 cbor_map_is_definite(item) == false ||
1361 cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) {
1362 fido_log_debug("%s: cbor type", __func__);
1363 return (-1);
1364 }
1365
1366 return (0);
1367}
1368
1369int
1370cbor_decode_uint64(const cbor_item_t *item, uint64_t *n)
1371{
1372 if (cbor_isa_uint(item) == false) {
1373 fido_log_debug("%s: cbor type", __func__);
1374 return (-1);
1375 }
1376
1377 *n = cbor_get_int(item);
1378
1379 return (0);
1380}
1381
1382static int
1383decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1384{
1385 fido_blob_t *id = arg;
1386 char *name = NULL;
1387 int ok = -1;
1388
1389 if (cbor_string_copy(key, &name) < 0) {
1390 fido_log_debug("%s: cbor type", __func__);
1391 ok = 0; /* ignore */
1392 goto out;
1393 }
1394
1395 if (!strcmp(name, "id"))
1396 if (cbor_bytestring_copy(val, &id->ptr, &id->len) < 0) {
1397 fido_log_debug("%s: cbor_bytestring_copy", __func__);
1398 goto out;
1399 }
1400
1401 ok = 0;
1402out:
1403 free(name);
1404
1405 return (ok);
1406}
1407
1408int
1409cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id)
1410{
1411 if (cbor_isa_map(item) == false ||
1412 cbor_map_is_definite(item) == false ||
1413 cbor_map_iter(item, id, decode_cred_id_entry) < 0) {
1414 fido_log_debug("%s: cbor type", __func__);
1415 return (-1);
1416 }
1417
1418 return (0);
1419}
1420
1421static int
1422decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1423{
1424 fido_user_t *user = arg;
1425 char *name = NULL;
1426 int ok = -1;
1427
1428 if (cbor_string_copy(key, &name) < 0) {
1429 fido_log_debug("%s: cbor type", __func__);
1430 ok = 0; /* ignore */
1431 goto out;
1432 }
1433
1434 if (!strcmp(name, "icon")) {
1435 if (cbor_string_copy(val, &user->icon) < 0) {
1436 fido_log_debug("%s: icon", __func__);
1437 goto out;
1438 }
1439 } else if (!strcmp(name, "name")) {
1440 if (cbor_string_copy(val, &user->name) < 0) {
1441 fido_log_debug("%s: name", __func__);
1442 goto out;
1443 }
1444 } else if (!strcmp(name, "displayName")) {
1445 if (cbor_string_copy(val, &user->display_name) < 0) {
1446 fido_log_debug("%s: display_name", __func__);
1447 goto out;
1448 }
1449 } else if (!strcmp(name, "id")) {
1450 if (cbor_bytestring_copy(val, &user->id.ptr, &user->id.len) < 0) {
1451 fido_log_debug("%s: id", __func__);
1452 goto out;
1453 }
1454 }
1455
1456 ok = 0;
1457out:
1458 free(name);
1459
1460 return (ok);
1461}
1462
1463int
1464cbor_decode_user(const cbor_item_t *item, fido_user_t *user)
1465{
1466 if (cbor_isa_map(item) == false ||
1467 cbor_map_is_definite(item) == false ||
1468 cbor_map_iter(item, user, decode_user_entry) < 0) {
1469 fido_log_debug("%s: cbor type", __func__);
1470 return (-1);
1471 }
1472
1473 return (0);
1474}
1475
1476static int
1477decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val,
1478 void *arg)
1479{
1480 fido_rp_t *rp = arg;
1481 char *name = NULL;
1482 int ok = -1;
1483
1484 if (cbor_string_copy(key, &name) < 0) {
1485 fido_log_debug("%s: cbor type", __func__);
1486 ok = 0; /* ignore */
1487 goto out;
1488 }
1489
1490 if (!strcmp(name, "id")) {
1491 if (cbor_string_copy(val, &rp->id) < 0) {
1492 fido_log_debug("%s: id", __func__);
1493 goto out;
1494 }
1495 } else if (!strcmp(name, "name")) {
1496 if (cbor_string_copy(val, &rp->name) < 0) {
1497 fido_log_debug("%s: name", __func__);
1498 goto out;
1499 }
1500 }
1501
1502 ok = 0;
1503out:
1504 free(name);
1505
1506 return (ok);
1507}
1508
1509int
1510cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp)
1511{
1512 if (cbor_isa_map(item) == false ||
1513 cbor_map_is_definite(item) == false ||
1514 cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) {
1515 fido_log_debug("%s: cbor type", __func__);
1516 return (-1);
1517 }
1518
1519 return (0);
1520}