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