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/sha.h> 8 #include <openssl/x509.h> 9 10 #include <string.h> 11 #ifdef HAVE_UNISTD_H 12 #include <unistd.h> 13 #endif 14 15 #include "fido.h" 16 #include "fido/es256.h" 17 18 #if defined(_MSC_VER) 19 static int 20 usleep(unsigned int usec) 21 { 22 Sleep(usec / 1000); 23 24 return (0); 25 } 26 #endif 27 28 static int 29 sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len) 30 { 31 sig->len = *len; /* consume the whole buffer */ 32 if ((sig->ptr = calloc(1, sig->len)) == NULL || 33 fido_buf_read(buf, len, sig->ptr, sig->len) < 0) { 34 fido_log_debug("%s: fido_buf_read", __func__); 35 if (sig->ptr != NULL) { 36 explicit_bzero(sig->ptr, sig->len); 37 free(sig->ptr); 38 sig->ptr = NULL; 39 sig->len = 0; 40 return (-1); 41 } 42 } 43 44 return (0); 45 } 46 47 static int 48 x5c_get(fido_blob_t *x5c, const unsigned char **buf, size_t *len) 49 { 50 X509 *cert = NULL; 51 int ok = -1; 52 53 if (*len > LONG_MAX) { 54 fido_log_debug("%s: invalid len %zu", __func__, *len); 55 goto fail; 56 } 57 58 /* find out the certificate's length */ 59 const unsigned char *end = *buf; 60 if ((cert = d2i_X509(NULL, &end, (long)*len)) == NULL || end <= *buf || 61 (x5c->len = (size_t)(end - *buf)) >= *len) { 62 fido_log_debug("%s: d2i_X509", __func__); 63 goto fail; 64 } 65 66 /* read accordingly */ 67 if ((x5c->ptr = calloc(1, x5c->len)) == NULL || 68 fido_buf_read(buf, len, x5c->ptr, x5c->len) < 0) { 69 fido_log_debug("%s: fido_buf_read", __func__); 70 goto fail; 71 } 72 73 ok = 0; 74 fail: 75 if (cert != NULL) 76 X509_free(cert); 77 78 if (ok < 0) { 79 free(x5c->ptr); 80 x5c->ptr = NULL; 81 x5c->len = 0; 82 } 83 84 return (ok); 85 } 86 87 static int 88 authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount, 89 fido_blob_t *fake_cbor_ad) 90 { 91 fido_authdata_t ad; 92 cbor_item_t *item = NULL; 93 size_t alloc_len; 94 95 memset(&ad, 0, sizeof(ad)); 96 97 if (SHA256((const void *)rp_id, strlen(rp_id), 98 ad.rp_id_hash) != ad.rp_id_hash) { 99 fido_log_debug("%s: sha256", __func__); 100 return (-1); 101 } 102 103 ad.flags = flags; /* XXX translate? */ 104 ad.sigcount = sigcount; 105 106 if ((item = cbor_build_bytestring((const unsigned char *)&ad, 107 sizeof(ad))) == NULL) { 108 fido_log_debug("%s: cbor_build_bytestring", __func__); 109 return (-1); 110 } 111 112 if (fake_cbor_ad->ptr != NULL || 113 (fake_cbor_ad->len = cbor_serialize_alloc(item, &fake_cbor_ad->ptr, 114 &alloc_len)) == 0) { 115 fido_log_debug("%s: cbor_serialize_alloc", __func__); 116 cbor_decref(&item); 117 return (-1); 118 } 119 120 cbor_decref(&item); 121 122 return (0); 123 } 124 125 static int 126 send_dummy_register(fido_dev_t *dev, int ms) 127 { 128 iso7816_apdu_t *apdu = NULL; 129 unsigned char challenge[SHA256_DIGEST_LENGTH]; 130 unsigned char application[SHA256_DIGEST_LENGTH]; 131 unsigned char reply[FIDO_MAXMSG]; 132 int r; 133 134 #ifdef FIDO_FUZZ 135 ms = 0; /* XXX */ 136 #endif 137 138 /* dummy challenge & application */ 139 memset(&challenge, 0xff, sizeof(challenge)); 140 memset(&application, 0xff, sizeof(application)); 141 142 if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 * 143 SHA256_DIGEST_LENGTH)) == NULL || 144 iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || 145 iso7816_add(apdu, &application, sizeof(application)) < 0) { 146 fido_log_debug("%s: iso7816", __func__); 147 r = FIDO_ERR_INTERNAL; 148 goto fail; 149 } 150 151 do { 152 if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 153 iso7816_len(apdu)) < 0) { 154 fido_log_debug("%s: fido_tx", __func__); 155 r = FIDO_ERR_TX; 156 goto fail; 157 } 158 if (fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), ms) < 2) { 159 fido_log_debug("%s: fido_rx", __func__); 160 r = FIDO_ERR_RX; 161 goto fail; 162 } 163 if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { 164 fido_log_debug("%s: usleep", __func__); 165 r = FIDO_ERR_RX; 166 goto fail; 167 } 168 } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); 169 170 r = FIDO_OK; 171 fail: 172 iso7816_free(&apdu); 173 174 return (r); 175 } 176 177 static int 178 key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, 179 int *found, int ms) 180 { 181 iso7816_apdu_t *apdu = NULL; 182 unsigned char challenge[SHA256_DIGEST_LENGTH]; 183 unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; 184 unsigned char reply[FIDO_MAXMSG]; 185 uint8_t key_id_len; 186 int r; 187 188 if (key_id->len > UINT8_MAX || rp_id == NULL) { 189 fido_log_debug("%s: key_id->len=%zu, rp_id=%p", __func__, 190 key_id->len, (const void *)rp_id); 191 r = FIDO_ERR_INVALID_ARGUMENT; 192 goto fail; 193 } 194 195 memset(&challenge, 0xff, sizeof(challenge)); 196 memset(&rp_id_hash, 0, sizeof(rp_id_hash)); 197 198 if (SHA256((const void *)rp_id, strlen(rp_id), 199 rp_id_hash) != rp_id_hash) { 200 fido_log_debug("%s: sha256", __func__); 201 r = FIDO_ERR_INTERNAL; 202 goto fail; 203 } 204 205 key_id_len = (uint8_t)key_id->len; 206 207 if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, 2 * 208 SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || 209 iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || 210 iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || 211 iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || 212 iso7816_add(apdu, key_id->ptr, key_id_len) < 0) { 213 fido_log_debug("%s: iso7816", __func__); 214 r = FIDO_ERR_INTERNAL; 215 goto fail; 216 } 217 218 if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 219 iso7816_len(apdu)) < 0) { 220 fido_log_debug("%s: fido_tx", __func__); 221 r = FIDO_ERR_TX; 222 goto fail; 223 } 224 if (fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), ms) != 2) { 225 fido_log_debug("%s: fido_rx", __func__); 226 r = FIDO_ERR_RX; 227 goto fail; 228 } 229 230 switch ((reply[0] << 8) | reply[1]) { 231 case SW_CONDITIONS_NOT_SATISFIED: 232 *found = 1; /* key exists */ 233 break; 234 case SW_WRONG_DATA: 235 *found = 0; /* key does not exist */ 236 break; 237 default: 238 /* unexpected sw */ 239 r = FIDO_ERR_INTERNAL; 240 goto fail; 241 } 242 243 r = FIDO_OK; 244 fail: 245 iso7816_free(&apdu); 246 247 return (r); 248 } 249 250 static int 251 parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id, 252 const unsigned char *reply, size_t len) 253 { 254 uint8_t flags; 255 uint32_t sigcount; 256 257 if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { 258 fido_log_debug("%s: unexpected sw", __func__); 259 return (FIDO_ERR_RX); 260 } 261 262 len -= 2; 263 264 if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 || 265 fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) { 266 fido_log_debug("%s: fido_buf_read", __func__); 267 return (FIDO_ERR_RX); 268 } 269 270 if (sig_get(sig, &reply, &len) < 0) { 271 fido_log_debug("%s: sig_get", __func__); 272 return (FIDO_ERR_RX); 273 } 274 275 if (authdata_fake(rp_id, flags, sigcount, ad) < 0) { 276 fido_log_debug("%s; authdata_fake", __func__); 277 return (FIDO_ERR_RX); 278 } 279 280 return (FIDO_OK); 281 } 282 283 static int 284 do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, 285 const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int ms) 286 { 287 iso7816_apdu_t *apdu = NULL; 288 unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; 289 unsigned char reply[FIDO_MAXMSG]; 290 int reply_len; 291 uint8_t key_id_len; 292 int r; 293 294 #ifdef FIDO_FUZZ 295 ms = 0; /* XXX */ 296 #endif 297 298 if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX || 299 rp_id == NULL) { 300 r = FIDO_ERR_INVALID_ARGUMENT; 301 goto fail; 302 } 303 304 memset(&rp_id_hash, 0, sizeof(rp_id_hash)); 305 306 if (SHA256((const void *)rp_id, strlen(rp_id), 307 rp_id_hash) != rp_id_hash) { 308 fido_log_debug("%s: sha256", __func__); 309 r = FIDO_ERR_INTERNAL; 310 goto fail; 311 } 312 313 key_id_len = (uint8_t)key_id->len; 314 315 if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, 2 * 316 SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || 317 iso7816_add(apdu, cdh->ptr, cdh->len) < 0 || 318 iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || 319 iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || 320 iso7816_add(apdu, key_id->ptr, key_id_len) < 0) { 321 fido_log_debug("%s: iso7816", __func__); 322 r = FIDO_ERR_INTERNAL; 323 goto fail; 324 } 325 326 do { 327 if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 328 iso7816_len(apdu)) < 0) { 329 fido_log_debug("%s: fido_tx", __func__); 330 r = FIDO_ERR_TX; 331 goto fail; 332 } 333 if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, 334 sizeof(reply), ms)) < 2) { 335 fido_log_debug("%s: fido_rx", __func__); 336 r = FIDO_ERR_RX; 337 goto fail; 338 } 339 if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { 340 fido_log_debug("%s: usleep", __func__); 341 r = FIDO_ERR_RX; 342 goto fail; 343 } 344 } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); 345 346 if ((r = parse_auth_reply(sig, ad, rp_id, reply, 347 (size_t)reply_len)) != FIDO_OK) { 348 fido_log_debug("%s: parse_auth_reply", __func__); 349 goto fail; 350 } 351 352 fail: 353 iso7816_free(&apdu); 354 355 return (r); 356 } 357 358 static int 359 cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len, 360 fido_blob_t *cbor_blob) 361 { 362 es256_pk_t *pk = NULL; 363 cbor_item_t *pk_cbor = NULL; 364 size_t alloc_len; 365 int ok = -1; 366 367 /* only handle uncompressed points */ 368 if (ec_point_len != 65 || ec_point[0] != 0x04) { 369 fido_log_debug("%s: unexpected format", __func__); 370 goto fail; 371 } 372 373 if ((pk = es256_pk_new()) == NULL || 374 es256_pk_set_x(pk, &ec_point[1]) < 0 || 375 es256_pk_set_y(pk, &ec_point[33]) < 0) { 376 fido_log_debug("%s: es256_pk_set", __func__); 377 goto fail; 378 } 379 380 if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) { 381 fido_log_debug("%s: es256_pk_encode", __func__); 382 goto fail; 383 } 384 385 if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr, 386 &alloc_len)) != 77) { 387 fido_log_debug("%s: cbor_serialize_alloc", __func__); 388 goto fail; 389 } 390 391 ok = 0; 392 fail: 393 es256_pk_free(&pk); 394 395 if (pk_cbor) 396 cbor_decref(&pk_cbor); 397 398 return (ok); 399 } 400 401 static int 402 encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len, 403 const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out) 404 { 405 fido_authdata_t authdata; 406 fido_attcred_raw_t attcred_raw; 407 fido_blob_t pk_blob; 408 fido_blob_t authdata_blob; 409 cbor_item_t *authdata_cbor = NULL; 410 unsigned char *ptr; 411 size_t len; 412 size_t alloc_len; 413 int ok = -1; 414 415 memset(&pk_blob, 0, sizeof(pk_blob)); 416 memset(&authdata, 0, sizeof(authdata)); 417 memset(&authdata_blob, 0, sizeof(authdata_blob)); 418 memset(out, 0, sizeof(*out)); 419 420 if (rp_id == NULL) { 421 fido_log_debug("%s: NULL rp_id", __func__); 422 goto fail; 423 } 424 425 if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) { 426 fido_log_debug("%s: cbor_blob_from_ec_point", __func__); 427 goto fail; 428 } 429 430 if (SHA256((const void *)rp_id, strlen(rp_id), 431 authdata.rp_id_hash) != authdata.rp_id_hash) { 432 fido_log_debug("%s: sha256", __func__); 433 goto fail; 434 } 435 436 authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT); 437 authdata.sigcount = 0; 438 439 memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid)); 440 attcred_raw.id_len = htobe16(kh_len); 441 442 len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) + 443 kh_len + pk_blob.len; 444 ptr = authdata_blob.ptr = calloc(1, authdata_blob.len); 445 446 fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len); 447 448 if (authdata_blob.ptr == NULL) 449 goto fail; 450 451 if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 || 452 fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 || 453 fido_buf_write(&ptr, &len, kh, kh_len) < 0 || 454 fido_buf_write(&ptr, &len, pk_blob.ptr, pk_blob.len) < 0) { 455 fido_log_debug("%s: fido_buf_write", __func__); 456 goto fail; 457 } 458 459 if ((authdata_cbor = fido_blob_encode(&authdata_blob)) == NULL) { 460 fido_log_debug("%s: fido_blob_encode", __func__); 461 goto fail; 462 } 463 464 if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr, 465 &alloc_len)) == 0) { 466 fido_log_debug("%s: cbor_serialize_alloc", __func__); 467 goto fail; 468 } 469 470 ok = 0; 471 fail: 472 if (authdata_cbor) 473 cbor_decref(&authdata_cbor); 474 475 if (pk_blob.ptr) { 476 explicit_bzero(pk_blob.ptr, pk_blob.len); 477 free(pk_blob.ptr); 478 } 479 if (authdata_blob.ptr) { 480 explicit_bzero(authdata_blob.ptr, authdata_blob.len); 481 free(authdata_blob.ptr); 482 } 483 484 return (ok); 485 } 486 487 static int 488 parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len) 489 { 490 fido_blob_t x5c; 491 fido_blob_t sig; 492 fido_blob_t ad; 493 uint8_t dummy; 494 uint8_t pubkey[65]; 495 uint8_t kh_len = 0; 496 uint8_t *kh = NULL; 497 int r; 498 499 memset(&x5c, 0, sizeof(x5c)); 500 memset(&sig, 0, sizeof(sig)); 501 memset(&ad, 0, sizeof(ad)); 502 r = FIDO_ERR_RX; 503 504 /* status word */ 505 if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { 506 fido_log_debug("%s: unexpected sw", __func__); 507 goto fail; 508 } 509 510 len -= 2; 511 512 /* reserved byte */ 513 if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 || 514 dummy != 0x05) { 515 fido_log_debug("%s: reserved byte", __func__); 516 goto fail; 517 } 518 519 /* pubkey + key handle */ 520 if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 || 521 fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 || 522 (kh = calloc(1, kh_len)) == NULL || 523 fido_buf_read(&reply, &len, kh, kh_len) < 0) { 524 fido_log_debug("%s: fido_buf_read", __func__); 525 goto fail; 526 } 527 528 /* x5c + sig */ 529 if (x5c_get(&x5c, &reply, &len) < 0 || 530 sig_get(&sig, &reply, &len) < 0) { 531 fido_log_debug("%s: x5c || sig", __func__); 532 goto fail; 533 } 534 535 /* authdata */ 536 if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey, 537 sizeof(pubkey), &ad) < 0) { 538 fido_log_debug("%s: encode_cred_authdata", __func__); 539 goto fail; 540 } 541 542 if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK || 543 fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK || 544 fido_cred_set_x509(cred, x5c.ptr, x5c.len) != FIDO_OK || 545 fido_cred_set_sig(cred, sig.ptr, sig.len) != FIDO_OK) { 546 fido_log_debug("%s: fido_cred_set", __func__); 547 r = FIDO_ERR_INTERNAL; 548 goto fail; 549 } 550 551 r = FIDO_OK; 552 fail: 553 if (kh) { 554 explicit_bzero(kh, kh_len); 555 free(kh); 556 } 557 if (x5c.ptr) { 558 explicit_bzero(x5c.ptr, x5c.len); 559 free(x5c.ptr); 560 } 561 if (sig.ptr) { 562 explicit_bzero(sig.ptr, sig.len); 563 free(sig.ptr); 564 } 565 if (ad.ptr) { 566 explicit_bzero(ad.ptr, ad.len); 567 free(ad.ptr); 568 } 569 570 return (r); 571 } 572 573 int 574 u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms) 575 { 576 iso7816_apdu_t *apdu = NULL; 577 unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; 578 unsigned char reply[FIDO_MAXMSG]; 579 int reply_len; 580 int found; 581 int r; 582 583 #ifdef FIDO_FUZZ 584 ms = 0; /* XXX */ 585 #endif 586 587 if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) { 588 fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk, 589 cred->uv); 590 return (FIDO_ERR_UNSUPPORTED_OPTION); 591 } 592 593 if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL || 594 cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) { 595 fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__, 596 cred->type, (void *)cred->cdh.ptr, cred->cdh.len); 597 return (FIDO_ERR_INVALID_ARGUMENT); 598 } 599 600 for (size_t i = 0; i < cred->excl.len; i++) { 601 if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i], 602 &found, ms)) != FIDO_OK) { 603 fido_log_debug("%s: key_lookup", __func__); 604 return (r); 605 } 606 if (found) { 607 if ((r = send_dummy_register(dev, ms)) != FIDO_OK) { 608 fido_log_debug("%s: send_dummy_register", 609 __func__); 610 return (r); 611 } 612 return (FIDO_ERR_CREDENTIAL_EXCLUDED); 613 } 614 } 615 616 memset(&rp_id_hash, 0, sizeof(rp_id_hash)); 617 618 if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id), 619 rp_id_hash) != rp_id_hash) { 620 fido_log_debug("%s: sha256", __func__); 621 return (FIDO_ERR_INTERNAL); 622 } 623 624 if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 * 625 SHA256_DIGEST_LENGTH)) == NULL || 626 iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 || 627 iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) { 628 fido_log_debug("%s: iso7816", __func__); 629 r = FIDO_ERR_INTERNAL; 630 goto fail; 631 } 632 633 do { 634 if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 635 iso7816_len(apdu)) < 0) { 636 fido_log_debug("%s: fido_tx", __func__); 637 r = FIDO_ERR_TX; 638 goto fail; 639 } 640 if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, 641 sizeof(reply), ms)) < 2) { 642 fido_log_debug("%s: fido_rx", __func__); 643 r = FIDO_ERR_RX; 644 goto fail; 645 } 646 if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { 647 fido_log_debug("%s: usleep", __func__); 648 r = FIDO_ERR_RX; 649 goto fail; 650 } 651 } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); 652 653 if ((r = parse_register_reply(cred, reply, 654 (size_t)reply_len)) != FIDO_OK) { 655 fido_log_debug("%s: parse_register_reply", __func__); 656 goto fail; 657 } 658 fail: 659 iso7816_free(&apdu); 660 661 return (r); 662 } 663 664 static int 665 u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id, 666 fido_assert_t *fa, size_t idx, int ms) 667 { 668 fido_blob_t sig; 669 fido_blob_t ad; 670 int found; 671 int r; 672 673 memset(&sig, 0, sizeof(sig)); 674 memset(&ad, 0, sizeof(ad)); 675 676 if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) { 677 fido_log_debug("%s: key_lookup", __func__); 678 goto fail; 679 } 680 681 if (!found) { 682 fido_log_debug("%s: not found", __func__); 683 r = FIDO_ERR_CREDENTIAL_EXCLUDED; 684 goto fail; 685 } 686 687 if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0) { 688 fido_log_debug("%s: fido_blob_set", __func__); 689 r = FIDO_ERR_INTERNAL; 690 goto fail; 691 } 692 693 if (fa->up == FIDO_OPT_FALSE) { 694 fido_log_debug("%s: checking for key existence only", __func__); 695 r = FIDO_ERR_USER_PRESENCE_REQUIRED; 696 goto fail; 697 } 698 699 if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad, 700 ms)) != FIDO_OK) { 701 fido_log_debug("%s: do_auth", __func__); 702 goto fail; 703 } 704 705 if (fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK || 706 fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) { 707 fido_log_debug("%s: fido_assert_set", __func__); 708 r = FIDO_ERR_INTERNAL; 709 goto fail; 710 } 711 712 r = FIDO_OK; 713 fail: 714 if (sig.ptr) { 715 explicit_bzero(sig.ptr, sig.len); 716 free(sig.ptr); 717 } 718 if (ad.ptr) { 719 explicit_bzero(ad.ptr, ad.len); 720 free(ad.ptr); 721 } 722 723 return (r); 724 } 725 726 int 727 u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) 728 { 729 int nfound = 0; 730 int nauth_ok = 0; 731 int r; 732 733 if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) { 734 fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv, 735 (void *)fa->allow_list.ptr); 736 return (FIDO_ERR_UNSUPPORTED_OPTION); 737 } 738 739 if ((r = fido_assert_set_count(fa, fa->allow_list.len)) != FIDO_OK) { 740 fido_log_debug("%s: fido_assert_set_count", __func__); 741 return (r); 742 } 743 744 for (size_t i = 0; i < fa->allow_list.len; i++) { 745 switch ((r = u2f_authenticate_single(dev, 746 &fa->allow_list.ptr[i], fa, nfound, ms))) { 747 case FIDO_OK: 748 nauth_ok++; 749 /* FALLTHROUGH */ 750 case FIDO_ERR_USER_PRESENCE_REQUIRED: 751 nfound++; 752 break; 753 default: 754 if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) { 755 fido_log_debug("%s: u2f_authenticate_single", 756 __func__); 757 return (r); 758 } 759 /* ignore credentials that don't exist */ 760 } 761 } 762 763 fa->stmt_len = nfound; 764 765 if (nfound == 0) 766 return (FIDO_ERR_NO_CREDENTIALS); 767 if (nauth_ok == 0) 768 return (FIDO_ERR_USER_PRESENCE_REQUIRED); 769 770 return (FIDO_OK); 771 } 772