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