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.
7 #include <openssl/hmac.h>
8 #include <openssl/sha.h>
12 check_key_type(cbor_item_t *item)
14 if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT ||
15 item->type == CBOR_TYPE_STRING)
18 fido_log_debug("%s: invalid type: %d", __func__, item->type);
24 * Validate CTAP2 canonical CBOR encoding rules for maps.
27 ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr)
32 if (check_key_type(prev) < 0 || check_key_type(curr) < 0)
35 if (prev->type != curr->type) {
36 if (prev->type < curr->type)
38 fido_log_debug("%s: unsorted types", __func__);
42 if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) {
43 if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) &&
44 cbor_get_int(curr) > cbor_get_int(prev))
47 curr_len = cbor_string_length(curr);
48 prev_len = cbor_string_length(prev);
50 if (curr_len > prev_len || (curr_len == prev_len &&
51 memcmp(cbor_string_handle(prev), cbor_string_handle(curr),
56 fido_log_debug("%s: invalid cbor", __func__);
62 cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
63 const cbor_item_t *, void *))
68 if ((v = cbor_map_handle(item)) == NULL) {
69 fido_log_debug("%s: cbor_map_handle", __func__);
73 n = cbor_map_size(item);
75 for (size_t i = 0; i < n; i++) {
76 if (v[i].key == NULL || v[i].value == NULL) {
77 fido_log_debug("%s: key=%p, value=%p for i=%zu",
78 __func__, (void *)v[i].key, (void *)v[i].value, i);
81 if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) {
82 fido_log_debug("%s: ctap_check_cbor", __func__);
85 if (f(v[i].key, v[i].value, arg) < 0) {
86 fido_log_debug("%s: iterator < 0 on i=%zu", __func__,
96 cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
102 if ((v = cbor_array_handle(item)) == NULL) {
103 fido_log_debug("%s: cbor_array_handle", __func__);
107 n = cbor_array_size(item);
109 for (size_t i = 0; i < n; i++)
110 if (v[i] == NULL || f(v[i], arg) < 0) {
111 fido_log_debug("%s: iterator < 0 on i=%zu,%p",
112 __func__, i, (void *)v[i]);
120 cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg,
121 int(*parser)(const cbor_item_t *, const cbor_item_t *, void *))
123 cbor_item_t *item = NULL;
124 struct cbor_load_result cbor;
128 fido_log_debug("%s: blob_len=%zu", __func__, blob_len);
133 if (blob[0] != FIDO_OK) {
134 fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]);
139 if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) {
140 fido_log_debug("%s: cbor_load", __func__);
141 r = FIDO_ERR_RX_NOT_CBOR;
145 if (cbor_isa_map(item) == false ||
146 cbor_map_is_definite(item) == false) {
147 fido_log_debug("%s: cbor type", __func__);
148 r = FIDO_ERR_RX_INVALID_CBOR;
152 if (cbor_map_iter(item, arg, parser) < 0) {
153 fido_log_debug("%s: cbor_map_iter", __func__);
154 r = FIDO_ERR_RX_INVALID_CBOR;
167 cbor_vector_free(cbor_item_t **item, size_t len)
169 for (size_t i = 0; i < len; i++)
171 cbor_decref(&item[i]);
175 cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len)
177 if (*buf != NULL || *len != 0) {
178 fido_log_debug("%s: dup", __func__);
182 if (cbor_isa_bytestring(item) == false ||
183 cbor_bytestring_is_definite(item) == false) {
184 fido_log_debug("%s: cbor type", __func__);
188 *len = cbor_bytestring_length(item);
189 if ((*buf = malloc(*len)) == NULL) {
194 memcpy(*buf, cbor_bytestring_handle(item), *len);
200 cbor_string_copy(const cbor_item_t *item, char **str)
205 fido_log_debug("%s: dup", __func__);
209 if (cbor_isa_string(item) == false ||
210 cbor_string_is_definite(item) == false) {
211 fido_log_debug("%s: cbor type", __func__);
215 if ((len = cbor_string_length(item)) == SIZE_MAX ||
216 (*str = malloc(len + 1)) == NULL)
219 memcpy(*str, cbor_string_handle(item), len);
226 cbor_add_bytestring(cbor_item_t *item, const char *key,
227 const unsigned char *value, size_t value_len)
229 struct cbor_pair pair;
232 memset(&pair, 0, sizeof(pair));
234 if ((pair.key = cbor_build_string(key)) == NULL ||
235 (pair.value = cbor_build_bytestring(value, value_len)) == NULL) {
236 fido_log_debug("%s: cbor_build", __func__);
240 if (!cbor_map_add(item, pair)) {
241 fido_log_debug("%s: cbor_map_add", __func__);
248 cbor_decref(&pair.key);
250 cbor_decref(&pair.value);
256 cbor_add_string(cbor_item_t *item, const char *key, const char *value)
258 struct cbor_pair pair;
261 memset(&pair, 0, sizeof(pair));
263 if ((pair.key = cbor_build_string(key)) == NULL ||
264 (pair.value = cbor_build_string(value)) == NULL) {
265 fido_log_debug("%s: cbor_build", __func__);
269 if (!cbor_map_add(item, pair)) {
270 fido_log_debug("%s: cbor_map_add", __func__);
277 cbor_decref(&pair.key);
279 cbor_decref(&pair.value);
285 cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value)
287 struct cbor_pair pair;
290 memset(&pair, 0, sizeof(pair));
292 if ((pair.key = cbor_build_string(key)) == NULL ||
293 (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) {
294 fido_log_debug("%s: cbor_build", __func__);
298 if (!cbor_map_add(item, pair)) {
299 fido_log_debug("%s: cbor_map_add", __func__);
306 cbor_decref(&pair.key);
308 cbor_decref(&pair.value);
314 cbor_add_uint8(cbor_item_t *item, const char *key, uint8_t value)
316 struct cbor_pair pair;
319 memset(&pair, 0, sizeof(pair));
321 if ((pair.key = cbor_build_string(key)) == NULL ||
322 (pair.value = cbor_build_uint8(value)) == NULL) {
323 fido_log_debug("%s: cbor_build", __func__);
327 if (!cbor_map_add(item, pair)) {
328 fido_log_debug("%s: cbor_map_add", __func__);
335 cbor_decref(&pair.key);
337 cbor_decref(&pair.value);
343 cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg)
345 struct cbor_pair pair;
348 memset(&pair, 0, sizeof(pair));
351 return (0); /* empty argument */
353 if ((pair.key = cbor_build_uint8(n)) == NULL) {
354 fido_log_debug("%s: cbor_build", __func__);
360 if (!cbor_map_add(item, pair)) {
361 fido_log_debug("%s: cbor_map_add", __func__);
368 cbor_decref(&pair.key);
374 cbor_flatten_vector(cbor_item_t *argv[], size_t argc)
379 if (argc > UINT8_MAX - 1)
382 if ((map = cbor_new_definite_map(argc)) == NULL)
385 for (i = 0; i < argc; i++)
386 if (cbor_add_arg(map, (uint8_t)(i + 1), argv[i]) < 0)
398 cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f)
400 cbor_item_t *flat = NULL;
401 unsigned char *cbor = NULL;
403 size_t cbor_alloc_len;
406 if ((flat = cbor_flatten_vector(argv, argc)) == NULL)
409 cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len);
410 if (cbor_len == 0 || cbor_len == SIZE_MAX) {
411 fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len);
415 if ((f->ptr = malloc(cbor_len + 1)) == NULL)
418 f->len = cbor_len + 1;
420 memcpy(f->ptr + 1, cbor, f->len - 1);
433 cbor_encode_rp_entity(const fido_rp_t *rp)
435 cbor_item_t *item = NULL;
437 if ((item = cbor_new_definite_map(2)) == NULL)
440 if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) ||
441 (rp->name && cbor_add_string(item, "name", rp->name) < 0)) {
450 cbor_encode_user_entity(const fido_user_t *user)
452 cbor_item_t *item = NULL;
453 const fido_blob_t *id = &user->id;
454 const char *display = user->display_name;
456 if ((item = cbor_new_definite_map(4)) == NULL)
459 if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) ||
460 (user->icon && cbor_add_string(item, "icon", user->icon) < 0) ||
461 (user->name && cbor_add_string(item, "name", user->name) < 0) ||
462 (display && cbor_add_string(item, "displayName", display) < 0)) {
471 cbor_encode_pubkey_param(int cose_alg)
473 cbor_item_t *item = NULL;
474 cbor_item_t *body = NULL;
475 struct cbor_pair alg;
478 memset(&alg, 0, sizeof(alg));
480 if ((item = cbor_new_definite_array(1)) == NULL ||
481 (body = cbor_new_definite_map(2)) == NULL ||
482 cose_alg > -1 || cose_alg < INT16_MIN)
485 alg.key = cbor_build_string("alg");
487 if (-cose_alg - 1 > UINT8_MAX)
488 alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1));
490 alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1));
492 if (alg.key == NULL || alg.value == NULL) {
493 fido_log_debug("%s: cbor_build", __func__);
497 if (cbor_map_add(body, alg) == false ||
498 cbor_add_string(body, "type", "public-key") < 0 ||
499 cbor_array_push(item, body) == false)
514 cbor_decref(&alg.key);
515 if (alg.value != NULL)
516 cbor_decref(&alg.value);
522 cbor_encode_pubkey(const fido_blob_t *pubkey)
524 cbor_item_t *cbor_key = NULL;
526 if ((cbor_key = cbor_new_definite_map(2)) == NULL ||
527 cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 ||
528 cbor_add_string(cbor_key, "type", "public-key") < 0) {
530 cbor_decref(&cbor_key);
538 cbor_encode_pubkey_list(const fido_blob_array_t *list)
540 cbor_item_t *array = NULL;
541 cbor_item_t *key = NULL;
543 if ((array = cbor_new_definite_array(list->len)) == NULL)
546 for (size_t i = 0; i < list->len; i++) {
547 if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL ||
548 cbor_array_push(array, key) == false)
564 cbor_encode_largeblob_key_ext(cbor_item_t *map)
567 cbor_add_bool(map, "largeBlobKey", FIDO_OPT_TRUE) < 0)
574 cbor_encode_cred_ext(const fido_cred_ext_t *ext, const fido_blob_t *blob)
576 cbor_item_t *item = NULL;
579 if (ext->mask & FIDO_EXT_CRED_BLOB)
581 if (ext->mask & FIDO_EXT_HMAC_SECRET)
583 if (ext->mask & FIDO_EXT_CRED_PROTECT)
585 if (ext->mask & FIDO_EXT_LARGEBLOB_KEY)
588 if (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
591 if (ext->mask & FIDO_EXT_CRED_BLOB) {
592 if (cbor_add_bytestring(item, "credBlob", blob->ptr,
598 if (ext->mask & FIDO_EXT_CRED_PROTECT) {
599 if (ext->prot < 0 || ext->prot > UINT8_MAX ||
600 cbor_add_uint8(item, "credProtect",
601 (uint8_t)ext->prot) < 0) {
606 if (ext->mask & FIDO_EXT_HMAC_SECRET) {
607 if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) {
612 if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) {
613 if (cbor_encode_largeblob_key_ext(item) < 0) {
623 cbor_encode_cred_opt(fido_opt_t rk, fido_opt_t uv)
625 cbor_item_t *item = NULL;
627 if ((item = cbor_new_definite_map(2)) == NULL)
629 if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) ||
630 (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
639 cbor_encode_assert_opt(fido_opt_t up, fido_opt_t uv)
641 cbor_item_t *item = NULL;
643 if ((item = cbor_new_definite_map(2)) == NULL)
645 if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) ||
646 (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
655 cbor_encode_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
656 const fido_blob_t *data)
658 const EVP_MD *md = NULL;
659 unsigned char dgst[SHA256_DIGEST_LENGTH];
660 unsigned int dgst_len;
666 key.ptr = secret->ptr;
667 key.len = secret->len;
669 if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
670 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
674 /* select hmac portion of the shared secret */
675 if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
678 if ((md = EVP_sha256()) == NULL || HMAC(md, key.ptr,
679 (int)key.len, data->ptr, data->len, dgst,
680 &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH)
683 outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
685 return (cbor_build_bytestring(dgst, outlen));
689 cbor_encode_pin_opt(const fido_dev_t *dev)
693 if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
694 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
698 return (cbor_build_uint8(prot));
702 cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
703 const fido_blob_t *new_pin_enc, const fido_blob_t *pin_hash_enc)
705 unsigned char dgst[SHA256_DIGEST_LENGTH];
706 unsigned int dgst_len;
707 cbor_item_t *item = NULL;
708 const EVP_MD *md = NULL;
709 #if OPENSSL_VERSION_NUMBER < 0x10100000L
712 HMAC_CTX *ctx = NULL;
718 key.ptr = secret->ptr;
719 key.len = secret->len;
721 if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
722 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
726 if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
729 #if OPENSSL_VERSION_NUMBER < 0x10100000L
732 if ((md = EVP_sha256()) == NULL ||
733 HMAC_Init_ex(&ctx, key.ptr, (int)key.len, md, NULL) == 0 ||
734 HMAC_Update(&ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 ||
735 HMAC_Update(&ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 ||
736 HMAC_Final(&ctx, dgst, &dgst_len) == 0 ||
737 dgst_len != SHA256_DIGEST_LENGTH) {
738 fido_log_debug("%s: HMAC", __func__);
742 if ((ctx = HMAC_CTX_new()) == NULL ||
743 (md = EVP_sha256()) == NULL ||
744 HMAC_Init_ex(ctx, key.ptr, (int)key.len, md, NULL) == 0 ||
745 HMAC_Update(ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 ||
746 HMAC_Update(ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 ||
747 HMAC_Final(ctx, dgst, &dgst_len) == 0 ||
748 dgst_len != SHA256_DIGEST_LENGTH) {
749 fido_log_debug("%s: HMAC", __func__);
752 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
754 outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
756 if ((item = cbor_build_bytestring(dgst, outlen)) == NULL) {
757 fido_log_debug("%s: cbor_build_bytestring", __func__);
762 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
771 cbor_encode_hmac_secret_param(const fido_dev_t *dev, cbor_item_t *item,
772 const fido_blob_t *ecdh, const es256_pk_t *pk, const fido_blob_t *salt)
774 cbor_item_t *param = NULL;
775 cbor_item_t *argv[4];
776 struct cbor_pair pair;
777 fido_blob_t *enc = NULL;
780 memset(argv, 0, sizeof(argv));
781 memset(&pair, 0, sizeof(pair));
783 if (item == NULL || ecdh == NULL || pk == NULL || salt->ptr == NULL) {
784 fido_log_debug("%s: ecdh=%p, pk=%p, salt->ptr=%p", __func__,
785 (const void *)ecdh, (const void *)pk,
786 (const void *)salt->ptr);
787 r = FIDO_ERR_INTERNAL;
791 if (salt->len != 32 && salt->len != 64) {
792 fido_log_debug("%s: salt->len=%zu", __func__, salt->len);
793 r = FIDO_ERR_INTERNAL;
797 if ((enc = fido_blob_new()) == NULL ||
798 aes256_cbc_enc(dev, ecdh, salt, enc) < 0) {
799 fido_log_debug("%s: aes256_cbc_enc", __func__);
800 r = FIDO_ERR_INTERNAL;
804 /* XXX not pin, but salt */
805 if ((argv[0] = es256_pk_encode(pk, 1)) == NULL ||
806 (argv[1] = fido_blob_encode(enc)) == NULL ||
807 (argv[2] = cbor_encode_pin_auth(dev, ecdh, enc)) == NULL ||
808 (argv[3] = cbor_encode_pin_opt(dev)) == NULL) {
809 fido_log_debug("%s: cbor encode", __func__);
810 r = FIDO_ERR_INTERNAL;
814 if ((param = cbor_flatten_vector(argv, nitems(argv))) == NULL) {
815 fido_log_debug("%s: cbor_flatten_vector", __func__);
816 r = FIDO_ERR_INTERNAL;
820 if ((pair.key = cbor_build_string("hmac-secret")) == NULL) {
821 fido_log_debug("%s: cbor_build", __func__);
822 r = FIDO_ERR_INTERNAL;
828 if (!cbor_map_add(item, pair)) {
829 fido_log_debug("%s: cbor_map_add", __func__);
830 r = FIDO_ERR_INTERNAL;
837 cbor_vector_free(argv, nitems(argv));
841 if (pair.key != NULL)
842 cbor_decref(&pair.key);
844 fido_blob_free(&enc);
850 cbor_encode_assert_ext(fido_dev_t *dev, const fido_assert_ext_t *ext,
851 const fido_blob_t *ecdh, const es256_pk_t *pk)
853 cbor_item_t *item = NULL;
856 if (ext->mask & FIDO_EXT_CRED_BLOB)
858 if (ext->mask & FIDO_EXT_HMAC_SECRET)
860 if (ext->mask & FIDO_EXT_LARGEBLOB_KEY)
862 if (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
865 if (ext->mask & FIDO_EXT_CRED_BLOB) {
866 if (cbor_add_bool(item, "credBlob", FIDO_OPT_TRUE) < 0) {
871 if (ext->mask & FIDO_EXT_HMAC_SECRET) {
872 if (cbor_encode_hmac_secret_param(dev, item, ecdh, pk,
873 &ext->hmac_salt) < 0) {
878 if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) {
879 if (cbor_encode_largeblob_key_ext(item) < 0) {
889 cbor_decode_fmt(const cbor_item_t *item, char **fmt)
893 if (cbor_string_copy(item, &type) < 0) {
894 fido_log_debug("%s: cbor_string_copy", __func__);
898 if (strcmp(type, "packed") && strcmp(type, "fido-u2f") &&
899 strcmp(type, "none")) {
900 fido_log_debug("%s: type=%s", __func__, type);
917 find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg)
919 struct cose_key *cose_key = arg;
921 if (cbor_isa_uint(key) == true &&
922 cbor_int_get_width(key) == CBOR_INT_8) {
923 switch (cbor_get_uint8(key)) {
925 if (cbor_isa_uint(val) == false ||
926 cbor_get_int(val) > INT_MAX || cose_key->kty != 0) {
927 fido_log_debug("%s: kty", __func__);
931 cose_key->kty = (int)cbor_get_int(val);
935 if (cbor_isa_negint(val) == false ||
936 cbor_get_int(val) > INT_MAX || cose_key->alg != 0) {
937 fido_log_debug("%s: alg", __func__);
941 cose_key->alg = -(int)cbor_get_int(val) - 1;
945 } else if (cbor_isa_negint(key) == true &&
946 cbor_int_get_width(key) == CBOR_INT_8) {
947 if (cbor_get_uint8(key) == 0) {
948 /* get crv if not rsa, otherwise ignore */
949 if (cbor_isa_uint(val) == true &&
950 cbor_get_int(val) <= INT_MAX &&
952 cose_key->crv = (int)cbor_get_int(val);
960 get_cose_alg(const cbor_item_t *item, int *cose_alg)
962 struct cose_key cose_key;
964 memset(&cose_key, 0, sizeof(cose_key));
968 if (cbor_isa_map(item) == false ||
969 cbor_map_is_definite(item) == false ||
970 cbor_map_iter(item, &cose_key, find_cose_alg) < 0) {
971 fido_log_debug("%s: cbor type", __func__);
975 switch (cose_key.alg) {
977 if (cose_key.kty != COSE_KTY_EC2 ||
978 cose_key.crv != COSE_P256) {
979 fido_log_debug("%s: invalid kty/crv", __func__);
985 if (cose_key.kty != COSE_KTY_OKP ||
986 cose_key.crv != COSE_ED25519) {
987 fido_log_debug("%s: invalid kty/crv", __func__);
993 if (cose_key.kty != COSE_KTY_RSA) {
994 fido_log_debug("%s: invalid kty/crv", __func__);
1000 fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg);
1005 *cose_alg = cose_key.alg;
1011 cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key)
1013 if (get_cose_alg(item, type) < 0) {
1014 fido_log_debug("%s: get_cose_alg", __func__);
1020 if (es256_pk_decode(item, key) < 0) {
1021 fido_log_debug("%s: es256_pk_decode", __func__);
1026 if (rs256_pk_decode(item, key) < 0) {
1027 fido_log_debug("%s: rs256_pk_decode", __func__);
1032 if (eddsa_pk_decode(item, key) < 0) {
1033 fido_log_debug("%s: eddsa_pk_decode", __func__);
1038 fido_log_debug("%s: invalid cose_alg %d", __func__, *type);
1046 decode_attcred(const unsigned char **buf, size_t *len, int cose_alg,
1047 fido_attcred_t *attcred)
1049 cbor_item_t *item = NULL;
1050 struct cbor_load_result cbor;
1054 fido_log_xxd(*buf, *len, "%s", __func__);
1056 if (fido_buf_read(buf, len, &attcred->aaguid,
1057 sizeof(attcred->aaguid)) < 0) {
1058 fido_log_debug("%s: fido_buf_read aaguid", __func__);
1062 if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) {
1063 fido_log_debug("%s: fido_buf_read id_len", __func__);
1067 attcred->id.len = (size_t)be16toh(id_len);
1068 if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL)
1071 fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len);
1073 if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) {
1074 fido_log_debug("%s: fido_buf_read id", __func__);
1078 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1079 fido_log_debug("%s: cbor_load", __func__);
1083 if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) {
1084 fido_log_debug("%s: cbor_decode_pubkey", __func__);
1088 if (attcred->type != cose_alg) {
1089 fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__,
1090 attcred->type, cose_alg);
1106 decode_cred_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1108 fido_cred_ext_t *authdata_ext = arg;
1112 if (cbor_string_copy(key, &type) < 0) {
1113 fido_log_debug("%s: cbor type", __func__);
1114 ok = 0; /* ignore */
1118 if (strcmp(type, "hmac-secret") == 0) {
1119 if (cbor_isa_float_ctrl(val) == false ||
1120 cbor_float_get_width(val) != CBOR_FLOAT_0 ||
1121 cbor_is_bool(val) == false) {
1122 fido_log_debug("%s: cbor type", __func__);
1125 if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
1126 authdata_ext->mask |= FIDO_EXT_HMAC_SECRET;
1127 } else if (strcmp(type, "credProtect") == 0) {
1128 if (cbor_isa_uint(val) == false ||
1129 cbor_int_get_width(val) != CBOR_INT_8) {
1130 fido_log_debug("%s: cbor type", __func__);
1133 authdata_ext->mask |= FIDO_EXT_CRED_PROTECT;
1134 authdata_ext->prot = cbor_get_uint8(val);
1135 } else if (strcmp(type, "credBlob") == 0) {
1136 if (cbor_isa_float_ctrl(val) == false ||
1137 cbor_float_get_width(val) != CBOR_FLOAT_0 ||
1138 cbor_is_bool(val) == false) {
1139 fido_log_debug("%s: cbor type", __func__);
1142 if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
1143 authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
1154 decode_cred_extensions(const unsigned char **buf, size_t *len,
1155 fido_cred_ext_t *authdata_ext)
1157 cbor_item_t *item = NULL;
1158 struct cbor_load_result cbor;
1161 memset(authdata_ext, 0, sizeof(*authdata_ext));
1163 fido_log_xxd(*buf, *len, "%s", __func__);
1165 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1166 fido_log_debug("%s: cbor_load", __func__);
1170 if (cbor_isa_map(item) == false ||
1171 cbor_map_is_definite(item) == false ||
1172 cbor_map_iter(item, authdata_ext, decode_cred_extension) < 0) {
1173 fido_log_debug("%s: cbor type", __func__);
1189 decode_assert_extension(const cbor_item_t *key, const cbor_item_t *val,
1192 fido_assert_extattr_t *authdata_ext = arg;
1196 if (cbor_string_copy(key, &type) < 0) {
1197 fido_log_debug("%s: cbor type", __func__);
1198 ok = 0; /* ignore */
1202 if (strcmp(type, "hmac-secret") == 0) {
1203 if (fido_blob_decode(val, &authdata_ext->hmac_secret_enc) < 0) {
1204 fido_log_debug("%s: fido_blob_decode", __func__);
1207 authdata_ext->mask |= FIDO_EXT_HMAC_SECRET;
1208 } else if (strcmp(type, "credBlob") == 0) {
1209 if (fido_blob_decode(val, &authdata_ext->blob) < 0) {
1210 fido_log_debug("%s: fido_blob_decode", __func__);
1213 authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
1224 decode_assert_extensions(const unsigned char **buf, size_t *len,
1225 fido_assert_extattr_t *authdata_ext)
1227 cbor_item_t *item = NULL;
1228 struct cbor_load_result cbor;
1231 fido_log_xxd(*buf, *len, "%s", __func__);
1233 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1234 fido_log_debug("%s: cbor_load", __func__);
1238 if (cbor_isa_map(item) == false ||
1239 cbor_map_is_definite(item) == false ||
1240 cbor_map_iter(item, authdata_ext, decode_assert_extension) < 0) {
1241 fido_log_debug("%s: cbor type", __func__);
1257 cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
1258 fido_blob_t *authdata_cbor, fido_authdata_t *authdata,
1259 fido_attcred_t *attcred, fido_cred_ext_t *authdata_ext)
1261 const unsigned char *buf = NULL;
1265 if (cbor_isa_bytestring(item) == false ||
1266 cbor_bytestring_is_definite(item) == false) {
1267 fido_log_debug("%s: cbor type", __func__);
1271 if (authdata_cbor->ptr != NULL ||
1272 (authdata_cbor->len = cbor_serialize_alloc(item,
1273 &authdata_cbor->ptr, &alloc_len)) == 0) {
1274 fido_log_debug("%s: cbor_serialize_alloc", __func__);
1278 buf = cbor_bytestring_handle(item);
1279 len = cbor_bytestring_length(item);
1280 fido_log_xxd(buf, len, "%s", __func__);
1282 if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
1283 fido_log_debug("%s: fido_buf_read", __func__);
1287 authdata->sigcount = be32toh(authdata->sigcount);
1289 if (attcred != NULL) {
1290 if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 ||
1291 decode_attcred(&buf, &len, cose_alg, attcred) < 0)
1295 if (authdata_ext != NULL) {
1296 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 &&
1297 decode_cred_extensions(&buf, &len, authdata_ext) < 0)
1301 /* XXX we should probably ensure that len == 0 at this point */
1307 cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor,
1308 fido_authdata_t *authdata, fido_assert_extattr_t *authdata_ext)
1310 const unsigned char *buf = NULL;
1314 if (cbor_isa_bytestring(item) == false ||
1315 cbor_bytestring_is_definite(item) == false) {
1316 fido_log_debug("%s: cbor type", __func__);
1320 if (authdata_cbor->ptr != NULL ||
1321 (authdata_cbor->len = cbor_serialize_alloc(item,
1322 &authdata_cbor->ptr, &alloc_len)) == 0) {
1323 fido_log_debug("%s: cbor_serialize_alloc", __func__);
1327 buf = cbor_bytestring_handle(item);
1328 len = cbor_bytestring_length(item);
1330 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len);
1332 if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
1333 fido_log_debug("%s: fido_buf_read", __func__);
1337 authdata->sigcount = be32toh(authdata->sigcount);
1339 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) {
1340 if (decode_assert_extensions(&buf, &len, authdata_ext) < 0) {
1341 fido_log_debug("%s: decode_assert_extensions",
1347 /* XXX we should probably ensure that len == 0 at this point */
1353 decode_x5c(const cbor_item_t *item, void *arg)
1355 fido_blob_t *x5c = arg;
1358 return (0); /* ignore */
1360 return (fido_blob_decode(item, x5c));
1364 decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1366 fido_attstmt_t *attstmt = arg;
1371 if (cbor_string_copy(key, &name) < 0) {
1372 fido_log_debug("%s: cbor type", __func__);
1373 ok = 0; /* ignore */
1377 if (!strcmp(name, "alg")) {
1378 if (cbor_isa_negint(val) == false ||
1379 cbor_get_int(val) > UINT16_MAX) {
1380 fido_log_debug("%s: alg", __func__);
1383 if ((cose_alg = -(int)cbor_get_int(val) - 1) != COSE_ES256 &&
1384 cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA) {
1385 fido_log_debug("%s: unsupported cose_alg=%d", __func__,
1389 } else if (!strcmp(name, "sig")) {
1390 if (fido_blob_decode(val, &attstmt->sig) < 0) {
1391 fido_log_debug("%s: sig", __func__);
1394 } else if (!strcmp(name, "x5c")) {
1395 if (cbor_isa_array(val) == false ||
1396 cbor_array_is_definite(val) == false ||
1397 cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) {
1398 fido_log_debug("%s: x5c", __func__);
1411 cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt)
1413 if (cbor_isa_map(item) == false ||
1414 cbor_map_is_definite(item) == false ||
1415 cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) {
1416 fido_log_debug("%s: cbor type", __func__);
1424 cbor_decode_uint64(const cbor_item_t *item, uint64_t *n)
1426 if (cbor_isa_uint(item) == false) {
1427 fido_log_debug("%s: cbor type", __func__);
1431 *n = cbor_get_int(item);
1437 decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1439 fido_blob_t *id = arg;
1443 if (cbor_string_copy(key, &name) < 0) {
1444 fido_log_debug("%s: cbor type", __func__);
1445 ok = 0; /* ignore */
1449 if (!strcmp(name, "id"))
1450 if (fido_blob_decode(val, id) < 0) {
1451 fido_log_debug("%s: cbor_bytestring_copy", __func__);
1463 cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id)
1465 if (cbor_isa_map(item) == false ||
1466 cbor_map_is_definite(item) == false ||
1467 cbor_map_iter(item, id, decode_cred_id_entry) < 0) {
1468 fido_log_debug("%s: cbor type", __func__);
1476 decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1478 fido_user_t *user = arg;
1482 if (cbor_string_copy(key, &name) < 0) {
1483 fido_log_debug("%s: cbor type", __func__);
1484 ok = 0; /* ignore */
1488 if (!strcmp(name, "icon")) {
1489 if (cbor_string_copy(val, &user->icon) < 0) {
1490 fido_log_debug("%s: icon", __func__);
1493 } else if (!strcmp(name, "name")) {
1494 if (cbor_string_copy(val, &user->name) < 0) {
1495 fido_log_debug("%s: name", __func__);
1498 } else if (!strcmp(name, "displayName")) {
1499 if (cbor_string_copy(val, &user->display_name) < 0) {
1500 fido_log_debug("%s: display_name", __func__);
1503 } else if (!strcmp(name, "id")) {
1504 if (fido_blob_decode(val, &user->id) < 0) {
1505 fido_log_debug("%s: id", __func__);
1518 cbor_decode_user(const cbor_item_t *item, fido_user_t *user)
1520 if (cbor_isa_map(item) == false ||
1521 cbor_map_is_definite(item) == false ||
1522 cbor_map_iter(item, user, decode_user_entry) < 0) {
1523 fido_log_debug("%s: cbor type", __func__);
1531 decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val,
1534 fido_rp_t *rp = arg;
1538 if (cbor_string_copy(key, &name) < 0) {
1539 fido_log_debug("%s: cbor type", __func__);
1540 ok = 0; /* ignore */
1544 if (!strcmp(name, "id")) {
1545 if (cbor_string_copy(val, &rp->id) < 0) {
1546 fido_log_debug("%s: id", __func__);
1549 } else if (!strcmp(name, "name")) {
1550 if (cbor_string_copy(val, &rp->name) < 0) {
1551 fido_log_debug("%s: name", __func__);
1564 cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp)
1566 if (cbor_isa_map(item) == false ||
1567 cbor_map_is_definite(item) == false ||
1568 cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) {
1569 fido_log_debug("%s: cbor type", __func__);
1577 cbor_build_uint(const uint64_t value)
1579 if (value <= UINT8_MAX)
1580 return cbor_build_uint8((uint8_t)value);
1581 else if (value <= UINT16_MAX)
1582 return cbor_build_uint16((uint16_t)value);
1583 else if (value <= UINT32_MAX)
1584 return cbor_build_uint32((uint32_t)value);
1586 return cbor_build_uint64(value);
1590 cbor_array_append(cbor_item_t **array, cbor_item_t *item)
1592 cbor_item_t **v, *ret;
1595 if ((v = cbor_array_handle(*array)) == NULL ||
1596 (n = cbor_array_size(*array)) == SIZE_MAX ||
1597 (ret = cbor_new_definite_array(n + 1)) == NULL)
1599 for (size_t i = 0; i < n; i++) {
1600 if (cbor_array_push(ret, v[i]) == 0) {
1605 if (cbor_array_push(ret, item) == 0) {
1616 cbor_array_drop(cbor_item_t **array, size_t idx)
1618 cbor_item_t **v, *ret;
1621 if ((v = cbor_array_handle(*array)) == NULL ||
1622 (n = cbor_array_size(*array)) == 0 || idx >= n ||
1623 (ret = cbor_new_definite_array(n - 1)) == NULL)
1625 for (size_t i = 0; i < n; i++) {
1626 if (i != idx && cbor_array_push(ret, v[i]) == 0) {