1 /* 2 * Copyright (c) 2018-2022 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 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8 #include <openssl/sha.h> 9 #include "fido.h" 10 #include "fido/es256.h" 11 12 #define CTAP21_UV_TOKEN_PERM_MAKECRED 0x01 13 #define CTAP21_UV_TOKEN_PERM_ASSERT 0x02 14 #define CTAP21_UV_TOKEN_PERM_CRED_MGMT 0x04 15 #define CTAP21_UV_TOKEN_PERM_BIO 0x08 16 #define CTAP21_UV_TOKEN_PERM_LARGEBLOB 0x10 17 #define CTAP21_UV_TOKEN_PERM_CONFIG 0x20 18 19 int 20 fido_sha256(fido_blob_t *digest, const u_char *data, size_t data_len) 21 { 22 if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL) 23 return (-1); 24 25 digest->len = SHA256_DIGEST_LENGTH; 26 27 if (SHA256(data, data_len, digest->ptr) != digest->ptr) { 28 fido_blob_reset(digest); 29 return (-1); 30 } 31 32 return (0); 33 } 34 35 static int 36 pin_sha256_enc(const fido_dev_t *dev, const fido_blob_t *shared, 37 const fido_blob_t *pin, fido_blob_t **out) 38 { 39 fido_blob_t *ph = NULL; 40 int r; 41 42 if ((*out = fido_blob_new()) == NULL || 43 (ph = fido_blob_new()) == NULL) { 44 r = FIDO_ERR_INTERNAL; 45 goto fail; 46 } 47 48 if (fido_sha256(ph, pin->ptr, pin->len) < 0 || ph->len < 16) { 49 fido_log_debug("%s: SHA256", __func__); 50 r = FIDO_ERR_INTERNAL; 51 goto fail; 52 } 53 54 ph->len = 16; /* first 16 bytes */ 55 56 if (aes256_cbc_enc(dev, shared, ph, *out) < 0) { 57 fido_log_debug("%s: aes256_cbc_enc", __func__); 58 r = FIDO_ERR_INTERNAL; 59 goto fail; 60 } 61 62 r = FIDO_OK; 63 fail: 64 fido_blob_free(&ph); 65 66 return (r); 67 } 68 69 static int 70 pad64(const char *pin, fido_blob_t **ppin) 71 { 72 size_t pin_len; 73 size_t ppin_len; 74 75 pin_len = strlen(pin); 76 if (pin_len < 4 || pin_len > 63) { 77 fido_log_debug("%s: invalid pin length", __func__); 78 return (FIDO_ERR_PIN_POLICY_VIOLATION); 79 } 80 81 if ((*ppin = fido_blob_new()) == NULL) 82 return (FIDO_ERR_INTERNAL); 83 84 ppin_len = (pin_len + 63U) & ~63U; 85 if (ppin_len < pin_len || 86 ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) { 87 fido_blob_free(ppin); 88 return (FIDO_ERR_INTERNAL); 89 } 90 91 memcpy((*ppin)->ptr, pin, pin_len); 92 (*ppin)->len = ppin_len; 93 94 return (FIDO_OK); 95 } 96 97 static int 98 pin_pad64_enc(const fido_dev_t *dev, const fido_blob_t *shared, 99 const char *pin, fido_blob_t **out) 100 { 101 fido_blob_t *ppin = NULL; 102 int r; 103 104 if ((r = pad64(pin, &ppin)) != FIDO_OK) { 105 fido_log_debug("%s: pad64", __func__); 106 goto fail; 107 } 108 109 if ((*out = fido_blob_new()) == NULL) { 110 r = FIDO_ERR_INTERNAL; 111 goto fail; 112 } 113 114 if (aes256_cbc_enc(dev, shared, ppin, *out) < 0) { 115 fido_log_debug("%s: aes256_cbc_enc", __func__); 116 r = FIDO_ERR_INTERNAL; 117 goto fail; 118 } 119 120 r = FIDO_OK; 121 fail: 122 fido_blob_free(&ppin); 123 124 return (r); 125 } 126 127 static cbor_item_t * 128 encode_uv_permission(uint8_t cmd) 129 { 130 switch (cmd) { 131 case CTAP_CBOR_ASSERT: 132 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_ASSERT)); 133 case CTAP_CBOR_BIO_ENROLL_PRE: 134 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_BIO)); 135 case CTAP_CBOR_CONFIG: 136 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CONFIG)); 137 case CTAP_CBOR_MAKECRED: 138 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_MAKECRED)); 139 case CTAP_CBOR_CRED_MGMT_PRE: 140 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CRED_MGMT)); 141 case CTAP_CBOR_LARGEBLOB: 142 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_LARGEBLOB)); 143 default: 144 fido_log_debug("%s: cmd 0x%02x", __func__, cmd); 145 return (NULL); 146 } 147 } 148 149 static int 150 ctap20_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh, 151 const es256_pk_t *pk, int *ms) 152 { 153 fido_blob_t f; 154 fido_blob_t *p = NULL; 155 fido_blob_t *phe = NULL; 156 cbor_item_t *argv[6]; 157 int r; 158 159 memset(&f, 0, sizeof(f)); 160 memset(argv, 0, sizeof(argv)); 161 162 if (pin == NULL) { 163 fido_log_debug("%s: NULL pin", __func__); 164 r = FIDO_ERR_PIN_REQUIRED; 165 goto fail; 166 } 167 168 if ((p = fido_blob_new()) == NULL || fido_blob_set(p, 169 (const unsigned char *)pin, strlen(pin)) < 0) { 170 fido_log_debug("%s: fido_blob_set", __func__); 171 r = FIDO_ERR_INVALID_ARGUMENT; 172 goto fail; 173 } 174 175 if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) { 176 fido_log_debug("%s: pin_sha256_enc", __func__); 177 goto fail; 178 } 179 180 if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL || 181 (argv[1] = cbor_build_uint8(5)) == NULL || 182 (argv[2] = es256_pk_encode(pk, 1)) == NULL || 183 (argv[5] = fido_blob_encode(phe)) == NULL) { 184 fido_log_debug("%s: cbor encode", __func__); 185 r = FIDO_ERR_INTERNAL; 186 goto fail; 187 } 188 189 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), 190 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { 191 fido_log_debug("%s: fido_tx", __func__); 192 r = FIDO_ERR_TX; 193 goto fail; 194 } 195 196 r = FIDO_OK; 197 fail: 198 cbor_vector_free(argv, nitems(argv)); 199 fido_blob_free(&p); 200 fido_blob_free(&phe); 201 free(f.ptr); 202 203 return (r); 204 } 205 206 static int 207 ctap21_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh, 208 const es256_pk_t *pk, uint8_t cmd, const char *rpid, int *ms) 209 { 210 fido_blob_t f; 211 fido_blob_t *p = NULL; 212 fido_blob_t *phe = NULL; 213 cbor_item_t *argv[10]; 214 uint8_t subcmd; 215 int r; 216 217 memset(&f, 0, sizeof(f)); 218 memset(argv, 0, sizeof(argv)); 219 220 if (pin != NULL) { 221 if ((p = fido_blob_new()) == NULL || fido_blob_set(p, 222 (const unsigned char *)pin, strlen(pin)) < 0) { 223 fido_log_debug("%s: fido_blob_set", __func__); 224 r = FIDO_ERR_INVALID_ARGUMENT; 225 goto fail; 226 } 227 if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) { 228 fido_log_debug("%s: pin_sha256_enc", __func__); 229 goto fail; 230 } 231 subcmd = 9; /* getPinUvAuthTokenUsingPinWithPermissions */ 232 } else { 233 if (fido_dev_has_uv(dev) == false) { 234 fido_log_debug("%s: fido_dev_has_uv", __func__); 235 r = FIDO_ERR_PIN_REQUIRED; 236 goto fail; 237 } 238 subcmd = 6; /* getPinUvAuthTokenUsingUvWithPermissions */ 239 } 240 241 if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL || 242 (argv[1] = cbor_build_uint8(subcmd)) == NULL || 243 (argv[2] = es256_pk_encode(pk, 1)) == NULL || 244 (phe != NULL && (argv[5] = fido_blob_encode(phe)) == NULL) || 245 (argv[8] = encode_uv_permission(cmd)) == NULL || 246 (rpid != NULL && (argv[9] = cbor_build_string(rpid)) == NULL)) { 247 fido_log_debug("%s: cbor encode", __func__); 248 r = FIDO_ERR_INTERNAL; 249 goto fail; 250 } 251 252 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), 253 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { 254 fido_log_debug("%s: fido_tx", __func__); 255 r = FIDO_ERR_TX; 256 goto fail; 257 } 258 259 r = FIDO_OK; 260 fail: 261 cbor_vector_free(argv, nitems(argv)); 262 fido_blob_free(&p); 263 fido_blob_free(&phe); 264 free(f.ptr); 265 266 return (r); 267 } 268 269 static int 270 parse_uv_token(const cbor_item_t *key, const cbor_item_t *val, void *arg) 271 { 272 fido_blob_t *token = arg; 273 274 if (cbor_isa_uint(key) == false || 275 cbor_int_get_width(key) != CBOR_INT_8 || 276 cbor_get_uint8(key) != 2) { 277 fido_log_debug("%s: cbor type", __func__); 278 return (0); /* ignore */ 279 } 280 281 return (fido_blob_decode(val, token)); 282 } 283 284 static int 285 uv_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, fido_blob_t *token, 286 int *ms) 287 { 288 fido_blob_t *aes_token = NULL; 289 unsigned char *msg = NULL; 290 int msglen; 291 int r; 292 293 if ((aes_token = fido_blob_new()) == NULL) { 294 r = FIDO_ERR_INTERNAL; 295 goto fail; 296 } 297 298 if ((msg = malloc(FIDO_MAXMSG)) == NULL) { 299 r = FIDO_ERR_INTERNAL; 300 goto fail; 301 } 302 303 if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { 304 fido_log_debug("%s: fido_rx", __func__); 305 r = FIDO_ERR_RX; 306 goto fail; 307 } 308 309 if ((r = cbor_parse_reply(msg, (size_t)msglen, aes_token, 310 parse_uv_token)) != FIDO_OK) { 311 fido_log_debug("%s: parse_uv_token", __func__); 312 goto fail; 313 } 314 315 if (aes256_cbc_dec(dev, ecdh, aes_token, token) < 0) { 316 fido_log_debug("%s: aes256_cbc_dec", __func__); 317 r = FIDO_ERR_RX; 318 goto fail; 319 } 320 321 r = FIDO_OK; 322 fail: 323 fido_blob_free(&aes_token); 324 freezero(msg, FIDO_MAXMSG); 325 326 return (r); 327 } 328 329 static int 330 uv_token_wait(fido_dev_t *dev, uint8_t cmd, const char *pin, 331 const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid, 332 fido_blob_t *token, int *ms) 333 { 334 int r; 335 336 if (ecdh == NULL || pk == NULL) 337 return (FIDO_ERR_INVALID_ARGUMENT); 338 if (fido_dev_supports_permissions(dev)) 339 r = ctap21_uv_token_tx(dev, pin, ecdh, pk, cmd, rpid, ms); 340 else 341 r = ctap20_uv_token_tx(dev, pin, ecdh, pk, ms); 342 if (r != FIDO_OK) 343 return (r); 344 345 return (uv_token_rx(dev, ecdh, token, ms)); 346 } 347 348 int 349 fido_dev_get_uv_token(fido_dev_t *dev, uint8_t cmd, const char *pin, 350 const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid, 351 fido_blob_t *token, int *ms) 352 { 353 return (uv_token_wait(dev, cmd, pin, ecdh, pk, rpid, token, ms)); 354 } 355 356 static int 357 fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin, 358 int *ms) 359 { 360 fido_blob_t f; 361 fido_blob_t *ppine = NULL; 362 fido_blob_t *ecdh = NULL; 363 fido_blob_t *opin = NULL; 364 fido_blob_t *opinhe = NULL; 365 cbor_item_t *argv[6]; 366 es256_pk_t *pk = NULL; 367 int r; 368 369 memset(&f, 0, sizeof(f)); 370 memset(argv, 0, sizeof(argv)); 371 372 if ((opin = fido_blob_new()) == NULL || fido_blob_set(opin, 373 (const unsigned char *)oldpin, strlen(oldpin)) < 0) { 374 fido_log_debug("%s: fido_blob_set", __func__); 375 r = FIDO_ERR_INVALID_ARGUMENT; 376 goto fail; 377 } 378 379 if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { 380 fido_log_debug("%s: fido_do_ecdh", __func__); 381 goto fail; 382 } 383 384 /* pad and encrypt new pin */ 385 if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) { 386 fido_log_debug("%s: pin_pad64_enc", __func__); 387 goto fail; 388 } 389 390 /* hash and encrypt old pin */ 391 if ((r = pin_sha256_enc(dev, ecdh, opin, &opinhe)) != FIDO_OK) { 392 fido_log_debug("%s: pin_sha256_enc", __func__); 393 goto fail; 394 } 395 396 if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL || 397 (argv[1] = cbor_build_uint8(4)) == NULL || 398 (argv[2] = es256_pk_encode(pk, 1)) == NULL || 399 (argv[3] = cbor_encode_change_pin_auth(dev, ecdh, ppine, opinhe)) == NULL || 400 (argv[4] = fido_blob_encode(ppine)) == NULL || 401 (argv[5] = fido_blob_encode(opinhe)) == NULL) { 402 fido_log_debug("%s: cbor encode", __func__); 403 r = FIDO_ERR_INTERNAL; 404 goto fail; 405 } 406 407 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), 408 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { 409 fido_log_debug("%s: fido_tx", __func__); 410 r = FIDO_ERR_TX; 411 goto fail; 412 } 413 414 r = FIDO_OK; 415 fail: 416 cbor_vector_free(argv, nitems(argv)); 417 es256_pk_free(&pk); 418 fido_blob_free(&ppine); 419 fido_blob_free(&ecdh); 420 fido_blob_free(&opin); 421 fido_blob_free(&opinhe); 422 free(f.ptr); 423 424 return (r); 425 426 } 427 428 static int 429 fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin, int *ms) 430 { 431 fido_blob_t f; 432 fido_blob_t *ppine = NULL; 433 fido_blob_t *ecdh = NULL; 434 cbor_item_t *argv[5]; 435 es256_pk_t *pk = NULL; 436 int r; 437 438 memset(&f, 0, sizeof(f)); 439 memset(argv, 0, sizeof(argv)); 440 441 if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { 442 fido_log_debug("%s: fido_do_ecdh", __func__); 443 goto fail; 444 } 445 446 if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) { 447 fido_log_debug("%s: pin_pad64_enc", __func__); 448 goto fail; 449 } 450 451 if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL || 452 (argv[1] = cbor_build_uint8(3)) == NULL || 453 (argv[2] = es256_pk_encode(pk, 1)) == NULL || 454 (argv[3] = cbor_encode_pin_auth(dev, ecdh, ppine)) == NULL || 455 (argv[4] = fido_blob_encode(ppine)) == NULL) { 456 fido_log_debug("%s: cbor encode", __func__); 457 r = FIDO_ERR_INTERNAL; 458 goto fail; 459 } 460 461 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), 462 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { 463 fido_log_debug("%s: fido_tx", __func__); 464 r = FIDO_ERR_TX; 465 goto fail; 466 } 467 468 r = FIDO_OK; 469 fail: 470 cbor_vector_free(argv, nitems(argv)); 471 es256_pk_free(&pk); 472 fido_blob_free(&ppine); 473 fido_blob_free(&ecdh); 474 free(f.ptr); 475 476 return (r); 477 } 478 479 static int 480 fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin, 481 int *ms) 482 { 483 int r; 484 485 if (oldpin != NULL) { 486 if ((r = fido_dev_change_pin_tx(dev, pin, oldpin, 487 ms)) != FIDO_OK) { 488 fido_log_debug("%s: fido_dev_change_pin_tx", __func__); 489 return (r); 490 } 491 } else { 492 if ((r = fido_dev_set_pin_tx(dev, pin, ms)) != FIDO_OK) { 493 fido_log_debug("%s: fido_dev_set_pin_tx", __func__); 494 return (r); 495 } 496 } 497 498 if ((r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { 499 fido_log_debug("%s: fido_rx_cbor_status", __func__); 500 return (r); 501 } 502 503 if (dev->flags & FIDO_DEV_PIN_UNSET) { 504 dev->flags &= ~FIDO_DEV_PIN_UNSET; 505 dev->flags |= FIDO_DEV_PIN_SET; 506 } 507 508 return (FIDO_OK); 509 } 510 511 int 512 fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin) 513 { 514 int ms = dev->timeout_ms; 515 516 return (fido_dev_set_pin_wait(dev, pin, oldpin, &ms)); 517 } 518 519 static int 520 parse_retry_count(const uint8_t keyval, const cbor_item_t *key, 521 const cbor_item_t *val, void *arg) 522 { 523 int *retries = arg; 524 uint64_t n; 525 526 if (cbor_isa_uint(key) == false || 527 cbor_int_get_width(key) != CBOR_INT_8 || 528 cbor_get_uint8(key) != keyval) { 529 fido_log_debug("%s: cbor type", __func__); 530 return (0); /* ignore */ 531 } 532 533 if (cbor_decode_uint64(val, &n) < 0 || n > INT_MAX) { 534 fido_log_debug("%s: cbor_decode_uint64", __func__); 535 return (-1); 536 } 537 538 *retries = (int)n; 539 540 return (0); 541 } 542 543 static int 544 parse_pin_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) 545 { 546 return (parse_retry_count(3, key, val, arg)); 547 } 548 549 static int 550 parse_uv_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) 551 { 552 return (parse_retry_count(5, key, val, arg)); 553 } 554 555 static int 556 fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd, int *ms) 557 { 558 fido_blob_t f; 559 cbor_item_t *argv[2]; 560 int r; 561 562 memset(&f, 0, sizeof(f)); 563 memset(argv, 0, sizeof(argv)); 564 565 if ((argv[0] = cbor_build_uint8(1)) == NULL || 566 (argv[1] = cbor_build_uint8(subcmd)) == NULL) { 567 r = FIDO_ERR_INTERNAL; 568 goto fail; 569 } 570 571 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), 572 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { 573 fido_log_debug("%s: fido_tx", __func__); 574 r = FIDO_ERR_TX; 575 goto fail; 576 } 577 578 r = FIDO_OK; 579 fail: 580 cbor_vector_free(argv, nitems(argv)); 581 free(f.ptr); 582 583 return (r); 584 } 585 586 static int 587 fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int *ms) 588 { 589 unsigned char *msg; 590 int msglen; 591 int r; 592 593 *retries = 0; 594 595 if ((msg = malloc(FIDO_MAXMSG)) == NULL) { 596 r = FIDO_ERR_INTERNAL; 597 goto fail; 598 } 599 600 if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { 601 fido_log_debug("%s: fido_rx", __func__); 602 r = FIDO_ERR_RX; 603 goto fail; 604 } 605 606 if ((r = cbor_parse_reply(msg, (size_t)msglen, retries, 607 parse_pin_retry_count)) != FIDO_OK) { 608 fido_log_debug("%s: parse_pin_retry_count", __func__); 609 goto fail; 610 } 611 612 r = FIDO_OK; 613 fail: 614 freezero(msg, FIDO_MAXMSG); 615 616 return (r); 617 } 618 619 static int 620 fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int *ms) 621 { 622 int r; 623 624 if ((r = fido_dev_get_retry_count_tx(dev, 1, ms)) != FIDO_OK || 625 (r = fido_dev_get_pin_retry_count_rx(dev, retries, ms)) != FIDO_OK) 626 return (r); 627 628 return (FIDO_OK); 629 } 630 631 int 632 fido_dev_get_retry_count(fido_dev_t *dev, int *retries) 633 { 634 int ms = dev->timeout_ms; 635 636 return (fido_dev_get_pin_retry_count_wait(dev, retries, &ms)); 637 } 638 639 static int 640 fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int *ms) 641 { 642 unsigned char *msg; 643 int msglen; 644 int r; 645 646 *retries = 0; 647 648 if ((msg = malloc(FIDO_MAXMSG)) == NULL) { 649 r = FIDO_ERR_INTERNAL; 650 goto fail; 651 } 652 653 if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { 654 fido_log_debug("%s: fido_rx", __func__); 655 r = FIDO_ERR_RX; 656 goto fail; 657 } 658 659 if ((r = cbor_parse_reply(msg, (size_t)msglen, retries, 660 parse_uv_retry_count)) != FIDO_OK) { 661 fido_log_debug("%s: parse_uv_retry_count", __func__); 662 goto fail; 663 } 664 665 r = FIDO_OK; 666 fail: 667 freezero(msg, FIDO_MAXMSG); 668 669 return (r); 670 } 671 672 static int 673 fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int *ms) 674 { 675 int r; 676 677 if ((r = fido_dev_get_retry_count_tx(dev, 7, ms)) != FIDO_OK || 678 (r = fido_dev_get_uv_retry_count_rx(dev, retries, ms)) != FIDO_OK) 679 return (r); 680 681 return (FIDO_OK); 682 } 683 684 int 685 fido_dev_get_uv_retry_count(fido_dev_t *dev, int *retries) 686 { 687 int ms = dev->timeout_ms; 688 689 return (fido_dev_get_uv_retry_count_wait(dev, retries, &ms)); 690 } 691 692 int 693 cbor_add_uv_params(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *hmac_data, 694 const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, 695 const char *rpid, cbor_item_t **auth, cbor_item_t **opt, int *ms) 696 { 697 fido_blob_t *token = NULL; 698 int r; 699 700 if ((token = fido_blob_new()) == NULL) { 701 r = FIDO_ERR_INTERNAL; 702 goto fail; 703 } 704 705 if ((r = fido_dev_get_uv_token(dev, cmd, pin, ecdh, pk, rpid, 706 token, ms)) != FIDO_OK) { 707 fido_log_debug("%s: fido_dev_get_uv_token", __func__); 708 goto fail; 709 } 710 711 if ((*auth = cbor_encode_pin_auth(dev, token, hmac_data)) == NULL || 712 (*opt = cbor_encode_pin_opt(dev)) == NULL) { 713 fido_log_debug("%s: cbor encode", __func__); 714 r = FIDO_ERR_INTERNAL; 715 goto fail; 716 } 717 718 r = FIDO_OK; 719 fail: 720 fido_blob_free(&token); 721 722 return (r); 723 } 724