summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagendra modadugu <ngm@google.com>2016-07-14 15:49:34 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2016-07-17 01:38:40 +0000
commitdb5a1ca8a40be9bf7e741637cd8d7f15f520ab11 (patch)
tree9a71f19290c3a852e86c4e6b01cd0cfd9dcdc19e
parentd0d8b3b0f28ff2b2fcb437a340d28e105ff31afe (diff)
downloadchrome-ec-db5a1ca8a40be9bf7e741637cd8d7f15f520ab11.tar.gz
CR50: match privkey against certs on endorsement
This patch adds code for generating RSA and ECC keys from the endorsement seed. The generated keys are matched against the certificates being installed. The code for RSA key generation is time consuming and slows down certificate installation. RSA keygen code should hence be removed in future. ECC keygen code may remain, and an ECC key match will imply that both certificates verify. Also, certificates are not fully parsed, and hence a cert that contains the corresponding public key is considered to be a match. Also filed crosbug/p/55260, in which the TPMT_PUBLIC template is truncated during personalization, and hence requires a workaround in RW firmware. BRANCH=none BUG=chrome-os-partner:43025,chrome-os-partner:47524 BUG=chrome-os-partner:50115,chrome-os-partner:55260 TEST=test full personalize + cros_ack verify cert flow Change-Id: I1af83f1ec86e7ee4d325a4b7aabe03ce08c4108b Signed-off-by: nagendra modadugu <ngm@google.com> Reviewed-on: https://chromium-review.googlesource.com/360441 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org> Commit-Queue: Vadim Bendebury <vbendeb@chromium.org> Tested-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r--board/cr50/tpm2/ecc.c26
-rw-r--r--board/cr50/tpm2/manufacture.c187
-rw-r--r--board/cr50/tpm2/rsa.c29
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