diff options
-rw-r--r-- | board/cr50/tpm2/ecc.c | 26 | ||||
-rw-r--r-- | board/cr50/tpm2/manufacture.c | 187 | ||||
-rw-r--r-- | board/cr50/tpm2/rsa.c | 29 |
3 files changed, 218 insertions, 24 deletions
diff --git a/board/cr50/tpm2/ecc.c b/board/cr50/tpm2/ecc.c index d6f73c0cf1..a35f974ce2 100644 --- a/board/cr50/tpm2/ecc.c +++ b/board/cr50/tpm2/ecc.c @@ -128,6 +128,16 @@ CRYPT_RESULT _cpri__EccPointMultiply( } } +static const TPM2B_32_BYTE_VALUE ECC_TEMPLATE_EK_EXTRA = { + .t = {32, { + 0xC2, 0xE0, 0x31, 0x93, 0x40, 0xFB, 0x48, 0xF1, + 0x02, 0x53, 0x9E, 0xA9, 0x83, 0x63, 0xF8, 0x1E, + 0x2D, 0x30, 0x6E, 0x91, 0x8D, 0xD7, 0x78, 0xAB, + 0xF0, 0x54, 0x73, 0xA2, 0xA6, 0x0D, 0xAE, 0x09, + } + } +}; + /* Key generation based on FIPS-186.4 section B.1.2 (Key Generation by * Testing Candidates) */ CRYPT_RESULT _cpri__GenerateKeyEcc( @@ -137,6 +147,8 @@ CRYPT_RESULT _cpri__GenerateKeyEcc( { TPM2B_4_BYTE_VALUE marshaled_counter = { .t = {4} }; TPM2B_32_BYTE_VALUE local_seed = { .t = {32} }; + TPM2B_4_BYTE_VALUE truncated_extra = { .t = {4} }; + TPM2B *local_extra; uint32_t count = 0; uint8_t key_bytes[P256_NBYTES]; LITE_HMAC_CTX hmac; @@ -159,10 +171,22 @@ CRYPT_RESULT _cpri__GenerateKeyEcc( HASH_update(&hmac.hash, "ECC", 4); memcpy(local_seed.t.buffer, DCRYPTO_HMAC_final(&hmac), local_seed.t.size); + /* TODO(ngm): CRBUG/P/55260: the personalize code uses only + * the first 4 bytes of extra. + */ + if (extra && extra->size == ECC_TEMPLATE_EK_EXTRA.b.size && + memcmp(extra->buffer, + ECC_TEMPLATE_EK_EXTRA.b.buffer, + ECC_TEMPLATE_EK_EXTRA.b.size) == 0) { + memcpy(truncated_extra.b.buffer, extra->buffer, 4); + local_extra = &truncated_extra.b; + } else { + local_extra = extra; + } for (; count != 0; count++) { memcpy(marshaled_counter.t.buffer, &count, sizeof(count)); - _cpri__KDFa(hash_alg, &local_seed.b, label, extra, + _cpri__KDFa(hash_alg, &local_seed.b, label, local_extra, &marshaled_counter.b, sizeof(key_bytes) * 8, key_bytes, NULL, FALSE); if (DCRYPTO_p256_key_from_bytes( diff --git a/board/cr50/tpm2/manufacture.c b/board/cr50/tpm2/manufacture.c index 01697af208..ee02fa85b8 100644 --- a/board/cr50/tpm2/manufacture.c +++ b/board/cr50/tpm2/manufacture.c @@ -6,13 +6,19 @@ #include "tpm_manufacture.h" #include "tpm_registers.h" +#include "TPM_Types.h" +#include "TpmBuildSwitches.h" +#include "CryptoEngine.h" +#include "CpriECC_fp.h" +#include "CpriRSA_fp.h" +#include "tpm_types.h" + #include "Global.h" #include "Hierarchy_fp.h" #include "InternalRoutines.h" #include "Manufacture_fp.h" #include "NV_Write_fp.h" #include "NV_DefineSpace_fp.h" -#include "TPM_Types.h" #include "console.h" #include "extension.h" @@ -209,9 +215,136 @@ static void get_rwr(uint32_t *rwr) *rwr++ = *base_ptr++; } +static int memstr(const void *haystack, size_t haystack_len, + const void *needle, size_t needle_len) +{ + size_t i; + const uint8_t *p = haystack; + + if (haystack_len < needle_len) + return -1; + + for (i = 0; i < haystack_len - needle_len + 1; i++) { + if (memcmp(&p[i], needle, needle_len) == 0) + return i; + } + + return -1; +} + +/* The TPM2B_BYTE_VALUE macro does not work with a #defined parameter. */ +BUILD_ASSERT(PRIMARY_SEED_SIZE == 32); +TPM2B_BYTE_VALUE(32); + +/* This is the SHA-256 hash of the RSA template from the TCG + * EK Credential Profile spec. + */ +static const TPM2B_32_BYTE_VALUE RSA_TEMPLATE_EK_EXTRA = { + .t = {32, { + 0x68, 0xd1, 0xa2, 0x41, 0xfb, 0x27, 0x2f, 0x03, + 0x90, 0xbf, 0xd0, 0x42, 0x8d, 0xad, 0xee, 0xb0, + 0x2b, 0xf4, 0xa1, 0xcd, 0x46, 0xab, 0x6c, 0x39, + 0x1b, 0xa3, 0x1f, 0x51, 0x87, 0x06, 0x8e, 0x6a + } + } +}; +const char VENDOR_EK_RSA_LABEL[] = "RSA key by vendor"; +const char VENDOR_EK_ECC_LABEL[] = "ECC key by vendor"; + +/* Verify that the endorsement certificate being installs corresponds + * to RSA endorsement key. + */ +static int validate_cert_rsa( + const struct cros_perso_certificate_response_v0 *cert, + const uint8_t eps[PRIMARY_SEED_SIZE]) +{ + int result = 0; + TPM2B_32_BYTE_VALUE seed; + + seed.b.size = PRIMARY_SEED_SIZE; + memcpy(seed.b.buffer, eps, PRIMARY_SEED_SIZE); + + do { + TPM2B_PUBLIC_KEY_RSA N; + TPM2B_PRIVATE_KEY_RSA p; + + if (_cpri__GenerateKeyRSA( + &N.b, &p.b, 2048, RSA_F4, + TPM_ALG_SHA256, &seed.b, VENDOR_EK_RSA_LABEL, + (TPM2B *) &RSA_TEMPLATE_EK_EXTRA.b, NULL) + != CRYPT_SUCCESS) + break; + + if (memstr(cert->cert, cert->cert_len, + N.b.buffer, N.b.size) >= 0) + result = 1; + else + result = 0; + + memset(N.b.buffer, 0, 256); + memset(p.b.buffer, 0, 128); + } while (0); + + memset(seed.b.buffer, 0, seed.b.size); + return result; +} + +/* This is the SHA-256 hash of the RSA template from the TCG + * EK Credential Profile spec. + */ +static const TPM2B_32_BYTE_VALUE ECC_TEMPLATE_EK_EXTRA = { + .t = {32, { + 0xC2, 0xE0, 0x31, 0x93, 0x40, 0xFB, 0x48, 0xF1, + 0x02, 0x53, 0x9E, 0xA9, 0x83, 0x63, 0xF8, 0x1E, + 0x2D, 0x30, 0x6E, 0x91, 0x8D, 0xD7, 0x78, 0xAB, + 0xF0, 0x54, 0x73, 0xA2, 0xA6, 0x0D, 0xAE, 0x09, + } + } +}; + +/* Verify that the endorsement certificate being installs corresponds + * to P256 endorsement key. + */ +static int validate_cert_ecc( + const struct cros_perso_certificate_response_v0 *cert, + const uint8_t eps[PRIMARY_SEED_SIZE]) +{ + int result = 0; + TPM2B_32_BYTE_VALUE seed; + + seed.b.size = PRIMARY_SEED_SIZE; + memcpy(seed.b.buffer, eps, PRIMARY_SEED_SIZE); + + do { + TPMS_ECC_POINT q; + TPM2B_ECC_PARAMETER d; + + if (_cpri__GenerateKeyEcc( + &q, &d, TPM_ECC_NIST_P256, TPM_ALG_SHA256, + &seed.b, VENDOR_EK_ECC_LABEL, + (TPM2B *) &ECC_TEMPLATE_EK_EXTRA.b, NULL) + != CRYPT_SUCCESS) + break; + + if (memstr(cert->cert, cert->cert_len, + q.x.b.buffer, P256_NBYTES) >= 0) + result = 1; + else + result = 0; + + memset(q.x.b.buffer, 0, P256_NBYTES); + memset(q.y.b.buffer, 0, P256_NBYTES); + memset(d.b.buffer, 0, P256_NBYTES); + } while (0); + + memset(seed.b.buffer, 0, seed.b.size); + return result; +} + static int validate_cert( const struct cros_perso_response_component_info_v0 *cert_info, - const struct cros_perso_certificate_response_v0 *cert) + const struct cros_perso_certificate_response_v0 *cert, + const uint8_t eps[PRIMARY_SEED_SIZE]) { if (cert_info->component_type != CROS_PERSO_COMPONENT_TYPE_RSA_CERT && cert_info->component_type != @@ -227,8 +360,17 @@ static int validate_cert( cert->cert_len > MAX_NV_BUFFER_SIZE) return 0; - return DCRYPTO_x509_verify(cert->cert, cert->cert_len, - &ENDORSEMENT_CA_RSA_PUB); + /* Verify certificate signature. */ + if (!DCRYPTO_x509_verify(cert->cert, cert->cert_len, + &ENDORSEMENT_CA_RSA_PUB)) + return 0; + + /* Generate corresponding key, and match cert. */ + /* TODO(ngm): time consuming: remove from production runs. */ + if (cert_info->component_type == CROS_PERSO_COMPONENT_TYPE_RSA_CERT) + return validate_cert_rsa(cert, eps); + else + return validate_cert_ecc(cert, eps); } static int store_cert(enum cros_perso_component_type component_type, @@ -339,6 +481,13 @@ static int compute_frk2(uint8_t frk2[AES256_BLOCK_CIPHER_KEY_SIZE]) { int i; + /* TODO(ngm): reading ITOP in hw_key_ladder_step hangs on + * second run of this function (i.e. install of ECC cert, + * which re-generates FRK2) unless the SHA engine is reset. + */ + GREG32(KEYMGR, SHA_TRIG) = + GC_KEYMGR_SHA_TRIG_TRIG_RESET_MASK; + if (hw_key_ladder_step(KEYMGR_CERT_0)) return 0; /* Derive HC_PHIK --> Deposited into ISR0 */ @@ -375,7 +524,7 @@ static int compute_frk2(uint8_t frk2[AES256_BLOCK_CIPHER_KEY_SIZE]) /* EPS is stored XOR'd with FRK2, so make sure that the sizes match. */ BUILD_ASSERT(AES256_BLOCK_CIPHER_KEY_SIZE == PRIMARY_SEED_SIZE); -static int decrypt_and_copy_eps(void) +static int get_decrypted_eps(uint8_t eps[PRIMARY_SEED_SIZE]) { int i; uint8_t frk2[AES256_BLOCK_CIPHER_KEY_SIZE]; @@ -387,15 +536,26 @@ static int decrypt_and_copy_eps(void) uint32_t word; if (flash_physical_info_read_word( - INFO1_EPS_OFFSET + i, &word) != EC_SUCCESS) + INFO1_EPS_OFFSET + i, &word) != EC_SUCCESS) { + memset(frk2, 0, sizeof(frk2)); return 0; /* Flash read INFO1 failed. */ - /* gp is a TPM global state structure , declared in Global.h. */ - memcpy(gp.EPSeed.t.buffer + i, &word, sizeof(word)); + } + memcpy(eps + i, &word, sizeof(word)); } /* One-time-pad decrypt EPS. */ for (i = 0; i < PRIMARY_SEED_SIZE; i++) - gp.EPSeed.t.buffer[i] ^= frk2[i]; + eps[i] ^= frk2[i]; + + memset(frk2, 0, sizeof(frk2)); + return 1; +} + +static int store_eps(uint8_t eps[PRIMARY_SEED_SIZE]) +{ + /* gp is a TPM global state structure, declared in Global.h. */ + memcpy(gp.EPSeed.t.buffer, eps, PRIMARY_SEED_SIZE); + /* Persist the seed to flash. */ NvWriteReserved(NV_EP_SEED, &gp.EPSeed); return 1; @@ -486,6 +646,7 @@ static void perso_command_handler(void *request, size_t command_size, size_t *response_size) { uint16_t ok = RESPONSE_NOT_OK; + uint8_t eps[PRIMARY_SEED_SIZE]; const struct cros_perso_response_v0 *perso_response = request; struct cros_perso_ok_response_v0 *ok_response = (struct cros_perso_ok_response_v0 *) request; @@ -500,9 +661,12 @@ static void perso_command_handler(void *request, size_t command_size, if (command_size != sizeof(struct cros_perso_response_v0)) break; + if (!get_decrypted_eps(eps)) + break; + /* Write RSA / P256 endorsement certificate. */ if (!validate_cert(&perso_response->cert_info, - &perso_response->cert)) + &perso_response->cert, eps)) break; /* Invalid cert. */ if (!rsa_cert_done && !p256_cert_done) @@ -527,7 +691,7 @@ static void perso_command_handler(void *request, size_t command_size, flash_info_write_enable(); /* Copy EPS from INFO1 to flash data region. */ - if (!decrypt_and_copy_eps()) + if (!store_eps(eps)) break; /* TODO: generate RSA and ECC keys, @@ -541,6 +705,7 @@ static void perso_command_handler(void *request, size_t command_size, ok = RESPONSE_OK; } while (0); + memset(eps, 0, sizeof(eps)); *response_size = sizeof(*ok_response); ok_response->ok = ok; } diff --git a/board/cr50/tpm2/rsa.c b/board/cr50/tpm2/rsa.c index 6ee310dbce..f01024fd7e 100644 --- a/board/cr50/tpm2/rsa.c +++ b/board/cr50/tpm2/rsa.c @@ -283,6 +283,15 @@ static int generate_prime(struct LITE_BIGNUM *b, TPM_ALG_ID hashing, return 0; } +#ifdef CRYPTO_TEST_SETUP +static const uint8_t VERIFY_SEED[32] = { + 0x54, 0xef, 0xe3, 0xe9, 0x1e, 0xfa, 0xad, 0x9b, + 0x18, 0x3f, 0x27, 0x12, 0xfd, 0xe7, 0xfb, 0xc6, + 0x60, 0xcc, 0x34, 0x05, 0x00, 0x7d, 0x21, 0x6e, + 0xc2, 0x1e, 0x78, 0xbe, 0x61, 0xc8, 0x41, 0x99 +}; +#endif + CRYPT_RESULT _cpri__GenerateKeyRSA( TPM2B *N_buf, TPM2B *p_buf, uint16_t num_bits, uint32_t e_buf, TPM_ALG_ID hashing, TPM2B *seed, @@ -317,11 +326,15 @@ CRYPT_RESULT _cpri__GenerateKeyRSA( return CRYPT_FAIL; /* Hash down the primary seed for RSA key generation, so that - * the derivation tree is distinct from ECC key derivation. */ + * the derivation tree is distinct from ECC key derivation. + */ #ifdef CRYPTO_TEST_SETUP - /* Test seed has already been hashed down. */ - memcpy(local_seed.t.buffer, seed->buffer, seed->size); -#else + if (seed->size == sizeof(VERIFY_SEED) && + memcmp(seed->buffer, VERIFY_SEED, seed->size) == 0) { + /* Test seed has already been hashed down. */ + memcpy(local_seed.t.buffer, seed->buffer, seed->size); + } else +#endif { LITE_HMAC_CTX hmac; @@ -330,7 +343,6 @@ CRYPT_RESULT _cpri__GenerateKeyRSA( memcpy(local_seed.t.buffer, DCRYPTO_HMAC_final(&hmac), local_seed.t.size); } -#endif if (e_buf == 0) e_buf = RSA_F4; @@ -758,13 +770,6 @@ static const TPM2B_PUBLIC_KEY_RSA RSA_2048_Q = { } }; -static const uint8_t VERIFY_SEED[32] = { - 0x54, 0xef, 0xe3, 0xe9, 0x1e, 0xfa, 0xad, 0x9b, - 0x18, 0x3f, 0x27, 0x12, 0xfd, 0xe7, 0xfb, 0xc6, - 0x60, 0xcc, 0x34, 0x05, 0x00, 0x7d, 0x21, 0x6e, - 0xc2, 0x1e, 0x78, 0xbe, 0x61, 0xc8, 0x41, 0x99 -}; - #define MAX_MSG_BYTES RSA_MAX_BYTES #define MAX_LABEL_LEN 32 |