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