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