diff options
author | Howard Yang <hcyang@google.com> | 2022-05-26 12:29:01 +0800 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-06-03 07:55:37 +0000 |
commit | e5b0f03a6f132d57337212c3928c820d785072e0 (patch) | |
tree | 92d598703fba4aacef54bb882e945f4ffb099a4e | |
parent | 1e27cdddad231f9cd75c77923d1e952883f6125e (diff) | |
download | chrome-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.c | 44 | ||||
-rw-r--r-- | include/u2f.h | 36 | ||||
-rw-r--r-- | test/tpm_test/u2f_test.py | 21 |
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')) |