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