summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYicheng Li <yichengli@chromium.org>2020-05-12 11:10:11 -0700
committerCommit Bot <commit-bot@chromium.org>2020-07-03 21:01:33 +0000
commit8855605441c69ace829d4acbe584df4f8bf140a5 (patch)
tree221ef35f05e9b56e2c5887215df5b4e113289532
parent5f921bc00db9f9b1c8cee87cceb420ab46af857b (diff)
downloadchrome-ec-8855605441c69ace829d4acbe584df4f8bf140a5.tar.gz
u2f: Add support for versioned key handles
Support generating and signing versioned key handles in addition to non-versioned ones. BUG=b:144861739 TEST=used webauthntool to verify that KH generated by old cr50 firmware can be signed with this firmware TEST=used webauthntool to verify that non-versioned KH generated by this firmware can be signed by old cr50 firmware (This and the first TEST proves that non-versioned path is the same as old firmware.) TEST=used webauthntool to verify that non-versioned KH generated by this firmware can be signed by this firmware TEST=used webauthntool to verify that versioned KH generated by this firmware can be signed by this firmware TEST=test_that --board=nami <IP> firmware_Cr50U2fCommands Cq-Depend: chromium:2280394 Change-Id: Idf413a1a3e6c35a3e7e651faaa91fe2894b805db Signed-off-by: Yicheng Li <yichengli@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2202949 Reviewed-by: Louis Collard <louiscollard@chromium.org>
-rw-r--r--board/cr50/u2f.c45
-rw-r--r--common/u2f.c203
-rw-r--r--include/u2f.h33
-rw-r--r--include/u2f_impl.h34
4 files changed, 246 insertions, 69 deletions
diff --git a/board/cr50/u2f.c b/board/cr50/u2f.c
index b9ad2de20a..3e6e0c3a69 100644
--- a/board/cr50/u2f.c
+++ b/board/cr50/u2f.c
@@ -177,10 +177,9 @@ int u2f_origin_key(const uint8_t *seed, p256_int *d)
(const uint8_t *)tmp) == 0;
}
-int u2f_origin_user_keyhandle(const uint8_t *origin,
- const uint8_t *user,
+int u2f_origin_user_keyhandle(const uint8_t *origin, const uint8_t *user,
const uint8_t *origin_seed,
- uint8_t *key_handle)
+ struct u2f_key_handle *key_handle)
{
LITE_HMAC_CTX ctx;
struct u2f_state *state = get_state();
@@ -188,23 +187,44 @@ int u2f_origin_user_keyhandle(const uint8_t *origin,
if (!state)
return EC_ERROR_UNKNOWN;
- memcpy(key_handle, origin_seed, P256_NBYTES);
+ memcpy(key_handle->origin_seed, origin_seed, P256_NBYTES);
DCRYPTO_HMAC_SHA256_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE);
HASH_update(&ctx.hash, origin, P256_NBYTES);
HASH_update(&ctx.hash, user, P256_NBYTES);
HASH_update(&ctx.hash, origin_seed, P256_NBYTES);
- memcpy(key_handle + P256_NBYTES,
- DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE);
+ memcpy(key_handle->hmac, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE);
return EC_SUCCESS;
}
-int u2f_origin_user_keypair(const uint8_t *key_handle,
- p256_int *d,
- p256_int *pk_x,
- p256_int *pk_y)
+int u2f_origin_user_versioned_keyhandle(
+ const uint8_t *origin, const uint8_t *user, const uint8_t *origin_seed,
+ uint8_t version, struct u2f_versioned_key_handle *key_handle)
+{
+ LITE_HMAC_CTX ctx;
+ struct u2f_state *state = get_state();
+
+ if (!state)
+ return EC_ERROR_UNKNOWN;
+
+ key_handle->version = version;
+ memcpy(key_handle->origin_seed, origin_seed, P256_NBYTES);
+
+ DCRYPTO_HMAC_SHA256_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE);
+ HASH_update(&ctx.hash, origin, P256_NBYTES);
+ HASH_update(&ctx.hash, user, P256_NBYTES);
+ HASH_update(&ctx.hash, origin_seed, P256_NBYTES);
+ HASH_update(&ctx.hash, &version, sizeof(key_handle->version));
+
+ memcpy(key_handle->hmac, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE);
+
+ return EC_SUCCESS;
+}
+
+int u2f_origin_user_keypair(const uint8_t *key_handle, size_t key_handle_size,
+ p256_int *d, p256_int *pk_x, p256_int *pk_y)
{
uint32_t dev_salt[P256_NDIGITS];
uint8_t key_seed[P256_NBYTES];
@@ -221,9 +241,8 @@ int u2f_origin_user_keypair(const uint8_t *key_handle,
hmac_drbg_init(&drbg, state->salt_kh, P256_NBYTES, dev_salt,
P256_NBYTES, NULL, 0);
- hmac_drbg_generate(&drbg,
- key_seed, sizeof(key_seed),
- key_handle, P256_NBYTES * 2);
+ hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed), key_handle,
+ key_handle_size);
if (!DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, key_seed))
return EC_ERROR_TRY_AGAIN;
diff --git a/common/u2f.c b/common/u2f.c
index 79ad69c01a..27e1685696 100644
--- a/common/u2f.c
+++ b/common/u2f.c
@@ -79,20 +79,59 @@ int g2f_attestation_cert(uint8_t *buf)
G2F_ATTESTATION_CERT_MAX_LEN);
}
+static void copy_kh_pubkey_out(p256_int *opk_x, p256_int *opk_y,
+ struct u2f_key_handle *kh, void *buf)
+{
+ struct u2f_generate_resp *resp = buf;
+
+ /* Insert origin-specific public keys into the response */
+ p256_to_bin(opk_x, resp->pubKey.x); /* endianness */
+ p256_to_bin(opk_y, resp->pubKey.y); /* endianness */
+
+ resp->pubKey.pointFormat = U2F_POINT_UNCOMPRESSED;
+
+ /* Copy key handle to response. */
+ memcpy(&resp->keyHandle, kh, sizeof(struct u2f_key_handle));
+}
+
+static void copy_versioned_kh_pubkey_out(p256_int *opk_x, p256_int *opk_y,
+ struct u2f_versioned_key_handle *kh,
+ void *buf)
+{
+ struct u2f_generate_versioned_resp *resp = buf;
+
+ /* Insert origin-specific public keys into the response */
+ p256_to_bin(opk_x, resp->pubKey.x); /* endianness */
+ p256_to_bin(opk_y, resp->pubKey.y); /* endianness */
+
+ resp->pubKey.pointFormat = U2F_POINT_UNCOMPRESSED;
+
+ /* Copy key handle to response. */
+ memcpy(&resp->keyHandle, kh, sizeof(struct u2f_versioned_key_handle));
+}
+
/* U2F GENERATE command */
static enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, void *buf,
size_t input_size, size_t *response_size)
{
struct u2f_generate_req *req = buf;
- struct u2f_generate_resp *resp;
+ uint8_t kh_version =
+ (req->flags & U2F_UV_ENABLED_KH) ? U2F_KH_VERSION_1 : 0;
- /* Origin keypair */
- uint8_t od_seed[P256_NBYTES];
+ /* Origin keypair. Must be word aligned, otherwise TRNG will crash. */
+ uint8_t od_seed[P256_NBYTES] __aligned(4);
p256_int od, opk_x, opk_y;
- /* Key handle */
- uint8_t kh[U2F_FIXED_KH_SIZE];
+ /* Buffer for generating key handle. */
+ union {
+ struct u2f_key_handle kh;
+ struct u2f_versioned_key_handle vkh;
+ } kh_buf;
+ size_t kh_size = (kh_version == 0) ? sizeof(kh_buf.kh) :
+ sizeof(kh_buf.vkh);
+ /* Whether key handle generation succeeded */
+ int generate_kh_rc;
/* Whether keypair generation succeeded */
int generate_keypair_rc;
@@ -100,10 +139,18 @@ static enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, void *buf,
*response_size = 0;
- if (input_size != sizeof(struct u2f_generate_req) ||
- response_buf_size < sizeof(struct u2f_generate_resp))
+ if (input_size != sizeof(struct u2f_generate_req))
return VENDOR_RC_BOGUS_ARGS;
+ if (kh_version == 0) {
+ if (response_buf_size < sizeof(struct u2f_generate_resp))
+ return VENDOR_RC_BOGUS_ARGS;
+ } else {
+ if (response_buf_size <
+ sizeof(struct u2f_generate_versioned_resp))
+ return VENDOR_RC_BOGUS_ARGS;
+ }
+
/* Maybe enforce user presence, w/ optional consume */
if (pop_check_presence(req->flags & G2F_CONSUME) != POP_TOUCH_YES &&
(req->flags & U2F_AUTH_FLAG_TUP) != 0)
@@ -114,12 +161,20 @@ static enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, void *buf,
if (!DCRYPTO_ladder_random(&od_seed))
return VENDOR_RC_INTERNAL_ERROR;
- if (u2f_origin_user_keyhandle(req->appId, req->userSecret,
- od_seed, kh) != EC_SUCCESS)
+ if (kh_version == 0)
+ generate_kh_rc = u2f_origin_user_keyhandle(
+ req->appId, req->userSecret, od_seed,
+ &kh_buf.kh);
+ else
+ generate_kh_rc = u2f_origin_user_versioned_keyhandle(
+ req->appId, req->userSecret, od_seed,
+ kh_version, &kh_buf.vkh);
+
+ if (generate_kh_rc != EC_SUCCESS)
return VENDOR_RC_INTERNAL_ERROR;
- generate_keypair_rc =
- u2f_origin_user_keypair(kh, &od, &opk_x, &opk_y);
+ generate_keypair_rc = u2f_origin_user_keypair(
+ (uint8_t *)&kh_buf, kh_size, &od, &opk_x, &opk_y);
} while (generate_keypair_rc == EC_ERROR_TRY_AGAIN);
if (generate_keypair_rc != EC_SUCCESS)
@@ -129,31 +184,27 @@ static enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, void *buf,
* From this point: the request 'req' content is invalid as it is
* overridden by the response we are building in the same buffer.
*/
- resp = buf;
-
- *response_size = sizeof(*resp);
-
- /* Insert origin-specific public keys into the response */
- p256_to_bin(&opk_x, resp->pubKey.x); /* endianness */
- p256_to_bin(&opk_y, resp->pubKey.y); /* endianness */
-
- resp->pubKey.pointFormat = U2F_POINT_UNCOMPRESSED;
-
- /* Copy key handle to response. */
- memcpy(resp->keyHandle, kh, sizeof(kh));
+ if (kh_version == 0) {
+ copy_kh_pubkey_out(&opk_x, &opk_y, &kh_buf.kh, buf);
+ *response_size = sizeof(struct u2f_generate_resp);
+ } else {
+ copy_versioned_kh_pubkey_out(&opk_x, &opk_y, &kh_buf.vkh, buf);
+ *response_size = sizeof(struct u2f_generate_versioned_resp);
+ }
return VENDOR_RC_SUCCESS;
}
DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_GENERATE, u2f_generate);
-static int verify_kh_pubkey(const uint8_t *key_handle,
+static int verify_kh_pubkey(const uint8_t *key_handle, size_t key_handle_size,
const struct u2f_ec_point *public_key, int *matches)
{
int rc;
struct u2f_ec_point kh_pubkey;
p256_int od, opk_x, opk_y;
- rc = u2f_origin_user_keypair(key_handle, &od, &opk_x, &opk_y);
+ rc = u2f_origin_user_keypair(key_handle, key_handle_size, &od, &opk_x,
+ &opk_y);
if (rc != EC_SUCCESS)
return rc;
@@ -169,11 +220,36 @@ static int verify_kh_pubkey(const uint8_t *key_handle,
}
static int verify_kh_owned(const uint8_t *user_secret, const uint8_t *app_id,
- const uint8_t *key_handle, int *owned)
+ const struct u2f_key_handle *key_handle, int *owned)
+{
+ int rc;
+ /* Re-created key handle. */
+ struct u2f_key_handle recreated_kh;
+
+ /*
+ * Re-create the key handle and compare against that which
+ * was provided. This allows us to verify that the key handle
+ * is owned by this combination of device, current user and app_id.
+ */
+
+ rc = u2f_origin_user_keyhandle(app_id, user_secret,
+ key_handle->origin_seed, &recreated_kh);
+
+ if (rc == EC_SUCCESS)
+ *owned = safe_memcmp(&recreated_kh, key_handle,
+ sizeof(recreated_kh)) == 0;
+
+ return rc;
+}
+
+static int
+verify_versioned_kh_owned(const uint8_t *user_secret, const uint8_t *app_id,
+ const struct u2f_versioned_key_handle *key_handle,
+ int *owned)
{
int rc;
/* Re-created key handle. */
- uint8_t recreated_kh[KH_LEN];
+ struct u2f_versioned_key_handle recreated_kh;
/*
* Re-create the key handle and compare against that which
@@ -181,11 +257,14 @@ static int verify_kh_owned(const uint8_t *user_secret, const uint8_t *app_id,
* is owned by this combination of device, current user and app_id.
*/
- rc = u2f_origin_user_keyhandle(app_id, user_secret, key_handle,
- recreated_kh);
+ rc = u2f_origin_user_versioned_keyhandle(app_id, user_secret,
+ key_handle->origin_seed,
+ key_handle->version,
+ &recreated_kh);
if (rc == EC_SUCCESS)
- *owned = safe_memcmp(recreated_kh, key_handle, KH_LEN) == 0;
+ *owned = safe_memcmp(&recreated_kh, key_handle,
+ sizeof(recreated_kh)) == 0;
return rc;
}
@@ -219,12 +298,15 @@ static enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf,
size_t input_size, size_t *response_size)
{
const struct u2f_sign_req *req = buf;
+ const struct u2f_sign_versioned_req *req_versioned = buf;
+ const uint8_t *key_handle, *hash;
+ uint8_t flags;
struct u2f_sign_resp *resp;
struct drbg_ctx ctx;
/* Whether the key handle is owned by this device. */
- int kh_owned;
+ int kh_owned = 0;
/* Origin private key. */
uint8_t legacy_origin_seed[SHA256_DIGEST_SIZE];
@@ -236,18 +318,47 @@ static enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf,
/* Whether the key handle uses the legacy key derivation scheme. */
int legacy_kh = 0;
+ /* Version of KH; 0 if KH is not versioned. */
+ uint8_t version;
+
+ /* Size of KH in bytes. */
+ size_t kh_size;
+
+ int verify_owned_rc;
+
/* Response is smaller than request, so no need to check this. */
*response_size = 0;
- if (input_size != sizeof(struct u2f_sign_req))
+ if (input_size == sizeof(struct u2f_sign_req)) {
+ version = 0;
+ key_handle = (uint8_t *)&req->keyHandle;
+ hash = req->hash;
+ flags = req->flags;
+ kh_size = sizeof(struct u2f_key_handle);
+ verify_owned_rc = verify_kh_owned(req->userSecret, req->appId,
+ &req->keyHandle, &kh_owned);
+ } else if (input_size == sizeof(struct u2f_sign_versioned_req)) {
+ version = req_versioned->keyHandle.version;
+ key_handle = (uint8_t *)&req->keyHandle;
+ hash = req_versioned->hash;
+ flags = req_versioned->flags;
+ kh_size = sizeof(struct u2f_versioned_key_handle);
+ verify_owned_rc = verify_versioned_kh_owned(
+ req_versioned->userSecret, req_versioned->appId,
+ &req_versioned->keyHandle, &kh_owned);
+ } else {
return VENDOR_RC_BOGUS_ARGS;
+ }
- if (verify_kh_owned(req->userSecret, req->appId, req->keyHandle,
- &kh_owned) != EC_SUCCESS)
+ if (verify_owned_rc != EC_SUCCESS)
return VENDOR_RC_INTERNAL_ERROR;
if (!kh_owned) {
- if ((req->flags & SIGN_LEGACY_KH) == 0)
+ if ((flags & SIGN_LEGACY_KH) == 0)
+ return VENDOR_RC_PASSWORD_REQUIRED;
+
+ /* Legacy KH must be version 0. */
+ if (version != 0)
return VENDOR_RC_PASSWORD_REQUIRED;
/*
@@ -255,7 +366,8 @@ static enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf,
* but may be a valid legacy key handle, and we have been asked
* to sign legacy key handles.
*/
- if (verify_legacy_kh_owned(req->appId, req->keyHandle,
+ if (verify_legacy_kh_owned(req->appId,
+ (uint8_t *)&req->keyHandle,
legacy_origin_seed))
legacy_kh = 1;
else
@@ -263,11 +375,11 @@ static enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf,
}
/* We might not actually need to sign anything. */
- if (req->flags == U2F_AUTH_CHECK_ONLY)
+ if ((flags & U2F_AUTH_CHECK_ONLY) == U2F_AUTH_CHECK_ONLY)
return VENDOR_RC_SUCCESS;
/* Always enforce user presence, with optional consume. */
- if (pop_check_presence(req->flags & G2F_CONSUME) != POP_TOUCH_YES)
+ if (pop_check_presence(flags & G2F_CONSUME) != POP_TOUCH_YES)
return VENDOR_RC_NOT_ALLOWED;
/* Re-create origin-specific key. */
@@ -275,13 +387,13 @@ static enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf,
if (u2f_origin_key(legacy_origin_seed, &origin_d) != EC_SUCCESS)
return VENDOR_RC_INTERNAL_ERROR;
} else {
- if (u2f_origin_user_keypair(req->keyHandle, &origin_d, NULL,
- NULL) != EC_SUCCESS)
+ if (u2f_origin_user_keypair(key_handle, kh_size, &origin_d,
+ NULL, NULL) != EC_SUCCESS)
return VENDOR_RC_INTERNAL_ERROR;
}
/* Prepare hash to sign. */
- p256_from_bin(req->hash, &h);
+ p256_from_bin(hash, &h);
/* Sign. */
hmac_drbg_init_rfc6979(&ctx, &origin_d, &h);
@@ -321,6 +433,8 @@ static inline int u2f_attest_verify_reg_resp(const uint8_t *user_secret,
{
struct g2f_register_msg *msg = (void *)data;
int verified;
+ /* We only do u2f_attest on non-versioned KHs. */
+ const int key_handle_size = sizeof(struct u2f_key_handle);
if (data_size != sizeof(struct g2f_register_msg))
return VENDOR_RC_NOT_ALLOWED;
@@ -328,15 +442,16 @@ static inline int u2f_attest_verify_reg_resp(const uint8_t *user_secret,
if (msg->reserved != 0)
return VENDOR_RC_NOT_ALLOWED;
- if (verify_kh_owned(user_secret, msg->app_id, msg->key_handle,
+ if (verify_kh_owned(user_secret, msg->app_id,
+ (struct u2f_key_handle *)&msg->key_handle,
&verified) != EC_SUCCESS)
return VENDOR_RC_INTERNAL_ERROR;
if (!verified)
return VENDOR_RC_NOT_ALLOWED;
- if (verify_kh_pubkey(msg->key_handle, &msg->public_key, &verified) !=
- EC_SUCCESS)
+ if (verify_kh_pubkey(msg->key_handle, key_handle_size, &msg->public_key,
+ &verified) != EC_SUCCESS)
return VENDOR_RC_INTERNAL_ERROR;
if (!verified)
diff --git a/include/u2f.h b/include/u2f.h
index 5af23bc773..61b9677185 100644
--- a/include/u2f.h
+++ b/include/u2f.h
@@ -30,7 +30,6 @@ extern "C" {
#define U2F_CHAL_SIZE 32 /* Size of challenge */
#define U2F_MAX_ATTEST_SIZE 256 /* Size of largest blob to sign */
#define U2F_P256_SIZE 32
-#define U2F_FIXED_KH_SIZE 64 /* Size of fixed size key handles */
#define ENC_SIZE(x) ((x + 7) & 0xfff8)
@@ -49,6 +48,21 @@ struct u2f_ec_point {
#define U2F_AUTH_ENFORCE 0x03 /* Enforce user presence and sign */
#define U2F_AUTH_CHECK_ONLY 0x07 /* Check only */
#define U2F_AUTH_FLAG_TUP 0x01 /* Test of user presence set */
+/* The key handle can be used with fingerprint or PIN. */
+#define U2F_UV_ENABLED_KH 0x08
+
+#define U2F_KH_VERSION_1 0x01
+
+struct u2f_key_handle {
+ uint8_t origin_seed[U2F_P256_SIZE];
+ uint8_t hmac[U2F_P256_SIZE];
+};
+
+struct u2f_versioned_key_handle {
+ uint8_t version;
+ uint8_t origin_seed[U2F_P256_SIZE];
+ uint8_t hmac[U2F_P256_SIZE];
+};
/* TODO(louiscollard): Add Descriptions. */
@@ -60,15 +74,28 @@ struct u2f_generate_req {
struct u2f_generate_resp {
struct u2f_ec_point pubKey; /* Generated public key */
- uint8_t keyHandle[U2F_FIXED_KH_SIZE]; /* Key handle */
+ struct u2f_key_handle keyHandle;
+};
+
+struct u2f_generate_versioned_resp {
+ struct u2f_ec_point pubKey; /* Generated public key */
+ struct u2f_versioned_key_handle keyHandle;
};
struct u2f_sign_req {
uint8_t appId[U2F_APPID_SIZE]; /* Application id */
uint8_t userSecret[U2F_P256_SIZE];
- uint8_t keyHandle[U2F_FIXED_KH_SIZE]; /* Key handle */
+ struct u2f_key_handle keyHandle;
+ uint8_t hash[U2F_P256_SIZE];
+ uint8_t flags;
+};
+
+struct u2f_sign_versioned_req {
+ uint8_t appId[U2F_APPID_SIZE]; /* Application id */
+ uint8_t userSecret[U2F_P256_SIZE];
uint8_t hash[U2F_P256_SIZE];
uint8_t flags;
+ struct u2f_versioned_key_handle keyHandle;
};
struct u2f_sign_resp {
diff --git a/include/u2f_impl.h b/include/u2f_impl.h
index 0732a1b72d..5bd69309c6 100644
--- a/include/u2f_impl.h
+++ b/include/u2f_impl.h
@@ -10,6 +10,7 @@
#include "common.h"
#include "cryptoc/p256.h"
+#include "u2f.h"
/* ---- Physical presence ---- */
@@ -58,14 +59,30 @@ int u2f_origin_key(const uint8_t *seed, p256_int *d);
*
* @param origin pointer to origin id
* @param user pointer to user secret
- * @param pointer to origin-specific random seed
+ * @param seed pointer to origin-specific random seed
+ * @param key_handle buffer to hold the output key handle
*
* @return EC_SUCCESS if a valid keypair was created.
*/
-int u2f_origin_user_keyhandle(const uint8_t *origin,
- const uint8_t *user,
+int u2f_origin_user_keyhandle(const uint8_t *origin, const uint8_t *user,
const uint8_t *seed,
- uint8_t *key_handle);
+ struct u2f_key_handle *key_handle);
+
+/**
+ * Pack the specified origin, user secret, origin-specific seed and version
+ * byte into a key handle.
+ *
+ * @param origin pointer to origin id
+ * @param user pointer to user secret
+ * @param seed pointer to origin-specific random seed
+ * @param version the version byte to pack; should be greater than 0.
+ * @param key_handle buffer to hold the output key handle
+ *
+ * @return EC_SUCCESS if a valid keypair was created.
+ */
+int u2f_origin_user_versioned_keyhandle(
+ const uint8_t *origin, const uint8_t *user, const uint8_t *seed,
+ uint8_t version, struct u2f_versioned_key_handle *key_handle);
/**
* Generate an origin and user-specific ECDSA keypair from the specified
@@ -73,17 +90,16 @@ int u2f_origin_user_keyhandle(const uint8_t *origin,
*
* If pk_x and pk_y are NULL, public key generation will be skipped.
*
- * @param key_handle pointer to the 64 byte key handle
+ * @param key_handle pointer to the key handle
+ * @param key_handle_size size of the key handle in bytes
* @param d pointer to ECDSA private key
* @param pk_x pointer to public key point
* @param pk_y pointer to public key point
*
* @return EC_SUCCESS if a valid keypair was created.
*/
-int u2f_origin_user_keypair(const uint8_t *key_handle,
- p256_int *d,
- p256_int *pk_x,
- p256_int *pk_y);
+int u2f_origin_user_keypair(const uint8_t *key_handle, size_t key_handle_size,
+ p256_int *d, p256_int *pk_x, p256_int *pk_y);
/***
* Generate a hardware derived 256b private key.