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