summaryrefslogtreecommitdiff
path: root/common/u2f.c
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2021-09-30 23:53:39 -0700
committerCommit Bot <commit-bot@chromium.org>2021-10-06 04:01:05 +0000
commit38690405baf21e64dd7ec4f6be329098a2e330ac (patch)
treedbae268e5971c37612d6336e00f7d2b4e0791677 /common/u2f.c
parentcc7679235b5b30083cd74a68890b54c71bb61f7f (diff)
downloadchrome-ec-38690405baf21e64dd7ec4f6be329098a2e330ac.tar.gz
cr50: add support for v2 of U2F key handle for WebAuthnstabilize-14267.B-cr50_stab
Adding v2 of key handle which drops kh_hmac field and use single authorization code for all relevant fields. BUG=b:172971998 TEST=make BOARD=cr50 CRYPTO_TEST=1 U2F_TEST=1; in ccd: u2f_test - unit tests test/tpm_test/tpmtest.py Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com> Change-Id: I647ded7a2c157cea91ac48a2ba679def318c1e63 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3199671 Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Reviewed-by: Andrey Pronin <apronin@chromium.org> Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Auto-Submit: Vadim Sukhomlinov <sukhomlinov@chromium.org> Commit-Queue: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Diffstat (limited to 'common/u2f.c')
-rw-r--r--common/u2f.c125
1 files changed, 70 insertions, 55 deletions
diff --git a/common/u2f.c b/common/u2f.c
index 0795d88359..89565950dd 100644
--- a/common/u2f.c
+++ b/common/u2f.c
@@ -55,20 +55,24 @@ 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;
+ union u2f_generate_response *resp = buf;
+ struct u2f_ec_point *pubKey = NULL;
const struct u2f_state *state = u2f_get_state();
- uint8_t kh_version =
- (req->flags & U2F_UV_ENABLED_KH) ? U2F_KH_VERSION_1 : 0;
+ uint8_t kh_version = 0; /* Fall back version of key handle. */
+
+ static const size_t kh_version_response_size[] = {
+ sizeof(struct u2f_generate_resp),
+ sizeof(struct u2f_generate_versioned_resp),
+ sizeof(struct u2f_generate_versioned_resp_v2)
+ };
/**
* 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;
+ union u2f_key_handle_variant *kh_buf = NULL;
uint8_t authTimeSecretHash[U2F_AUTH_TIME_SECRET_SIZE];
@@ -83,22 +87,32 @@ enum vendor_cmd_rc u2f_generate_cmd(enum vendor_cmd_cc code, void *buf,
if (state == NULL)
return VENDOR_RC_INTERNAL_ERROR;
+ if ((req->flags & U2F_V2_KH_MASK) == U2F_V2_KH_MASK)
+ kh_version = U2F_KH_VERSION_2;
+ else if (req->flags & U2F_UV_ENABLED_KH)
+ kh_version = U2F_KH_VERSION_1;
+
+ /* Check there is enough room for response in response buffer. */
+ if (response_buf_size < kh_version_response_size[kh_version])
+ return VENDOR_RC_BOGUS_ARGS;
+
/* 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;
+ switch (kh_version) {
+ case U2F_KH_VERSION_2:
+ pubKey = &resp->v2.pubKey;
+ kh_buf = (union u2f_key_handle_variant *)&resp->v2.keyHandle;
+ break;
+ case U2F_KH_VERSION_1:
+ pubKey = &resp->v1.pubKey;
+ kh_buf = (union u2f_key_handle_variant *)&resp->v1.keyHandle;
+ break;
+ default: /* Version 0 */
+ pubKey = &resp->v0.pubKey;
+ kh_buf = (union u2f_key_handle_variant *)&resp->v0.keyHandle;
+ break;
}
/* Maybe enforce user presence, w/ optional consume */
@@ -122,12 +136,7 @@ enum vendor_cmd_rc u2f_generate_cmd(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.
*/
- if (kh_version == 0) {
- *response_size = sizeof(struct u2f_generate_resp);
- } else {
- *response_size = sizeof(struct u2f_generate_versioned_resp);
- }
-
+ *response_size = kh_version_response_size[kh_version];
return VENDOR_RC_SUCCESS;
}
DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_GENERATE, u2f_generate_cmd);
@@ -135,17 +144,17 @@ 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_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 union u2f_sign_request *req = buf;
union u2f_key_handle_variant *kh;
const struct u2f_state *state = u2f_get_state();
- const uint8_t *hash, *user, *origin /* TODO: *authTimeSecret = NULL */;
+ const uint8_t *hash, *user, *origin, *authTimeSecret = NULL;
uint8_t flags;
struct u2f_sign_resp *resp;
@@ -167,26 +176,38 @@ enum vendor_cmd_rc u2f_sign_cmd(enum vendor_cmd_cc code, void *buf,
*/
if (input_size == sizeof(struct u2f_sign_req)) {
kh_version = 0;
- kh = (union u2f_key_handle_variant *)&req->keyHandle;
- hash = req->hash;
- flags = req->flags;
- user = req->userSecret;
- origin = req->appId;
+ kh = (union u2f_key_handle_variant *)&req->v0.keyHandle;
+ hash = req->v0.hash;
+ flags = req->v0.flags;
+ user = req->v0.userSecret;
+ origin = req->v0.appId;
} else if (input_size == sizeof(struct u2f_sign_versioned_req)) {
- kh = (union u2f_key_handle_variant *)&req_versioned->keyHandle;
- kh_version = kh->v1.version;
- hash = req_versioned->hash;
- flags = req_versioned->flags;
- user = req_versioned->userSecret;
- origin = req_versioned->appId;
- /* TODO: authTimeSecret = req_versioned->authTimeSecret; */
- } else {
+ kh = (union u2f_key_handle_variant *)&req->v1.keyHandle;
+ kh_version = U2F_KH_VERSION_1;
+ hash = req->v1.hash;
+ flags = req->v1.flags;
+ user = req->v1.userSecret;
+ origin = req->v1.appId;
+ /**
+ * TODO(b/184393647): Enforce user verification if no user
+ * presence check is requested. Set
+ * authTimeSecret = req->v1.authTimeSecret;
+ * unconditionally or if (flags & U2F_AUTH_FLAG_TUP) == 0
+ */
+ authTimeSecret = NULL;
+ } else if (input_size == sizeof(struct u2f_sign_versioned_req_v2)) {
+ kh = (union u2f_key_handle_variant *)&req->v2.keyHandle;
+ kh_version = U2F_KH_VERSION_2;
+ hash = req->v2.hash;
+ flags = req->v2.flags;
+ user = req->v2.userSecret;
+ origin = req->v2.appId;
+ authTimeSecret = req->v2.authTimeSecret;
+ } else
return VENDOR_RC_BOGUS_ARGS;
- }
- /* TODO(b/184393647): pass authTimeSecret when ready. */
result = u2f_authorize_keyhandle(state, kh, kh_version, user, origin,
- NULL);
+ authTimeSecret);
if (result == EC_ERROR_ACCESS_DENIED)
return VENDOR_RC_PASSWORD_REQUIRED;
if (result != EC_SUCCESS)
@@ -198,6 +219,7 @@ enum vendor_cmd_rc u2f_sign_cmd(enum vendor_cmd_cc code, void *buf,
/*
* Enforce user presence for version 0 KHs, with optional consume.
+ * TODO(b/184393647): update logic for version 2 if needed.
*/
if (pop_check_presence(flags & G2F_CONSUME) != POP_TOUCH_YES) {
if (kh_version != U2F_KH_VERSION_1)
@@ -215,15 +237,8 @@ enum vendor_cmd_rc u2f_sign_cmd(enum vendor_cmd_cc code, void *buf,
*/
resp = buf;
- /**
- * 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,
- (struct u2f_signature *)resp);
+ result = u2f_sign(state, kh, kh_version, user, origin, authTimeSecret,
+ hash, (struct u2f_signature *)resp);
if (result == EC_ERROR_ACCESS_DENIED)
return VENDOR_RC_PASSWORD_REQUIRED;
@@ -240,7 +255,7 @@ static inline size_t u2f_attest_format_size(uint8_t format)
{
switch (format) {
case U2F_ATTEST_FORMAT_REG_RESP:
- return sizeof(struct g2f_register_msg);
+ return sizeof(struct g2f_register_msg_v0);
default:
return 0;
}
@@ -253,7 +268,7 @@ static enum vendor_cmd_rc u2f_attest_cmd(enum vendor_cmd_cc code, void *buf,
{
const struct u2f_attest_req *req = buf;
struct u2f_attest_resp *resp;
- struct g2f_register_msg *msg = (void *)req->data;
+ struct g2f_register_msg_v0 *msg = (void *)req->data;
enum ec_error_list result;
size_t response_buf_size = *response_size;
@@ -276,7 +291,7 @@ static enum vendor_cmd_rc u2f_attest_cmd(enum vendor_cmd_cc code, void *buf,
if (req->format != U2F_ATTEST_FORMAT_REG_RESP)
return VENDOR_RC_NOT_ALLOWED;
- if (req->dataLen != sizeof(struct g2f_register_msg))
+ if (req->dataLen != sizeof(struct g2f_register_msg_v0))
return VENDOR_RC_NOT_ALLOWED;
if (msg->reserved != 0)