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, 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 (cbor_add_uint8(item, "credProtect", ext->prot) < 0) { 587 cbor_decref(&item); 588 return (NULL); 589 } 590 } 591 592 return (item); 593 } 594 595 cbor_item_t * 596 cbor_encode_options(fido_opt_t rk, fido_opt_t uv) 597 { 598 cbor_item_t *item = NULL; 599 600 if ((item = cbor_new_definite_map(2)) == NULL) 601 return (NULL); 602 603 if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) || 604 (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { 605 cbor_decref(&item); 606 return (NULL); 607 } 608 609 return (item); 610 } 611 612 cbor_item_t * 613 cbor_encode_assert_options(fido_opt_t up, fido_opt_t uv) 614 { 615 cbor_item_t *item = NULL; 616 617 if ((item = cbor_new_definite_map(2)) == NULL) 618 return (NULL); 619 620 if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) || 621 (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { 622 cbor_decref(&item); 623 return (NULL); 624 } 625 626 return (item); 627 } 628 629 cbor_item_t * 630 cbor_encode_pin_auth(const fido_blob_t *hmac_key, const fido_blob_t *data) 631 { 632 const EVP_MD *md = NULL; 633 unsigned char dgst[SHA256_DIGEST_LENGTH]; 634 unsigned int dgst_len; 635 636 if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr, 637 (int)hmac_key->len, data->ptr, (int)data->len, dgst, 638 &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) 639 return (NULL); 640 641 return (cbor_build_bytestring(dgst, 16)); 642 } 643 644 cbor_item_t * 645 cbor_encode_pin_opt(void) 646 { 647 return (cbor_build_uint8(1)); 648 } 649 650 cbor_item_t * 651 cbor_encode_pin_enc(const fido_blob_t *key, const fido_blob_t *pin) 652 { 653 fido_blob_t pe; 654 cbor_item_t *item = NULL; 655 656 if (aes256_cbc_enc(key, pin, &pe) < 0) 657 return (NULL); 658 659 item = cbor_build_bytestring(pe.ptr, pe.len); 660 free(pe.ptr); 661 662 return (item); 663 } 664 665 static int 666 sha256(const unsigned char *data, size_t data_len, fido_blob_t *digest) 667 { 668 if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL) 669 return (-1); 670 671 digest->len = SHA256_DIGEST_LENGTH; 672 673 if (SHA256(data, data_len, digest->ptr) != digest->ptr) { 674 free(digest->ptr); 675 digest->ptr = NULL; 676 digest->len = 0; 677 return (-1); 678 } 679 680 return (0); 681 } 682 683 cbor_item_t * 684 cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin, 685 const fido_blob_t *pin) 686 { 687 unsigned char dgst[SHA256_DIGEST_LENGTH]; 688 unsigned int dgst_len; 689 cbor_item_t *item = NULL; 690 const EVP_MD *md = NULL; 691 #if OPENSSL_VERSION_NUMBER < 0x10100000L 692 HMAC_CTX ctx; 693 #else 694 HMAC_CTX *ctx = NULL; 695 #endif 696 fido_blob_t *npe = NULL; /* new pin, encrypted */ 697 fido_blob_t *ph = NULL; /* pin hash */ 698 fido_blob_t *phe = NULL; /* pin hash, encrypted */ 699 int ok = -1; 700 701 if ((npe = fido_blob_new()) == NULL || 702 (ph = fido_blob_new()) == NULL || 703 (phe = fido_blob_new()) == NULL) 704 goto fail; 705 706 if (aes256_cbc_enc(key, new_pin, npe) < 0) { 707 fido_log_debug("%s: aes256_cbc_enc 1", __func__); 708 goto fail; 709 } 710 711 if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) { 712 fido_log_debug("%s: sha256", __func__); 713 goto fail; 714 } 715 716 ph->len = 16; /* first 16 bytes */ 717 718 if (aes256_cbc_enc(key, ph, phe) < 0) { 719 fido_log_debug("%s: aes256_cbc_enc 2", __func__); 720 goto fail; 721 } 722 723 #if OPENSSL_VERSION_NUMBER < 0x10100000L 724 HMAC_CTX_init(&ctx); 725 726 if ((md = EVP_sha256()) == NULL || 727 HMAC_Init_ex(&ctx, key->ptr, (int)key->len, md, NULL) == 0 || 728 HMAC_Update(&ctx, npe->ptr, (int)npe->len) == 0 || 729 HMAC_Update(&ctx, phe->ptr, (int)phe->len) == 0 || 730 HMAC_Final(&ctx, dgst, &dgst_len) == 0 || dgst_len != 32) { 731 fido_log_debug("%s: HMAC", __func__); 732 goto fail; 733 } 734 #else 735 if ((ctx = HMAC_CTX_new()) == NULL || 736 (md = EVP_sha256()) == NULL || 737 HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 || 738 HMAC_Update(ctx, npe->ptr, (int)npe->len) == 0 || 739 HMAC_Update(ctx, phe->ptr, (int)phe->len) == 0 || 740 HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) { 741 fido_log_debug("%s: HMAC", __func__); 742 goto fail; 743 } 744 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ 745 746 if ((item = cbor_build_bytestring(dgst, 16)) == NULL) { 747 fido_log_debug("%s: cbor_build_bytestring", __func__); 748 goto fail; 749 } 750 751 ok = 0; 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 if (ok < 0) { 763 if (item != NULL) { 764 cbor_decref(&item); 765 item = NULL; 766 } 767 } 768 769 return (item); 770 } 771 772 cbor_item_t * 773 cbor_encode_set_pin_auth(const fido_blob_t *key, const fido_blob_t *pin) 774 { 775 const EVP_MD *md = NULL; 776 unsigned char dgst[SHA256_DIGEST_LENGTH]; 777 unsigned int dgst_len; 778 cbor_item_t *item = NULL; 779 fido_blob_t *pe = NULL; 780 781 if ((pe = fido_blob_new()) == NULL) 782 goto fail; 783 784 if (aes256_cbc_enc(key, pin, pe) < 0) { 785 fido_log_debug("%s: aes256_cbc_enc", __func__); 786 goto fail; 787 } 788 789 if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr, 790 (int)key->len, pe->ptr, (int)pe->len, dgst, &dgst_len) == NULL || 791 dgst_len != SHA256_DIGEST_LENGTH) { 792 fido_log_debug("%s: HMAC", __func__); 793 goto fail; 794 } 795 796 item = cbor_build_bytestring(dgst, 16); 797 fail: 798 fido_blob_free(&pe); 799 800 return (item); 801 } 802 803 cbor_item_t * 804 cbor_encode_pin_hash_enc(const fido_blob_t *shared, const fido_blob_t *pin) 805 { 806 cbor_item_t *item = NULL; 807 fido_blob_t *ph = NULL; 808 fido_blob_t *phe = NULL; 809 810 if ((ph = fido_blob_new()) == NULL || (phe = fido_blob_new()) == NULL) 811 goto fail; 812 813 if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) { 814 fido_log_debug("%s: SHA256", __func__); 815 goto fail; 816 } 817 818 ph->len = 16; /* first 16 bytes */ 819 820 if (aes256_cbc_enc(shared, ph, phe) < 0) { 821 fido_log_debug("%s: aes256_cbc_enc", __func__); 822 goto fail; 823 } 824 825 item = cbor_build_bytestring(phe->ptr, phe->len); 826 fail: 827 fido_blob_free(&ph); 828 fido_blob_free(&phe); 829 830 return (item); 831 } 832 833 cbor_item_t * 834 cbor_encode_hmac_secret_param(const fido_blob_t *ecdh, const es256_pk_t *pk, 835 const fido_blob_t *hmac_salt) 836 { 837 cbor_item_t *item = NULL; 838 cbor_item_t *param = NULL; 839 cbor_item_t *argv[3]; 840 struct cbor_pair pair; 841 842 memset(argv, 0, sizeof(argv)); 843 memset(&pair, 0, sizeof(pair)); 844 845 if (ecdh == NULL || pk == NULL || hmac_salt->ptr == NULL) { 846 fido_log_debug("%s: ecdh=%p, pk=%p, hmac_salt->ptr=%p", 847 __func__, (const void *)ecdh, (const void *)pk, 848 (const void *)hmac_salt->ptr); 849 goto fail; 850 } 851 852 if (hmac_salt->len != 32 && hmac_salt->len != 64) { 853 fido_log_debug("%s: hmac_salt->len=%zu", __func__, 854 hmac_salt->len); 855 goto fail; 856 } 857 858 /* XXX not pin, but salt */ 859 if ((argv[0] = es256_pk_encode(pk, 1)) == NULL || 860 (argv[1] = cbor_encode_pin_enc(ecdh, hmac_salt)) == NULL || 861 (argv[2] = cbor_encode_set_pin_auth(ecdh, hmac_salt)) == NULL) { 862 fido_log_debug("%s: cbor encode", __func__); 863 goto fail; 864 } 865 866 if ((param = cbor_flatten_vector(argv, 3)) == NULL) { 867 fido_log_debug("%s: cbor_flatten_vector", __func__); 868 goto fail; 869 } 870 871 if ((item = cbor_new_definite_map(1)) == NULL) { 872 fido_log_debug("%s: cbor_new_definite_map", __func__); 873 goto fail; 874 } 875 876 if ((pair.key = cbor_build_string("hmac-secret")) == NULL) { 877 fido_log_debug("%s: cbor_build", __func__); 878 goto fail; 879 } 880 881 pair.value = param; 882 883 if (!cbor_map_add(item, pair)) { 884 fido_log_debug("%s: cbor_map_add", __func__); 885 cbor_decref(&item); 886 item = NULL; 887 goto fail; 888 } 889 890 fail: 891 for (size_t i = 0; i < 3; i++) 892 if (argv[i] != NULL) 893 cbor_decref(&argv[i]); 894 895 if (param != NULL) 896 cbor_decref(¶m); 897 if (pair.key != NULL) 898 cbor_decref(&pair.key); 899 900 return (item); 901 } 902 903 int 904 cbor_decode_fmt(const cbor_item_t *item, char **fmt) 905 { 906 char *type = NULL; 907 908 if (cbor_string_copy(item, &type) < 0) { 909 fido_log_debug("%s: cbor_string_copy", __func__); 910 return (-1); 911 } 912 913 if (strcmp(type, "packed") && strcmp(type, "fido-u2f")) { 914 fido_log_debug("%s: type=%s", __func__, type); 915 free(type); 916 return (-1); 917 } 918 919 *fmt = type; 920 921 return (0); 922 } 923 924 struct cose_key { 925 int kty; 926 int alg; 927 int crv; 928 }; 929 930 static int 931 find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg) 932 { 933 struct cose_key *cose_key = arg; 934 935 if (cbor_isa_uint(key) == true && 936 cbor_int_get_width(key) == CBOR_INT_8) { 937 switch (cbor_get_uint8(key)) { 938 case 1: 939 if (cbor_isa_uint(val) == false || 940 cbor_get_int(val) > INT_MAX || cose_key->kty != 0) { 941 fido_log_debug("%s: kty", __func__); 942 return (-1); 943 } 944 945 cose_key->kty = (int)cbor_get_int(val); 946 947 break; 948 case 3: 949 if (cbor_isa_negint(val) == false || 950 cbor_get_int(val) > INT_MAX || cose_key->alg != 0) { 951 fido_log_debug("%s: alg", __func__); 952 return (-1); 953 } 954 955 cose_key->alg = -(int)cbor_get_int(val) - 1; 956 957 break; 958 } 959 } else if (cbor_isa_negint(key) == true && 960 cbor_int_get_width(key) == CBOR_INT_8) { 961 if (cbor_get_uint8(key) == 0) { 962 /* get crv if not rsa, otherwise ignore */ 963 if (cbor_isa_uint(val) == true && 964 cbor_get_int(val) <= INT_MAX && 965 cose_key->crv == 0) 966 cose_key->crv = (int)cbor_get_int(val); 967 } 968 } 969 970 return (0); 971 } 972 973 static int 974 get_cose_alg(const cbor_item_t *item, int *cose_alg) 975 { 976 struct cose_key cose_key; 977 978 memset(&cose_key, 0, sizeof(cose_key)); 979 980 *cose_alg = 0; 981 982 if (cbor_isa_map(item) == false || 983 cbor_map_is_definite(item) == false || 984 cbor_map_iter(item, &cose_key, find_cose_alg) < 0) { 985 fido_log_debug("%s: cbor type", __func__); 986 return (-1); 987 } 988 989 switch (cose_key.alg) { 990 case COSE_ES256: 991 if (cose_key.kty != COSE_KTY_EC2 || 992 cose_key.crv != COSE_P256) { 993 fido_log_debug("%s: invalid kty/crv", __func__); 994 return (-1); 995 } 996 997 break; 998 case COSE_EDDSA: 999 if (cose_key.kty != COSE_KTY_OKP || 1000 cose_key.crv != COSE_ED25519) { 1001 fido_log_debug("%s: invalid kty/crv", __func__); 1002 return (-1); 1003 } 1004 1005 break; 1006 case COSE_RS256: 1007 if (cose_key.kty != COSE_KTY_RSA) { 1008 fido_log_debug("%s: invalid kty/crv", __func__); 1009 return (-1); 1010 } 1011 1012 break; 1013 default: 1014 fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg); 1015 1016 return (-1); 1017 } 1018 1019 *cose_alg = cose_key.alg; 1020 1021 return (0); 1022 } 1023 1024 int 1025 cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key) 1026 { 1027 if (get_cose_alg(item, type) < 0) { 1028 fido_log_debug("%s: get_cose_alg", __func__); 1029 return (-1); 1030 } 1031 1032 switch (*type) { 1033 case COSE_ES256: 1034 if (es256_pk_decode(item, key) < 0) { 1035 fido_log_debug("%s: es256_pk_decode", __func__); 1036 return (-1); 1037 } 1038 break; 1039 case COSE_RS256: 1040 if (rs256_pk_decode(item, key) < 0) { 1041 fido_log_debug("%s: rs256_pk_decode", __func__); 1042 return (-1); 1043 } 1044 break; 1045 case COSE_EDDSA: 1046 if (eddsa_pk_decode(item, key) < 0) { 1047 fido_log_debug("%s: eddsa_pk_decode", __func__); 1048 return (-1); 1049 } 1050 break; 1051 default: 1052 fido_log_debug("%s: invalid cose_alg %d", __func__, *type); 1053 return (-1); 1054 } 1055 1056 return (0); 1057 } 1058 1059 static int 1060 decode_attcred(const unsigned char **buf, size_t *len, int cose_alg, 1061 fido_attcred_t *attcred) 1062 { 1063 cbor_item_t *item = NULL; 1064 struct cbor_load_result cbor; 1065 uint16_t id_len; 1066 int ok = -1; 1067 1068 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, 1069 *len); 1070 1071 if (fido_buf_read(buf, len, &attcred->aaguid, 1072 sizeof(attcred->aaguid)) < 0) { 1073 fido_log_debug("%s: fido_buf_read aaguid", __func__); 1074 return (-1); 1075 } 1076 1077 if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) { 1078 fido_log_debug("%s: fido_buf_read id_len", __func__); 1079 return (-1); 1080 } 1081 1082 attcred->id.len = (size_t)be16toh(id_len); 1083 if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL) 1084 return (-1); 1085 1086 fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len); 1087 1088 if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) { 1089 fido_log_debug("%s: fido_buf_read id", __func__); 1090 return (-1); 1091 } 1092 1093 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { 1094 fido_log_debug("%s: cbor_load", __func__); 1095 fido_log_xxd(*buf, *len); 1096 goto fail; 1097 } 1098 1099 if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) { 1100 fido_log_debug("%s: cbor_decode_pubkey", __func__); 1101 goto fail; 1102 } 1103 1104 if (attcred->type != cose_alg) { 1105 fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__, 1106 attcred->type, cose_alg); 1107 goto fail; 1108 } 1109 1110 *buf += cbor.read; 1111 *len -= cbor.read; 1112 1113 ok = 0; 1114 fail: 1115 if (item != NULL) 1116 cbor_decref(&item); 1117 1118 return (ok); 1119 } 1120 1121 static int 1122 decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1123 { 1124 fido_cred_ext_t *authdata_ext = arg; 1125 char *type = NULL; 1126 int ok = -1; 1127 1128 if (cbor_string_copy(key, &type) < 0) { 1129 fido_log_debug("%s: cbor type", __func__); 1130 ok = 0; /* ignore */ 1131 goto out; 1132 } 1133 1134 if (strcmp(type, "hmac-secret") == 0) { 1135 if (cbor_isa_float_ctrl(val) == false || 1136 cbor_float_get_width(val) != CBOR_FLOAT_0 || 1137 cbor_is_bool(val) == false) { 1138 fido_log_debug("%s: cbor type", __func__); 1139 goto out; 1140 } 1141 if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) 1142 authdata_ext->mask |= FIDO_EXT_HMAC_SECRET; 1143 } else if (strcmp(type, "credProtect") == 0) { 1144 if (cbor_isa_uint(val) == false || 1145 cbor_int_get_width(val) != CBOR_INT_8) { 1146 fido_log_debug("%s: cbor type", __func__); 1147 goto out; 1148 } 1149 authdata_ext->mask |= FIDO_EXT_CRED_PROTECT; 1150 authdata_ext->prot = cbor_get_uint8(val); 1151 } 1152 1153 ok = 0; 1154 out: 1155 free(type); 1156 1157 return (ok); 1158 } 1159 1160 static int 1161 decode_extensions(const unsigned char **buf, size_t *len, 1162 fido_cred_ext_t *authdata_ext) 1163 { 1164 cbor_item_t *item = NULL; 1165 struct cbor_load_result cbor; 1166 int ok = -1; 1167 1168 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, 1169 *len); 1170 fido_log_xxd(*buf, *len); 1171 1172 memset(authdata_ext, 0, sizeof(*authdata_ext)); 1173 1174 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { 1175 fido_log_debug("%s: cbor_load", __func__); 1176 fido_log_xxd(*buf, *len); 1177 goto fail; 1178 } 1179 1180 if (cbor_isa_map(item) == false || 1181 cbor_map_is_definite(item) == false || 1182 cbor_map_iter(item, authdata_ext, decode_extension) < 0) { 1183 fido_log_debug("%s: cbor type", __func__); 1184 goto fail; 1185 } 1186 1187 *buf += cbor.read; 1188 *len -= cbor.read; 1189 1190 ok = 0; 1191 fail: 1192 if (item != NULL) 1193 cbor_decref(&item); 1194 1195 return (ok); 1196 } 1197 1198 static int 1199 decode_hmac_secret_aux(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1200 { 1201 fido_blob_t *out = arg; 1202 char *type = NULL; 1203 int ok = -1; 1204 1205 if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) { 1206 fido_log_debug("%s: cbor type", __func__); 1207 ok = 0; /* ignore */ 1208 goto out; 1209 } 1210 1211 ok = cbor_bytestring_copy(val, &out->ptr, &out->len); 1212 out: 1213 free(type); 1214 1215 return (ok); 1216 } 1217 1218 static int 1219 decode_hmac_secret(const unsigned char **buf, size_t *len, fido_blob_t *out) 1220 { 1221 cbor_item_t *item = NULL; 1222 struct cbor_load_result cbor; 1223 int ok = -1; 1224 1225 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, 1226 *len); 1227 1228 if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { 1229 fido_log_debug("%s: cbor_load", __func__); 1230 fido_log_xxd(*buf, *len); 1231 goto fail; 1232 } 1233 1234 if (cbor_isa_map(item) == false || 1235 cbor_map_is_definite(item) == false || 1236 cbor_map_size(item) != 1 || 1237 cbor_map_iter(item, out, decode_hmac_secret_aux) < 0) { 1238 fido_log_debug("%s: cbor type", __func__); 1239 goto fail; 1240 } 1241 1242 *buf += cbor.read; 1243 *len -= cbor.read; 1244 1245 ok = 0; 1246 fail: 1247 if (item != NULL) 1248 cbor_decref(&item); 1249 1250 return (ok); 1251 } 1252 1253 int 1254 cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, 1255 fido_blob_t *authdata_cbor, fido_authdata_t *authdata, 1256 fido_attcred_t *attcred, fido_cred_ext_t *authdata_ext) 1257 { 1258 const unsigned char *buf = NULL; 1259 size_t len; 1260 size_t alloc_len; 1261 1262 if (cbor_isa_bytestring(item) == false || 1263 cbor_bytestring_is_definite(item) == false) { 1264 fido_log_debug("%s: cbor type", __func__); 1265 return (-1); 1266 } 1267 1268 if (authdata_cbor->ptr != NULL || 1269 (authdata_cbor->len = cbor_serialize_alloc(item, 1270 &authdata_cbor->ptr, &alloc_len)) == 0) { 1271 fido_log_debug("%s: cbor_serialize_alloc", __func__); 1272 return (-1); 1273 } 1274 1275 buf = cbor_bytestring_handle(item); 1276 len = cbor_bytestring_length(item); 1277 1278 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); 1279 fido_log_xxd(buf, len); 1280 1281 if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { 1282 fido_log_debug("%s: fido_buf_read", __func__); 1283 return (-1); 1284 } 1285 1286 authdata->sigcount = be32toh(authdata->sigcount); 1287 1288 if (attcred != NULL) { 1289 if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 || 1290 decode_attcred(&buf, &len, cose_alg, attcred) < 0) 1291 return (-1); 1292 } 1293 1294 if (authdata_ext != NULL) { 1295 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && 1296 decode_extensions(&buf, &len, authdata_ext) < 0) 1297 return (-1); 1298 } 1299 1300 /* XXX we should probably ensure that len == 0 at this point */ 1301 1302 return (FIDO_OK); 1303 } 1304 1305 int 1306 cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor, 1307 fido_authdata_t *authdata, int *authdata_ext, fido_blob_t *hmac_secret_enc) 1308 { 1309 const unsigned char *buf = NULL; 1310 size_t len; 1311 size_t alloc_len; 1312 1313 if (cbor_isa_bytestring(item) == false || 1314 cbor_bytestring_is_definite(item) == false) { 1315 fido_log_debug("%s: cbor type", __func__); 1316 return (-1); 1317 } 1318 1319 if (authdata_cbor->ptr != NULL || 1320 (authdata_cbor->len = cbor_serialize_alloc(item, 1321 &authdata_cbor->ptr, &alloc_len)) == 0) { 1322 fido_log_debug("%s: cbor_serialize_alloc", __func__); 1323 return (-1); 1324 } 1325 1326 buf = cbor_bytestring_handle(item); 1327 len = cbor_bytestring_length(item); 1328 1329 fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); 1330 1331 if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { 1332 fido_log_debug("%s: fido_buf_read", __func__); 1333 return (-1); 1334 } 1335 1336 authdata->sigcount = be32toh(authdata->sigcount); 1337 1338 *authdata_ext = 0; 1339 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) { 1340 /* XXX semantic leap: extensions -> hmac_secret */ 1341 if (decode_hmac_secret(&buf, &len, hmac_secret_enc) < 0) { 1342 fido_log_debug("%s: decode_hmac_secret", __func__); 1343 return (-1); 1344 } 1345 *authdata_ext = FIDO_EXT_HMAC_SECRET; 1346 } 1347 1348 /* XXX we should probably ensure that len == 0 at this point */ 1349 1350 return (FIDO_OK); 1351 } 1352 1353 static int 1354 decode_x5c(const cbor_item_t *item, void *arg) 1355 { 1356 fido_blob_t *x5c = arg; 1357 1358 if (x5c->len) 1359 return (0); /* ignore */ 1360 1361 return (cbor_bytestring_copy(item, &x5c->ptr, &x5c->len)); 1362 } 1363 1364 static int 1365 decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1366 { 1367 fido_attstmt_t *attstmt = arg; 1368 char *name = NULL; 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_int_get_width(val) != CBOR_INT_8 || 1380 cbor_get_uint8(val) != -COSE_ES256 - 1) { 1381 fido_log_debug("%s: alg", __func__); 1382 goto out; 1383 } 1384 } else if (!strcmp(name, "sig")) { 1385 if (cbor_bytestring_copy(val, &attstmt->sig.ptr, 1386 &attstmt->sig.len) < 0) { 1387 fido_log_debug("%s: sig", __func__); 1388 goto out; 1389 } 1390 } else if (!strcmp(name, "x5c")) { 1391 if (cbor_isa_array(val) == false || 1392 cbor_array_is_definite(val) == false || 1393 cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) { 1394 fido_log_debug("%s: x5c", __func__); 1395 goto out; 1396 } 1397 } 1398 1399 ok = 0; 1400 out: 1401 free(name); 1402 1403 return (ok); 1404 } 1405 1406 int 1407 cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt) 1408 { 1409 if (cbor_isa_map(item) == false || 1410 cbor_map_is_definite(item) == false || 1411 cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) { 1412 fido_log_debug("%s: cbor type", __func__); 1413 return (-1); 1414 } 1415 1416 return (0); 1417 } 1418 1419 int 1420 cbor_decode_uint64(const cbor_item_t *item, uint64_t *n) 1421 { 1422 if (cbor_isa_uint(item) == false) { 1423 fido_log_debug("%s: cbor type", __func__); 1424 return (-1); 1425 } 1426 1427 *n = cbor_get_int(item); 1428 1429 return (0); 1430 } 1431 1432 static int 1433 decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1434 { 1435 fido_blob_t *id = arg; 1436 char *name = NULL; 1437 int ok = -1; 1438 1439 if (cbor_string_copy(key, &name) < 0) { 1440 fido_log_debug("%s: cbor type", __func__); 1441 ok = 0; /* ignore */ 1442 goto out; 1443 } 1444 1445 if (!strcmp(name, "id")) 1446 if (cbor_bytestring_copy(val, &id->ptr, &id->len) < 0) { 1447 fido_log_debug("%s: cbor_bytestring_copy", __func__); 1448 goto out; 1449 } 1450 1451 ok = 0; 1452 out: 1453 free(name); 1454 1455 return (ok); 1456 } 1457 1458 int 1459 cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id) 1460 { 1461 if (cbor_isa_map(item) == false || 1462 cbor_map_is_definite(item) == false || 1463 cbor_map_iter(item, id, decode_cred_id_entry) < 0) { 1464 fido_log_debug("%s: cbor type", __func__); 1465 return (-1); 1466 } 1467 1468 return (0); 1469 } 1470 1471 static int 1472 decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1473 { 1474 fido_user_t *user = arg; 1475 char *name = NULL; 1476 int ok = -1; 1477 1478 if (cbor_string_copy(key, &name) < 0) { 1479 fido_log_debug("%s: cbor type", __func__); 1480 ok = 0; /* ignore */ 1481 goto out; 1482 } 1483 1484 if (!strcmp(name, "icon")) { 1485 if (cbor_string_copy(val, &user->icon) < 0) { 1486 fido_log_debug("%s: icon", __func__); 1487 goto out; 1488 } 1489 } else if (!strcmp(name, "name")) { 1490 if (cbor_string_copy(val, &user->name) < 0) { 1491 fido_log_debug("%s: name", __func__); 1492 goto out; 1493 } 1494 } else if (!strcmp(name, "displayName")) { 1495 if (cbor_string_copy(val, &user->display_name) < 0) { 1496 fido_log_debug("%s: display_name", __func__); 1497 goto out; 1498 } 1499 } else if (!strcmp(name, "id")) { 1500 if (cbor_bytestring_copy(val, &user->id.ptr, &user->id.len) < 0) { 1501 fido_log_debug("%s: id", __func__); 1502 goto out; 1503 } 1504 } 1505 1506 ok = 0; 1507 out: 1508 free(name); 1509 1510 return (ok); 1511 } 1512 1513 int 1514 cbor_decode_user(const cbor_item_t *item, fido_user_t *user) 1515 { 1516 if (cbor_isa_map(item) == false || 1517 cbor_map_is_definite(item) == false || 1518 cbor_map_iter(item, user, decode_user_entry) < 0) { 1519 fido_log_debug("%s: cbor type", __func__); 1520 return (-1); 1521 } 1522 1523 return (0); 1524 } 1525 1526 static int 1527 decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val, 1528 void *arg) 1529 { 1530 fido_rp_t *rp = arg; 1531 char *name = NULL; 1532 int ok = -1; 1533 1534 if (cbor_string_copy(key, &name) < 0) { 1535 fido_log_debug("%s: cbor type", __func__); 1536 ok = 0; /* ignore */ 1537 goto out; 1538 } 1539 1540 if (!strcmp(name, "id")) { 1541 if (cbor_string_copy(val, &rp->id) < 0) { 1542 fido_log_debug("%s: id", __func__); 1543 goto out; 1544 } 1545 } else if (!strcmp(name, "name")) { 1546 if (cbor_string_copy(val, &rp->name) < 0) { 1547 fido_log_debug("%s: name", __func__); 1548 goto out; 1549 } 1550 } 1551 1552 ok = 0; 1553 out: 1554 free(name); 1555 1556 return (ok); 1557 } 1558 1559 int 1560 cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp) 1561 { 1562 if (cbor_isa_map(item) == false || 1563 cbor_map_is_definite(item) == false || 1564 cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) { 1565 fido_log_debug("%s: cbor type", __func__); 1566 return (-1); 1567 } 1568 1569 return (0); 1570 } 1571