From 7e2f4d3004026f0633c18c17287192f4df124e79 Mon Sep 17 00:00:00 2001 From: Yicheng Li Date: Wed, 17 Feb 2021 14:41:04 -0800 Subject: u2f: Move some u2f logic to common/ for testing Since this is cr50's branch, there's no semantic difference whether we put logic in board/cr50/u2f.c or common/u2f.c. EC's build system doesn't quite allow unit-testing board-specific logic, so to unit-test some of the crypto logic in board/cr50/u2f.c, things need to move to common/u2f.c. There's no change in functionality. There should also be no problem for merging/cherry-picking ToT changes to cr50_stab, because any new u2f changes are made on cr50_stab only and not on ToT. BUG=b:172971998 TEST=make run-u2f TEST=make CR50_DEV=1 BOARD=cr50 Change-Id: I3cb8d78fd6427620a6fe20cef12708899d2896b5 Signed-off-by: Yicheng Li Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2702496 Reviewed-by: Mary Ruthven --- board/cr50/u2f.c | 79 +----------------------------------------------------- common/u2f.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++-- include/u2f_impl.h | 20 ++++++++++++++ test/u2f.c | 40 +++++++++++++-------------- 4 files changed, 110 insertions(+), 102 deletions(-) diff --git a/board/cr50/u2f.c b/board/cr50/u2f.c index 12af471ff9..750708012b 100644 --- a/board/cr50/u2f.c +++ b/board/cr50/u2f.c @@ -54,14 +54,6 @@ enum touch_state pop_check_presence(int consume) return recent ? POP_TOUCH_YES : POP_TOUCH_NO; } -/* ---- non-volatile U2F state ---- */ - -struct u2f_state { - uint32_t salt[8]; - uint32_t salt_kek[8]; - uint32_t salt_kh[8]; -}; - static const uint8_t k_salt = NVMEM_VAR_G2F_SALT; static const uint8_t k_salt_deprecated = NVMEM_VAR_U2F_SALT; @@ -138,7 +130,7 @@ static int load_state(struct u2f_state *state) return 1; } -static struct u2f_state *get_state(void) +struct u2f_state *get_state(void) { static int state_loaded; static struct u2f_state state; @@ -166,54 +158,6 @@ static int _derive_key(enum dcrypto_appid appid, const uint32_t input[8], return result; } -int u2f_origin_user_keyhandle(const uint8_t *origin, const uint8_t *user, - const uint8_t *origin_seed, - struct u2f_key_handle *key_handle) -{ - LITE_HMAC_CTX ctx; - struct u2f_state *state = get_state(); - - if (!state) - return EC_ERROR_UNKNOWN; - - memcpy(key_handle->origin_seed, origin_seed, P256_NBYTES); - - DCRYPTO_HMAC_SHA256_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE); - HASH_update(&ctx.hash, origin, P256_NBYTES); - HASH_update(&ctx.hash, user, P256_NBYTES); - HASH_update(&ctx.hash, origin_seed, P256_NBYTES); - - memcpy(key_handle->hmac, DCRYPTO_HMAC_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) -{ - LITE_HMAC_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); - - DCRYPTO_HMAC_SHA256_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE); - HASH_update(&ctx.hash, origin, P256_NBYTES); - HASH_update(&ctx.hash, user, P256_NBYTES); - HASH_update(&ctx.hash, origin_seed, P256_NBYTES); - HASH_update(&ctx.hash, &version, sizeof(key_handle_header->version)); - - memcpy(key_handle_header->kh_hmac, DCRYPTO_HMAC_final(&ctx), - SHA256_DIGEST_SIZE); - - return EC_SUCCESS; -} - int u2f_origin_user_keypair(const uint8_t *key_handle, size_t key_handle_size, p256_int *d, p256_int *pk_x, p256_int *pk_y) { @@ -241,27 +185,6 @@ int u2f_origin_user_keypair(const uint8_t *key_handle, size_t key_handle_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) -{ - LITE_HMAC_CTX ctx; - struct u2f_state *state = get_state(); - - if (!state) - return EC_ERROR_UNKNOWN; - - DCRYPTO_HMAC_SHA256_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE); - HASH_update(&ctx.hash, authorization_salt, U2F_AUTHORIZATION_SALT_SIZE); - HASH_update(&ctx.hash, (uint8_t *)header, - sizeof(struct u2f_versioned_key_handle_header)); - HASH_update(&ctx.hash, auth_time_secret_hash, SHA256_DIGEST_SIZE); - - memcpy(hmac, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); - - return EC_SUCCESS; -} - int u2f_gen_kek(const uint8_t *origin, uint8_t *kek, size_t key_len) { uint32_t buf[P256_NDIGITS]; diff --git a/common/u2f.c b/common/u2f.c index 936dd7f035..7a5b3e5945 100644 --- a/common/u2f.c +++ b/common/u2f.c @@ -264,8 +264,8 @@ static int verify_versioned_kh_owned( BUILD_ASSERT(sizeof(struct u2f_sign_resp) <= sizeof(struct u2f_sign_req)); /* U2F SIGN command */ -static 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(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; @@ -504,3 +504,72 @@ static enum vendor_cmd_rc u2f_attest(enum vendor_cmd_cc code, void *buf, 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) +{ + LITE_HMAC_CTX ctx; + struct u2f_state *state = get_state(); + + if (!state) + return EC_ERROR_UNKNOWN; + + memcpy(key_handle->origin_seed, origin_seed, P256_NBYTES); + + DCRYPTO_HMAC_SHA256_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, origin, P256_NBYTES); + HASH_update(&ctx.hash, user, P256_NBYTES); + HASH_update(&ctx.hash, origin_seed, P256_NBYTES); + + memcpy(key_handle->hmac, DCRYPTO_HMAC_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) +{ + LITE_HMAC_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); + + DCRYPTO_HMAC_SHA256_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, origin, P256_NBYTES); + HASH_update(&ctx.hash, user, P256_NBYTES); + HASH_update(&ctx.hash, origin_seed, P256_NBYTES); + HASH_update(&ctx.hash, &version, sizeof(key_handle_header->version)); + + memcpy(key_handle_header->kh_hmac, DCRYPTO_HMAC_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) +{ + LITE_HMAC_CTX ctx; + struct u2f_state *state = get_state(); + + if (!state) + return EC_ERROR_UNKNOWN; + + DCRYPTO_HMAC_SHA256_init(&ctx, state->salt_kek, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, authorization_salt, U2F_AUTHORIZATION_SALT_SIZE); + HASH_update(&ctx.hash, (uint8_t *)header, + sizeof(struct u2f_versioned_key_handle_header)); + HASH_update(&ctx.hash, auth_time_secret_hash, SHA256_DIGEST_SIZE); + + memcpy(hmac, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); + + return EC_SUCCESS; +} diff --git a/include/u2f_impl.h b/include/u2f_impl.h index a2f2cfaa97..d3f4800387 100644 --- a/include/u2f_impl.h +++ b/include/u2f_impl.h @@ -33,6 +33,19 @@ enum touch_state { */ enum touch_state pop_check_presence(int consume); +/* ---- non-volatile U2F state ---- */ + +struct u2f_state { + uint32_t salt[8]; + uint32_t salt_kek[8]; + uint32_t salt_kh[8]; +}; + +/** + * Get the current u2f state from the board. + */ +struct u2f_state *get_state(void); + /* ---- platform cryptography hooks ---- */ /** @@ -145,4 +158,11 @@ int g2f_attestation_cert(uint8_t *buf); enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, void *buf, size_t input_size, size_t *response_size); +/** + * U2F_SIGN command handler. Verifies a key handle is owned and signs data with + * it. + */ +enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf, + size_t input_size, size_t *response_size); + #endif /* __CROS_EC_U2F_IMPL_H */ diff --git a/test/u2f.c b/test/u2f.c index 3d36ff1830..56ae0cf65e 100644 --- a/test/u2f.c +++ b/test/u2f.c @@ -65,11 +65,29 @@ void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required) SHA256_init(ctx); } +void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key, + unsigned int len) +{ + SHA256_init(&ctx->hash); +} + +const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx) +{ + return SHA256_final(&ctx->hash); +} + /******************************************************************************/ /* Mock implementations of U2F functionality. */ static int presence; +static struct u2f_state state; + +struct u2f_state *get_state(void) +{ + return &state; +} + enum touch_state pop_check_presence(int consume) { enum touch_state ret = presence ? @@ -80,21 +98,6 @@ enum touch_state pop_check_presence(int consume) return ret; } -int u2f_origin_user_keyhandle(const uint8_t *origin, const uint8_t *user, - const uint8_t *seed, - struct u2f_key_handle *key_handle) -{ - return EC_SUCCESS; -} - -int u2f_origin_user_versioned_keyhandle( - const uint8_t *origin, const uint8_t *user, const uint8_t *seed, - uint8_t version, - struct u2f_versioned_key_handle_header *key_handle_header) -{ - return EC_SUCCESS; -} - int u2f_origin_user_keypair(const uint8_t *key_handle, size_t key_handle_size, p256_int *d, p256_int *pk_x, p256_int *pk_y) { @@ -106,13 +109,6 @@ int g2f_individual_keypair(p256_int *d, p256_int *pk_x, p256_int *pk_y) 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) -{ - return EC_SUCCESS; -} - /******************************************************************************/ /* Tests begin here. */ -- cgit v1.2.1