Module Name: src Committed By: christos Date: Fri Aug 11 23:02:08 UTC 2023
Modified Files: src/external/bsd/libfido2/dist/src: assert.c cred.c hid_netbsd.c src/external/bsd/libfido2/dist/tools: util.c src/external/bsd/libfido2/lib: Makefile Removed Files: src/external/bsd/libfido2/dist/openbsd-compat: hkdf.c hkdf.h Log Message: Merge conflicts between libfido2-1.8.0 and libfido2-1.13.0 To generate a diff of this commit: cvs rdiff -u -r1.1.1.1 -r0 \ src/external/bsd/libfido2/dist/openbsd-compat/hkdf.c \ src/external/bsd/libfido2/dist/openbsd-compat/hkdf.h cvs rdiff -u -r1.2 -r1.3 src/external/bsd/libfido2/dist/src/assert.c \ src/external/bsd/libfido2/dist/src/cred.c cvs rdiff -u -r1.3 -r1.4 src/external/bsd/libfido2/dist/src/hid_netbsd.c cvs rdiff -u -r1.3 -r1.4 src/external/bsd/libfido2/dist/tools/util.c cvs rdiff -u -r1.10 -r1.11 src/external/bsd/libfido2/lib/Makefile Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/external/bsd/libfido2/dist/src/assert.c diff -u src/external/bsd/libfido2/dist/src/assert.c:1.2 src/external/bsd/libfido2/dist/src/assert.c:1.3 --- src/external/bsd/libfido2/dist/src/assert.c:1.2 Mon May 8 19:45:52 2023 +++ src/external/bsd/libfido2/dist/src/assert.c Fri Aug 11 19:02:08 2023 @@ -1,10 +1,10 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause */ -#include <openssl/ecdsa.h> #include <openssl/sha.h> #include "fido.h" @@ -79,7 +79,7 @@ parse_assert_reply(const cbor_item_t *ke static int fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert, - const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin) + const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms) { fido_blob_t f; fido_opt_t uv = assert->uv; @@ -127,7 +127,7 @@ fido_dev_get_assert_tx(fido_dev_t *dev, if (pin != NULL || (uv == FIDO_OPT_TRUE && fido_dev_supports_permissions(dev))) { if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh, - pin, assert->rp_id, &argv[5], &argv[6])) != FIDO_OK) { + pin, assert->rp_id, &argv[5], &argv[6], ms)) != FIDO_OK) { fido_log_debug("%s: cbor_add_uv_params", __func__); goto fail; } @@ -144,7 +144,7 @@ fido_dev_get_assert_tx(fido_dev_t *dev, /* frame and transmit */ if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; @@ -159,52 +159,61 @@ fail: } static int -fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) +fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; fido_assert_reset_rx(assert); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } /* start with room for a single assertion */ - if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) - return (FIDO_ERR_INTERNAL); - + if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } assert->stmt_len = 0; assert->stmt_cnt = 1; /* adjust as needed */ - if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert, + if ((r = cbor_parse_reply(msg, (size_t)msglen, assert, adjust_assert_count)) != FIDO_OK) { fido_log_debug("%s: adjust_assert_count", __func__); - return (r); + goto out; } /* parse the first assertion */ - if ((r = cbor_parse_reply(reply, (size_t)reply_len, - &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { + if ((r = cbor_parse_reply(msg, (size_t)msglen, &assert->stmt[0], + parse_assert_reply)) != FIDO_OK) { fido_log_debug("%s: parse_assert_reply", __func__); - return (r); + goto out; } + assert->stmt_len = 1; - assert->stmt_len++; + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); - return (FIDO_OK); + return (r); } static int -fido_get_next_assert_tx(fido_dev_t *dev) +fido_get_next_assert_tx(fido_dev_t *dev, int *ms) { const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT }; - if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) { + if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) { fido_log_debug("%s: fido_tx", __func__); return (FIDO_ERR_TX); } @@ -213,46 +222,57 @@ fido_get_next_assert_tx(fido_dev_t *dev) } static int -fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) +fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; + + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } /* sanity check */ if (assert->stmt_len >= assert->stmt_cnt) { fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__, assert->stmt_len, assert->stmt_cnt); - return (FIDO_ERR_INTERNAL); + r = FIDO_ERR_INTERNAL; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, + if ((r = cbor_parse_reply(msg, (size_t)msglen, &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { fido_log_debug("%s: parse_assert_reply", __func__); - return (r); + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } static int fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert, - const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms) + const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms) { int r; - if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK || + if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin, + ms)) != FIDO_OK || (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK) return (r); while (assert->stmt_len < assert->stmt_cnt) { - if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK || + if ((r = fido_get_next_assert_tx(dev, ms)) != FIDO_OK || (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK) return (r); assert->stmt_len++; @@ -286,11 +306,12 @@ fido_dev_get_assert(fido_dev_t *dev, fid { fido_blob_t *ecdh = NULL; es256_pk_t *pk = NULL; + int ms = dev->timeout_ms; int r; #ifdef USE_WINHELLO if (dev->flags & FIDO_DEV_WINHELLO) - return (fido_winhello_get_assert(dev, assert, pin)); + return (fido_winhello_get_assert(dev, assert, pin, ms)); #endif if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { @@ -302,19 +323,19 @@ fido_dev_get_assert(fido_dev_t *dev, fid if (fido_dev_is_fido2(dev) == false) { if (pin != NULL || assert->ext.mask != 0) return (FIDO_ERR_UNSUPPORTED_OPTION); - return (u2f_authenticate(dev, assert, -1)); + return (u2f_authenticate(dev, assert, &ms)); } if (pin != NULL || (assert->uv == FIDO_OPT_TRUE && fido_dev_supports_permissions(dev)) || (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) { - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } } - r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1); + r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, &ms); if (r == FIDO_OK && (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) if (decrypt_hmac_secrets(dev, assert, ecdh) < 0) { fido_log_debug("%s: decrypt_hmac_secrets", __func__); @@ -364,169 +385,107 @@ check_extensions(int authdata_ext, int e return (0); } -int -fido_get_signed_hash(int cose_alg, fido_blob_t *dgst, - const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor) +static int +get_es256_hash(fido_blob_t *dgst, const fido_blob_t *clientdata, + const fido_blob_t *authdata) { - cbor_item_t *item = NULL; - unsigned char *authdata_ptr = NULL; - size_t authdata_len; - struct cbor_load_result cbor; - SHA256_CTX ctx; - int ok = -1; + const EVP_MD *md; + EVP_MD_CTX *ctx = NULL; - if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, - &cbor)) == NULL || cbor_isa_bytestring(item) == false || - cbor_bytestring_is_definite(item) == false) { - fido_log_debug("%s: authdata", __func__); - goto fail; + if (dgst->len < SHA256_DIGEST_LENGTH || + (md = EVP_sha256()) == NULL || + (ctx = EVP_MD_CTX_new()) == NULL || + EVP_DigestInit_ex(ctx, md, NULL) != 1 || + EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 || + EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 || + EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) { + EVP_MD_CTX_free(ctx); + return (-1); } + dgst->len = SHA256_DIGEST_LENGTH; - authdata_ptr = cbor_bytestring_handle(item); - authdata_len = cbor_bytestring_length(item); - - if (cose_alg != COSE_EDDSA) { - if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || - SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 || - SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || - SHA256_Final(dgst->ptr, &ctx) == 0) { - fido_log_debug("%s: sha256", __func__); - goto fail; - } - dgst->len = SHA256_DIGEST_LENGTH; - } else { - if (SIZE_MAX - authdata_len < clientdata->len || - dgst->len < authdata_len + clientdata->len) { - fido_log_debug("%s: memcpy", __func__); - goto fail; - } - memcpy(dgst->ptr, authdata_ptr, authdata_len); - memcpy(dgst->ptr + authdata_len, clientdata->ptr, - clientdata->len); - dgst->len = authdata_len + clientdata->len; - } + EVP_MD_CTX_free(ctx); - ok = 0; -fail: - if (item != NULL) - cbor_decref(&item); - - return (ok); + return (0); } -int -fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk, - const fido_blob_t *sig) +static int +get_es384_hash(fido_blob_t *dgst, const fido_blob_t *clientdata, + const fido_blob_t *authdata) { - EVP_PKEY *pkey = NULL; - EC_KEY *ec = NULL; - int ok = -1; - - /* ECDSA_verify needs ints */ - if (dgst->len > INT_MAX || sig->len > INT_MAX) { - fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, - dgst->len, sig->len); - return (-1); - } - - if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL || - (ec = __UNCONST(EVP_PKEY_get0_EC_KEY(pkey))) == NULL) { - fido_log_debug("%s: pk -> ec", __func__); - goto fail; - } + const EVP_MD *md; + EVP_MD_CTX *ctx = NULL; - if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, - (int)sig->len, ec) != 1) { - fido_log_debug("%s: ECDSA_verify", __func__); - goto fail; + if (dgst->len < SHA384_DIGEST_LENGTH || + (md = EVP_sha384()) == NULL || + (ctx = EVP_MD_CTX_new()) == NULL || + EVP_DigestInit_ex(ctx, md, NULL) != 1 || + EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 || + EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 || + EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) { + EVP_MD_CTX_free(ctx); + return (-1); } + dgst->len = SHA384_DIGEST_LENGTH; - ok = 0; -fail: - if (pkey != NULL) - EVP_PKEY_free(pkey); + EVP_MD_CTX_free(ctx); - return (ok); + return (0); } -int -fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk, - const fido_blob_t *sig) +static int +get_eddsa_hash(fido_blob_t *dgst, const fido_blob_t *clientdata, + const fido_blob_t *authdata) { - EVP_PKEY *pkey = NULL; - RSA *rsa = NULL; - int ok = -1; - - /* RSA_verify needs unsigned ints */ - if (dgst->len > UINT_MAX || sig->len > UINT_MAX) { - fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, - dgst->len, sig->len); + if (SIZE_MAX - authdata->len < clientdata->len || + dgst->len < authdata->len + clientdata->len) return (-1); - } - - if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL || - (rsa = __UNCONST(EVP_PKEY_get0_RSA(pkey))) == NULL) { - fido_log_debug("%s: pk -> ec", __func__); - goto fail; - } - if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr, - (unsigned int)sig->len, rsa) != 1) { - fido_log_debug("%s: RSA_verify", __func__); - goto fail; - } - - ok = 0; -fail: - if (pkey != NULL) - EVP_PKEY_free(pkey); + memcpy(dgst->ptr, authdata->ptr, authdata->len); + memcpy(dgst->ptr + authdata->len, clientdata->ptr, clientdata->len); + dgst->len = authdata->len + clientdata->len; - return (ok); + return (0); } int -fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk, - const fido_blob_t *sig) +fido_get_signed_hash(int cose_alg, fido_blob_t *dgst, + const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor) { - EVP_PKEY *pkey = NULL; - EVP_MD_CTX *mdctx = NULL; - int ok = -1; - - /* EVP_DigestVerify needs ints */ - if (dgst->len > INT_MAX || sig->len > INT_MAX) { - fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, - dgst->len, sig->len); - return (-1); - } + cbor_item_t *item = NULL; + fido_blob_t authdata; + struct cbor_load_result cbor; + int ok = -1; - if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { - fido_log_debug("%s: pk -> pkey", __func__); - goto fail; - } + fido_log_debug("%s: cose_alg=%d", __func__, cose_alg); - if ((mdctx = EVP_MD_CTX_new()) == NULL) { - fido_log_debug("%s: EVP_MD_CTX_new", __func__); - goto fail; - } - - if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) { - fido_log_debug("%s: EVP_DigestVerifyInit", __func__); + if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, + &cbor)) == NULL || cbor_isa_bytestring(item) == false || + cbor_bytestring_is_definite(item) == false) { + fido_log_debug("%s: authdata", __func__); goto fail; } + authdata.ptr = cbor_bytestring_handle(item); + authdata.len = cbor_bytestring_length(item); - if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr, - dgst->len) != 1) { - fido_log_debug("%s: EVP_DigestVerify", __func__); - goto fail; + switch (cose_alg) { + case COSE_ES256: + case COSE_RS256: + ok = get_es256_hash(dgst, clientdata, &authdata); + break; + case COSE_ES384: + ok = get_es384_hash(dgst, clientdata, &authdata); + break; + case COSE_EDDSA: + ok = get_eddsa_hash(dgst, clientdata, &authdata); + break; + default: + fido_log_debug("%s: unknown cose_alg", __func__); + break; } - - ok = 0; fail: - if (mdctx != NULL) - EVP_MD_CTX_free(mdctx); - - if (pkey != NULL) - EVP_PKEY_free(pkey); + if (item != NULL) + cbor_decref(&item); return (ok); } @@ -589,13 +548,16 @@ fido_assert_verify(const fido_assert_t * switch (cose_alg) { case COSE_ES256: - ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig); + ok = es256_pk_verify_sig(&dgst, pk, &stmt->sig); + break; + case COSE_ES384: + ok = es384_pk_verify_sig(&dgst, pk, &stmt->sig); break; case COSE_RS256: - ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig); + ok = rs256_pk_verify_sig(&dgst, pk, &stmt->sig); break; case COSE_EDDSA: - ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig); + ok = eddsa_pk_verify_sig(&dgst, pk, &stmt->sig); break; default: fido_log_debug("%s: unsupported cose_alg %d", __func__, @@ -711,7 +673,15 @@ fail: free(id.ptr); return (r); +} +int +fido_assert_empty_allow_list(fido_assert_t *assert) +{ + fido_free_blob_array(&assert->allow_list); + memset(&assert->allow_list, 0, sizeof(assert->allow_list)); + + return (FIDO_OK); } int @@ -778,15 +748,15 @@ fido_assert_reset_tx(fido_assert_t *asse fido_blob_reset(&assert->cd); fido_blob_reset(&assert->cdh); fido_blob_reset(&assert->ext.hmac_salt); - fido_free_blob_array(&assert->allow_list); + fido_assert_empty_allow_list(assert); memset(&assert->ext, 0, sizeof(assert->ext)); - memset(&assert->allow_list, 0, sizeof(assert->allow_list)); assert->rp_id = NULL; assert->up = FIDO_OPT_OMIT; assert->uv = FIDO_OPT_OMIT; } -static void fido_assert_reset_extattr(fido_assert_extattr_t *ext) +static void +fido_assert_reset_extattr(fido_assert_extattr_t *ext) { fido_blob_reset(&ext->hmac_secret_enc); fido_blob_reset(&ext->blob); Index: src/external/bsd/libfido2/dist/src/cred.c diff -u src/external/bsd/libfido2/dist/src/cred.c:1.2 src/external/bsd/libfido2/dist/src/cred.c:1.3 --- src/external/bsd/libfido2/dist/src/cred.c:1.2 Mon May 8 19:45:52 2023 +++ src/external/bsd/libfido2/dist/src/cred.c Fri Aug 11 19:02:08 2023 @@ -1,7 +1,8 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause */ #include <openssl/sha.h> @@ -10,6 +11,10 @@ #include "fido.h" #include "fido/es256.h" +#ifndef FIDO_MAXMSG_CRED +#define FIDO_MAXMSG_CRED 4096 +#endif + static int parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) { @@ -43,7 +48,8 @@ parse_makecred_reply(const cbor_item_t * } static int -fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin) +fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin, + int *ms) { fido_blob_t f; fido_blob_t *ecdh = NULL; @@ -92,12 +98,12 @@ fido_dev_make_cred_tx(fido_dev_t *dev, f /* user verification */ if (pin != NULL || (uv == FIDO_OPT_TRUE && fido_dev_supports_permissions(dev))) { - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh, - pin, cred->rp.id, &argv[7], &argv[8])) != FIDO_OK) { + pin, cred->rp.id, &argv[7], &argv[8], ms)) != FIDO_OK) { fido_log_debug("%s: cbor_add_uv_params", __func__); goto fail; } @@ -114,7 +120,7 @@ fido_dev_make_cred_tx(fido_dev_t *dev, f /* framing and transmission */ if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; @@ -131,42 +137,55 @@ fail: } static int -fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms) +fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int *ms) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *reply; + int reply_len; + int r; fido_cred_reset_rx(cred); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), + if ((reply = malloc(FIDO_MAXMSG_CRED)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto fail; + } + + if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, reply, FIDO_MAXMSG_CRED, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto fail; } if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred, parse_makecred_reply)) != FIDO_OK) { fido_log_debug("%s: parse_makecred_reply", __func__); - return (r); + goto fail; } if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) || fido_blob_is_empty(&cred->attcred.id)) { - fido_cred_reset_rx(cred); - return (FIDO_ERR_INVALID_CBOR); + r = FIDO_ERR_INVALID_CBOR; + goto fail; } - return (FIDO_OK); + r = FIDO_OK; +fail: + free(reply); + + if (r != FIDO_OK) + fido_cred_reset_rx(cred); + + return (r); } static int fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, - int ms) + int *ms) { int r; - if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK || + if ((r = fido_dev_make_cred_tx(dev, cred, pin, ms)) != FIDO_OK || (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK) return (r); @@ -176,18 +195,20 @@ fido_dev_make_cred_wait(fido_dev_t *dev, int fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) { + int ms = dev->timeout_ms; + #ifdef USE_WINHELLO if (dev->flags & FIDO_DEV_WINHELLO) - return (fido_winhello_make_cred(dev, cred, pin)); + return (fido_winhello_make_cred(dev, cred, pin, ms)); #endif if (fido_dev_is_fido2(dev) == false) { if (pin != NULL || cred->rk == FIDO_OPT_TRUE || cred->ext.mask != 0) return (FIDO_ERR_UNSUPPORTED_OPTION); - return (u2f_register(dev, cred, -1)); + return (u2f_register(dev, cred, &ms)); } - return (fido_dev_make_cred_wait(dev, cred, pin, -1)); + return (fido_dev_make_cred_wait(dev, cred, pin, &ms)); } static int @@ -225,66 +246,85 @@ get_signed_hash_u2f(fido_blob_t *dgst, c size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id, const es256_pk_t *pk) { - const uint8_t zero = 0; - const uint8_t four = 4; /* uncompressed point */ - SHA256_CTX ctx; - - if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || - SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 || - SHA256_Update(&ctx, rp_id, rp_id_len) == 0 || - SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || - SHA256_Update(&ctx, id->ptr, id->len) == 0 || - SHA256_Update(&ctx, &four, sizeof(four)) == 0 || - SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 || - SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 || - SHA256_Final(dgst->ptr, &ctx) == 0) { + const uint8_t zero = 0; + const uint8_t four = 4; /* uncompressed point */ + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx = NULL; + int ok = -1; + + if (dgst->len < SHA256_DIGEST_LENGTH || + (md = EVP_sha256()) == NULL || + (ctx = EVP_MD_CTX_new()) == NULL || + EVP_DigestInit_ex(ctx, md, NULL) != 1 || + EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 || + EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 || + EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 || + EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 || + EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 || + EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 || + EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 || + EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) { fido_log_debug("%s: sha256", __func__); - return (-1); + goto fail; } + dgst->len = SHA256_DIGEST_LENGTH; - return (0); + ok = 0; +fail: + EVP_MD_CTX_free(ctx); + + return (ok); } static int -verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c, - const fido_blob_t *sig) +verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt) { BIO *rawcert = NULL; X509 *cert = NULL; EVP_PKEY *pkey = NULL; - EC_KEY *ec; int ok = -1; /* openssl needs ints */ - if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) { - fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu", - __func__, dgst->len, x5c->len, sig->len); + if (attstmt->x5c.len > INT_MAX) { + fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len); return (-1); } /* fetch key from x509 */ - if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL || + if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr, + (int)attstmt->x5c.len)) == NULL || (cert = d2i_X509_bio(rawcert, NULL)) == NULL || - (pkey = X509_get_pubkey(cert)) == NULL || - (ec = __UNCONST(EVP_PKEY_get0_EC_KEY(pkey))) == NULL) { + (pkey = X509_get_pubkey(cert)) == NULL) { fido_log_debug("%s: x509 key", __func__); goto fail; } - if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, - (int)sig->len, ec) != 1) { - fido_log_debug("%s: ECDSA_verify", __func__); - goto fail; + switch (attstmt->alg) { + case COSE_UNSPEC: + case COSE_ES256: + ok = es256_verify_sig(dgst, pkey, &attstmt->sig); + break; + case COSE_ES384: + ok = es384_verify_sig(dgst, pkey, &attstmt->sig); + break; + case COSE_RS256: + ok = rs256_verify_sig(dgst, pkey, &attstmt->sig); + break; + case COSE_RS1: + ok = rs1_verify_sig(dgst, pkey, &attstmt->sig); + break; + case COSE_EDDSA: + ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig); + break; + default: + fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg); + break; } - ok = 0; fail: - if (rawcert != NULL) - BIO_free(rawcert); - if (cert != NULL) - X509_free(cert); - if (pkey != NULL) - EVP_PKEY_free(pkey); + BIO_free(rawcert); + X509_free(cert); + EVP_PKEY_free(pkey); return (ok); } @@ -292,8 +332,9 @@ fail: int fido_cred_verify(const fido_cred_t *cred) { - unsigned char buf[SHA256_DIGEST_LENGTH]; + unsigned char buf[1024]; /* XXX */ fido_blob_t dgst; + int cose_alg; int r; dgst.ptr = buf; @@ -333,8 +374,11 @@ fido_cred_verify(const fido_cred_t *cred goto out; } + if ((cose_alg = cred->attstmt.alg) == COSE_UNSPEC) + cose_alg = COSE_ES256; /* backwards compat */ + if (!strcmp(cred->fmt, "packed")) { - if (fido_get_signed_hash(COSE_ES256, &dgst, &cred->cdh, + if (fido_get_signed_hash(cose_alg, &dgst, &cred->cdh, &cred->authdata_cbor) < 0) { fido_log_debug("%s: fido_get_signed_hash", __func__); r = FIDO_ERR_INTERNAL; @@ -348,14 +392,21 @@ fido_cred_verify(const fido_cred_t *cred r = FIDO_ERR_INTERNAL; goto out; } + } else if (!strcmp(cred->fmt, "tpm")) { + if (fido_get_signed_hash_tpm(&dgst, &cred->cdh, + &cred->authdata_raw, &cred->attstmt, &cred->attcred) < 0) { + fido_log_debug("%s: fido_get_signed_hash_tpm", __func__); + r = FIDO_ERR_INTERNAL; + goto out; + } } else { fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt); r = FIDO_ERR_INVALID_ARGUMENT; goto out; } - if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) { - fido_log_debug("%s: verify_sig", __func__); + if (verify_attstmt(&dgst, &cred->attstmt) < 0) { + fido_log_debug("%s: verify_attstmt", __func__); r = FIDO_ERR_INVALID_SIG; goto out; } @@ -435,15 +486,19 @@ fido_cred_verify_self(const fido_cred_t switch (cred->attcred.type) { case COSE_ES256: - ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256, + ok = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256, + &cred->attstmt.sig); + break; + case COSE_ES384: + ok = es384_pk_verify_sig(&dgst, &cred->attcred.pubkey.es384, &cred->attstmt.sig); break; case COSE_RS256: - ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256, + ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256, &cred->attstmt.sig); break; case COSE_EDDSA: - ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa, + ok = eddsa_pk_verify_sig(&dgst, &cred->attcred.pubkey.eddsa, &cred->attstmt.sig); break; default: @@ -482,6 +537,18 @@ fido_cred_clean_authdata(fido_cred_t *cr memset(&cred->attcred, 0, sizeof(cred->attcred)); } +static void +fido_cred_clean_attstmt(fido_attstmt_t *attstmt) +{ + fido_blob_reset(&attstmt->certinfo); + fido_blob_reset(&attstmt->pubarea); + fido_blob_reset(&attstmt->cbor); + fido_blob_reset(&attstmt->x5c); + fido_blob_reset(&attstmt->sig); + + memset(attstmt, 0, sizeof(*attstmt)); +} + void fido_cred_reset_tx(fido_cred_t *cred) { @@ -495,11 +562,10 @@ fido_cred_reset_tx(fido_cred_t *cred) free(cred->user.icon); free(cred->user.name); free(cred->user.display_name); - fido_free_blob_array(&cred->excl); + fido_cred_empty_exclude_list(cred); memset(&cred->rp, 0, sizeof(cred->rp)); memset(&cred->user, 0, sizeof(cred->user)); - memset(&cred->excl, 0, sizeof(cred->excl)); memset(&cred->ext, 0, sizeof(cred->ext)); cred->type = 0; @@ -513,8 +579,7 @@ fido_cred_reset_rx(fido_cred_t *cred) free(cred->fmt); cred->fmt = NULL; fido_cred_clean_authdata(cred); - fido_blob_reset(&cred->attstmt.x5c); - fido_blob_reset(&cred->attstmt.sig); + fido_cred_clean_attstmt(&cred->attstmt); fido_blob_reset(&cred->largeblob_key); } @@ -568,7 +633,6 @@ fail: fido_cred_clean_authdata(cred); return (r); - } int @@ -610,7 +674,6 @@ fail: fido_cred_clean_authdata(cred); return (r); - } int @@ -641,6 +704,39 @@ fido_cred_set_sig(fido_cred_t *cred, con } int +fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len) +{ + cbor_item_t *item = NULL; + struct cbor_load_result cbor; + int r = FIDO_ERR_INVALID_ARGUMENT; + + fido_cred_clean_attstmt(&cred->attstmt); + + if (ptr == NULL || len == 0) + goto fail; + + if ((item = cbor_load(ptr, len, &cbor)) == NULL) { + fido_log_debug("%s: cbor_load", __func__); + goto fail; + } + + if (cbor_decode_attstmt(item, &cred->attstmt) < 0) { + fido_log_debug("%s: cbor_decode_attstmt", __func__); + goto fail; + } + + r = FIDO_OK; +fail: + if (item != NULL) + cbor_decref(&item); + + if (r != FIDO_OK) + fido_cred_clean_attstmt(&cred->attstmt); + + return (r); +} + +int fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len) { fido_blob_t id_blob; @@ -669,6 +765,15 @@ fido_cred_exclude(fido_cred_t *cred, con } int +fido_cred_empty_exclude_list(fido_cred_t *cred) +{ + fido_free_blob_array(&cred->excl); + memset(&cred->excl, 0, sizeof(cred->excl)); + + return (FIDO_OK); +} + +int fido_cred_set_clientdata(fido_cred_t *cred, const unsigned char *data, size_t data_len) { @@ -834,6 +939,19 @@ fido_cred_set_prot(fido_cred_t *cred, in } int +fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len) +{ + if (len == 0) + cred->ext.mask &= ~FIDO_EXT_MINPINLEN; + else + cred->ext.mask |= FIDO_EXT_MINPINLEN; + + cred->ext.minpinlen = len; + + return (FIDO_OK); +} + +int fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len) { if (ptr == NULL || len == 0) @@ -856,7 +974,7 @@ fido_cred_set_fmt(fido_cred_t *cred, con return (FIDO_ERR_INVALID_ARGUMENT); if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f") && - strcmp(fmt, "none")) + strcmp(fmt, "none") && strcmp(fmt, "tpm")) return (FIDO_ERR_INVALID_ARGUMENT); if ((cred->fmt = strdup(fmt)) == NULL) @@ -868,8 +986,10 @@ fido_cred_set_fmt(fido_cred_t *cred, con int fido_cred_set_type(fido_cred_t *cred, int cose_alg) { - if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 && - cose_alg != COSE_EDDSA) || cred->type != 0) + if (cred->type != 0) + return (FIDO_ERR_INVALID_ARGUMENT); + if (cose_alg != COSE_ES256 && cose_alg != COSE_ES384 && + cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA) return (FIDO_ERR_INVALID_ARGUMENT); cred->type = cose_alg; @@ -956,6 +1076,18 @@ fido_cred_authdata_raw_len(const fido_cr } const unsigned char * +fido_cred_attstmt_ptr(const fido_cred_t *cred) +{ + return (cred->attstmt.cbor.ptr); +} + +size_t +fido_cred_attstmt_len(const fido_cred_t *cred) +{ + return (cred->attstmt.cbor.len); +} + +const unsigned char * fido_cred_pubkey_ptr(const fido_cred_t *cred) { const void *ptr; @@ -964,6 +1096,9 @@ fido_cred_pubkey_ptr(const fido_cred_t * case COSE_ES256: ptr = &cred->attcred.pubkey.es256; break; + case COSE_ES384: + ptr = &cred->attcred.pubkey.es384; + break; case COSE_RS256: ptr = &cred->attcred.pubkey.rs256; break; @@ -987,6 +1122,9 @@ fido_cred_pubkey_len(const fido_cred_t * case COSE_ES256: len = sizeof(cred->attcred.pubkey.es256); break; + case COSE_ES384: + len = sizeof(cred->attcred.pubkey.es384); + break; case COSE_RS256: len = sizeof(cred->attcred.pubkey.rs256); break; @@ -1031,6 +1169,12 @@ fido_cred_prot(const fido_cred_t *cred) return (cred->ext.prot); } +size_t +fido_cred_pin_minlen(const fido_cred_t *cred) +{ + return (cred->ext.minpinlen); +} + const char * fido_cred_fmt(const fido_cred_t *cred) { Index: src/external/bsd/libfido2/dist/src/hid_netbsd.c diff -u src/external/bsd/libfido2/dist/src/hid_netbsd.c:1.3 src/external/bsd/libfido2/dist/src/hid_netbsd.c:1.4 --- src/external/bsd/libfido2/dist/src/hid_netbsd.c:1.3 Thu Jun 17 08:53:43 2021 +++ src/external/bsd/libfido2/dist/src/hid_netbsd.c Fri Aug 11 19:02:08 2023 @@ -2,6 +2,7 @@ * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause */ #include <sys/types.h> Index: src/external/bsd/libfido2/dist/tools/util.c diff -u src/external/bsd/libfido2/dist/tools/util.c:1.3 src/external/bsd/libfido2/dist/tools/util.c:1.4 --- src/external/bsd/libfido2/dist/tools/util.c:1.3 Fri Sep 24 09:07:34 2021 +++ src/external/bsd/libfido2/dist/tools/util.c Fri Aug 11 19:02:08 2023 @@ -1,7 +1,8 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause */ #include <sys/types.h> @@ -13,6 +14,7 @@ #include <fido.h> #include <fido/es256.h> +#include <fido/es384.h> #include <fido/rs256.h> #include <fido/eddsa.h> @@ -245,7 +247,7 @@ fail: } int -write_ec_pubkey(FILE *f, const void *ptr, size_t len) +write_es256_pubkey(FILE *f, const void *ptr, size_t len) { EVP_PKEY *pkey = NULL; es256_pk_t *pk = NULL; @@ -282,6 +284,44 @@ fail: return (ok); } +int +write_es384_pubkey(FILE *f, const void *ptr, size_t len) +{ + EVP_PKEY *pkey = NULL; + es384_pk_t *pk = NULL; + int ok = -1; + + if ((pk = es384_pk_new()) == NULL) { + warnx("es384_pk_new"); + goto fail; + } + + if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) { + warnx("es384_pk_from_ptr"); + goto fail; + } + + if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) { + warnx("es384_pk_to_EVP_PKEY"); + goto fail; + } + + if (PEM_write_PUBKEY(f, pkey) == 0) { + warnx("PEM_write_PUBKEY"); + goto fail; + } + + ok = 0; +fail: + es384_pk_free(&pk); + + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + + return (ok); +} + RSA * read_rsa_pubkey(const char *path) { @@ -426,16 +466,24 @@ print_cred(FILE *out_f, int type, const fprintf(out_f, "%s\n", id); - if (type == COSE_ES256) { - write_ec_pubkey(out_f, fido_cred_pubkey_ptr(cred), + switch (type) { + case COSE_ES256: + write_es256_pubkey(out_f, fido_cred_pubkey_ptr(cred), + fido_cred_pubkey_len(cred)); + break; + case COSE_ES384: + write_es384_pubkey(out_f, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); - } else if (type == COSE_RS256) { + break; + case COSE_RS256: write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); - } else if (type == COSE_EDDSA) { + break; + case COSE_EDDSA: write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); - } else { + break; + default: errx(1, "print_cred: unknown type"); } @@ -447,6 +495,8 @@ cose_type(const char *str, int *type) { if (strcmp(str, "es256") == 0) *type = COSE_ES256; + else if (strcmp(str, "es384") == 0) + *type = COSE_ES384; else if (strcmp(str, "rs256") == 0) *type = COSE_RS256; else if (strcmp(str, "eddsa") == 0) @@ -463,12 +513,14 @@ const char * cose_string(int type) { switch (type) { - case COSE_EDDSA: - return ("eddsa"); case COSE_ES256: return ("es256"); + case COSE_ES384: + return ("es384"); case COSE_RS256: return ("rs256"); + case COSE_EDDSA: + return ("eddsa"); default: return ("unknown"); } Index: src/external/bsd/libfido2/lib/Makefile diff -u src/external/bsd/libfido2/lib/Makefile:1.10 src/external/bsd/libfido2/lib/Makefile:1.11 --- src/external/bsd/libfido2/lib/Makefile:1.10 Sat May 13 09:04:03 2023 +++ src/external/bsd/libfido2/lib/Makefile Fri Aug 11 19:02:08 2023 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.10 2023/05/13 13:04:03 riastradh Exp $ +# $NetBSD: Makefile,v 1.11 2023/08/11 23:02:08 christos Exp $ NOLINT= .include <bsd.own.mk> @@ -32,6 +32,7 @@ ecdh.c \ eddsa.c \ err.c \ es256.c \ +es384.c \ hid.c \ hid_netbsd.c \ hid_unix.c \ @@ -43,7 +44,12 @@ log.c \ pin.c \ random.c \ reset.c \ +rs1.c \ rs256.c \ +time.c \ +tpm.c \ +touch.c \ +types.c \ u2f.c SRCS+= \ @@ -60,6 +66,7 @@ fido/credman.h \ fido/eddsa.h \ fido/err.h \ fido/es256.h \ +fido/es384.h \ fido/param.h \ fido/rs256.h \ fido/types.h @@ -69,6 +76,7 @@ INCSDIR=/usr/include MAN+= \ eddsa_pk_new.3 \ es256_pk_new.3 \ +es384_pk_new.3 \ fido_assert_allow_cred.3 \ fido_assert_new.3 \ fido_assert_set_authdata.3 \ @@ -96,7 +104,7 @@ fido_init.3 \ fido_strerr.3 \ rs256_pk_new.3 -SHLIB_MAJOR=4 +SHLIB_MAJOR=5 SHLIB_MINOR=0 .SUFFIXES: .in @@ -118,6 +126,7 @@ COPTS.cred.c+=-Wno-error=deprecated-decl COPTS.ecdh.c+=-Wno-error=deprecated-declarations COPTS.ecdh.c+=-Wno-error=pointer-sign COPTS.es256.c+=-Wno-error=deprecated-declarations +COPTS.es384.c+=-Wno-error=deprecated-declarations COPTS.rs256.c+=-Wno-error=deprecated-declarations .include <bsd.lib.mk>