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/ec.h> 8 #include <openssl/ecdsa.h> 9 #include <openssl/evp.h> 10 #include <openssl/sha.h> 11 12 #include <string.h> 13 #include "fido.h" 14 #include "fido/es256.h" 15 #include "fido/rs256.h" 16 #include "fido/eddsa.h" 17 18 static int 19 adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) 20 { 21 fido_assert_t *assert = arg; 22 uint64_t n; 23 24 /* numberOfCredentials; see section 6.2 */ 25 if (cbor_isa_uint(key) == false || 26 cbor_int_get_width(key) != CBOR_INT_8 || 27 cbor_get_uint8(key) != 5) { 28 fido_log_debug("%s: cbor_type", __func__); 29 return (0); /* ignore */ 30 } 31 32 if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { 33 fido_log_debug("%s: cbor_decode_uint64", __func__); 34 return (-1); 35 } 36 37 if (assert->stmt_len != 0 || assert->stmt_cnt != 1 || 38 (size_t)n < assert->stmt_cnt) { 39 fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu", 40 __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n); 41 return (-1); 42 } 43 44 if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) { 45 fido_log_debug("%s: fido_assert_set_count", __func__); 46 return (-1); 47 } 48 49 assert->stmt_len = 0; /* XXX */ 50 51 return (0); 52 } 53 54 static int 55 parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) 56 { 57 fido_assert_stmt *stmt = arg; 58 59 if (cbor_isa_uint(key) == false || 60 cbor_int_get_width(key) != CBOR_INT_8) { 61 fido_log_debug("%s: cbor type", __func__); 62 return (0); /* ignore */ 63 } 64 65 switch (cbor_get_uint8(key)) { 66 case 1: /* credential id */ 67 return (cbor_decode_cred_id(val, &stmt->id)); 68 case 2: /* authdata */ 69 return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor, 70 &stmt->authdata, &stmt->authdata_ext, 71 &stmt->hmac_secret_enc)); 72 case 3: /* signature */ 73 return (fido_blob_decode(val, &stmt->sig)); 74 case 4: /* user attributes */ 75 return (cbor_decode_user(val, &stmt->user)); 76 default: /* ignore */ 77 fido_log_debug("%s: cbor type", __func__); 78 return (0); 79 } 80 } 81 82 static int 83 fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert, 84 const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin) 85 { 86 fido_blob_t f; 87 cbor_item_t *argv[7]; 88 int r; 89 90 memset(argv, 0, sizeof(argv)); 91 memset(&f, 0, sizeof(f)); 92 93 /* do we have everything we need? */ 94 if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { 95 fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, 96 (void *)assert->rp_id, (void *)assert->cdh.ptr); 97 r = FIDO_ERR_INVALID_ARGUMENT; 98 goto fail; 99 } 100 101 if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL || 102 (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) { 103 fido_log_debug("%s: cbor encode", __func__); 104 r = FIDO_ERR_INTERNAL; 105 goto fail; 106 } 107 108 /* allowed credentials */ 109 if (assert->allow_list.len) { 110 const fido_blob_array_t *cl = &assert->allow_list; 111 if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) { 112 fido_log_debug("%s: cbor_encode_pubkey_list", __func__); 113 r = FIDO_ERR_INTERNAL; 114 goto fail; 115 } 116 } 117 118 /* hmac-secret extension */ 119 if (assert->ext & FIDO_EXT_HMAC_SECRET) 120 if ((argv[3] = cbor_encode_hmac_secret_param(ecdh, pk, 121 &assert->hmac_salt)) == NULL) { 122 fido_log_debug("%s: cbor_encode_hmac_secret_param", 123 __func__); 124 r = FIDO_ERR_INTERNAL; 125 goto fail; 126 } 127 128 /* options */ 129 if (assert->up != FIDO_OPT_OMIT || assert->uv != FIDO_OPT_OMIT) 130 if ((argv[4] = cbor_encode_assert_options(assert->up, 131 assert->uv)) == NULL) { 132 fido_log_debug("%s: cbor_encode_assert_options", 133 __func__); 134 r = FIDO_ERR_INTERNAL; 135 goto fail; 136 } 137 138 /* pin authentication */ 139 if (pin) { 140 if (pk == NULL || ecdh == NULL) { 141 fido_log_debug("%s: pin=%p, pk=%p, ecdh=%p", __func__, 142 (const void *)pin, (const void *)pk, 143 (const void *)ecdh); 144 r = FIDO_ERR_INVALID_ARGUMENT; 145 goto fail; 146 } 147 if ((r = cbor_add_pin_params(dev, &assert->cdh, pk, ecdh, pin, 148 &argv[5], &argv[6])) != FIDO_OK) { 149 fido_log_debug("%s: cbor_add_pin_params", __func__); 150 goto fail; 151 } 152 } 153 154 /* frame and transmit */ 155 if (cbor_build_frame(CTAP_CBOR_ASSERT, argv, nitems(argv), &f) < 0 || 156 fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { 157 fido_log_debug("%s: fido_tx", __func__); 158 r = FIDO_ERR_TX; 159 goto fail; 160 } 161 162 r = FIDO_OK; 163 fail: 164 cbor_vector_free(argv, nitems(argv)); 165 free(f.ptr); 166 167 return (r); 168 } 169 170 static int 171 fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) 172 { 173 unsigned char reply[FIDO_MAXMSG]; 174 int reply_len; 175 int r; 176 177 fido_assert_reset_rx(assert); 178 179 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 180 ms)) < 0) { 181 fido_log_debug("%s: fido_rx", __func__); 182 return (FIDO_ERR_RX); 183 } 184 185 /* start with room for a single assertion */ 186 if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) 187 return (FIDO_ERR_INTERNAL); 188 189 assert->stmt_len = 0; 190 assert->stmt_cnt = 1; 191 192 /* adjust as needed */ 193 if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert, 194 adjust_assert_count)) != FIDO_OK) { 195 fido_log_debug("%s: adjust_assert_count", __func__); 196 return (r); 197 } 198 199 /* parse the first assertion */ 200 if ((r = cbor_parse_reply(reply, (size_t)reply_len, 201 &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { 202 fido_log_debug("%s: parse_assert_reply", __func__); 203 return (r); 204 } 205 206 assert->stmt_len++; 207 208 return (FIDO_OK); 209 } 210 211 static int 212 fido_get_next_assert_tx(fido_dev_t *dev) 213 { 214 const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT }; 215 216 if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) { 217 fido_log_debug("%s: fido_tx", __func__); 218 return (FIDO_ERR_TX); 219 } 220 221 return (FIDO_OK); 222 } 223 224 static int 225 fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) 226 { 227 unsigned char reply[FIDO_MAXMSG]; 228 int reply_len; 229 int r; 230 231 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 232 ms)) < 0) { 233 fido_log_debug("%s: fido_rx", __func__); 234 return (FIDO_ERR_RX); 235 } 236 237 /* sanity check */ 238 if (assert->stmt_len >= assert->stmt_cnt) { 239 fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__, 240 assert->stmt_len, assert->stmt_cnt); 241 return (FIDO_ERR_INTERNAL); 242 } 243 244 if ((r = cbor_parse_reply(reply, (size_t)reply_len, 245 &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { 246 fido_log_debug("%s: parse_assert_reply", __func__); 247 return (r); 248 } 249 250 return (FIDO_OK); 251 } 252 253 static int 254 fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert, 255 const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms) 256 { 257 int r; 258 259 if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK || 260 (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK) 261 return (r); 262 263 while (assert->stmt_len < assert->stmt_cnt) { 264 if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK || 265 (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK) 266 return (r); 267 assert->stmt_len++; 268 } 269 270 return (FIDO_OK); 271 } 272 273 static int 274 decrypt_hmac_secrets(fido_assert_t *assert, const fido_blob_t *key) 275 { 276 for (size_t i = 0; i < assert->stmt_cnt; i++) { 277 fido_assert_stmt *stmt = &assert->stmt[i]; 278 if (stmt->hmac_secret_enc.ptr != NULL) { 279 if (aes256_cbc_dec(key, &stmt->hmac_secret_enc, 280 &stmt->hmac_secret) < 0) { 281 fido_log_debug("%s: aes256_cbc_dec %zu", 282 __func__, i); 283 return (-1); 284 } 285 } 286 } 287 288 return (0); 289 } 290 291 int 292 fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin) 293 { 294 fido_blob_t *ecdh = NULL; 295 es256_pk_t *pk = NULL; 296 int r; 297 298 if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { 299 fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, 300 (void *)assert->rp_id, (void *)assert->cdh.ptr); 301 return (FIDO_ERR_INVALID_ARGUMENT); 302 } 303 304 if (fido_dev_is_fido2(dev) == false) { 305 if (pin != NULL || assert->ext != 0) 306 return (FIDO_ERR_UNSUPPORTED_OPTION); 307 return (u2f_authenticate(dev, assert, -1)); 308 } 309 310 if (pin != NULL || assert->ext != 0) { 311 if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { 312 fido_log_debug("%s: fido_do_ecdh", __func__); 313 goto fail; 314 } 315 } 316 317 r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1); 318 if (r == FIDO_OK && assert->ext & FIDO_EXT_HMAC_SECRET) 319 if (decrypt_hmac_secrets(assert, ecdh) < 0) { 320 fido_log_debug("%s: decrypt_hmac_secrets", __func__); 321 r = FIDO_ERR_INTERNAL; 322 goto fail; 323 } 324 325 fail: 326 es256_pk_free(&pk); 327 fido_blob_free(&ecdh); 328 329 return (r); 330 } 331 332 int 333 fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv) 334 { 335 fido_log_debug("%s: flags=%02x", __func__, flags); 336 fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv); 337 338 if (up == FIDO_OPT_TRUE && 339 (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) { 340 fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__); 341 return (-1); /* user not present */ 342 } 343 344 if (uv == FIDO_OPT_TRUE && 345 (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) { 346 fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__); 347 return (-1); /* user not verified */ 348 } 349 350 return (0); 351 } 352 353 static int 354 check_extensions(int authdata_ext, int ext) 355 { 356 if (authdata_ext != ext) { 357 fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__, 358 authdata_ext, ext); 359 return (-1); 360 } 361 362 return (0); 363 } 364 365 static int 366 get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata, 367 const fido_blob_t *authdata_cbor) 368 { 369 cbor_item_t *item = NULL; 370 unsigned char *authdata_ptr = NULL; 371 size_t authdata_len; 372 struct cbor_load_result cbor; 373 SHA256_CTX ctx; 374 int ok = -1; 375 376 if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, 377 &cbor)) == NULL || cbor_isa_bytestring(item) == false || 378 cbor_bytestring_is_definite(item) == false) { 379 fido_log_debug("%s: authdata", __func__); 380 goto fail; 381 } 382 383 authdata_ptr = cbor_bytestring_handle(item); 384 authdata_len = cbor_bytestring_length(item); 385 386 if (cose_alg != COSE_EDDSA) { 387 if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || 388 SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 || 389 SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || 390 SHA256_Final(dgst->ptr, &ctx) == 0) { 391 fido_log_debug("%s: sha256", __func__); 392 goto fail; 393 } 394 dgst->len = SHA256_DIGEST_LENGTH; 395 } else { 396 if (SIZE_MAX - authdata_len < clientdata->len || 397 dgst->len < authdata_len + clientdata->len) { 398 fido_log_debug("%s: memcpy", __func__); 399 goto fail; 400 } 401 memcpy(dgst->ptr, authdata_ptr, authdata_len); 402 memcpy(dgst->ptr + authdata_len, clientdata->ptr, 403 clientdata->len); 404 dgst->len = authdata_len + clientdata->len; 405 } 406 407 ok = 0; 408 fail: 409 if (item != NULL) 410 cbor_decref(&item); 411 412 return (ok); 413 } 414 415 int 416 fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk, 417 const fido_blob_t *sig) 418 { 419 EVP_PKEY *pkey = NULL; 420 EC_KEY *ec = NULL; 421 int ok = -1; 422 423 /* ECDSA_verify needs ints */ 424 if (dgst->len > INT_MAX || sig->len > INT_MAX) { 425 fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, 426 dgst->len, sig->len); 427 return (-1); 428 } 429 430 if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL || 431 (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) { 432 fido_log_debug("%s: pk -> ec", __func__); 433 goto fail; 434 } 435 436 if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, 437 (int)sig->len, ec) != 1) { 438 fido_log_debug("%s: ECDSA_verify", __func__); 439 goto fail; 440 } 441 442 ok = 0; 443 fail: 444 if (pkey != NULL) 445 EVP_PKEY_free(pkey); 446 447 return (ok); 448 } 449 450 int 451 fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk, 452 const fido_blob_t *sig) 453 { 454 EVP_PKEY *pkey = NULL; 455 RSA *rsa = NULL; 456 int ok = -1; 457 458 /* RSA_verify needs unsigned ints */ 459 if (dgst->len > UINT_MAX || sig->len > UINT_MAX) { 460 fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, 461 dgst->len, sig->len); 462 return (-1); 463 } 464 465 if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL || 466 (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) { 467 fido_log_debug("%s: pk -> ec", __func__); 468 goto fail; 469 } 470 471 if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr, 472 (unsigned int)sig->len, rsa) != 1) { 473 fido_log_debug("%s: RSA_verify", __func__); 474 goto fail; 475 } 476 477 ok = 0; 478 fail: 479 if (pkey != NULL) 480 EVP_PKEY_free(pkey); 481 482 return (ok); 483 } 484 485 int 486 fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk, 487 const fido_blob_t *sig) 488 { 489 EVP_PKEY *pkey = NULL; 490 EVP_MD_CTX *mdctx = NULL; 491 int ok = -1; 492 493 /* EVP_DigestVerify needs ints */ 494 if (dgst->len > INT_MAX || sig->len > INT_MAX) { 495 fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, 496 dgst->len, sig->len); 497 return (-1); 498 } 499 500 if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { 501 fido_log_debug("%s: pk -> pkey", __func__); 502 goto fail; 503 } 504 505 if ((mdctx = EVP_MD_CTX_new()) == NULL) { 506 fido_log_debug("%s: EVP_MD_CTX_new", __func__); 507 goto fail; 508 } 509 510 if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) { 511 fido_log_debug("%s: EVP_DigestVerifyInit", __func__); 512 goto fail; 513 } 514 515 if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr, 516 dgst->len) != 1) { 517 fido_log_debug("%s: EVP_DigestVerify", __func__); 518 goto fail; 519 } 520 521 ok = 0; 522 fail: 523 if (mdctx != NULL) 524 EVP_MD_CTX_free(mdctx); 525 526 if (pkey != NULL) 527 EVP_PKEY_free(pkey); 528 529 return (ok); 530 } 531 532 int 533 fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, 534 const void *pk) 535 { 536 unsigned char buf[1024]; /* XXX */ 537 fido_blob_t dgst; 538 const fido_assert_stmt *stmt = NULL; 539 int ok = -1; 540 int r; 541 542 dgst.ptr = buf; 543 dgst.len = sizeof(buf); 544 545 if (idx >= assert->stmt_len || pk == NULL) { 546 r = FIDO_ERR_INVALID_ARGUMENT; 547 goto out; 548 } 549 550 stmt = &assert->stmt[idx]; 551 552 /* do we have everything we need? */ 553 if (assert->cdh.ptr == NULL || assert->rp_id == NULL || 554 stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) { 555 fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p", 556 __func__, (void *)assert->cdh.ptr, assert->rp_id, 557 (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr); 558 r = FIDO_ERR_INVALID_ARGUMENT; 559 goto out; 560 } 561 562 if (fido_check_flags(stmt->authdata.flags, assert->up, 563 assert->uv) < 0) { 564 fido_log_debug("%s: fido_check_flags", __func__); 565 r = FIDO_ERR_INVALID_PARAM; 566 goto out; 567 } 568 569 if (check_extensions(stmt->authdata_ext, assert->ext) < 0) { 570 fido_log_debug("%s: check_extensions", __func__); 571 r = FIDO_ERR_INVALID_PARAM; 572 goto out; 573 } 574 575 if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) { 576 fido_log_debug("%s: fido_check_rp_id", __func__); 577 r = FIDO_ERR_INVALID_PARAM; 578 goto out; 579 } 580 581 if (get_signed_hash(cose_alg, &dgst, &assert->cdh, 582 &stmt->authdata_cbor) < 0) { 583 fido_log_debug("%s: get_signed_hash", __func__); 584 r = FIDO_ERR_INTERNAL; 585 goto out; 586 } 587 588 switch (cose_alg) { 589 case COSE_ES256: 590 ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig); 591 break; 592 case COSE_RS256: 593 ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig); 594 break; 595 case COSE_EDDSA: 596 ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig); 597 break; 598 default: 599 fido_log_debug("%s: unsupported cose_alg %d", __func__, 600 cose_alg); 601 r = FIDO_ERR_UNSUPPORTED_OPTION; 602 goto out; 603 } 604 605 if (ok < 0) 606 r = FIDO_ERR_INVALID_SIG; 607 else 608 r = FIDO_OK; 609 out: 610 explicit_bzero(buf, sizeof(buf)); 611 612 return (r); 613 } 614 615 int 616 fido_assert_set_clientdata_hash(fido_assert_t *assert, 617 const unsigned char *hash, size_t hash_len) 618 { 619 if (fido_blob_set(&assert->cdh, hash, hash_len) < 0) 620 return (FIDO_ERR_INVALID_ARGUMENT); 621 622 return (FIDO_OK); 623 } 624 625 int 626 fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt, 627 size_t salt_len) 628 { 629 if ((salt_len != 32 && salt_len != 64) || 630 fido_blob_set(&assert->hmac_salt, salt, salt_len) < 0) 631 return (FIDO_ERR_INVALID_ARGUMENT); 632 633 return (FIDO_OK); 634 } 635 636 int 637 fido_assert_set_rp(fido_assert_t *assert, const char *id) 638 { 639 if (assert->rp_id != NULL) { 640 free(assert->rp_id); 641 assert->rp_id = NULL; 642 } 643 644 if (id == NULL) 645 return (FIDO_ERR_INVALID_ARGUMENT); 646 647 if ((assert->rp_id = strdup(id)) == NULL) 648 return (FIDO_ERR_INTERNAL); 649 650 return (FIDO_OK); 651 } 652 653 int 654 fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr, 655 size_t len) 656 { 657 fido_blob_t id; 658 fido_blob_t *list_ptr; 659 int r; 660 661 memset(&id, 0, sizeof(id)); 662 663 if (assert->allow_list.len == SIZE_MAX) { 664 r = FIDO_ERR_INVALID_ARGUMENT; 665 goto fail; 666 } 667 668 if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr = 669 recallocarray(assert->allow_list.ptr, assert->allow_list.len, 670 assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) { 671 r = FIDO_ERR_INVALID_ARGUMENT; 672 goto fail; 673 } 674 675 list_ptr[assert->allow_list.len++] = id; 676 assert->allow_list.ptr = list_ptr; 677 678 return (FIDO_OK); 679 fail: 680 free(id.ptr); 681 682 return (r); 683 684 } 685 686 int 687 fido_assert_set_extensions(fido_assert_t *assert, int ext) 688 { 689 if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET) 690 return (FIDO_ERR_INVALID_ARGUMENT); 691 692 assert->ext = ext; 693 694 return (FIDO_OK); 695 } 696 697 int 698 fido_assert_set_options(fido_assert_t *assert, bool up, bool uv) 699 { 700 assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; 701 assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; 702 703 return (FIDO_OK); 704 } 705 706 int 707 fido_assert_set_up(fido_assert_t *assert, fido_opt_t up) 708 { 709 assert->up = up; 710 711 return (FIDO_OK); 712 } 713 714 int 715 fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv) 716 { 717 assert->uv = uv; 718 719 return (FIDO_OK); 720 } 721 722 const unsigned char * 723 fido_assert_clientdata_hash_ptr(const fido_assert_t *assert) 724 { 725 return (assert->cdh.ptr); 726 } 727 728 size_t 729 fido_assert_clientdata_hash_len(const fido_assert_t *assert) 730 { 731 return (assert->cdh.len); 732 } 733 734 fido_assert_t * 735 fido_assert_new(void) 736 { 737 return (calloc(1, sizeof(fido_assert_t))); 738 } 739 740 void 741 fido_assert_reset_tx(fido_assert_t *assert) 742 { 743 free(assert->rp_id); 744 free(assert->cdh.ptr); 745 free(assert->hmac_salt.ptr); 746 fido_free_blob_array(&assert->allow_list); 747 748 memset(&assert->cdh, 0, sizeof(assert->cdh)); 749 memset(&assert->hmac_salt, 0, sizeof(assert->hmac_salt)); 750 memset(&assert->allow_list, 0, sizeof(assert->allow_list)); 751 752 assert->rp_id = NULL; 753 assert->up = FIDO_OPT_OMIT; 754 assert->uv = FIDO_OPT_OMIT; 755 assert->ext = 0; 756 } 757 758 void 759 fido_assert_reset_rx(fido_assert_t *assert) 760 { 761 for (size_t i = 0; i < assert->stmt_cnt; i++) { 762 free(assert->stmt[i].user.id.ptr); 763 free(assert->stmt[i].user.icon); 764 free(assert->stmt[i].user.name); 765 free(assert->stmt[i].user.display_name); 766 free(assert->stmt[i].id.ptr); 767 if (assert->stmt[i].hmac_secret.ptr != NULL) { 768 explicit_bzero(assert->stmt[i].hmac_secret.ptr, 769 assert->stmt[i].hmac_secret.len); 770 } 771 free(assert->stmt[i].hmac_secret.ptr); 772 free(assert->stmt[i].hmac_secret_enc.ptr); 773 free(assert->stmt[i].authdata_cbor.ptr); 774 free(assert->stmt[i].sig.ptr); 775 memset(&assert->stmt[i], 0, sizeof(assert->stmt[i])); 776 } 777 778 free(assert->stmt); 779 780 assert->stmt = NULL; 781 assert->stmt_len = 0; 782 assert->stmt_cnt = 0; 783 } 784 785 void 786 fido_assert_free(fido_assert_t **assert_p) 787 { 788 fido_assert_t *assert; 789 790 if (assert_p == NULL || (assert = *assert_p) == NULL) 791 return; 792 793 fido_assert_reset_tx(assert); 794 fido_assert_reset_rx(assert); 795 796 free(assert); 797 798 *assert_p = NULL; 799 } 800 801 size_t 802 fido_assert_count(const fido_assert_t *assert) 803 { 804 return (assert->stmt_len); 805 } 806 807 const char * 808 fido_assert_rp_id(const fido_assert_t *assert) 809 { 810 return (assert->rp_id); 811 } 812 813 uint8_t 814 fido_assert_flags(const fido_assert_t *assert, size_t idx) 815 { 816 if (idx >= assert->stmt_len) 817 return (0); 818 819 return (assert->stmt[idx].authdata.flags); 820 } 821 822 uint32_t 823 fido_assert_sigcount(const fido_assert_t *assert, size_t idx) 824 { 825 if (idx >= assert->stmt_len) 826 return (0); 827 828 return (assert->stmt[idx].authdata.sigcount); 829 } 830 831 const unsigned char * 832 fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx) 833 { 834 if (idx >= assert->stmt_len) 835 return (NULL); 836 837 return (assert->stmt[idx].authdata_cbor.ptr); 838 } 839 840 size_t 841 fido_assert_authdata_len(const fido_assert_t *assert, size_t idx) 842 { 843 if (idx >= assert->stmt_len) 844 return (0); 845 846 return (assert->stmt[idx].authdata_cbor.len); 847 } 848 849 const unsigned char * 850 fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx) 851 { 852 if (idx >= assert->stmt_len) 853 return (NULL); 854 855 return (assert->stmt[idx].sig.ptr); 856 } 857 858 size_t 859 fido_assert_sig_len(const fido_assert_t *assert, size_t idx) 860 { 861 if (idx >= assert->stmt_len) 862 return (0); 863 864 return (assert->stmt[idx].sig.len); 865 } 866 867 const unsigned char * 868 fido_assert_id_ptr(const fido_assert_t *assert, size_t idx) 869 { 870 if (idx >= assert->stmt_len) 871 return (NULL); 872 873 return (assert->stmt[idx].id.ptr); 874 } 875 876 size_t 877 fido_assert_id_len(const fido_assert_t *assert, size_t idx) 878 { 879 if (idx >= assert->stmt_len) 880 return (0); 881 882 return (assert->stmt[idx].id.len); 883 } 884 885 const unsigned char * 886 fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx) 887 { 888 if (idx >= assert->stmt_len) 889 return (NULL); 890 891 return (assert->stmt[idx].user.id.ptr); 892 } 893 894 size_t 895 fido_assert_user_id_len(const fido_assert_t *assert, size_t idx) 896 { 897 if (idx >= assert->stmt_len) 898 return (0); 899 900 return (assert->stmt[idx].user.id.len); 901 } 902 903 const char * 904 fido_assert_user_icon(const fido_assert_t *assert, size_t idx) 905 { 906 if (idx >= assert->stmt_len) 907 return (NULL); 908 909 return (assert->stmt[idx].user.icon); 910 } 911 912 const char * 913 fido_assert_user_name(const fido_assert_t *assert, size_t idx) 914 { 915 if (idx >= assert->stmt_len) 916 return (NULL); 917 918 return (assert->stmt[idx].user.name); 919 } 920 921 const char * 922 fido_assert_user_display_name(const fido_assert_t *assert, size_t idx) 923 { 924 if (idx >= assert->stmt_len) 925 return (NULL); 926 927 return (assert->stmt[idx].user.display_name); 928 } 929 930 const unsigned char * 931 fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx) 932 { 933 if (idx >= assert->stmt_len) 934 return (NULL); 935 936 return (assert->stmt[idx].hmac_secret.ptr); 937 } 938 939 size_t 940 fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx) 941 { 942 if (idx >= assert->stmt_len) 943 return (0); 944 945 return (assert->stmt[idx].hmac_secret.len); 946 } 947 948 static void 949 fido_assert_clean_authdata(fido_assert_stmt *as) 950 { 951 free(as->authdata_cbor.ptr); 952 free(as->hmac_secret_enc.ptr); 953 954 memset(&as->authdata_ext, 0, sizeof(as->authdata_ext)); 955 memset(&as->authdata_cbor, 0, sizeof(as->authdata_cbor)); 956 memset(&as->authdata, 0, sizeof(as->authdata)); 957 memset(&as->hmac_secret_enc, 0, sizeof(as->hmac_secret_enc)); 958 } 959 960 int 961 fido_assert_set_authdata(fido_assert_t *assert, size_t idx, 962 const unsigned char *ptr, size_t len) 963 { 964 cbor_item_t *item = NULL; 965 fido_assert_stmt *stmt = NULL; 966 struct cbor_load_result cbor; 967 int r; 968 969 if (idx >= assert->stmt_len || ptr == NULL || len == 0) 970 return (FIDO_ERR_INVALID_ARGUMENT); 971 972 stmt = &assert->stmt[idx]; 973 fido_assert_clean_authdata(stmt); 974 975 if ((item = cbor_load(ptr, len, &cbor)) == NULL) { 976 fido_log_debug("%s: cbor_load", __func__); 977 r = FIDO_ERR_INVALID_ARGUMENT; 978 goto fail; 979 } 980 981 if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, 982 &stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) { 983 fido_log_debug("%s: cbor_decode_assert_authdata", __func__); 984 r = FIDO_ERR_INVALID_ARGUMENT; 985 goto fail; 986 } 987 988 r = FIDO_OK; 989 fail: 990 if (item != NULL) 991 cbor_decref(&item); 992 993 if (r != FIDO_OK) 994 fido_assert_clean_authdata(stmt); 995 996 return (r); 997 } 998 999 int 1000 fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx, 1001 const unsigned char *ptr, size_t len) 1002 { 1003 cbor_item_t *item = NULL; 1004 fido_assert_stmt *stmt = NULL; 1005 int r; 1006 1007 if (idx >= assert->stmt_len || ptr == NULL || len == 0) 1008 return (FIDO_ERR_INVALID_ARGUMENT); 1009 1010 stmt = &assert->stmt[idx]; 1011 fido_assert_clean_authdata(stmt); 1012 1013 if ((item = cbor_build_bytestring(ptr, len)) == NULL) { 1014 fido_log_debug("%s: cbor_build_bytestring", __func__); 1015 r = FIDO_ERR_INTERNAL; 1016 goto fail; 1017 } 1018 1019 if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, 1020 &stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) { 1021 fido_log_debug("%s: cbor_decode_assert_authdata", __func__); 1022 r = FIDO_ERR_INVALID_ARGUMENT; 1023 goto fail; 1024 } 1025 1026 r = FIDO_OK; 1027 fail: 1028 if (item != NULL) 1029 cbor_decref(&item); 1030 1031 if (r != FIDO_OK) 1032 fido_assert_clean_authdata(stmt); 1033 1034 return (r); 1035 } 1036 1037 static void 1038 fido_assert_clean_sig(fido_assert_stmt *as) 1039 { 1040 free(as->sig.ptr); 1041 as->sig.ptr = NULL; 1042 as->sig.len = 0; 1043 } 1044 1045 int 1046 fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr, 1047 size_t len) 1048 { 1049 unsigned char *sig; 1050 1051 if (idx >= a->stmt_len || ptr == NULL || len == 0) 1052 return (FIDO_ERR_INVALID_ARGUMENT); 1053 1054 fido_assert_clean_sig(&a->stmt[idx]); 1055 1056 if ((sig = malloc(len)) == NULL) 1057 return (FIDO_ERR_INTERNAL); 1058 1059 memcpy(sig, ptr, len); 1060 a->stmt[idx].sig.ptr = sig; 1061 a->stmt[idx].sig.len = len; 1062 1063 return (FIDO_OK); 1064 } 1065 1066 /* XXX shrinking leaks memory; fortunately that shouldn't happen */ 1067 int 1068 fido_assert_set_count(fido_assert_t *assert, size_t n) 1069 { 1070 void *new_stmt; 1071 1072 #ifdef FIDO_FUZZ 1073 if (n > UINT8_MAX) { 1074 fido_log_debug("%s: n > UINT8_MAX", __func__); 1075 return (FIDO_ERR_INTERNAL); 1076 } 1077 #endif 1078 1079 new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n, 1080 sizeof(fido_assert_stmt)); 1081 if (new_stmt == NULL) 1082 return (FIDO_ERR_INTERNAL); 1083 1084 assert->stmt = new_stmt; 1085 assert->stmt_cnt = n; 1086 assert->stmt_len = n; 1087 1088 return (FIDO_OK); 1089 } 1090