From 72a3dd167c24a20a6df568d0c84c77dd45a6d2cf Mon Sep 17 00:00:00 2001 From: Yicheng Li Date: Mon, 4 Jan 2021 14:49:19 -0800 Subject: cr50_stab: Add unittests for u2f The u2f functionality had no unittests at all. This change is more of a setup (in terms of build dependencies) so that u2f tests can be easily added in the future. This change comes with a few simple tests for u2f_generate. The basic idea here is to use board/host/dcrypto.h to mock the dcrypto functionalities. Since board/host/dcrypto.h includes an alternative to cryptoc's sha256 definitions, we need to exclude cryptoc/sha256.h in the test builds. BUG=b:172971998 TEST=make -j run-u2f TEST=make CR50_DEV=1 BOARD=cr50 -j Signed-off-by: Yicheng Li Change-Id: Idae6f55f599a017aedcaf0fe4cdb6c0506e72712 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2610133 Reviewed-by: Mary Ruthven --- board/host/dcrypto.h | 25 +++++++- common/u2f.c | 10 ++- include/u2f_impl.h | 13 ++++ test/build.mk | 2 + test/test_config.h | 6 ++ test/u2f.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++ test/u2f.tasklist | 9 +++ 7 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 test/u2f.c create mode 100644 test/u2f.tasklist diff --git a/board/host/dcrypto.h b/board/host/dcrypto.h index 31f04e51aa..ce924e64fa 100644 --- a/board/host/dcrypto.h +++ b/board/host/dcrypto.h @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* Provides the minimal declarations needed by pinweaver to build on +/* Provides the minimal declarations needed by pinweaver and u2f to build on * CHIP_HOST. While it might be preferable to simply use the original dcrypto.h, * That would require incorporating additional headers / dependencies such as * cryptoc. @@ -73,6 +73,29 @@ void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx); int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], uint32_t output[8]); +#include "cryptoc/p256.h" + +int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + const char *name, uint8_t *cert, + const int n); + +int DCRYPTO_ladder_random(void *output); + +#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / sizeof(uint32_t)) + +struct drbg_ctx { + uint32_t k[SHA256_DIGEST_WORDS]; + uint32_t v[SHA256_DIGEST_WORDS]; + uint32_t reseed_counter; +}; + +int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, + const p256_int *message, p256_int *r, p256_int *s); + +void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, const p256_int *key, + const p256_int *message); + #endif /* CONFIG_DCRYPTO_MOCK */ #endif /* __CROS_EC_HOST_DCRYPTO_H */ diff --git a/common/u2f.c b/common/u2f.c index 5205809379..936dd7f035 100644 --- a/common/u2f.c +++ b/common/u2f.c @@ -7,7 +7,11 @@ #include "console.h" #include "cryptoc/p256.h" + +#ifndef TEST_BUILD #include "cryptoc/sha256.h" +#endif + #include "dcrypto.h" #include "extension.h" #include "system.h" @@ -79,8 +83,8 @@ static void copy_versioned_kh_pubkey_out(p256_int *opk_x, p256_int *opk_y, } /* U2F GENERATE command */ -static 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(enum vendor_cmd_cc code, void *buf, + size_t input_size, size_t *response_size) { struct u2f_generate_req *req = buf; uint8_t kh_version = @@ -440,7 +444,7 @@ static enum vendor_cmd_rc u2f_attest(enum vendor_cmd_cc code, void *buf, int verify_ret; - HASH_CTX h_ctx; + struct HASH_CTX h_ctx; struct drbg_ctx dr_ctx; /* Data hash, and corresponding signature. */ diff --git a/include/u2f_impl.h b/include/u2f_impl.h index fd2cc05ba1..a2f2cfaa97 100644 --- a/include/u2f_impl.h +++ b/include/u2f_impl.h @@ -9,7 +9,13 @@ #define __CROS_EC_U2F_IMPL_H #include "common.h" + +#ifdef TEST_BUILD +#include "board/host/dcrypto.h" +#endif + #include "cryptoc/p256.h" +#include "tpm_vendor_cmds.h" #include "u2f.h" /* ---- Physical presence ---- */ @@ -132,4 +138,11 @@ int u2f_gen_kek_seed(int commit); */ int g2f_attestation_cert(uint8_t *buf); +/** + * U2F_GENERATE command handler. Generates a key handle according to input + * parameters. + */ +enum vendor_cmd_rc u2f_generate(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/build.mk b/test/build.mk index ec40d00b95..ec51ab4bf9 100644 --- a/test/build.mk +++ b/test/build.mk @@ -48,6 +48,7 @@ test-list-host += static_if_error test-list-host += system test-list-host += thermal test-list-host += timer_dos +test-list-host += u2f test-list-host += uptime test-list-host += utils test-list-host += utils_str @@ -91,6 +92,7 @@ system-y=system.o thermal-y=thermal.o timer_calib-y=timer_calib.o timer_dos-y=timer_dos.o +u2f-y=u2f.o uptime-y=uptime.o utils-y=utils.o utils_str-y=utils_str.o diff --git a/test/test_config.h b/test/test_config.h index 75ca65a6c3..0a66429ef1 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -180,6 +180,12 @@ enum nvmem_users { NVMEM_TPM = 0, NVMEM_CR50, NVMEM_NUM_USERS }; #define CONFIG_HOSTCMD_RTC #endif +#ifdef TEST_U2F +#define CONFIG_DCRYPTO_MOCK +#define CONFIG_U2F +#define CC_EXTENSION CC_COMMAND +#endif + #ifdef TEST_VBOOT #define CONFIG_RWSIG #define CONFIG_SHA256 diff --git a/test/u2f.c b/test/u2f.c new file mode 100644 index 0000000000..3d36ff1830 --- /dev/null +++ b/test/u2f.c @@ -0,0 +1,173 @@ +/* Copyright 2021 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "test_util.h" +#include "u2f_impl.h" + +/******************************************************************************/ +/* Mock implementations of cr50 board. + */ +int system_get_chip_unique_id(uint8_t **id) +{ + return P256_NBYTES; +} + +/******************************************************************************/ +/* Mock implementations of Dcrypto functionality. + */ +int DCRYPTO_ladder_random(void *output) +{ + memset(output, 0, P256_NBYTES); + /* Return 1 for success, 0 for error. */ + return 1; +} + +int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + const char *name, uint8_t *cert, + const int n) +{ + /* Return the size of certificate, 0 means error. */ + return 0; +} + +int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, + const p256_int *message, p256_int *r, p256_int *s) +{ + memset(r, 0, sizeof(p256_int)); + memset(s, 0, sizeof(p256_int)); + /* Return 1 for success, 0 for error. */ + return 1; +} + +void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, + const p256_int *key, + const p256_int *message) +{ + memset(ctx, 0, sizeof(struct drbg_ctx)); +} + +void HASH_update(struct HASH_CTX *ctx, const void *data, size_t len) +{ + if (ctx) + SHA256_update(ctx, data, len); +} + +uint8_t *HASH_final(struct HASH_CTX *ctx) +{ + return SHA256_final(ctx); +} + +void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required) +{ + SHA256_init(ctx); +} + +/******************************************************************************/ +/* Mock implementations of U2F functionality. + */ +static int presence; + +enum touch_state pop_check_presence(int consume) +{ + enum touch_state ret = presence ? + POP_TOUCH_YES : POP_TOUCH_NO; + + if (consume) + presence = 0; + 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) +{ + return EC_SUCCESS; +} + +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. + */ +static uint8_t buffer[512]; + +test_static int test_u2f_generate_no_require_presence(void) +{ + struct u2f_generate_req *req = (struct u2f_generate_req *)buffer; + size_t response_size = sizeof(struct u2f_generate_resp); + int ret; + + memset(buffer, 0, sizeof(buffer)); + req->flags = 0; + presence = 0; + ret = u2f_generate( + VENDOR_CC_U2F_GENERATE, &buffer, + sizeof(struct u2f_generate_req), + &response_size); + + TEST_ASSERT(ret == VENDOR_RC_SUCCESS); + return EC_SUCCESS; +} + +test_static int test_u2f_generate_require_presence(void) +{ + struct u2f_generate_req *req = (struct u2f_generate_req *)buffer; + size_t response_size = sizeof(struct u2f_generate_resp); + int ret; + + memset(buffer, 0, sizeof(buffer)); + req->flags = U2F_AUTH_FLAG_TUP; + presence = 0; + ret = u2f_generate( + VENDOR_CC_U2F_GENERATE, &buffer, + sizeof(struct u2f_generate_req), + &response_size); + TEST_ASSERT(ret == VENDOR_RC_NOT_ALLOWED); + + memset(buffer, 0, sizeof(buffer)); + req->flags = U2F_AUTH_FLAG_TUP; + response_size = sizeof(struct u2f_generate_resp); + presence = 1; + ret = u2f_generate( + VENDOR_CC_U2F_GENERATE, &buffer, + sizeof(struct u2f_generate_req), + &response_size); + TEST_ASSERT(ret == VENDOR_RC_SUCCESS); + + return EC_SUCCESS; +} + +void run_test(void) +{ + RUN_TEST(test_u2f_generate_no_require_presence); + RUN_TEST(test_u2f_generate_require_presence); + + test_print_result(); +} diff --git a/test/u2f.tasklist b/test/u2f.tasklist new file mode 100644 index 0000000000..299cf25390 --- /dev/null +++ b/test/u2f.tasklist @@ -0,0 +1,9 @@ +/* Copyright 2021 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** + * See CONFIG_TASK_LIST in config.h for details. + */ +#define CONFIG_TEST_TASK_LIST -- cgit v1.2.1