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