diff options
author | Randall Spangler <rspangler@chromium.org> | 2017-06-21 13:10:57 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-06-30 16:02:50 -0700 |
commit | 282765fdd409fd16ed1e092e5d7fee8de5af7a5a (patch) | |
tree | 6ba38fa099ef790c72d34f1caa458bd731aa39d3 /test | |
parent | 4a8b509020ce5104abf9b43335283cb39c7b75b2 (diff) | |
download | chrome-ec-282765fdd409fd16ed1e092e5d7fee8de5af7a5a.tar.gz |
common: Add RMA reset auth challenge-response crypto
RMA auth uses X25519 to generate a relatively small challenge and
response.
Currently, nothing calls the rma_auth code. We'll need console and
TPM vendor commands to do so.
BUG=b:37952913
BRANCH=none
TEST=make buildall
Change-Id: Iec7f2d0e3dc8243f79b009ead16bb3ba9f1bef9d
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/544184
Diffstat (limited to 'test')
-rw-r--r-- | test/build.mk | 2 | ||||
-rw-r--r-- | test/rma_auth.c | 199 | ||||
-rw-r--r-- | test/rma_auth.tasklist | 17 | ||||
-rw-r--r-- | test/test_config.h | 10 |
4 files changed, 228 insertions, 0 deletions
diff --git a/test/build.mk b/test/build.mk index b7ba92fcbc..2a1102748d 100644 --- a/test/build.mk +++ b/test/build.mk @@ -66,6 +66,7 @@ test-list-host += nvmem_vars test-list-host += pingpong test-list-host += power_button test-list-host += queue +test-list-host += rma_auth test-list-host += rsa test-list-host += rsa3 test-list-host += sbs_charging_v2 @@ -113,6 +114,7 @@ pingpong-y=pingpong.o power_button-y=power_button.o powerdemo-y=powerdemo.o queue-y=queue.o +rma_auth-y=rma_auth.o rsa-y=rsa.o rsa3-y=rsa.o sbs_charging-y=sbs_charging.o diff --git a/test/rma_auth.c b/test/rma_auth.c new file mode 100644 index 0000000000..d833a2c33b --- /dev/null +++ b/test/rma_auth.c @@ -0,0 +1,199 @@ +/* Copyright 2017 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. + * + * Test RMA auth challenge/response + */ + +#include <stdio.h> +#include "common.h" +#include "chip/g/board_id.h" +#include "curve25519.h" +#include "base32.h" +#include "sha256.h" +#include "rma_auth.h" +#include "test_util.h" +#include "timer.h" +#include "util.h" + +/* Dummy implementations for testing */ +static uint8_t dummy_board_id[4] = {'Z', 'Z', 'C', 'R'}; +static uint8_t dummy_device_id[8] = {'T', 'H', 'X', 1, 1, 3, 8, 0xfe}; +static int server_protocol_version = RMA_CHALLENGE_VERSION; +static uint8_t server_private_key[32] = RMA_TEST_SERVER_PRIVATE_KEY; +static int server_key_id = RMA_TEST_SERVER_KEY_ID; + +void rand_bytes(void *buffer, size_t len) +{ + FILE *f = fopen("/dev/urandom", "rb"); + + assert(f); + fread(buffer, 1, len, f); + fclose(f); +} + +int read_board_id(struct board_id *id) +{ + memcpy(&id->type, dummy_board_id, sizeof(id->type)); + id->type_inv = ~id->type; + id->flags = 0xFF00; + return EC_SUCCESS; +} + +int system_get_chip_unique_id(uint8_t **id) +{ + *id = dummy_device_id; + return sizeof(dummy_device_id); +} + +/** + * Simulate the server side of a RMA challenge-response. + * + * @param out_auth_code Buffer for generated authorization code + * (must be >= CR50_AUTH_CODE_CHARS + 1 chars) + * @param challenge Challenge from device + * @return 0 if success, non-zero if error. + */ +int rma_server_side(char *out_auth_code, const char *challenge) +{ + int version, key_id; + uint32_t device_id[2]; + uint8_t secret[32]; + uint8_t hmac[32]; + struct rma_challenge c; + uint8_t *cptr = (uint8_t *)&c; + + /* Convert the challenge back into binary */ + if (base32_decode(cptr, 8 * sizeof(c), challenge, 9) != 8 * sizeof(c)) { + printf("Error decoding challenge\n"); + return -1; + } + + version = RMA_CHALLENGE_GET_VERSION(c.version_key_id); + if (version != server_protocol_version) { + printf("Unsupported challenge version %d\n", version); + return -1; + } + + key_id = RMA_CHALLENGE_GET_KEY_ID(c.version_key_id); + + printf("\nChallenge: %s\n", challenge); + printf(" Version: %d\n", version); + printf(" Server KeyID: %d\n", key_id); + printf(" BoardID: %c%c%c%c\n", + isprint(c.board_id[0]) ? c.board_id[0] : '?', + isprint(c.board_id[1]) ? c.board_id[1] : '?', + isprint(c.board_id[2]) ? c.board_id[2] : '?', + isprint(c.board_id[3]) ? c.board_id[3] : '?'); + + memcpy(device_id, c.device_id, sizeof(device_id)); + printf(" DeviceID: 0x%08x 0x%08x\n", device_id[0], device_id[1]); + + if (key_id != server_key_id) { + printf("Unsupported KeyID %d\n", key_id); + return -1; + } + + /* + * Make sure the current user is authorized to reset this board. + * + * Since this is just a test, here we'll just make sure the BoardID + * and DeviceID match what we expected. + */ + if (memcmp(c.board_id, dummy_board_id, sizeof(c.board_id))) { + printf("BoardID mismatch\n"); + return -1; + } + if (memcmp(c.device_id, dummy_device_id, sizeof(c.device_id))) { + printf("DeviceID mismatch\n"); + return -1; + } + + /* Calculate the shared secret */ + X25519(secret, server_private_key, c.device_pub_key); + + /* + * Auth code is a truncated HMAC of the ephemeral public key, BoardID, + * and DeviceID. + */ + hmac_SHA256(hmac, secret, sizeof(secret), cptr + 1, sizeof(c) - 1); + if (base32_encode(out_auth_code, RMA_AUTHCODE_BUF_SIZE, + hmac, RMA_AUTHCODE_CHARS * 5, 0)) { + printf("Error encoding auth code\n"); + return -1; + } + printf("Authcode: %s\n", out_auth_code); + + return 0; +}; + +#define FORCE_TIME(t) { ts.val = (t); force_time(ts); } + +static int test_rma_auth(void) +{ + const char *challenge; + char authcode[RMA_AUTHCODE_BUF_SIZE]; + timestamp_t ts; + + /* Test rate limiting */ + FORCE_TIME(9 * SECOND); + TEST_ASSERT(rma_create_challenge() == EC_ERROR_TIMEOUT); + TEST_ASSERT(rma_try_authcode("Bad") == EC_ERROR_ACCESS_DENIED); + TEST_ASSERT(strlen(rma_get_challenge()) == 0); + + FORCE_TIME(10 * SECOND); + TEST_ASSERT(rma_create_challenge() == 0); + TEST_ASSERT(strlen(rma_get_challenge()) == RMA_CHALLENGE_CHARS); + + /* Test using up tries */ + TEST_ASSERT(rma_try_authcode("Bad") == EC_ERROR_INVAL); + TEST_ASSERT(strlen(rma_get_challenge()) == RMA_CHALLENGE_CHARS); + TEST_ASSERT(rma_try_authcode("BadCodeZ") == EC_ERROR_INVAL); + TEST_ASSERT(strlen(rma_get_challenge()) == RMA_CHALLENGE_CHARS); + TEST_ASSERT(rma_try_authcode("BadLongCode") == EC_ERROR_INVAL); + /* Out of tries now */ + TEST_ASSERT(strlen(rma_get_challenge()) == 0); + TEST_ASSERT(rma_try_authcode("Bad") == EC_ERROR_ACCESS_DENIED); + + FORCE_TIME(19 * SECOND); + TEST_ASSERT(rma_create_challenge() == EC_ERROR_TIMEOUT); + TEST_ASSERT(strlen(rma_get_challenge()) == 0); + + FORCE_TIME(21 * SECOND); + TEST_ASSERT(rma_create_challenge() == 0); + challenge = rma_get_challenge(); + TEST_ASSERT(strlen(challenge) == RMA_CHALLENGE_CHARS); + TEST_ASSERT(rma_server_side(authcode, challenge) == 0); + TEST_ASSERT(rma_try_authcode(authcode) == EC_SUCCESS); + + /* + * Make sure the server-side checks for fields work. That is, test + * our ability to test those fields... + */ + server_protocol_version++; + TEST_ASSERT(rma_server_side(authcode, challenge) == -1); + server_protocol_version--; + + server_key_id++; + TEST_ASSERT(rma_server_side(authcode, challenge) == -1); + server_key_id--; + + dummy_board_id[0]++; + TEST_ASSERT(rma_server_side(authcode, challenge) == -1); + dummy_board_id[0]--; + + dummy_device_id[0]++; + TEST_ASSERT(rma_server_side(authcode, challenge) == -1); + dummy_device_id[0]--; + + return EC_SUCCESS; +} + +void run_test(void) +{ + test_reset(); + + RUN_TEST(test_rma_auth); + + test_print_result(); +} diff --git a/test/rma_auth.tasklist b/test/rma_auth.tasklist new file mode 100644 index 0000000000..e241aab4bb --- /dev/null +++ b/test/rma_auth.tasklist @@ -0,0 +1,17 @@ +/* Copyright 2017 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. + */ + +/** + * List of enabled tasks in the priority order + * + * The first one has the lowest priority. + * + * For each task, use the macro TASK_TEST(n, r, d, s) where : + * 'n' in the name of the task + * 'r' in the main routine of the task + * 'd' in an opaque parameter passed to the routine at startup + * 's' is the stack size in bytes; must be a multiple of 8 + */ +#define CONFIG_TEST_TASK_LIST /* No test task */ diff --git a/test/test_config.h b/test/test_config.h index e01218bc10..b90aac3966 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -58,6 +58,16 @@ #define CONFIG_TABLET_MODE #endif +#ifdef TEST_RMA_AUTH +#define CONFIG_BASE32 +#define CONFIG_CURVE25519 +#define CONFIG_RMA_AUTH +#define CONFIG_RMA_AUTH_SERVER_PUBLIC_KEY RMA_TEST_SERVER_PUBLIC_KEY +#define CONFIG_RMA_AUTH_SERVER_KEY_ID RMA_TEST_SERVER_KEY_ID +#define CONFIG_RNG +#define CONFIG_SHA256 +#endif + #ifdef TEST_RSA #define CONFIG_RSA #define CONFIG_RSA_KEY_SIZE 2048 |