From 7b0018521683070cfa5beda948a8ea5278d802cc Mon Sep 17 00:00:00 2001 From: Vadim Bendebury Date: Sat, 26 May 2018 21:01:12 -0700 Subject: cr50: move RMA challenge-response to P256 Using the p256 curve is beneficial, because RMA feature is currently the only user of the x25519 curve in Cr50, whereas p256 support is required by other subsystems and its implementation is based on dcrypto. The p256 public key is 65 bytes in size, appropriate adjustments are being made for the structure storing the server public key and the key ID. The compact representation of the p256 public key requires 33 bytes, including the X coordinate and one extra byte used to communicate if the omitted Y coordinate is odd or even. The challenge structure communicated to the RMA server allows exactly 32 bytes for the public key. To comply, the generated ephemeral public key is used in compressed form (only the X coordinate is used). For the server to properly uncompress the public key one extra bit is required, to indicate if the original key's Y coordinate is odd or even. Since there is no room for the extra bit in the challenge structure, a convention is used where the generated ephemeral public key is guaranteed to have an odd Y coordinate. When generating the ephemeral key, the Y coordinate is checked, and if it is even, generation attempt is repeated. Some clean up is also included: even with debug enabled, generated challenge is displayed only once as a long string, convenient for copying and pasting. The new feature is not yet enabled, p256 support on the RMA server side is not yet available. Enabling p256 curve for RMA authentication saves 5336 bytes of the flash space. BRANCH=cr50, cr50-mp BUG=b:73296606 TEST=enabled CONFIG_RMA_AUTH_USE_P256 in board.h, generated challenge and verified matching auth code generated by the rma_reset utility. Change-Id: I857543c89a7c33c6fc2dc00e142fe9fa6fc642cf Signed-off-by: Vadim Bendebury Reviewed-on: https://chromium-review.googlesource.com/1074743 Reviewed-by: Randall Spangler --- common/build.mk | 8 +++- common/rma_auth.c | 137 ++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 109 insertions(+), 36 deletions(-) (limited to 'common') diff --git a/common/build.mk b/common/build.mk index d1d6f88ee4..f39c716d80 100644 --- a/common/build.mk +++ b/common/build.mk @@ -179,9 +179,15 @@ endif ifeq ($(TEST_BUILD),) +ifeq ($(CONFIG_RMA_AUTH_USE_P256),) +BLOB_FILE = rma_key_blob.test +else +BLOB_FILE = rma_key_blob.p256.test +endif + $(out)/RW/common/rma_auth.o: $(out)/rma_key_from_blob.h -$(out)/rma_key_from_blob.h: board/$(BOARD)/rma_key_blob.test util/bin2h.sh +$(out)/rma_key_from_blob.h: board/$(BOARD)/$(BLOB_FILE) util/bin2h.sh $(Q)util/bin2h.sh RMA_KEY_BLOB $< $@ endif diff --git a/common/rma_auth.c b/common/rma_auth.c index 51516966b8..87894e70ad 100644 --- a/common/rma_auth.c +++ b/common/rma_auth.c @@ -11,7 +11,9 @@ #include "ccd_config.h" #include "chip/g/board_id.h" #include "console.h" +#ifdef CONFIG_CURVE25519 #include "curve25519.h" +#endif #include "extension.h" #include "hooks.h" #include "rma_auth.h" @@ -20,10 +22,17 @@ #include "timer.h" #include "tpm_registers.h" #include "tpm_vendor_cmds.h" +#ifdef CONFIG_RMA_AUTH_USE_P256 +#include "trng.h" +#endif #include "util.h" #ifndef TEST_BUILD +#include "cryptoc/util.h" #include "rma_key_from_blob.h" +#else +/* Cryptoc library is not available to the test layer. */ +#define always_memset memset #endif #ifdef CONFIG_DCRYPTO @@ -40,12 +49,18 @@ /* Number of tries to properly enter auth code */ #define MAX_AUTHCODE_TRIES 3 +#ifdef CONFIG_RMA_AUTH_USE_P256 +#define RMA_SERVER_PUB_KEY_SZ 65 +#else +#define RMA_SERVER_PUB_KEY_SZ 32 +#endif + /* Server public key and key ID */ static const struct { union { - uint8_t raw_blob[33]; + uint8_t raw_blob[RMA_SERVER_PUB_KEY_SZ + 1]; struct { - uint8_t server_pub_key[32]; + uint8_t server_pub_key[RMA_SERVER_PUB_KEY_SZ]; volatile uint8_t server_key_id; }; }; @@ -53,7 +68,7 @@ static const struct { .raw_blob = RMA_KEY_BLOB }; -BUILD_ASSERT(sizeof(rma_key_blob) == 33); +BUILD_ASSERT(sizeof(rma_key_blob) == (RMA_SERVER_PUB_KEY_SZ + 1)); static char challenge[RMA_CHALLENGE_BUF_SIZE]; static char authcode[RMA_AUTHCODE_BUF_SIZE]; @@ -87,6 +102,71 @@ static void hash_buffer(void *dest, size_t dest_size, memcpy(dest, temp, dest_size); } +#ifdef CONFIG_RMA_AUTH_USE_P256 +/* + * Generate a p256 key pair, such that Y coordinate component of the public + * key is an odd value. Use the X component value as the compressed public key + * to be sent to the server. Multiply server public key by our private key to + * generate the shared secret. + * + * @pub_key - array to return 32 bytes of the X coordinate public key + * component. + * @secet - array to return the X coordinate of the product of the server + * public key multiplied by our private key. + */ +static void p256_get_pub_key_and_secret(uint8_t pub_key[P256_NBYTES], + uint8_t secret[P256_NBYTES]) +{ + uint8_t buf[SHA256_DIGEST_SIZE]; + p256_int d; + p256_int pk_x; + p256_int pk_y; + + /* Get some noise for private key. */ + rand_bytes(buf, sizeof(buf)); + + /* + * By convention with the RMA server the Y coordinate of the Cr50 + * public key component is required to be an odd value. Keep trying + * until the genreated bublic key has the compliant Y coordinate. + */ + while (1) { + HASH_CTX sha; + + if (DCRYPTO_p256_key_from_bytes(&pk_x, &pk_y, &d, buf)) { + + /* Is Y coordinate an odd value? */ + if (p256_is_odd(&pk_y)) + break; /* Yes it is, got a good key. */ + } + + /* Did not succeed, rehash the private key and try again. */ + DCRYPTO_SHA256_init(&sha, 0); + HASH_update(&sha, buf, sizeof(buf)); + memcpy(buf, HASH_final(&sha), sizeof(buf)); + } + + /* X coordinate is passed to the server as the public key. */ + p256_to_bin(&pk_x, pub_key); + + /* + * Now let's calculate the secret as a the server pub key multiplied + * by our private key. + */ + p256_from_bin(rma_key_blob.raw_blob + 1, &pk_x); + p256_from_bin(rma_key_blob.raw_blob + 1 + P256_NBYTES, &pk_y); + + /* Use input space for storing multiplication results. */ + DCRYPTO_p256_point_mul(&pk_x, &pk_y, &d, &pk_x, &pk_y); + + /* X value is the seed for the shared secret. */ + p256_to_bin(&pk_x, secret); + + /* Wipe out the private key just in case. */ + always_memset(&d, 0, sizeof(d)); +} +#endif + /** * Create a new RMA challenge/response * @@ -139,15 +219,18 @@ int rma_create_challenge(void) device_id, unique_device_id_size); } - /* Calculate a new ephemeral key pair */ + /* Calculate a new ephemeral key pair and the shared secret. */ +#ifdef CONFIG_RMA_AUTH_USE_P256 + p256_get_pub_key_and_secret(c.device_pub_key, secret); +#endif +#ifdef CONFIG_CURVE25519 X25519_keypair(c.device_pub_key, temp); - + X25519(secret, temp, rma_key_blob.server_pub_key); +#endif /* Encode the challenge */ if (base32_encode(challenge, sizeof(challenge), cptr, 8 * sizeof(c), 9)) return EC_ERROR_UNKNOWN; - /* Calculate the shared secret */ - X25519(secret, temp, rma_key_blob.server_pub_key); /* * Auth code is a truncated HMAC of the ephemeral public key, BoardID, @@ -206,6 +289,7 @@ int rma_try_authcode(const char *code) static enum vendor_cmd_rc get_challenge(uint8_t *buf, size_t *buf_size) { int rv; + size_t i; if (*buf_size < sizeof(challenge)) { *buf_size = 1; @@ -223,22 +307,19 @@ static enum vendor_cmd_rc get_challenge(uint8_t *buf, size_t *buf_size) *buf_size = sizeof(challenge) - 1; memcpy(buf, rma_get_challenge(), *buf_size); + + CPRINTF("generated challenge:\n\n"); + for (i = 0; i < *buf_size; i++) + CPRINTF("%c", ((uint8_t *)buf)[i]); + CPRINTF("\n\n"); + #ifdef CR50_DEV - { - size_t i; - - CPRINTF("%s: generated challenge:\n", __func__); - for (i = 0; i < *buf_size; i++) - CPRINTF("%c", ((uint8_t *)buf)[i]); - CPRINTF("\n"); - - CPRINTF("%s: expected authcode: ", __func__); - for (i = 0; i < RMA_AUTHCODE_CHARS; i++) - CPRINTF("%c", authcode[i]); - CPRINTF("\n"); - } -#endif + CPRINTF("expected authcode: "); + for (i = 0; i < RMA_AUTHCODE_CHARS; i++) + CPRINTF("%c", authcode[i]); + CPRINTF("\n"); +#endif return VENDOR_RC_SUCCESS; } @@ -429,20 +510,6 @@ static int rma_auth_cmd(int argc, char **argv) if (tpmh->command_code) { ccprintf("RMA Auth error 0x%x\n", be32toh(tpmh->command_code)); rv = EC_ERROR_UNKNOWN; - } else { - /* Success, let's print out the challenge. */ - int i; - char *challenge = (char *)(tpmh + 1); - - for (i = 0; i < RMA_CHALLENGE_CHARS; i++) { - if (!(i % 5)) { - if (!(i % 20)) - ccprintf("\n"); - ccprintf(" "); - } - ccprintf("%c", challenge[i]); - } - ccprintf("\n"); } shared_mem_release(tpmh); -- cgit v1.2.1