summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Yang <hcyang@google.com>2022-05-26 12:29:01 +0800
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-06-03 07:55:37 +0000
commite5b0f03a6f132d57337212c3928c820d785072e0 (patch)
tree92d598703fba4aacef54bb882e945f4ffb099a4e
parent1e27cdddad231f9cd75c77923d1e952883f6125e (diff)
downloadchrome-ec-e5b0f03a6f132d57337212c3928c820d785072e0.tar.gz
cr50: Add corp format to u2f_attest
Add a format for u2fd-corp attestation to u2f_attest, and corresponding test case in u2f_test.py BUG=b:233147441 TEST=make buildall -j TEST=u2f_test.py Change-Id: I4d12345fd0531a4be091c05670215444fe38e706 Signed-off-by: Howard Yang <hcyang@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3670107 Reviewed-by: Andrey Pronin <apronin@chromium.org> Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org>
-rw-r--r--common/u2f.c44
-rw-r--r--include/u2f.h36
-rw-r--r--test/tpm_test/u2f_test.py21
3 files changed, 77 insertions, 24 deletions
diff --git a/common/u2f.c b/common/u2f.c
index cccc6b06b9..1a4026b559 100644
--- a/common/u2f.c
+++ b/common/u2f.c
@@ -266,6 +266,8 @@ 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_v0);
+ case CORP_ATTEST_FORMAT_REG_RESP:
+ return sizeof(struct corp_attest_data);
default:
return 0;
}
@@ -277,9 +279,13 @@ 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_v0 *msg = (void *)req->data;
+ union u2f_attest_msg_variant *msg = (void *)req->data;
enum ec_error_list result;
+ const union u2f_key_handle_variant *kh;
+ const uint8_t *origin;
+ const struct u2f_ec_point *pubKey;
+
size_t response_buf_size = *response_size;
const struct u2f_state *state = u2f_get_state();
@@ -296,15 +302,30 @@ enum vendor_cmd_rc u2f_attest_cmd(enum vendor_cmd_cc code, void *buf,
response_buf_size < sizeof(*resp))
return VENDOR_RC_BOGUS_ARGS;
- /* Only one format is supported, key handle version is 0. */
- if (req->format != U2F_ATTEST_FORMAT_REG_RESP)
- return VENDOR_RC_NOT_ALLOWED;
+ /*
+ * Two formats are supported, U2F Attest format and Corp Attest format,
+ * both with key handle version 0.
+ */
+ if (req->format == U2F_ATTEST_FORMAT_REG_RESP) {
+ if (req->dataLen != sizeof(struct g2f_register_msg_v0))
+ return VENDOR_RC_NOT_ALLOWED;
- if (req->dataLen != sizeof(struct g2f_register_msg_v0))
- return VENDOR_RC_NOT_ALLOWED;
+ if (msg->g2f.reserved != 0)
+ return VENDOR_RC_NOT_ALLOWED;
- if (msg->reserved != 0)
+ kh = (union u2f_key_handle_variant *)&msg->g2f.key_handle;
+ origin = msg->g2f.app_id;
+ pubKey = &msg->g2f.public_key;
+ } else if (req->format == CORP_ATTEST_FORMAT_REG_RESP) {
+ if (req->dataLen != sizeof(struct corp_register_msg_v0))
+ return VENDOR_RC_NOT_ALLOWED;
+
+ kh = (union u2f_key_handle_variant *)&msg->corp.key_handle;
+ origin = msg->corp.app_id;
+ pubKey = &msg->corp.data.public_key;
+ } else {
return VENDOR_RC_NOT_ALLOWED;
+ }
/*
* u2f_attest first consume all data from request 'req', and compute
@@ -316,18 +337,15 @@ enum vendor_cmd_rc u2f_attest_cmd(enum vendor_cmd_cc code, void *buf,
resp = buf;
/* 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),
+ result = u2f_attest(state, kh, 0, req->userSecret, origin, NULL, pubKey,
+ req->data, u2f_attest_format_size(req->format),
(struct u2f_signature *)resp);
if (result == EC_ERROR_ACCESS_DENIED)
return VENDOR_RC_NOT_ALLOWED;
if (result != EC_SUCCESS) {
- CPRINTF("G2F Attestation failed");
+ CPRINTF("Attestation failed");
return VENDOR_RC_INTERNAL_ERROR;
}
diff --git a/include/u2f.h b/include/u2f.h
index a9d42db03a..6e7c3e5d5e 100644
--- a/include/u2f.h
+++ b/include/u2f.h
@@ -39,14 +39,16 @@ extern "C" {
#define U2F_MAX_ATTEST_SIZE 256 /* Size of largest blob to sign */
#define U2F_P256_SIZE 32
/* Origin seed is a random nonce generated during key handle creation. */
-#define U2F_ORIGIN_SEED_SIZE 32
-#define U2F_USER_SECRET_SIZE 32 /* Size of user secret */
+#define U2F_ORIGIN_SEED_SIZE 32
+#define U2F_USER_SECRET_SIZE 32 /* Size of user secret */
#define U2F_AUTH_TIME_SECRET_SIZE 32
-#define SHA256_DIGEST_SIZE 32
+#define SHA256_DIGEST_SIZE 32
#define U2F_MESSAGE_DIGEST_SIZE SHA256_DIGEST_SIZE
+#define CORP_CHAL_SIZE 16
+#define CORP_SALT_SIZE 16
#define ENC_SIZE(x) ((x + 7) & 0xfff8)
@@ -69,15 +71,14 @@ struct u2f_ec_point {
#define U2F_UV_ENABLED_KH 0x08
/* Request v2 key handle. Should be used with U2F_UV_ENABLED_KH */
-#define U2F_V2_KH 0x10
+#define U2F_V2_KH 0x10
#define U2F_V2_KH_MASK (U2F_V2_KH | U2F_UV_ENABLED_KH)
-
#define U2F_KH_VERSION_1 0x01
#define U2F_KH_VERSION_2 0x02
#define U2F_AUTHORIZATION_SALT_SIZE 16
-#define U2F_V0_KH_SIZE 64
+#define U2F_V0_KH_SIZE 64
/**
* Key handle version = 1 for WebAuthn, bound to device and user.
@@ -252,7 +253,8 @@ struct u2f_attest_req {
uint8_t userSecret[U2F_USER_SECRET_SIZE];
uint8_t format;
uint8_t dataLen;
- uint8_t data[U2F_MAX_ATTEST_SIZE]; /* struct g2f_register_msg_vX */
+ /* struct g2f_register_msg_vX or corp_register_msg_vX */
+ uint8_t data[U2F_MAX_ATTEST_SIZE];
};
struct g2f_register_msg_v0 {
@@ -263,6 +265,23 @@ struct g2f_register_msg_v0 {
struct u2f_ec_point public_key;
};
+struct corp_attest_data {
+ uint8_t challenge[CORP_CHAL_SIZE];
+ struct u2f_ec_point public_key;
+ uint8_t salt[65];
+};
+
+struct corp_register_msg_v0 {
+ struct corp_attest_data data;
+ uint8_t app_id[U2F_APPID_SIZE];
+ struct u2f_key_handle_v0 key_handle;
+};
+
+union u2f_attest_msg_variant {
+ struct g2f_register_msg_v0 g2f;
+ struct corp_register_msg_v0 corp;
+};
+
struct u2f_attest_resp {
uint8_t sig_r[U2F_P256_SIZE];
uint8_t sig_s[U2F_P256_SIZE];
@@ -300,6 +319,9 @@ struct u2f_attest_resp {
/* U2F Attest format for U2F Register Response. */
#define U2F_ATTEST_FORMAT_REG_RESP 0
+/* Corp Attest format for U2F Register Response. */
+#define CORP_ATTEST_FORMAT_REG_RESP 1
+
/* Vendor command to enable/disable the extensions */
#define U2F_VENDOR_MODE U2F_VENDOR_LAST
diff --git a/test/tpm_test/u2f_test.py b/test/tpm_test/u2f_test.py
index a0118c7b13..a5f9e0743c 100644
--- a/test/tpm_test/u2f_test.py
+++ b/test/tpm_test/u2f_test.py
@@ -57,12 +57,20 @@ def u2f_sign(tpm, origin, user, auth, kh, msg, flag, fail=False):
return b''
return sig
-def u2f_attest(tpm, origin, user, challenge, kh, public_key, fail=False):
+def u2f_attest(tpm, origin, user, challenge, kh, public_key, corp_format=False, fail=False):
origin = origin[:32].ljust(32, b'\0')
user = user[:32].ljust(32, b'\0')
- challenge = challenge[:32].ljust(32, b'\0')
- g2f_cmd = b'\0' + origin + challenge + kh + public_key
- cmd = user + b'\0' + len(g2f_cmd).to_bytes(1, 'big') + g2f_cmd
+ if not corp_format:
+ challenge = challenge[:32].ljust(32, b'\0')
+ g2f_cmd = b'\0' + origin + challenge + kh + public_key
+ cmd = user + b'\0' + len(g2f_cmd).to_bytes(1, 'big') + g2f_cmd
+ else:
+ challenge = challenge[:16].ljust(16, b'\0')
+ salt = b'\0' * 65
+ corp_data = challenge + public_key + salt
+ corp_cmd = corp_data + origin + kh
+ cmd = user + b'\1' + len(corp_cmd).to_bytes(1, 'big') + corp_cmd
+
if fail==False:
wrapped_response = tpm.command(tpm.wrap_ext_command(
subcmd.U2F_ATTEST, cmd))
@@ -171,4 +179,9 @@ def u2f_test(tpm):
sig_attest = u2f_attest(tpm, origin, user, auth, khv0, public_key0)
if tpm.debug_enabled():
print('sig attest = ',utils.hex_dump(sig_attest), len(sig_attest))
+
+ print('U2F_ATTEST corp');
+ sig_attest = u2f_attest(tpm, origin, user, auth, khv0, public_key0, corp_format=True)
+ if tpm.debug_enabled():
+ print('sig attest = ',utils.hex_dump(sig_attest), len(sig_attest))
print('%sSUCCESS: %s' % (utils.cursor_back(), 'U2F test'))