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/ec.h> 8 #include <openssl/evp.h> 9 #include <openssl/sha.h> 10 #include <openssl/x509.h> 11 12 #include <string.h> 13 #include "fido.h" 14 #include "fido/es256.h" 15 16 static int 17 parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) 18 { 19 fido_cred_t *cred = arg; 20 21 if (cbor_isa_uint(key) == false || 22 cbor_int_get_width(key) != CBOR_INT_8) { 23 fido_log_debug("%s: cbor type", __func__); 24 return (0); /* ignore */ 25 } 26 27 switch (cbor_get_uint8(key)) { 28 case 1: /* fmt */ 29 return (cbor_decode_fmt(val, &cred->fmt)); 30 case 2: /* authdata */ 31 return (cbor_decode_cred_authdata(val, cred->type, 32 &cred->authdata_cbor, &cred->authdata, &cred->attcred, 33 &cred->authdata_ext)); 34 case 3: /* attestation statement */ 35 return (cbor_decode_attstmt(val, &cred->attstmt)); 36 default: /* ignore */ 37 fido_log_debug("%s: cbor type", __func__); 38 return (0); 39 } 40 } 41 42 static int 43 fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin) 44 { 45 fido_blob_t f; 46 fido_blob_t *ecdh = NULL; 47 es256_pk_t *pk = NULL; 48 cbor_item_t *argv[9]; 49 int r; 50 51 memset(&f, 0, sizeof(f)); 52 memset(argv, 0, sizeof(argv)); 53 54 if (cred->cdh.ptr == NULL || cred->type == 0) { 55 fido_log_debug("%s: cdh=%p, type=%d", __func__, 56 (void *)cred->cdh.ptr, cred->type); 57 r = FIDO_ERR_INVALID_ARGUMENT; 58 goto fail; 59 } 60 61 if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL || 62 (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL || 63 (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL || 64 (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) { 65 fido_log_debug("%s: cbor encode", __func__); 66 r = FIDO_ERR_INTERNAL; 67 goto fail; 68 } 69 70 /* excluded credentials */ 71 if (cred->excl.len) 72 if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) { 73 fido_log_debug("%s: cbor_encode_pubkey_list", __func__); 74 r = FIDO_ERR_INTERNAL; 75 goto fail; 76 } 77 78 /* extensions */ 79 if (cred->ext.mask) 80 if ((argv[5] = cbor_encode_extensions(&cred->ext)) == NULL) { 81 fido_log_debug("%s: cbor_encode_extensions", __func__); 82 r = FIDO_ERR_INTERNAL; 83 goto fail; 84 } 85 86 /* options */ 87 if (cred->rk != FIDO_OPT_OMIT || cred->uv != FIDO_OPT_OMIT) 88 if ((argv[6] = cbor_encode_options(cred->rk, 89 cred->uv)) == NULL) { 90 fido_log_debug("%s: cbor_encode_options", __func__); 91 r = FIDO_ERR_INTERNAL; 92 goto fail; 93 } 94 95 /* pin authentication */ 96 if (pin) { 97 if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { 98 fido_log_debug("%s: fido_do_ecdh", __func__); 99 goto fail; 100 } 101 if ((r = cbor_add_pin_params(dev, &cred->cdh, pk, ecdh, pin, 102 &argv[7], &argv[8])) != FIDO_OK) { 103 fido_log_debug("%s: cbor_add_pin_params", __func__); 104 goto fail; 105 } 106 } 107 108 /* framing and transmission */ 109 if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 || 110 fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { 111 fido_log_debug("%s: fido_tx", __func__); 112 r = FIDO_ERR_TX; 113 goto fail; 114 } 115 116 r = FIDO_OK; 117 fail: 118 es256_pk_free(&pk); 119 fido_blob_free(&ecdh); 120 cbor_vector_free(argv, nitems(argv)); 121 free(f.ptr); 122 123 return (r); 124 } 125 126 static int 127 fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms) 128 { 129 unsigned char reply[FIDO_MAXMSG]; 130 int reply_len; 131 int r; 132 133 fido_cred_reset_rx(cred); 134 135 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 136 ms)) < 0) { 137 fido_log_debug("%s: fido_rx", __func__); 138 return (FIDO_ERR_RX); 139 } 140 141 if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred, 142 parse_makecred_reply)) != FIDO_OK) { 143 fido_log_debug("%s: parse_makecred_reply", __func__); 144 return (r); 145 } 146 147 if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) || 148 fido_blob_is_empty(&cred->attcred.id) || 149 fido_blob_is_empty(&cred->attstmt.sig)) { 150 fido_cred_reset_rx(cred); 151 return (FIDO_ERR_INVALID_CBOR); 152 } 153 154 return (FIDO_OK); 155 } 156 157 static int 158 fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, int ms) 159 { 160 int r; 161 162 if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK || 163 (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK) 164 return (r); 165 166 return (FIDO_OK); 167 } 168 169 int 170 fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) 171 { 172 if (fido_dev_is_fido2(dev) == false) { 173 if (pin != NULL || cred->rk == FIDO_OPT_TRUE || 174 cred->ext.mask != 0) 175 return (FIDO_ERR_UNSUPPORTED_OPTION); 176 return (u2f_register(dev, cred, -1)); 177 } 178 179 return (fido_dev_make_cred_wait(dev, cred, pin, -1)); 180 } 181 182 static int 183 check_extensions(const fido_cred_ext_t *authdata_ext, const fido_cred_ext_t *ext) 184 { 185 return (timingsafe_bcmp(authdata_ext, ext, sizeof(*authdata_ext))); 186 } 187 188 int 189 fido_check_rp_id(const char *id, const unsigned char *obtained_hash) 190 { 191 unsigned char expected_hash[SHA256_DIGEST_LENGTH]; 192 193 explicit_bzero(expected_hash, sizeof(expected_hash)); 194 195 if (SHA256((const unsigned char *)id, strlen(id), 196 expected_hash) != expected_hash) { 197 fido_log_debug("%s: sha256", __func__); 198 return (-1); 199 } 200 201 return (timingsafe_bcmp(expected_hash, obtained_hash, 202 SHA256_DIGEST_LENGTH)); 203 } 204 205 static int 206 get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id, 207 size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id, 208 const es256_pk_t *pk) 209 { 210 const uint8_t zero = 0; 211 const uint8_t four = 4; /* uncompressed point */ 212 SHA256_CTX ctx; 213 214 if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || 215 SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 || 216 SHA256_Update(&ctx, rp_id, rp_id_len) == 0 || 217 SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || 218 SHA256_Update(&ctx, id->ptr, id->len) == 0 || 219 SHA256_Update(&ctx, &four, sizeof(four)) == 0 || 220 SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 || 221 SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 || 222 SHA256_Final(dgst->ptr, &ctx) == 0) { 223 fido_log_debug("%s: sha256", __func__); 224 return (-1); 225 } 226 227 return (0); 228 } 229 230 static int 231 verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c, 232 const fido_blob_t *sig) 233 { 234 BIO *rawcert = NULL; 235 X509 *cert = NULL; 236 EVP_PKEY *pkey = NULL; 237 EC_KEY *ec; 238 int ok = -1; 239 240 /* openssl needs ints */ 241 if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) { 242 fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu", 243 __func__, dgst->len, x5c->len, sig->len); 244 return (-1); 245 } 246 247 /* fetch key from x509 */ 248 if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL || 249 (cert = d2i_X509_bio(rawcert, NULL)) == NULL || 250 (pkey = X509_get_pubkey(cert)) == NULL || 251 (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) { 252 fido_log_debug("%s: x509 key", __func__); 253 goto fail; 254 } 255 256 if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, 257 (int)sig->len, ec) != 1) { 258 fido_log_debug("%s: ECDSA_verify", __func__); 259 goto fail; 260 } 261 262 ok = 0; 263 fail: 264 if (rawcert != NULL) 265 BIO_free(rawcert); 266 if (cert != NULL) 267 X509_free(cert); 268 if (pkey != NULL) 269 EVP_PKEY_free(pkey); 270 271 return (ok); 272 } 273 274 int 275 fido_cred_verify(const fido_cred_t *cred) 276 { 277 unsigned char buf[SHA256_DIGEST_LENGTH]; 278 fido_blob_t dgst; 279 int r; 280 281 dgst.ptr = buf; 282 dgst.len = sizeof(buf); 283 284 /* do we have everything we need? */ 285 if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL || 286 cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL || 287 cred->fmt == NULL || cred->attcred.id.ptr == NULL || 288 cred->rp.id == NULL) { 289 fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, " 290 "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr, 291 (void *)cred->authdata_cbor.ptr, 292 (void *)cred->attstmt.x5c.ptr, 293 (void *)cred->attstmt.sig.ptr, (void *)cred->fmt, 294 (void *)cred->attcred.id.ptr, cred->rp.id); 295 r = FIDO_ERR_INVALID_ARGUMENT; 296 goto out; 297 } 298 299 if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) { 300 fido_log_debug("%s: fido_check_rp_id", __func__); 301 r = FIDO_ERR_INVALID_PARAM; 302 goto out; 303 } 304 305 if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE, 306 cred->uv) < 0) { 307 fido_log_debug("%s: fido_check_flags", __func__); 308 r = FIDO_ERR_INVALID_PARAM; 309 goto out; 310 } 311 312 if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) { 313 fido_log_debug("%s: check_extensions", __func__); 314 r = FIDO_ERR_INVALID_PARAM; 315 goto out; 316 } 317 318 if (!strcmp(cred->fmt, "packed")) { 319 if (fido_get_signed_hash(COSE_ES256, &dgst, &cred->cdh, 320 &cred->authdata_cbor) < 0) { 321 fido_log_debug("%s: fido_get_signed_hash", __func__); 322 r = FIDO_ERR_INTERNAL; 323 goto out; 324 } 325 } else { 326 if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash, 327 sizeof(cred->authdata.rp_id_hash), &cred->cdh, 328 &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) { 329 fido_log_debug("%s: get_signed_hash_u2f", __func__); 330 r = FIDO_ERR_INTERNAL; 331 goto out; 332 } 333 } 334 335 if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) { 336 fido_log_debug("%s: verify_sig", __func__); 337 r = FIDO_ERR_INVALID_SIG; 338 goto out; 339 } 340 341 r = FIDO_OK; 342 out: 343 explicit_bzero(buf, sizeof(buf)); 344 345 return (r); 346 } 347 348 int 349 fido_cred_verify_self(const fido_cred_t *cred) 350 { 351 unsigned char buf[1024]; /* XXX */ 352 fido_blob_t dgst; 353 int ok = -1; 354 int r; 355 356 dgst.ptr = buf; 357 dgst.len = sizeof(buf); 358 359 /* do we have everything we need? */ 360 if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL || 361 cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL || 362 cred->fmt == NULL || cred->attcred.id.ptr == NULL || 363 cred->rp.id == NULL) { 364 fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, " 365 "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr, 366 (void *)cred->authdata_cbor.ptr, 367 (void *)cred->attstmt.x5c.ptr, 368 (void *)cred->attstmt.sig.ptr, (void *)cred->fmt, 369 (void *)cred->attcred.id.ptr, cred->rp.id); 370 r = FIDO_ERR_INVALID_ARGUMENT; 371 goto out; 372 } 373 374 if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) { 375 fido_log_debug("%s: fido_check_rp_id", __func__); 376 r = FIDO_ERR_INVALID_PARAM; 377 goto out; 378 } 379 380 if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE, 381 cred->uv) < 0) { 382 fido_log_debug("%s: fido_check_flags", __func__); 383 r = FIDO_ERR_INVALID_PARAM; 384 goto out; 385 } 386 387 if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) { 388 fido_log_debug("%s: check_extensions", __func__); 389 r = FIDO_ERR_INVALID_PARAM; 390 goto out; 391 } 392 393 if (!strcmp(cred->fmt, "packed")) { 394 if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh, 395 &cred->authdata_cbor) < 0) { 396 fido_log_debug("%s: fido_get_signed_hash", __func__); 397 r = FIDO_ERR_INTERNAL; 398 goto out; 399 } 400 } else { 401 if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash, 402 sizeof(cred->authdata.rp_id_hash), &cred->cdh, 403 &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) { 404 fido_log_debug("%s: get_signed_hash_u2f", __func__); 405 r = FIDO_ERR_INTERNAL; 406 goto out; 407 } 408 } 409 410 switch (cred->attcred.type) { 411 case COSE_ES256: 412 ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256, 413 &cred->attstmt.sig); 414 break; 415 case COSE_RS256: 416 ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256, 417 &cred->attstmt.sig); 418 break; 419 case COSE_EDDSA: 420 ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa, 421 &cred->attstmt.sig); 422 break; 423 default: 424 fido_log_debug("%s: unsupported cose_alg %d", __func__, 425 cred->attcred.type); 426 r = FIDO_ERR_UNSUPPORTED_OPTION; 427 goto out; 428 } 429 430 if (ok < 0) 431 r = FIDO_ERR_INVALID_SIG; 432 else 433 r = FIDO_OK; 434 435 out: 436 explicit_bzero(buf, sizeof(buf)); 437 438 return (r); 439 } 440 441 fido_cred_t * 442 fido_cred_new(void) 443 { 444 return (calloc(1, sizeof(fido_cred_t))); 445 } 446 447 static void 448 fido_cred_clean_authdata(fido_cred_t *cred) 449 { 450 free(cred->authdata_cbor.ptr); 451 free(cred->attcred.id.ptr); 452 453 memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext)); 454 memset(&cred->authdata_cbor, 0, sizeof(cred->authdata_cbor)); 455 memset(&cred->authdata, 0, sizeof(cred->authdata)); 456 memset(&cred->attcred, 0, sizeof(cred->attcred)); 457 } 458 459 void 460 fido_cred_reset_tx(fido_cred_t *cred) 461 { 462 free(cred->cdh.ptr); 463 free(cred->rp.id); 464 free(cred->rp.name); 465 free(cred->user.id.ptr); 466 free(cred->user.icon); 467 free(cred->user.name); 468 free(cred->user.display_name); 469 fido_free_blob_array(&cred->excl); 470 471 memset(&cred->cdh, 0, sizeof(cred->cdh)); 472 memset(&cred->rp, 0, sizeof(cred->rp)); 473 memset(&cred->user, 0, sizeof(cred->user)); 474 memset(&cred->excl, 0, sizeof(cred->excl)); 475 memset(&cred->ext, 0, sizeof(cred->ext)); 476 477 cred->type = 0; 478 cred->rk = FIDO_OPT_OMIT; 479 cred->uv = FIDO_OPT_OMIT; 480 } 481 482 static void 483 fido_cred_clean_x509(fido_cred_t *cred) 484 { 485 free(cred->attstmt.x5c.ptr); 486 cred->attstmt.x5c.ptr = NULL; 487 cred->attstmt.x5c.len = 0; 488 } 489 490 static void 491 fido_cred_clean_sig(fido_cred_t *cred) 492 { 493 free(cred->attstmt.sig.ptr); 494 cred->attstmt.sig.ptr = NULL; 495 cred->attstmt.sig.len = 0; 496 } 497 498 void 499 fido_cred_reset_rx(fido_cred_t *cred) 500 { 501 free(cred->fmt); 502 cred->fmt = NULL; 503 504 fido_cred_clean_authdata(cred); 505 fido_cred_clean_x509(cred); 506 fido_cred_clean_sig(cred); 507 } 508 509 void 510 fido_cred_free(fido_cred_t **cred_p) 511 { 512 fido_cred_t *cred; 513 514 if (cred_p == NULL || (cred = *cred_p) == NULL) 515 return; 516 517 fido_cred_reset_tx(cred); 518 fido_cred_reset_rx(cred); 519 520 free(cred); 521 522 *cred_p = NULL; 523 } 524 525 int 526 fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len) 527 { 528 cbor_item_t *item = NULL; 529 struct cbor_load_result cbor; 530 int r; 531 532 fido_cred_clean_authdata(cred); 533 534 if (ptr == NULL || len == 0) { 535 r = FIDO_ERR_INVALID_ARGUMENT; 536 goto fail; 537 } 538 539 if ((item = cbor_load(ptr, len, &cbor)) == NULL) { 540 fido_log_debug("%s: cbor_load", __func__); 541 r = FIDO_ERR_INVALID_ARGUMENT; 542 goto fail; 543 } 544 545 if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor, 546 &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) { 547 fido_log_debug("%s: cbor_decode_cred_authdata", __func__); 548 r = FIDO_ERR_INVALID_ARGUMENT; 549 goto fail; 550 } 551 552 r = FIDO_OK; 553 fail: 554 if (item != NULL) 555 cbor_decref(&item); 556 557 if (r != FIDO_OK) 558 fido_cred_clean_authdata(cred); 559 560 return (r); 561 562 } 563 564 int 565 fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr, 566 size_t len) 567 { 568 cbor_item_t *item = NULL; 569 int r; 570 571 fido_cred_clean_authdata(cred); 572 573 if (ptr == NULL || len == 0) { 574 r = FIDO_ERR_INVALID_ARGUMENT; 575 goto fail; 576 } 577 578 if ((item = cbor_build_bytestring(ptr, len)) == NULL) { 579 fido_log_debug("%s: cbor_build_bytestring", __func__); 580 r = FIDO_ERR_INTERNAL; 581 goto fail; 582 } 583 584 if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor, 585 &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) { 586 fido_log_debug("%s: cbor_decode_cred_authdata", __func__); 587 r = FIDO_ERR_INVALID_ARGUMENT; 588 goto fail; 589 } 590 591 r = FIDO_OK; 592 fail: 593 if (item != NULL) 594 cbor_decref(&item); 595 596 if (r != FIDO_OK) 597 fido_cred_clean_authdata(cred); 598 599 return (r); 600 601 } 602 603 int 604 fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len) 605 { 606 unsigned char *x509; 607 608 fido_cred_clean_x509(cred); 609 610 if (ptr == NULL || len == 0) 611 return (FIDO_ERR_INVALID_ARGUMENT); 612 if ((x509 = malloc(len)) == NULL) 613 return (FIDO_ERR_INTERNAL); 614 615 memcpy(x509, ptr, len); 616 cred->attstmt.x5c.ptr = x509; 617 cred->attstmt.x5c.len = len; 618 619 return (FIDO_OK); 620 } 621 622 int 623 fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len) 624 { 625 unsigned char *sig; 626 627 fido_cred_clean_sig(cred); 628 629 if (ptr == NULL || len == 0) 630 return (FIDO_ERR_INVALID_ARGUMENT); 631 if ((sig = malloc(len)) == NULL) 632 return (FIDO_ERR_INTERNAL); 633 634 memcpy(sig, ptr, len); 635 cred->attstmt.sig.ptr = sig; 636 cred->attstmt.sig.len = len; 637 638 return (FIDO_OK); 639 } 640 641 int 642 fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len) 643 { 644 fido_blob_t id_blob; 645 fido_blob_t *list_ptr; 646 647 memset(&id_blob, 0, sizeof(id_blob)); 648 649 if (fido_blob_set(&id_blob, id_ptr, id_len) < 0) 650 return (FIDO_ERR_INVALID_ARGUMENT); 651 652 if (cred->excl.len == SIZE_MAX) { 653 free(id_blob.ptr); 654 return (FIDO_ERR_INVALID_ARGUMENT); 655 } 656 657 if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len, 658 cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) { 659 free(id_blob.ptr); 660 return (FIDO_ERR_INTERNAL); 661 } 662 663 list_ptr[cred->excl.len++] = id_blob; 664 cred->excl.ptr = list_ptr; 665 666 return (FIDO_OK); 667 } 668 669 int 670 fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash, 671 size_t hash_len) 672 { 673 if (fido_blob_set(&cred->cdh, hash, hash_len) < 0) 674 return (FIDO_ERR_INVALID_ARGUMENT); 675 676 return (FIDO_OK); 677 } 678 679 int 680 fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name) 681 { 682 fido_rp_t *rp = &cred->rp; 683 684 if (rp->id != NULL) { 685 free(rp->id); 686 rp->id = NULL; 687 } 688 if (rp->name != NULL) { 689 free(rp->name); 690 rp->name = NULL; 691 } 692 693 if (id != NULL && (rp->id = strdup(id)) == NULL) 694 goto fail; 695 if (name != NULL && (rp->name = strdup(name)) == NULL) 696 goto fail; 697 698 return (FIDO_OK); 699 fail: 700 free(rp->id); 701 free(rp->name); 702 rp->id = NULL; 703 rp->name = NULL; 704 705 return (FIDO_ERR_INTERNAL); 706 } 707 708 int 709 fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id, 710 size_t user_id_len, const char *name, const char *display_name, 711 const char *icon) 712 { 713 fido_user_t *up = &cred->user; 714 715 if (up->id.ptr != NULL) { 716 free(up->id.ptr); 717 up->id.ptr = NULL; 718 up->id.len = 0; 719 } 720 if (up->name != NULL) { 721 free(up->name); 722 up->name = NULL; 723 } 724 if (up->display_name != NULL) { 725 free(up->display_name); 726 up->display_name = NULL; 727 } 728 if (up->icon != NULL) { 729 free(up->icon); 730 up->icon = NULL; 731 } 732 733 if (user_id != NULL) { 734 if ((up->id.ptr = malloc(user_id_len)) == NULL) 735 goto fail; 736 memcpy(up->id.ptr, user_id, user_id_len); 737 up->id.len = user_id_len; 738 } 739 if (name != NULL && (up->name = strdup(name)) == NULL) 740 goto fail; 741 if (display_name != NULL && 742 (up->display_name = strdup(display_name)) == NULL) 743 goto fail; 744 if (icon != NULL && (up->icon = strdup(icon)) == NULL) 745 goto fail; 746 747 return (FIDO_OK); 748 fail: 749 free(up->id.ptr); 750 free(up->name); 751 free(up->display_name); 752 free(up->icon); 753 754 up->id.ptr = NULL; 755 up->id.len = 0; 756 up->name = NULL; 757 up->display_name = NULL; 758 up->icon = NULL; 759 760 return (FIDO_ERR_INTERNAL); 761 } 762 763 int 764 fido_cred_set_extensions(fido_cred_t *cred, int ext) 765 { 766 if (ext == 0) 767 cred->ext.mask = 0; 768 else { 769 if (ext != FIDO_EXT_HMAC_SECRET && 770 ext != FIDO_EXT_CRED_PROTECT) 771 return (FIDO_ERR_INVALID_ARGUMENT); 772 cred->ext.mask |= ext; 773 } 774 775 return (FIDO_OK); 776 } 777 778 int 779 fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv) 780 { 781 cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; 782 cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; 783 784 return (FIDO_OK); 785 } 786 787 int 788 fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk) 789 { 790 cred->rk = rk; 791 792 return (FIDO_OK); 793 } 794 795 int 796 fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv) 797 { 798 cred->uv = uv; 799 800 return (FIDO_OK); 801 } 802 803 int 804 fido_cred_set_prot(fido_cred_t *cred, int prot) 805 { 806 if (prot == 0) { 807 cred->ext.mask &= ~FIDO_EXT_CRED_PROTECT; 808 cred->ext.prot = 0; 809 } else { 810 if (prot != FIDO_CRED_PROT_UV_OPTIONAL && 811 prot != FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID && 812 prot != FIDO_CRED_PROT_UV_REQUIRED) 813 return (FIDO_ERR_INVALID_ARGUMENT); 814 815 cred->ext.mask |= FIDO_EXT_CRED_PROTECT; 816 cred->ext.prot = prot; 817 } 818 819 return (FIDO_OK); 820 } 821 822 int 823 fido_cred_set_fmt(fido_cred_t *cred, const char *fmt) 824 { 825 free(cred->fmt); 826 cred->fmt = NULL; 827 828 if (fmt == NULL) 829 return (FIDO_ERR_INVALID_ARGUMENT); 830 831 if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f")) 832 return (FIDO_ERR_INVALID_ARGUMENT); 833 834 if ((cred->fmt = strdup(fmt)) == NULL) 835 return (FIDO_ERR_INTERNAL); 836 837 return (FIDO_OK); 838 } 839 840 int 841 fido_cred_set_type(fido_cred_t *cred, int cose_alg) 842 { 843 if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 && 844 cose_alg != COSE_EDDSA) || cred->type != 0) 845 return (FIDO_ERR_INVALID_ARGUMENT); 846 847 cred->type = cose_alg; 848 849 return (FIDO_OK); 850 } 851 852 int 853 fido_cred_type(const fido_cred_t *cred) 854 { 855 return (cred->type); 856 } 857 858 uint8_t 859 fido_cred_flags(const fido_cred_t *cred) 860 { 861 return (cred->authdata.flags); 862 } 863 864 const unsigned char * 865 fido_cred_clientdata_hash_ptr(const fido_cred_t *cred) 866 { 867 return (cred->cdh.ptr); 868 } 869 870 size_t 871 fido_cred_clientdata_hash_len(const fido_cred_t *cred) 872 { 873 return (cred->cdh.len); 874 } 875 876 const unsigned char * 877 fido_cred_x5c_ptr(const fido_cred_t *cred) 878 { 879 return (cred->attstmt.x5c.ptr); 880 } 881 882 size_t 883 fido_cred_x5c_len(const fido_cred_t *cred) 884 { 885 return (cred->attstmt.x5c.len); 886 } 887 888 const unsigned char * 889 fido_cred_sig_ptr(const fido_cred_t *cred) 890 { 891 return (cred->attstmt.sig.ptr); 892 } 893 894 size_t 895 fido_cred_sig_len(const fido_cred_t *cred) 896 { 897 return (cred->attstmt.sig.len); 898 } 899 900 const unsigned char * 901 fido_cred_authdata_ptr(const fido_cred_t *cred) 902 { 903 return (cred->authdata_cbor.ptr); 904 } 905 906 size_t 907 fido_cred_authdata_len(const fido_cred_t *cred) 908 { 909 return (cred->authdata_cbor.len); 910 } 911 912 const unsigned char * 913 fido_cred_pubkey_ptr(const fido_cred_t *cred) 914 { 915 const void *ptr; 916 917 switch (cred->attcred.type) { 918 case COSE_ES256: 919 ptr = &cred->attcred.pubkey.es256; 920 break; 921 case COSE_RS256: 922 ptr = &cred->attcred.pubkey.rs256; 923 break; 924 case COSE_EDDSA: 925 ptr = &cred->attcred.pubkey.eddsa; 926 break; 927 default: 928 ptr = NULL; 929 break; 930 } 931 932 return (ptr); 933 } 934 935 size_t 936 fido_cred_pubkey_len(const fido_cred_t *cred) 937 { 938 size_t len; 939 940 switch (cred->attcred.type) { 941 case COSE_ES256: 942 len = sizeof(cred->attcred.pubkey.es256); 943 break; 944 case COSE_RS256: 945 len = sizeof(cred->attcred.pubkey.rs256); 946 break; 947 case COSE_EDDSA: 948 len = sizeof(cred->attcred.pubkey.eddsa); 949 break; 950 default: 951 len = 0; 952 break; 953 } 954 955 return (len); 956 } 957 958 const unsigned char * 959 fido_cred_id_ptr(const fido_cred_t *cred) 960 { 961 return (cred->attcred.id.ptr); 962 } 963 964 size_t 965 fido_cred_id_len(const fido_cred_t *cred) 966 { 967 return (cred->attcred.id.len); 968 } 969 970 const unsigned char * 971 fido_cred_aaguid_ptr(const fido_cred_t *cred) 972 { 973 return (cred->attcred.aaguid); 974 } 975 976 size_t 977 fido_cred_aaguid_len(const fido_cred_t *cred) 978 { 979 return (sizeof(cred->attcred.aaguid)); 980 } 981 982 int 983 fido_cred_prot(const fido_cred_t *cred) 984 { 985 return (cred->ext.prot); 986 } 987 988 const char * 989 fido_cred_fmt(const fido_cred_t *cred) 990 { 991 return (cred->fmt); 992 } 993 994 const char * 995 fido_cred_rp_id(const fido_cred_t *cred) 996 { 997 return (cred->rp.id); 998 } 999 1000 const char * 1001 fido_cred_rp_name(const fido_cred_t *cred) 1002 { 1003 return (cred->rp.name); 1004 } 1005 1006 const char * 1007 fido_cred_user_name(const fido_cred_t *cred) 1008 { 1009 return (cred->user.name); 1010 } 1011 1012 const char * 1013 fido_cred_display_name(const fido_cred_t *cred) 1014 { 1015 return (cred->user.display_name); 1016 } 1017 1018 const unsigned char * 1019 fido_cred_user_id_ptr(const fido_cred_t *cred) 1020 { 1021 return (cred->user.id.ptr); 1022 } 1023 1024 size_t 1025 fido_cred_user_id_len(const fido_cred_t *cred) 1026 { 1027 return (cred->user.id.len); 1028 } 1029