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 *found = 0; /* key does not exist */ 264 break; 265 default: 266 /* unexpected sw */ 267 r = FIDO_ERR_INTERNAL; 268 goto fail; 269 } 270 271 r = FIDO_OK; 272 fail: 273 iso7816_free(&apdu); 274 freezero(reply, FIDO_MAXMSG); 275 276 return (r); 277 } 278 279 static int 280 parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id, 281 const unsigned char *reply, size_t len) 282 { 283 uint8_t flags; 284 uint32_t sigcount; 285 286 if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { 287 fido_log_debug("%s: unexpected sw", __func__); 288 return (FIDO_ERR_RX); 289 } 290 291 len -= 2; 292 293 if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 || 294 fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) { 295 fido_log_debug("%s: fido_buf_read", __func__); 296 return (FIDO_ERR_RX); 297 } 298 299 if (sig_get(sig, &reply, &len) < 0) { 300 fido_log_debug("%s: sig_get", __func__); 301 return (FIDO_ERR_RX); 302 } 303 304 if (authdata_fake(rp_id, flags, sigcount, ad) < 0) { 305 fido_log_debug("%s; authdata_fake", __func__); 306 return (FIDO_ERR_RX); 307 } 308 309 return (FIDO_OK); 310 } 311 312 static int 313 do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, 314 const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int *ms) 315 { 316 iso7816_apdu_t *apdu = NULL; 317 unsigned char *reply = NULL; 318 unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; 319 int reply_len; 320 uint8_t key_id_len; 321 int r; 322 323 #ifdef FIDO_FUZZ 324 *ms = 0; /* XXX */ 325 #endif 326 327 if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX || 328 rp_id == NULL) { 329 r = FIDO_ERR_INVALID_ARGUMENT; 330 goto fail; 331 } 332 333 memset(&rp_id_hash, 0, sizeof(rp_id_hash)); 334 335 if (SHA256((const void *)rp_id, strlen(rp_id), 336 rp_id_hash) != rp_id_hash) { 337 fido_log_debug("%s: sha256", __func__); 338 r = FIDO_ERR_INTERNAL; 339 goto fail; 340 } 341 342 key_id_len = (uint8_t)key_id->len; 343 344 if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_SIGN, (uint16_t)(2 * 345 SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL || 346 iso7816_add(apdu, cdh->ptr, cdh->len) < 0 || 347 iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || 348 iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || 349 iso7816_add(apdu, key_id->ptr, key_id_len) < 0) { 350 fido_log_debug("%s: iso7816", __func__); 351 r = FIDO_ERR_INTERNAL; 352 goto fail; 353 } 354 355 if ((reply = malloc(FIDO_MAXMSG)) == NULL) { 356 fido_log_debug("%s: malloc", __func__); 357 r = FIDO_ERR_INTERNAL; 358 goto fail; 359 } 360 361 do { 362 if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 363 iso7816_len(apdu), ms) < 0) { 364 fido_log_debug("%s: fido_tx", __func__); 365 r = FIDO_ERR_TX; 366 goto fail; 367 } 368 if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, 369 FIDO_MAXMSG, ms)) < 2) { 370 fido_log_debug("%s: fido_rx", __func__); 371 r = FIDO_ERR_RX; 372 goto fail; 373 } 374 if (delay_ms(U2F_PACE_MS, ms) != 0) { 375 fido_log_debug("%s: delay_ms", __func__); 376 r = FIDO_ERR_RX; 377 goto fail; 378 } 379 } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); 380 381 if ((r = parse_auth_reply(sig, ad, rp_id, reply, 382 (size_t)reply_len)) != FIDO_OK) { 383 fido_log_debug("%s: parse_auth_reply", __func__); 384 goto fail; 385 } 386 387 fail: 388 iso7816_free(&apdu); 389 freezero(reply, FIDO_MAXMSG); 390 391 return (r); 392 } 393 394 static int 395 cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len, 396 fido_blob_t *cbor_blob) 397 { 398 es256_pk_t *pk = NULL; 399 cbor_item_t *pk_cbor = NULL; 400 size_t alloc_len; 401 int ok = -1; 402 403 /* only handle uncompressed points */ 404 if (ec_point_len != 65 || ec_point[0] != 0x04) { 405 fido_log_debug("%s: unexpected format", __func__); 406 goto fail; 407 } 408 409 if ((pk = es256_pk_new()) == NULL || 410 es256_pk_set_x(pk, &ec_point[1]) < 0 || 411 es256_pk_set_y(pk, &ec_point[33]) < 0) { 412 fido_log_debug("%s: es256_pk_set", __func__); 413 goto fail; 414 } 415 416 if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) { 417 fido_log_debug("%s: es256_pk_encode", __func__); 418 goto fail; 419 } 420 421 if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr, 422 &alloc_len)) != 77) { 423 fido_log_debug("%s: cbor_serialize_alloc", __func__); 424 goto fail; 425 } 426 427 ok = 0; 428 fail: 429 es256_pk_free(&pk); 430 431 if (pk_cbor) 432 cbor_decref(&pk_cbor); 433 434 return (ok); 435 } 436 437 static int 438 encode_cred_attstmt(int cose_alg, const fido_blob_t *x5c, 439 const fido_blob_t *sig, fido_blob_t *out) 440 { 441 cbor_item_t *item = NULL; 442 cbor_item_t *x5c_cbor = NULL; 443 const uint8_t alg_cbor = (uint8_t)(-cose_alg - 1); 444 struct cbor_pair kv[3]; 445 size_t alloc_len; 446 int ok = -1; 447 448 memset(&kv, 0, sizeof(kv)); 449 memset(out, 0, sizeof(*out)); 450 451 if ((item = cbor_new_definite_map(3)) == NULL) { 452 fido_log_debug("%s: cbor_new_definite_map", __func__); 453 goto fail; 454 } 455 456 if ((kv[0].key = cbor_build_string("alg")) == NULL || 457 (kv[0].value = cbor_build_negint8(alg_cbor)) == NULL || 458 !cbor_map_add(item, kv[0])) { 459 fido_log_debug("%s: alg", __func__); 460 goto fail; 461 } 462 463 if ((kv[1].key = cbor_build_string("sig")) == NULL || 464 (kv[1].value = fido_blob_encode(sig)) == NULL || 465 !cbor_map_add(item, kv[1])) { 466 fido_log_debug("%s: sig", __func__); 467 goto fail; 468 } 469 470 if ((kv[2].key = cbor_build_string("x5c")) == NULL || 471 (kv[2].value = cbor_new_definite_array(1)) == NULL || 472 (x5c_cbor = fido_blob_encode(x5c)) == NULL || 473 !cbor_array_push(kv[2].value, x5c_cbor) || 474 !cbor_map_add(item, kv[2])) { 475 fido_log_debug("%s: x5c", __func__); 476 goto fail; 477 } 478 479 if ((out->len = cbor_serialize_alloc(item, &out->ptr, 480 &alloc_len)) == 0) { 481 fido_log_debug("%s: cbor_serialize_alloc", __func__); 482 goto fail; 483 } 484 485 ok = 0; 486 fail: 487 if (item != NULL) 488 cbor_decref(&item); 489 if (x5c_cbor != NULL) 490 cbor_decref(&x5c_cbor); 491 492 for (size_t i = 0; i < nitems(kv); i++) { 493 if (kv[i].key) 494 cbor_decref(&kv[i].key); 495 if (kv[i].value) 496 cbor_decref(&kv[i].value); 497 } 498 499 return (ok); 500 } 501 502 static int 503 encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len, 504 const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out) 505 { 506 fido_authdata_t authdata; 507 fido_attcred_raw_t attcred_raw; 508 fido_blob_t pk_blob; 509 fido_blob_t authdata_blob; 510 cbor_item_t *authdata_cbor = NULL; 511 unsigned char *ptr; 512 size_t len; 513 size_t alloc_len; 514 int ok = -1; 515 516 memset(&pk_blob, 0, sizeof(pk_blob)); 517 memset(&authdata, 0, sizeof(authdata)); 518 memset(&authdata_blob, 0, sizeof(authdata_blob)); 519 memset(out, 0, sizeof(*out)); 520 521 if (rp_id == NULL) { 522 fido_log_debug("%s: NULL rp_id", __func__); 523 goto fail; 524 } 525 526 if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) { 527 fido_log_debug("%s: cbor_blob_from_ec_point", __func__); 528 goto fail; 529 } 530 531 if (SHA256((const void *)rp_id, strlen(rp_id), 532 authdata.rp_id_hash) != authdata.rp_id_hash) { 533 fido_log_debug("%s: sha256", __func__); 534 goto fail; 535 } 536 537 authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT); 538 authdata.sigcount = 0; 539 540 memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid)); 541 attcred_raw.id_len = htobe16(kh_len); 542 543 len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) + 544 kh_len + pk_blob.len; 545 ptr = authdata_blob.ptr = calloc(1, authdata_blob.len); 546 547 fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len); 548 549 if (authdata_blob.ptr == NULL) 550 goto fail; 551 552 if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 || 553 fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 || 554 fido_buf_write(&ptr, &len, kh, kh_len) < 0 || 555 fido_buf_write(&ptr, &len, pk_blob.ptr, pk_blob.len) < 0) { 556 fido_log_debug("%s: fido_buf_write", __func__); 557 goto fail; 558 } 559 560 if ((authdata_cbor = fido_blob_encode(&authdata_blob)) == NULL) { 561 fido_log_debug("%s: fido_blob_encode", __func__); 562 goto fail; 563 } 564 565 if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr, 566 &alloc_len)) == 0) { 567 fido_log_debug("%s: cbor_serialize_alloc", __func__); 568 goto fail; 569 } 570 571 ok = 0; 572 fail: 573 if (authdata_cbor) 574 cbor_decref(&authdata_cbor); 575 576 fido_blob_reset(&pk_blob); 577 fido_blob_reset(&authdata_blob); 578 579 return (ok); 580 } 581 582 static int 583 parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len) 584 { 585 fido_blob_t x5c; 586 fido_blob_t sig; 587 fido_blob_t ad; 588 fido_blob_t stmt; 589 uint8_t dummy; 590 uint8_t pubkey[65]; 591 uint8_t kh_len = 0; 592 uint8_t *kh = NULL; 593 int r; 594 595 memset(&x5c, 0, sizeof(x5c)); 596 memset(&sig, 0, sizeof(sig)); 597 memset(&ad, 0, sizeof(ad)); 598 memset(&stmt, 0, sizeof(stmt)); 599 r = FIDO_ERR_RX; 600 601 /* status word */ 602 if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { 603 fido_log_debug("%s: unexpected sw", __func__); 604 goto fail; 605 } 606 607 len -= 2; 608 609 /* reserved byte */ 610 if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 || 611 dummy != 0x05) { 612 fido_log_debug("%s: reserved byte", __func__); 613 goto fail; 614 } 615 616 /* pubkey + key handle */ 617 if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 || 618 fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 || 619 (kh = calloc(1, kh_len)) == NULL || 620 fido_buf_read(&reply, &len, kh, kh_len) < 0) { 621 fido_log_debug("%s: fido_buf_read", __func__); 622 goto fail; 623 } 624 625 /* x5c + sig */ 626 if (x5c_get(&x5c, &reply, &len) < 0 || 627 sig_get(&sig, &reply, &len) < 0) { 628 fido_log_debug("%s: x5c || sig", __func__); 629 goto fail; 630 } 631 632 /* attstmt */ 633 if (encode_cred_attstmt(COSE_ES256, &x5c, &sig, &stmt) < 0) { 634 fido_log_debug("%s: encode_cred_attstmt", __func__); 635 goto fail; 636 } 637 638 /* authdata */ 639 if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey, 640 sizeof(pubkey), &ad) < 0) { 641 fido_log_debug("%s: encode_cred_authdata", __func__); 642 goto fail; 643 } 644 645 if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK || 646 fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK || 647 fido_cred_set_attstmt(cred, stmt.ptr, stmt.len) != FIDO_OK) { 648 fido_log_debug("%s: fido_cred_set", __func__); 649 r = FIDO_ERR_INTERNAL; 650 goto fail; 651 } 652 653 r = FIDO_OK; 654 fail: 655 freezero(kh, kh_len); 656 fido_blob_reset(&x5c); 657 fido_blob_reset(&sig); 658 fido_blob_reset(&ad); 659 fido_blob_reset(&stmt); 660 661 return (r); 662 } 663 664 int 665 u2f_register(fido_dev_t *dev, fido_cred_t *cred, int *ms) 666 { 667 iso7816_apdu_t *apdu = NULL; 668 unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; 669 unsigned char *reply = NULL; 670 int reply_len; 671 int found; 672 int r; 673 674 if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) { 675 fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk, 676 cred->uv); 677 return (FIDO_ERR_UNSUPPORTED_OPTION); 678 } 679 680 if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL || 681 cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) { 682 fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__, 683 cred->type, (void *)cred->cdh.ptr, cred->cdh.len); 684 return (FIDO_ERR_INVALID_ARGUMENT); 685 } 686 687 for (size_t i = 0; i < cred->excl.len; i++) { 688 if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i], 689 &found, ms)) != FIDO_OK) { 690 fido_log_debug("%s: key_lookup", __func__); 691 return (r); 692 } 693 if (found) { 694 if ((r = send_dummy_register(dev, ms)) != FIDO_OK) { 695 fido_log_debug("%s: send_dummy_register", 696 __func__); 697 return (r); 698 } 699 return (FIDO_ERR_CREDENTIAL_EXCLUDED); 700 } 701 } 702 703 memset(&rp_id_hash, 0, sizeof(rp_id_hash)); 704 705 if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id), 706 rp_id_hash) != rp_id_hash) { 707 fido_log_debug("%s: sha256", __func__); 708 return (FIDO_ERR_INTERNAL); 709 } 710 711 if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 * 712 SHA256_DIGEST_LENGTH)) == NULL || 713 iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 || 714 iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) { 715 fido_log_debug("%s: iso7816", __func__); 716 r = FIDO_ERR_INTERNAL; 717 goto fail; 718 } 719 720 if ((reply = malloc(FIDO_MAXMSG)) == NULL) { 721 fido_log_debug("%s: malloc", __func__); 722 r = FIDO_ERR_INTERNAL; 723 goto fail; 724 } 725 726 do { 727 if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 728 iso7816_len(apdu), ms) < 0) { 729 fido_log_debug("%s: fido_tx", __func__); 730 r = FIDO_ERR_TX; 731 goto fail; 732 } 733 if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, 734 FIDO_MAXMSG, ms)) < 2) { 735 fido_log_debug("%s: fido_rx", __func__); 736 r = FIDO_ERR_RX; 737 goto fail; 738 } 739 if (delay_ms(U2F_PACE_MS, ms) != 0) { 740 fido_log_debug("%s: delay_ms", __func__); 741 r = FIDO_ERR_RX; 742 goto fail; 743 } 744 } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); 745 746 if ((r = parse_register_reply(cred, reply, 747 (size_t)reply_len)) != FIDO_OK) { 748 fido_log_debug("%s: parse_register_reply", __func__); 749 goto fail; 750 } 751 fail: 752 iso7816_free(&apdu); 753 freezero(reply, FIDO_MAXMSG); 754 755 return (r); 756 } 757 758 static int 759 u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id, 760 fido_assert_t *fa, size_t idx, int *ms) 761 { 762 fido_blob_t sig; 763 fido_blob_t ad; 764 int found; 765 int r; 766 767 memset(&sig, 0, sizeof(sig)); 768 memset(&ad, 0, sizeof(ad)); 769 770 if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) { 771 fido_log_debug("%s: key_lookup", __func__); 772 goto fail; 773 } 774 775 if (!found) { 776 fido_log_debug("%s: not found", __func__); 777 r = FIDO_ERR_CREDENTIAL_EXCLUDED; 778 goto fail; 779 } 780 781 if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0) { 782 fido_log_debug("%s: fido_blob_set", __func__); 783 r = FIDO_ERR_INTERNAL; 784 goto fail; 785 } 786 787 if (fa->up == FIDO_OPT_FALSE) { 788 fido_log_debug("%s: checking for key existence only", __func__); 789 r = FIDO_ERR_USER_PRESENCE_REQUIRED; 790 goto fail; 791 } 792 793 if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad, 794 ms)) != FIDO_OK) { 795 fido_log_debug("%s: do_auth", __func__); 796 goto fail; 797 } 798 799 if (fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK || 800 fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) { 801 fido_log_debug("%s: fido_assert_set", __func__); 802 r = FIDO_ERR_INTERNAL; 803 goto fail; 804 } 805 806 r = FIDO_OK; 807 fail: 808 fido_blob_reset(&sig); 809 fido_blob_reset(&ad); 810 811 return (r); 812 } 813 814 int 815 u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int *ms) 816 { 817 size_t nfound = 0; 818 size_t nauth_ok = 0; 819 int r; 820 821 if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) { 822 fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv, 823 (void *)fa->allow_list.ptr); 824 return (FIDO_ERR_UNSUPPORTED_OPTION); 825 } 826 827 if ((r = fido_assert_set_count(fa, fa->allow_list.len)) != FIDO_OK) { 828 fido_log_debug("%s: fido_assert_set_count", __func__); 829 return (r); 830 } 831 832 for (size_t i = 0; i < fa->allow_list.len; i++) { 833 switch ((r = u2f_authenticate_single(dev, 834 &fa->allow_list.ptr[i], fa, nfound, ms))) { 835 case FIDO_OK: 836 nauth_ok++; 837 FALLTHROUGH 838 case FIDO_ERR_USER_PRESENCE_REQUIRED: 839 nfound++; 840 break; 841 default: 842 if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) { 843 fido_log_debug("%s: u2f_authenticate_single", 844 __func__); 845 return (r); 846 } 847 /* ignore credentials that don't exist */ 848 } 849 } 850 851 fa->stmt_len = nfound; 852 853 if (nfound == 0) 854 return (FIDO_ERR_NO_CREDENTIALS); 855 if (nauth_ok == 0) 856 return (FIDO_ERR_USER_PRESENCE_REQUIRED); 857 858 return (FIDO_OK); 859 } 860 861 int 862 u2f_get_touch_begin(fido_dev_t *dev, int *ms) 863 { 864 iso7816_apdu_t *apdu = NULL; 865 const char *clientdata = FIDO_DUMMY_CLIENTDATA; 866 const char *rp_id = FIDO_DUMMY_RP_ID; 867 unsigned char *reply = NULL; 868 unsigned char clientdata_hash[SHA256_DIGEST_LENGTH]; 869 unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; 870 int r; 871 872 memset(&clientdata_hash, 0, sizeof(clientdata_hash)); 873 memset(&rp_id_hash, 0, sizeof(rp_id_hash)); 874 875 if (SHA256((const void *)clientdata, strlen(clientdata), 876 clientdata_hash) != clientdata_hash || SHA256((const void *)rp_id, 877 strlen(rp_id), rp_id_hash) != rp_id_hash) { 878 fido_log_debug("%s: sha256", __func__); 879 return (FIDO_ERR_INTERNAL); 880 } 881 882 if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 * 883 SHA256_DIGEST_LENGTH)) == NULL || 884 iso7816_add(apdu, clientdata_hash, sizeof(clientdata_hash)) < 0 || 885 iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) { 886 fido_log_debug("%s: iso7816", __func__); 887 r = FIDO_ERR_INTERNAL; 888 goto fail; 889 } 890 891 if ((reply = malloc(FIDO_MAXMSG)) == NULL) { 892 fido_log_debug("%s: malloc", __func__); 893 r = FIDO_ERR_INTERNAL; 894 goto fail; 895 } 896 897 if (dev->attr.flags & FIDO_CAP_WINK) { 898 fido_tx(dev, CTAP_CMD_WINK, NULL, 0, ms); 899 fido_rx(dev, CTAP_CMD_WINK, reply, FIDO_MAXMSG, ms); 900 } 901 902 if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 903 iso7816_len(apdu), ms) < 0) { 904 fido_log_debug("%s: fido_tx", __func__); 905 r = FIDO_ERR_TX; 906 goto fail; 907 } 908 909 r = FIDO_OK; 910 fail: 911 iso7816_free(&apdu); 912 freezero(reply, FIDO_MAXMSG); 913 914 return (r); 915 } 916 917 int 918 u2f_get_touch_status(fido_dev_t *dev, int *touched, int *ms) 919 { 920 unsigned char *reply; 921 int reply_len; 922 int r; 923 924 if ((reply = malloc(FIDO_MAXMSG)) == NULL) { 925 fido_log_debug("%s: malloc", __func__); 926 r = FIDO_ERR_INTERNAL; 927 goto out; 928 } 929 930 if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, 931 ms)) < 2) { 932 fido_log_debug("%s: fido_rx", __func__); 933 r = FIDO_OK; /* ignore */ 934 goto out; 935 } 936 937 switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) { 938 case SW_CONDITIONS_NOT_SATISFIED: 939 if ((r = u2f_get_touch_begin(dev, ms)) != FIDO_OK) { 940 fido_log_debug("%s: u2f_get_touch_begin", __func__); 941 goto out; 942 } 943 *touched = 0; 944 break; 945 case SW_NO_ERROR: 946 *touched = 1; 947 break; 948 default: 949 fido_log_debug("%s: unexpected sw", __func__); 950 r = FIDO_ERR_RX; 951 goto out; 952 } 953 954 r = FIDO_OK; 955 out: 956 freezero(reply, FIDO_MAXMSG); 957 958 return (r); 959 } 960