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