diff options
Diffstat (limited to 'common/u2f.c')
-rw-r--r-- | common/u2f.c | 547 |
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); |