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