1 /* 2 * Copyright (c) 2018 Yubico AB. All rights reserved. 3 * Use of this source code is governed by a BSD-style 4 * license that can be found in the LICENSE file. 5 */ 6 7 #include <openssl/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 static int 564 cbor_encode_largeblob_key_ext(cbor_item_t *map) 565 { 566 if (map == NULL || 567 cbor_add_bool(map, "largeBlobKey", FIDO_OPT_TRUE) < 0) 568 return (-1); 569 570 return (0); 571 } 572 573 cbor_item_t * 574 cbor_encode_cred_ext(const fido_cred_ext_t *ext, const fido_blob_t *blob) 575 { 576 cbor_item_t *item = NULL; 577 size_t size = 0; 578 579 if (ext->mask & FIDO_EXT_CRED_BLOB) 580 size++; 581 if (ext->mask & FIDO_EXT_HMAC_SECRET) 582 size++; 583 if (ext->mask & FIDO_EXT_CRED_PROTECT) 584 size++; 585 if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) 586 size++; 587 588 if (size == 0 || (item = cbor_new_definite_map(size)) == NULL) 589 return (NULL); 590 591 if (ext->mask & FIDO_EXT_CRED_BLOB) { 592 if (cbor_add_bytestring(item, "credBlob", blob->ptr, 593 blob->len) < 0) { 594 cbor_decref(&item); 595 return (NULL); 596 } 597 } 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) { 602 cbor_decref(&item); 603 return (NULL); 604 } 605 } 606 if (ext->mask & FIDO_EXT_HMAC_SECRET) { 607 if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) { 608 cbor_decref(&item); 609 return (NULL); 610 } 611 } 612 if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) { 613 if (cbor_encode_largeblob_key_ext(item) < 0) { 614 cbor_decref(&item); 615 return (NULL); 616 } 617 } 618 619 return (item); 620 } 621 622 cbor_item_t * 623 cbor_encode_cred_opt(fido_opt_t rk, fido_opt_t uv) 624 { 625 cbor_item_t *item = NULL; 626 627 if ((item = cbor_new_definite_map(2)) == NULL) 628 return (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)) { 631 cbor_decref(&item); 632 return (NULL); 633 } 634 635 return (item); 636 } 637 638 cbor_item_t * 639 cbor_encode_assert_opt(fido_opt_t up, fido_opt_t uv) 640 { 641 cbor_item_t *item = NULL; 642 643 if ((item = cbor_new_definite_map(2)) == NULL) 644 return (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)) { 647 cbor_decref(&item); 648 return (NULL); 649 } 650 651 return (item); 652 } 653 654 cbor_item_t * 655 cbor_encode_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret, 656 const fido_blob_t *data) 657 { 658 const EVP_MD *md = NULL; 659 unsigned char dgst[SHA256_DIGEST_LENGTH]; 660 unsigned int dgst_len; 661 size_t outlen; 662 uint8_t prot; 663 fido_blob_t key; 664 665 666 key.ptr = secret->ptr; 667 key.len = secret->len; 668 669 if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { 670 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); 671 return (NULL); 672 } 673 674 /* select hmac portion of the shared secret */ 675 if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32) 676 key.len = 32; 677 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) 681 return (NULL); 682 683 outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len; 684 685 return (cbor_build_bytestring(dgst, outlen)); 686 } 687 688 cbor_item_t * 689 cbor_encode_pin_opt(const fido_dev_t *dev) 690 { 691 uint8_t prot; 692 693 if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { 694 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); 695 return (NULL); 696 } 697 698 return (cbor_build_uint8(prot)); 699 } 700 701 cbor_item_t * 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) 704 { 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 710 HMAC_CTX ctx; 711 #else 712 HMAC_CTX *ctx = NULL; 713 #endif 714 fido_blob_t key; 715 uint8_t prot; 716 size_t outlen; 717 718 key.ptr = secret->ptr; 719 key.len = secret->len; 720 721 if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { 722 fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); 723 goto fail; 724 } 725 726 if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32) 727 key.len = 32; 728 729 #if OPENSSL_VERSION_NUMBER < 0x10100000L 730 HMAC_CTX_init(&ctx); 731 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__); 739 goto fail; 740 } 741 #else 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__); 750 goto fail; 751 } 752 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ 753 754 outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len; 755 756 if ((item = cbor_build_bytestring(dgst, outlen)) == NULL) { 757 fido_log_debug("%s: cbor_build_bytestring", __func__); 758 goto fail; 759 } 760 761 fail: 762 #if OPENSSL_VERSION_NUMBER >= 0x10100000L 763 if (ctx != NULL) 764 HMAC_CTX_free(ctx); 765 #endif 766 767 return (item); 768 } 769 770 static int 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) 773 { 774 cbor_item_t *param = NULL; 775 cbor_item_t *argv[4]; 776 struct cbor_pair pair; 777 fido_blob_t *enc = NULL; 778 int r; 779 780 memset(argv, 0, sizeof(argv)); 781 memset(&pair, 0, sizeof(pair)); 782 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; 788 goto fail; 789 } 790 791 if (salt->len != 32 && salt->len != 64) { 792 fido_log_debug("%s: salt->len=%zu", __func__, salt->len); 793 r = FIDO_ERR_INTERNAL; 794 goto fail; 795 } 796 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; 801 goto fail; 802 } 803 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; 811 goto fail; 812 } 813 814 if ((param = cbor_flatten_vector(argv, nitems(argv))) == NULL) { 815 fido_log_debug("%s: cbor_flatten_vector", __func__); 816 r = FIDO_ERR_INTERNAL; 817 goto fail; 818 } 819 820 if ((pair.key = cbor_build_string("hmac-secret")) == NULL) { 821 fido_log_debug("%s: cbor_build", __func__); 822 r = FIDO_ERR_INTERNAL; 823 goto fail; 824 } 825 826 pair.value = param; 827 828 if (!cbor_map_add(item, pair)) { 829 fido_log_debug("%s: cbor_map_add", __func__); 830 r = FIDO_ERR_INTERNAL; 831 goto fail; 832 } 833 834 r = FIDO_OK; 835 836 fail: 837 cbor_vector_free(argv, nitems(argv)); 838 839 if (param != NULL) 840 cbor_decref(¶m); 841 if (pair.key != NULL) 842 cbor_decref(&pair.key); 843 844 fido_blob_free(&enc); 845 846 return (r); 847 } 848 849 cbor_item_t * 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) 852 { 853 cbor_item_t *item = NULL; 854 size_t size = 0; 855 856 if (ext->mask & FIDO_EXT_CRED_BLOB) 857 size++; 858 if (ext->mask & FIDO_EXT_HMAC_SECRET) 859 size++; 860 if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) 861 size++; 862 if (size == 0 || (item = cbor_new_definite_map(size)) == NULL) 863 return (NULL); 864 865 if (ext->mask & FIDO_EXT_CRED_BLOB) { 866 if (cbor_add_bool(item, "credBlob", FIDO_OPT_TRUE) < 0) { 867 cbor_decref(&item); 868 return (NULL); 869 } 870 } 871 if (ext->mask & FIDO_EXT_HMAC_SECRET) { 872 if (cbor_encode_hmac_secret_param(dev, item, ecdh, pk, 873 &ext->hmac_salt) < 0) { 874 cbor_decref(&item); 875 return (NULL); 876 } 877 } 878 if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) { 879 if (cbor_encode_largeblob_key_ext(item) < 0) { 880 cbor_decref(&item); 881 return (NULL); 882 } 883 } 884 885 return (item); 886 } 887 888 int 889 cbor_decode_fmt(const cbor_item_t *item, char **fmt) 890 { 891 char *type = NULL; 892 893 if (cbor_string_copy(item, &type) < 0) { 894 fido_log_debug("%s: cbor_string_copy", __func__); 895 return (-1); 896 } 897 898 if (strcmp(type, "packed") && strcmp(type, "fido-u2f") && 899 strcmp(type, "none")) { 900 fido_log_debug("%s: type=%s", __func__, type); 901 free(type); 902 return (-1); 903 } 904 905 *fmt = type; 906 907 return (0); 908 } 909 910 struct cose_key { 911 int kty; 912 int alg; 913 int crv; 914 }; 915 916 static int 917 find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg) 918 { 919 struct cose_key *cose_key = arg; 920 921 if (cbor_isa_uint(key) == true && 922 cbor_int_get_width(key) == CBOR_INT_8) { 923 switch (cbor_get_uint8(key)) { 924 case 1: 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__); 928 return (-1); 929 } 930 931 cose_key->kty = (int)cbor_get_int(val); 932 933 break; 934 case 3: 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__); 938 return (-1); 939 } 940 941 cose_key->alg = -(int)cbor_get_int(val) - 1; 942 943 break; 944 } 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 && 951 cose_key->crv == 0) 952 cose_key->crv = (int)cbor_get_int(val); 953 } 954 } 955 956 return (0); 957 } 958 959 static int 960 get_cose_alg(const cbor_item_t *item, int *cose_alg) 961 { 962 struct cose_key cose_key; 963 964 memset(&cose_key, 0, sizeof(cose_key)); 965 966 *cose_alg = 0; 967 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__); 972 return (-1); 973 } 974 975 switch (cose_key.alg) { 976 case COSE_ES256: 977 if (cose_key.kty != COSE_KTY_EC2 || 978 cose_key.crv != COSE_P256) { 979 fido_log_debug("%s: invalid kty/crv", __func__); 980 return (-1); 981 } 982 983 break; 984 case COSE_EDDSA: 985 if (cose_key.kty != COSE_KTY_OKP || 986 cose_key.crv != COSE_ED25519) { 987 fido_log_debug("%s: invalid kty/crv", __func__); 988 return (-1); 989 } 990 991 break; 992 case COSE_RS256: 993 if (cose_key.kty != COSE_KTY_RSA) { 994 fido_log_debug("%s: invalid kty/crv", __func__); 995 return (-1); 996 } 997 998 break; 999 default: 1000 fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg); 1001 1002 return (-1); 1003 } 1004 1005 *cose_alg = cose_key.alg; 1006 1007 return (0); 1008 } 1009 1010 int 1011 cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key) 1012 { 1013 if (get_cose_alg(item, type) < 0) { 1014 fido_log_debug("%s: get_cose_alg", __func__); 1015 return (-1); 1016 } 1017 1018 switch (*type) { 1019 case COSE_ES256: 1020 if (es256_pk_decode(item, key) < 0) { 1021 fido_log_debug("%s: es256_pk_decode", __func__); 1022 return (-1); 1023 } 1024 break; 1025 case COSE_RS256: 1026 if (rs256_pk_decode(item, key) < 0) { 1027 fido_log_debug("%s: rs256_pk_decode", __func__); 1028 return (-1); 1029 } 1030 break; 1031 case COSE_EDDSA: 1032 if (eddsa_pk_decode(item, key) < 0) { 1033 fido_log_debug("%s: eddsa_pk_decode", __func__); 1034 return (-1); 1035 } 1036 break; 1037 default: 1038 fido_log_debug("%s: invalid cose_alg %d", __func__, *type); 1039 return (-1); 1040 } 1041 1042 return (0); 1043 } 1044 1045 static int 1046 decode_attcred(const unsigned char **buf, size_t *len, int cose_alg, 1047 fido_attcred_t *attcred) 1048 { 1049 cbor_item_t *item = NULL; 1050 struct cbor_load_result cbor; 1051 uint16_t id_len; 1052 int ok = -1; 1053 1054 fido_log_xxd(*buf, *len, "%s", __func__); 1055 1056 if (fido_buf_read(buf, len, &attcred->aaguid, 1057 sizeof(attcred->aaguid)) < 0) { 1058 fido_log_debug("%s: fido_buf_read aaguid", __func__); 1059 return (-1); 1060 } 1061 1062 if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) { 1063 fido_log_debug("%s: fido_buf_read id_len", __func__); 1064 return (-1); 1065 } 1066 1067 attcred->id.len = (size_t)be16toh(id_len); 1068 if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL) 1069 return (-1); 1070 1071 fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len); 1072 1073 if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) { 1074 fido_log_debug("%s: fido_buf_read id", __func__); 1075 return (-1); 1076 } 1077 1078 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { 1079 fido_log_debug("%s: cbor_load", __func__); 1080 goto fail; 1081 } 1082 1083 if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) { 1084 fido_log_debug("%s: cbor_decode_pubkey", __func__); 1085 goto fail; 1086 } 1087 1088 if (attcred->type != cose_alg) { 1089 fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__, 1090 attcred->type, cose_alg); 1091 goto fail; 1092 } 1093 1094 *buf += cbor.read; 1095 *len -= cbor.read; 1096 1097 ok = 0; 1098 fail: 1099 if (item != NULL) 1100 cbor_decref(&item); 1101 1102 return (ok); 1103 } 1104 1105 static int 1106 decode_cred_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1107 { 1108 fido_cred_ext_t *authdata_ext = arg; 1109 char *type = NULL; 1110 int ok = -1; 1111 1112 if (cbor_string_copy(key, &type) < 0) { 1113 fido_log_debug("%s: cbor type", __func__); 1114 ok = 0; /* ignore */ 1115 goto out; 1116 } 1117 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__); 1123 goto out; 1124 } 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__); 1131 goto out; 1132 } 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__); 1140 goto out; 1141 } 1142 if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) 1143 authdata_ext->mask |= FIDO_EXT_CRED_BLOB; 1144 } 1145 1146 ok = 0; 1147 out: 1148 free(type); 1149 1150 return (ok); 1151 } 1152 1153 static int 1154 decode_cred_extensions(const unsigned char **buf, size_t *len, 1155 fido_cred_ext_t *authdata_ext) 1156 { 1157 cbor_item_t *item = NULL; 1158 struct cbor_load_result cbor; 1159 int ok = -1; 1160 1161 memset(authdata_ext, 0, sizeof(*authdata_ext)); 1162 1163 fido_log_xxd(*buf, *len, "%s", __func__); 1164 1165 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { 1166 fido_log_debug("%s: cbor_load", __func__); 1167 goto fail; 1168 } 1169 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__); 1174 goto fail; 1175 } 1176 1177 *buf += cbor.read; 1178 *len -= cbor.read; 1179 1180 ok = 0; 1181 fail: 1182 if (item != NULL) 1183 cbor_decref(&item); 1184 1185 return (ok); 1186 } 1187 1188 static int 1189 decode_assert_extension(const cbor_item_t *key, const cbor_item_t *val, 1190 void *arg) 1191 { 1192 fido_assert_extattr_t *authdata_ext = arg; 1193 char *type = NULL; 1194 int ok = -1; 1195 1196 if (cbor_string_copy(key, &type) < 0) { 1197 fido_log_debug("%s: cbor type", __func__); 1198 ok = 0; /* ignore */ 1199 goto out; 1200 } 1201 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__); 1205 goto out; 1206 } 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__); 1211 goto out; 1212 } 1213 authdata_ext->mask |= FIDO_EXT_CRED_BLOB; 1214 } 1215 1216 ok = 0; 1217 out: 1218 free(type); 1219 1220 return (ok); 1221 } 1222 1223 static int 1224 decode_assert_extensions(const unsigned char **buf, size_t *len, 1225 fido_assert_extattr_t *authdata_ext) 1226 { 1227 cbor_item_t *item = NULL; 1228 struct cbor_load_result cbor; 1229 int ok = -1; 1230 1231 fido_log_xxd(*buf, *len, "%s", __func__); 1232 1233 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { 1234 fido_log_debug("%s: cbor_load", __func__); 1235 goto fail; 1236 } 1237 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__); 1242 goto fail; 1243 } 1244 1245 *buf += cbor.read; 1246 *len -= cbor.read; 1247 1248 ok = 0; 1249 fail: 1250 if (item != NULL) 1251 cbor_decref(&item); 1252 1253 return (ok); 1254 } 1255 1256 int 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) 1260 { 1261 const unsigned char *buf = NULL; 1262 size_t len; 1263 size_t alloc_len; 1264 1265 if (cbor_isa_bytestring(item) == false || 1266 cbor_bytestring_is_definite(item) == false) { 1267 fido_log_debug("%s: cbor type", __func__); 1268 return (-1); 1269 } 1270 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__); 1275 return (-1); 1276 } 1277 1278 buf = cbor_bytestring_handle(item); 1279 len = cbor_bytestring_length(item); 1280 fido_log_xxd(buf, len, "%s", __func__); 1281 1282 if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { 1283 fido_log_debug("%s: fido_buf_read", __func__); 1284 return (-1); 1285 } 1286 1287 authdata->sigcount = be32toh(authdata->sigcount); 1288 1289 if (attcred != NULL) { 1290 if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 || 1291 decode_attcred(&buf, &len, cose_alg, attcred) < 0) 1292 return (-1); 1293 } 1294 1295 if (authdata_ext != NULL) { 1296 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && 1297 decode_cred_extensions(&buf, &len, authdata_ext) < 0) 1298 return (-1); 1299 } 1300 1301 /* XXX we should probably ensure that len == 0 at this point */ 1302 1303 return (FIDO_OK); 1304 } 1305 1306 int 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) 1309 { 1310 const unsigned char *buf = NULL; 1311 size_t len; 1312 size_t alloc_len; 1313 1314 if (cbor_isa_bytestring(item) == false || 1315 cbor_bytestring_is_definite(item) == false) { 1316 fido_log_debug("%s: cbor type", __func__); 1317 return (-1); 1318 } 1319 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__); 1324 return (-1); 1325 } 1326 1327 buf = cbor_bytestring_handle(item); 1328 len = cbor_bytestring_length(item); 1329 1330 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); 1331 1332 if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { 1333 fido_log_debug("%s: fido_buf_read", __func__); 1334 return (-1); 1335 } 1336 1337 authdata->sigcount = be32toh(authdata->sigcount); 1338 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", 1342 __func__); 1343 return (-1); 1344 } 1345 } 1346 1347 /* XXX we should probably ensure that len == 0 at this point */ 1348 1349 return (FIDO_OK); 1350 } 1351 1352 static int 1353 decode_x5c(const cbor_item_t *item, void *arg) 1354 { 1355 fido_blob_t *x5c = arg; 1356 1357 if (x5c->len) 1358 return (0); /* ignore */ 1359 1360 return (fido_blob_decode(item, x5c)); 1361 } 1362 1363 static int 1364 decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1365 { 1366 fido_attstmt_t *attstmt = arg; 1367 char *name = NULL; 1368 int cose_alg = 0; 1369 int ok = -1; 1370 1371 if (cbor_string_copy(key, &name) < 0) { 1372 fido_log_debug("%s: cbor type", __func__); 1373 ok = 0; /* ignore */ 1374 goto out; 1375 } 1376 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__); 1381 goto out; 1382 } 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__, 1386 cose_alg); 1387 goto out; 1388 } 1389 } else if (!strcmp(name, "sig")) { 1390 if (fido_blob_decode(val, &attstmt->sig) < 0) { 1391 fido_log_debug("%s: sig", __func__); 1392 goto out; 1393 } 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__); 1399 goto out; 1400 } 1401 } 1402 1403 ok = 0; 1404 out: 1405 free(name); 1406 1407 return (ok); 1408 } 1409 1410 int 1411 cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt) 1412 { 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__); 1417 return (-1); 1418 } 1419 1420 return (0); 1421 } 1422 1423 int 1424 cbor_decode_uint64(const cbor_item_t *item, uint64_t *n) 1425 { 1426 if (cbor_isa_uint(item) == false) { 1427 fido_log_debug("%s: cbor type", __func__); 1428 return (-1); 1429 } 1430 1431 *n = cbor_get_int(item); 1432 1433 return (0); 1434 } 1435 1436 static int 1437 decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1438 { 1439 fido_blob_t *id = arg; 1440 char *name = NULL; 1441 int ok = -1; 1442 1443 if (cbor_string_copy(key, &name) < 0) { 1444 fido_log_debug("%s: cbor type", __func__); 1445 ok = 0; /* ignore */ 1446 goto out; 1447 } 1448 1449 if (!strcmp(name, "id")) 1450 if (fido_blob_decode(val, id) < 0) { 1451 fido_log_debug("%s: cbor_bytestring_copy", __func__); 1452 goto out; 1453 } 1454 1455 ok = 0; 1456 out: 1457 free(name); 1458 1459 return (ok); 1460 } 1461 1462 int 1463 cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id) 1464 { 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__); 1469 return (-1); 1470 } 1471 1472 return (0); 1473 } 1474 1475 static int 1476 decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1477 { 1478 fido_user_t *user = arg; 1479 char *name = NULL; 1480 int ok = -1; 1481 1482 if (cbor_string_copy(key, &name) < 0) { 1483 fido_log_debug("%s: cbor type", __func__); 1484 ok = 0; /* ignore */ 1485 goto out; 1486 } 1487 1488 if (!strcmp(name, "icon")) { 1489 if (cbor_string_copy(val, &user->icon) < 0) { 1490 fido_log_debug("%s: icon", __func__); 1491 goto out; 1492 } 1493 } else if (!strcmp(name, "name")) { 1494 if (cbor_string_copy(val, &user->name) < 0) { 1495 fido_log_debug("%s: name", __func__); 1496 goto out; 1497 } 1498 } else if (!strcmp(name, "displayName")) { 1499 if (cbor_string_copy(val, &user->display_name) < 0) { 1500 fido_log_debug("%s: display_name", __func__); 1501 goto out; 1502 } 1503 } else if (!strcmp(name, "id")) { 1504 if (fido_blob_decode(val, &user->id) < 0) { 1505 fido_log_debug("%s: id", __func__); 1506 goto out; 1507 } 1508 } 1509 1510 ok = 0; 1511 out: 1512 free(name); 1513 1514 return (ok); 1515 } 1516 1517 int 1518 cbor_decode_user(const cbor_item_t *item, fido_user_t *user) 1519 { 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__); 1524 return (-1); 1525 } 1526 1527 return (0); 1528 } 1529 1530 static int 1531 decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val, 1532 void *arg) 1533 { 1534 fido_rp_t *rp = arg; 1535 char *name = NULL; 1536 int ok = -1; 1537 1538 if (cbor_string_copy(key, &name) < 0) { 1539 fido_log_debug("%s: cbor type", __func__); 1540 ok = 0; /* ignore */ 1541 goto out; 1542 } 1543 1544 if (!strcmp(name, "id")) { 1545 if (cbor_string_copy(val, &rp->id) < 0) { 1546 fido_log_debug("%s: id", __func__); 1547 goto out; 1548 } 1549 } else if (!strcmp(name, "name")) { 1550 if (cbor_string_copy(val, &rp->name) < 0) { 1551 fido_log_debug("%s: name", __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_rp_entity(const cbor_item_t *item, fido_rp_t *rp) 1565 { 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__); 1570 return (-1); 1571 } 1572 1573 return (0); 1574 } 1575 1576 cbor_item_t * 1577 cbor_build_uint(const uint64_t value) 1578 { 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); 1585 1586 return cbor_build_uint64(value); 1587 } 1588 1589 int 1590 cbor_array_append(cbor_item_t **array, cbor_item_t *item) 1591 { 1592 cbor_item_t **v, *ret; 1593 size_t n; 1594 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) 1598 return -1; 1599 for (size_t i = 0; i < n; i++) { 1600 if (cbor_array_push(ret, v[i]) == 0) { 1601 cbor_decref(&ret); 1602 return -1; 1603 } 1604 } 1605 if (cbor_array_push(ret, item) == 0) { 1606 cbor_decref(&ret); 1607 return -1; 1608 } 1609 cbor_decref(array); 1610 *array = ret; 1611 1612 return 0; 1613 } 1614 1615 int 1616 cbor_array_drop(cbor_item_t **array, size_t idx) 1617 { 1618 cbor_item_t **v, *ret; 1619 size_t n; 1620 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) 1624 return -1; 1625 for (size_t i = 0; i < n; i++) { 1626 if (i != idx && cbor_array_push(ret, v[i]) == 0) { 1627 cbor_decref(&ret); 1628 return -1; 1629 } 1630 } 1631 cbor_decref(array); 1632 *array = ret; 1633 1634 return 0; 1635 } 1636