summaryrefslogtreecommitdiff
path: root/common/u2f.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/u2f.c')
-rw-r--r--common/u2f.c547
1 files changed, 136 insertions, 411 deletions
diff --git a/common/u2f.c b/common/u2f.c
index f5f91376d1..e03e6819f7 100644
--- a/common/u2f.c
+++ b/common/u2f.c
@@ -9,118 +9,82 @@
#include "dcrypto.h"
#include "extension.h"
+#include "nvmem_vars.h"
+#include "physical_presence.h"
#include "system.h"
+#include "tpm_nvmem_ops.h"
+#include "tpm_vendor_cmds.h"
+#include "u2f_cmds.h"
#include "u2f_impl.h"
-#include "u2f.h"
#include "util.h"
-#define G2F_CERT_NAME "CrO2"
-
#define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ##args)
-/* Crypto parameters */
-#define AES_BLOCK_LEN 16
-#define KH_LEN 64
-static int individual_cert(const p256_int *d, const p256_int *pk_x,
- const p256_int *pk_y, uint8_t *cert, const int n)
+size_t g2f_attestation_cert(uint8_t *buf)
{
- p256_int *serial;
-
- if (system_get_chip_unique_id((uint8_t **)&serial) != P256_NBYTES)
- return 0;
-
- return DCRYPTO_x509_gen_u2f_cert_name(d, pk_x, pk_y, serial,
- G2F_CERT_NAME, cert, n);
-}
+ uint8_t *serial;
-int g2f_attestation_cert(uint8_t *buf)
-{
- p256_int d, pk_x, pk_y;
+ const struct u2f_state *state = u2f_get_state();
- if (g2f_individual_keypair(&d, &pk_x, &pk_y))
+ if (!state)
return 0;
- /* Note that max length is not currently respected here. */
- return individual_cert(&d, &pk_x, &pk_y, 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;
+ if (system_get_chip_unique_id(&serial) != P256_NBYTES)
+ return 0;
- /* Copy key handle to response. */
- memcpy(&resp->keyHandle, kh, sizeof(struct u2f_versioned_key_handle));
+ return g2f_attestation_cert_serial(state, serial, buf);
}
/* U2F GENERATE command */
-enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, void *buf,
- size_t input_size, size_t *response_size)
+enum vendor_cmd_rc u2f_generate_cmd(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 = buf;
+ struct u2f_generate_versioned_resp *resp_versioned = buf;
+ struct u2f_ec_point *pubKey;
+
+ const struct u2f_state *state = u2f_get_state();
uint8_t kh_version =
(req->flags & U2F_UV_ENABLED_KH) ? U2F_KH_VERSION_1 : 0;
- /* 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;
-
- /* Buffer for generating key handle. */
- union {
- struct u2f_key_handle kh;
- struct u2f_versioned_key_handle vkh;
- } kh_buf;
- size_t keypair_input_size =
- (kh_version == 0) ?
- sizeof(kh_buf.kh) :
- sizeof(struct u2f_versioned_key_handle_header);
-
- /* Whether key handle generation succeeded */
- int generate_kh_rc;
- /* Whether keypair generation succeeded */
- int generate_keypair_rc;
+ /**
+ * Buffer for generating key handle as part of response. Note, it
+ * overlaps with authTimeSecret in response since request and response
+ * shares same buffer.
+ */
+ union u2f_key_handle_variant *kh_buf;
- size_t response_buf_size = *response_size;
+ uint8_t authTimeSecretHash[U2F_AUTH_TIME_SECRET_SIZE];
- /* Authorization salt for versioned KHs */
- uint8_t *authorization_salt;
+ size_t response_buf_size = *response_size;
+ enum ec_error_list result;
*response_size = 0;
if (input_size != sizeof(struct u2f_generate_req))
return VENDOR_RC_BOGUS_ARGS;
+ if (state == NULL)
+ return VENDOR_RC_INTERNAL_ERROR;
+
+ /* Copy to avoid overwriting data before use. */
+ memcpy(authTimeSecretHash, req->authTimeSecretHash,
+ sizeof(authTimeSecretHash));
+
if (kh_version == 0) {
if (response_buf_size < sizeof(struct u2f_generate_resp))
return VENDOR_RC_BOGUS_ARGS;
+ pubKey = &resp->pubKey;
+ kh_buf = (union u2f_key_handle_variant *)&resp->keyHandle;
} else {
if (response_buf_size <
sizeof(struct u2f_generate_versioned_resp))
return VENDOR_RC_BOGUS_ARGS;
+ pubKey = &resp_versioned->pubKey;
+ kh_buf = (union u2f_key_handle_variant *)&resp_versioned
+ ->keyHandle;
}
/* Maybe enforce user presence, w/ optional consume */
@@ -128,29 +92,16 @@ enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, void *buf,
(req->flags & U2F_AUTH_FLAG_TUP) != 0)
return VENDOR_RC_NOT_ALLOWED;
- /* Generate origin-specific keypair */
- do {
- if (!DCRYPTO_ladder_random(&od_seed))
- return VENDOR_RC_INTERNAL_ERROR;
-
- 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.header);
-
- if (generate_kh_rc != EC_SUCCESS)
- return VENDOR_RC_INTERNAL_ERROR;
-
- generate_keypair_rc = u2f_origin_user_keypair(
- (uint8_t *)&kh_buf, keypair_input_size, &od, &opk_x,
- &opk_y);
- } while (generate_keypair_rc == EC_ERROR_TRY_AGAIN);
-
- if (generate_keypair_rc != EC_SUCCESS)
+ /**
+ * req->userSecret and req->appId are consumed by u2f_generate() before
+ * being overwritten.
+ */
+ result = u2f_generate(state, req->userSecret, req->appId,
+ authTimeSecretHash, kh_buf, kh_version, pubKey);
+
+ always_memset(authTimeSecretHash, 0, sizeof(authTimeSecretHash));
+
+ if (result != EC_SUCCESS)
return VENDOR_RC_INTERNAL_ERROR;
/*
@@ -158,165 +109,74 @@ enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, void *buf,
* overridden by the response we are building in the same buffer.
*/
if (kh_version == 0) {
- copy_kh_pubkey_out(&opk_x, &opk_y, &kh_buf.kh, buf);
*response_size = sizeof(struct u2f_generate_resp);
} else {
- authorization_salt = od_seed;
- /* Generate in word-aligned array so that TRNG doesn't crash */
- if (!DCRYPTO_ladder_random(authorization_salt))
- return VENDOR_RC_INTERNAL_ERROR;
-
- if (u2f_authorization_hmac(
- authorization_salt, &kh_buf.vkh.header,
- req->authTimeSecretHash,
- kh_buf.vkh.authorization_hmac) != EC_SUCCESS)
- return VENDOR_RC_INTERNAL_ERROR;
-
- memcpy(&kh_buf.vkh.authorization_salt, authorization_salt,
- U2F_AUTHORIZATION_SALT_SIZE);
- 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, 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, key_handle_size, &od, &opk_x,
- &opk_y);
- if (rc != EC_SUCCESS)
- return rc;
-
- /* Reconstruct the public key. */
- p256_to_bin(&opk_x, kh_pubkey.x);
- p256_to_bin(&opk_y, kh_pubkey.y);
- kh_pubkey.pointFormat = U2F_POINT_UNCOMPRESSED;
-
- *matches = safe_memcmp(&kh_pubkey, public_key,
- sizeof(struct u2f_ec_point)) == 0;
-
- return EC_SUCCESS;
-}
-
-static int verify_kh_owned(const uint8_t *user_secret, const uint8_t *app_id,
- 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_header *key_handle_header,
- int *owned)
-{
- int rc;
- /* Re-created key handle. */
- struct u2f_versioned_key_handle_header recreated_kh_header;
-
- /*
- * 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_versioned_keyhandle(app_id, user_secret,
- key_handle_header->origin_seed,
- key_handle_header->version,
- &recreated_kh_header);
-
- if (rc == EC_SUCCESS)
- *owned = safe_memcmp(&recreated_kh_header, key_handle_header,
- sizeof(recreated_kh_header)) == 0;
-
- return rc;
-}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_GENERATE, u2f_generate_cmd);
/* Below, we depend on the response not being larger than than the request. */
BUILD_ASSERT(sizeof(struct u2f_sign_resp) <= sizeof(struct u2f_sign_req));
/* U2F SIGN command */
-enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf,
- size_t input_size, size_t *response_size)
+enum vendor_cmd_rc u2f_sign_cmd(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;
+ union u2f_key_handle_variant *kh;
- struct drbg_ctx ctx;
+ const struct u2f_state *state = u2f_get_state();
- /* Whether the key handle is owned by this device. */
- int kh_owned = 0;
+ const uint8_t *hash, *user, *origin /* TODO: *authTimeSecret = NULL */;
- /* Origin private key. */
- p256_int origin_d;
-
- /* Hash, and corresponding signature. */
- p256_int h, r, s;
+ uint8_t flags;
+ struct u2f_sign_resp *resp;
/* Version of KH; 0 if KH is not versioned. */
- uint8_t version;
+ uint8_t kh_version;
- /* Size of the part of KH used to derive keypair, in bytes. */
- size_t keypair_input_size;
-
- int verify_owned_rc;
+ enum ec_error_list result;
/* Response is smaller than request, so no need to check this. */
*response_size = 0;
+ if (!state)
+ return VENDOR_RC_INTERNAL_ERROR;
+
+ /**
+ * Request can be in old (non-versioned) and new (versioned) formats,
+ * which differs in size. Use request size to distinguish it.
+ */
if (input_size == sizeof(struct u2f_sign_req)) {
- version = 0;
- key_handle = (uint8_t *)&req->keyHandle;
+ kh_version = 0;
+ kh = (union u2f_key_handle_variant *)&req->keyHandle;
hash = req->hash;
flags = req->flags;
- keypair_input_size = sizeof(struct u2f_key_handle);
- verify_owned_rc = verify_kh_owned(req->userSecret, req->appId,
- &req->keyHandle, &kh_owned);
+ user = req->userSecret;
+ origin = req->appId;
} else if (input_size == sizeof(struct u2f_sign_versioned_req)) {
- version = req_versioned->keyHandle.header.version;
- key_handle = (uint8_t *)&req_versioned->keyHandle;
+ kh_version = req_versioned->keyHandle.version;
+ kh = (union u2f_key_handle_variant *)&req_versioned->keyHandle;
hash = req_versioned->hash;
flags = req_versioned->flags;
- keypair_input_size =
- sizeof(struct u2f_versioned_key_handle_header);
- verify_owned_rc = verify_versioned_kh_owned(
- req_versioned->userSecret, req_versioned->appId,
- &req_versioned->keyHandle.header, &kh_owned);
+ user = req_versioned->userSecret;
+ origin = req_versioned->appId;
+ /* TODO: authTimeSecret = req_versioned->authTimeSecret; */
} else {
return VENDOR_RC_BOGUS_ARGS;
}
- if (verify_owned_rc != EC_SUCCESS)
- return VENDOR_RC_INTERNAL_ERROR;
-
- if (!kh_owned)
+ /* TODO(b/184393647): pass authTimeSecret when ready. */
+ result = u2f_authorize_keyhandle(state, kh, kh_version, user, origin,
+ NULL);
+ if (result == EC_ERROR_ACCESS_DENIED)
return VENDOR_RC_PASSWORD_REQUIRED;
+ if (result != EC_SUCCESS)
+ return VENDOR_RC_INTERNAL_ERROR;
/* We might not actually need to sign anything. */
if ((flags & U2F_AUTH_CHECK_ONLY) == U2F_AUTH_CHECK_ONLY)
@@ -326,99 +186,40 @@ enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf,
* Enforce user presence for version 0 KHs, with optional consume.
*/
if (pop_check_presence(flags & G2F_CONSUME) != POP_TOUCH_YES) {
- if (version != U2F_KH_VERSION_1)
+ if (kh_version != U2F_KH_VERSION_1)
return VENDOR_RC_NOT_ALLOWED;
if ((flags & U2F_AUTH_FLAG_TUP) != 0)
return VENDOR_RC_NOT_ALLOWED;
- /*
- * TODO(yichengli): When auth-time secrets is ready, enforce
- * authorization hmac when no power button press.
- */
}
- /* Re-create origin-specific key. */
- if (u2f_origin_user_keypair(key_handle, keypair_input_size, &origin_d,
- NULL, NULL) != EC_SUCCESS)
- return VENDOR_RC_INTERNAL_ERROR;
-
- /* Prepare hash to sign. */
- p256_from_bin(hash, &h);
-
- /* Sign. */
- hmac_drbg_init_rfc6979(&ctx, &origin_d, &h);
- if (!dcrypto_p256_ecdsa_sign(&ctx, &origin_d, &h, &r, &s)) {
- p256_clear(&origin_d);
- return VENDOR_RC_INTERNAL_ERROR;
- }
- p256_clear(&origin_d);
-
/*
- * From this point: the request 'req' content is invalid as it is
- * overridden by the response we are building in the same buffer.
+ * u2f_sign first consume all data from request 'req', and compute
+ * result in temporary storage. Once accomplished, it stores it in
+ * provided buffer. This allows overlap between input and output
+ * parameters.
* The response is smaller than the request, so we have the space.
*/
resp = buf;
- *response_size = sizeof(*resp);
-
- p256_to_bin(&r, resp->sig_r);
- p256_to_bin(&s, resp->sig_s);
-
- return VENDOR_RC_SUCCESS;
-}
-DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_SIGN, u2f_sign);
-
-struct g2f_register_msg {
- uint8_t reserved;
- uint8_t app_id[U2F_APPID_SIZE];
- uint8_t challenge[U2F_CHAL_SIZE];
- uint8_t key_handle[U2F_APPID_SIZE + sizeof(p256_int)];
- struct u2f_ec_point public_key;
-};
-
-static inline int u2f_attest_verify_reg_resp(const uint8_t *user_secret,
- uint8_t data_size,
- const uint8_t *data)
-{
- 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;
-
- if (msg->reserved != 0)
- return VENDOR_RC_NOT_ALLOWED;
-
- 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;
+ /**
+ * TODO(b/184393647): When auth-time secrets is ready, enforce
+ * authorization hmac when no power button press.
+ * use u2f_authorize_keyhandle_with_secret() which requires
+ * correct authorization mac to be provided by the caller.
+ */
+ result = u2f_sign(state, kh, kh_version, user, origin,
+ NULL /* TODO: authTimeSecret */, hash, &resp->sig);
- if (verify_kh_pubkey(msg->key_handle, key_handle_size, &msg->public_key,
- &verified) != EC_SUCCESS)
+ if (result == EC_ERROR_ACCESS_DENIED)
+ return VENDOR_RC_PASSWORD_REQUIRED;
+ if (result != EC_SUCCESS)
return VENDOR_RC_INTERNAL_ERROR;
- if (!verified)
- return VENDOR_RC_NOT_ALLOWED;
+ *response_size = sizeof(*resp);
return VENDOR_RC_SUCCESS;
}
-
-static int u2f_attest_verify(const uint8_t *user_secret, uint8_t format,
- uint8_t data_size, const uint8_t *data)
-{
- switch (format) {
- case U2F_ATTEST_FORMAT_REG_RESP:
- return u2f_attest_verify_reg_resp(user_secret, data_size, data);
- default:
- return VENDOR_RC_NOT_ALLOWED;
- }
-}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_SIGN, u2f_sign_cmd);
static inline size_t u2f_attest_format_size(uint8_t format)
{
@@ -431,27 +232,24 @@ static inline size_t u2f_attest_format_size(uint8_t format)
}
/* U2F ATTEST command */
-static enum vendor_cmd_rc u2f_attest(enum vendor_cmd_cc code, void *buf,
- size_t input_size, size_t *response_size)
+static enum vendor_cmd_rc u2f_attest_cmd(enum vendor_cmd_cc code, void *buf,
+ size_t input_size,
+ size_t *response_size)
{
const struct u2f_attest_req *req = buf;
struct u2f_attest_resp *resp;
-
- int verify_ret;
-
- struct sha256_ctx h_ctx;
- struct drbg_ctx dr_ctx;
-
- /* Data hash, and corresponding signature. */
- p256_int h, r, s;
-
- /* Attestation key */
- p256_int d, pk_x, pk_y;
+ struct g2f_register_msg *msg = (void *)req->data;
+ enum ec_error_list result;
size_t response_buf_size = *response_size;
+ const struct u2f_state *state = u2f_get_state();
+
*response_size = 0;
+ if (!state)
+ return VENDOR_RC_INTERNAL_ERROR;
+
if (input_size < offsetof(struct u2f_attest_req, data) ||
input_size <
(offsetof(struct u2f_attest_req, data) + req->dataLen) ||
@@ -459,114 +257,41 @@ static enum vendor_cmd_rc u2f_attest(enum vendor_cmd_cc code, void *buf,
response_buf_size < sizeof(*resp))
return VENDOR_RC_BOGUS_ARGS;
- verify_ret = u2f_attest_verify(req->userSecret, req->format,
- req->dataLen, req->data);
-
- if (verify_ret != VENDOR_RC_SUCCESS)
- return verify_ret;
-
- /* Message signature */
- SHA256_hw_init(&h_ctx);
- SHA256_update(&h_ctx, req->data, u2f_attest_format_size(req->format));
- p256_from_bin(SHA256_final(&h_ctx)->b8, &h);
+ /* Only one format is supported, key handle version is 0. */
+ if (req->format != U2F_ATTEST_FORMAT_REG_RESP)
+ return VENDOR_RC_NOT_ALLOWED;
- /* Derive G2F Attestation Key */
- if (g2f_individual_keypair(&d, &pk_x, &pk_y)) {
- CPRINTF("G2F Attestation key generation failed");
- return VENDOR_RC_INTERNAL_ERROR;
- }
+ if (req->dataLen != sizeof(struct g2f_register_msg))
+ return VENDOR_RC_NOT_ALLOWED;
- /* Sign over the response w/ the attestation key */
- hmac_drbg_init_rfc6979(&dr_ctx, &d, &h);
- if (!dcrypto_p256_ecdsa_sign(&dr_ctx, &d, &h, &r, &s)) {
- CPRINTF("Signing error");
- return VENDOR_RC_INTERNAL_ERROR;
- }
- p256_clear(&d);
+ if (msg->reserved != 0)
+ return VENDOR_RC_NOT_ALLOWED;
/*
- * From this point: the request 'req' content is invalid as it is
- * overridden by the response we are building in the same buffer.
+ * u2f_attest first consume all data from request 'req', and compute
+ * result in temporary storage. Once accomplished, it stores it in
+ * provided buffer. This allows overlap between input and output
+ * parameters.
* The response is smaller than the request, so we have the space.
*/
resp = buf;
- *response_size = sizeof(*resp);
-
- p256_to_bin(&r, resp->sig_r);
- p256_to_bin(&s, resp->sig_s);
-
- return VENDOR_RC_SUCCESS;
-}
-DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_ATTEST, u2f_attest);
-
-int u2f_origin_user_keyhandle(const uint8_t *origin, const uint8_t *user,
- const uint8_t *origin_seed,
- struct u2f_key_handle *key_handle)
-{
- struct hmac_sha256_ctx ctx;
- struct u2f_state *state = get_state();
-
- if (!state)
- return EC_ERROR_UNKNOWN;
-
- memcpy(key_handle->origin_seed, origin_seed, P256_NBYTES);
-
- HMAC_SHA256_hw_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE);
- HMAC_SHA256_update(&ctx, origin, P256_NBYTES);
- HMAC_SHA256_update(&ctx, user, P256_NBYTES);
- HMAC_SHA256_update(&ctx, origin_seed, P256_NBYTES);
+ /* TODO: If WebAuthn support is needed, pass AuthTimeSecret. */
+ result = u2f_attest(state,
+ (union u2f_key_handle_variant *)&msg->key_handle, 0,
+ req->userSecret, msg->app_id, NULL,
+ &msg->public_key, req->data,
+ u2f_attest_format_size(req->format), &resp->sig);
- memcpy(key_handle->hmac, HMAC_SHA256_hw_final(&ctx),
- SHA256_DIGEST_SIZE);
-
- return EC_SUCCESS;
-}
-
-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_header *key_handle_header)
-{
- struct hmac_sha256_ctx ctx;
- struct u2f_state *state = get_state();
-
- if (!state)
- return EC_ERROR_UNKNOWN;
-
- key_handle_header->version = version;
- memcpy(key_handle_header->origin_seed, origin_seed, P256_NBYTES);
-
- HMAC_SHA256_hw_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE);
- HMAC_SHA256_update(&ctx, origin, P256_NBYTES);
- HMAC_SHA256_update(&ctx, user, P256_NBYTES);
- HMAC_SHA256_update(&ctx, origin_seed, P256_NBYTES);
- HMAC_SHA256_update(&ctx, &version, sizeof(key_handle_header->version));
-
- memcpy(key_handle_header->kh_hmac, HMAC_SHA256_hw_final(&ctx),
- SHA256_DIGEST_SIZE);
-
- return EC_SUCCESS;
-}
-
-int u2f_authorization_hmac(const uint8_t *authorization_salt,
- const struct u2f_versioned_key_handle_header *header,
- const uint8_t *auth_time_secret_hash, uint8_t *hmac)
-{
- struct hmac_sha256_ctx ctx;
- struct u2f_state *state = get_state();
-
- if (!state)
- return EC_ERROR_UNKNOWN;
-
- HMAC_SHA256_hw_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE);
- HMAC_SHA256_update(&ctx, authorization_salt,
- U2F_AUTHORIZATION_SALT_SIZE);
- HMAC_SHA256_update(&ctx, (uint8_t *)header,
- sizeof(struct u2f_versioned_key_handle_header));
- HMAC_SHA256_update(&ctx, auth_time_secret_hash, SHA256_DIGEST_SIZE);
+ if (result == EC_ERROR_ACCESS_DENIED)
+ return VENDOR_RC_NOT_ALLOWED;
- memcpy(hmac, HMAC_SHA256_hw_final(&ctx), SHA256_DIGEST_SIZE);
+ if (result != EC_SUCCESS) {
+ CPRINTF("G2F Attestation failed");
+ return VENDOR_RC_INTERNAL_ERROR;
+ }
- return EC_SUCCESS;
+ *response_size = sizeof(*resp);
+ return VENDOR_RC_SUCCESS;
}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_ATTEST, u2f_attest_cmd);