summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagendra modadugu <ngm@google.com>2016-07-21 19:36:28 -0700
committerVadim Bendebury <vbendeb@chromium.org>2016-07-23 02:18:49 +0000
commite819881b8c191603b7861cb98ebbbf5e6172da5a (patch)
tree7dfd3734687611b8698900e29c488f8c0858bc87
parentc44ee5f93d354f38dfacec6bd63b5d40392a7e55 (diff)
downloadchrome-ec-e819881b8c191603b7861cb98ebbbf5e6172da5a.tar.gz
CR50: add endorsement certificate flow
This change implements logic for installing endorsement certificates in the RW section. The endorsement certificates are initially provisioned in a fixed RO flash region and are copied in the RW TPM data region (once this region has been initialized). Also add code for reading from the info bank, which is where the endorsement seed is initially stored. BRANCH=none BUG=chrome-os-partner:43025,chrome-os-partner:47524 BUG=chrome-os-partner:50115 TEST=TCG tests running Change-Id: Id8c16d399202eee4ac0c4e397bdd29641ff9d2f3 Signed-off-by: nagendra modadugu <ngm@google.com> Reviewed-on: https://chromium-review.googlesource.com/362402 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/build.mk1
-rw-r--r--board/cr50/tpm2/endorsement.c475
-rw-r--r--chip/g/flash.c26
-rw-r--r--chip/g/flash_info.h1
-rw-r--r--common/tpm_registers.c1
-rw-r--r--include/tpm_manufacture.h1
6 files changed, 505 insertions, 0 deletions
diff --git a/board/cr50/build.mk b/board/cr50/build.mk
index f1b1b18998..8710d11e41 100644
--- a/board/cr50/build.mk
+++ b/board/cr50/build.mk
@@ -39,6 +39,7 @@ board-y += tpm2/NVMem.o
board-y += tpm2/aes.o
board-y += tpm2/ecc.o
board-y += tpm2/ecies.o
+board-y += tpm2/endorsement.o
board-y += tpm2/hash.o
board-y += tpm2/hash_data.o
board-y += tpm2/hkdf.o
diff --git a/board/cr50/tpm2/endorsement.c b/board/cr50/tpm2/endorsement.c
new file mode 100644
index 0000000000..317b151ae6
--- /dev/null
+++ b/board/cr50/tpm2/endorsement.c
@@ -0,0 +1,475 @@
+/* Copyright 2016 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 "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 "console.h"
+#include "extension.h"
+#include "flash.h"
+#include "flash_config.h"
+#include "flash_info.h"
+#include "printf.h"
+#include "registers.h"
+
+#include "dcrypto.h"
+
+#include <cryptoc/sha256.h>
+
+#include <endian.h>
+#include <string.h>
+
+#define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ## args)
+
+#define EK_CERT_NV_START_INDEX 0x01C00000
+#define INFO1_EPS_SIZE PRIMARY_SEED_SIZE
+#define INFO1_EPS_OFFSET FLASH_INFO_MANUFACTURE_STATE_OFFSET
+#define AES256_BLOCK_CIPHER_KEY_SIZE 32
+
+#define RO_CERTS_START_ADDR 0x43800
+#define RO_CERTS_REGION_SIZE 0x0800
+
+enum cros_perso_component_type {
+ CROS_PERSO_COMPONENT_TYPE_EPS = 128,
+ CROS_PERSO_COMPONENT_TYPE_RSA_CERT = 129,
+ CROS_PERSO_COMPONENT_TYPE_P256_CERT = 130
+};
+
+struct cros_perso_response_component_info_v0 {
+ uint16_t component_size;
+ uint8_t component_type;
+ uint8_t reserved[5];
+} __packed; /* Size: 8B */
+
+/* key_id: key for which this is the certificate */
+/* cert_len: length of the following certificate */
+/* cert: the certificate bytes */
+struct cros_perso_certificate_response_v0 {
+ uint8_t key_id[4];
+ uint32_t cert_len;
+ uint8_t cert[0];
+} __packed; /* Size: 8B */
+
+/* Personalization response. */
+BUILD_ASSERT(sizeof(struct cros_perso_response_component_info_v0) == 8);
+BUILD_ASSERT(sizeof(struct cros_perso_certificate_response_v0) == 8);
+
+/* TODO(ngm): replace with real pub key. */
+static const uint32_t TEST_ENDORSEMENT_CA_RSA_N[64] = {
+ 0xfa3b34ed, 0x3c59ad05, 0x912d6623, 0x83302402,
+ 0xd43b6755, 0x5777021a, 0xaf37e9a1, 0x45c0e8ad,
+ 0x9728f946, 0x4391523d, 0xdf7a9164, 0x88f1a9ae,
+ 0x036c557e, 0x5d9df43e, 0x3e65de68, 0xe172008a,
+ 0x709dc81f, 0x27a75fe0, 0x3e77f89e, 0x4f400ecc,
+ 0x51a17dae, 0x2ff9c652, 0xd1d83cdb, 0x20d26349,
+ 0xbbad71dd, 0x30051b2b, 0x276b2459, 0x809bb8e1,
+ 0xb8737049, 0xdbe94466, 0x8287072b, 0x070ef311,
+ 0x6e2a26de, 0x29d69f11, 0x96463d95, 0xb4dc6950,
+ 0x097d4dfe, 0x1b4a88cc, 0xbd6b50c8, 0x9f7a5b34,
+ 0xda22c199, 0x9d1ac04b, 0x136af5e5, 0xb1a0e824,
+ 0x4a065b34, 0x1f67fb46, 0xa1f91ab1, 0x27bb769f,
+ 0xb704c992, 0xb669cbf4, 0x9299bb6c, 0xcb1b2208,
+ 0x2dc0d9db, 0xe1513e13, 0xc7f24923, 0xa74c6bcc,
+ 0xca1a9a69, 0x1b994244, 0x4f64b0d9, 0x78607fd6,
+ 0x486fb315, 0xa1098c31, 0x5dc50dd6, 0xcdc10874
+};
+
+static const struct RSA TEST_ENDORSEMENT_CA_RSA_PUB = {
+ .e = RSA_F4,
+ .N = {
+ .dmax = sizeof(TEST_ENDORSEMENT_CA_RSA_N) / sizeof(uint32_t),
+ .d = (struct access_helper *) TEST_ENDORSEMENT_CA_RSA_N,
+ },
+ .d = {
+ .dmax = 0,
+ .d = NULL,
+ },
+};
+
+static int validate_cert(
+ const struct cros_perso_response_component_info_v0 *cert_info,
+ 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 !=
+ CROS_PERSO_COMPONENT_TYPE_P256_CERT)
+ return 0; /* Invalid component type. */
+
+ /* TODO(ngm): verify key_id against HIK/FRK0. */
+ if (cert->cert_len > MAX_NV_BUFFER_SIZE)
+ return 0;
+
+ /* Verify certificate signature. */
+ return DCRYPTO_x509_verify(cert->cert, cert->cert_len,
+ &TEST_ENDORSEMENT_CA_RSA_PUB);
+}
+
+static int store_cert(enum cros_perso_component_type component_type,
+ const struct cros_perso_certificate_response_v0 *cert)
+{
+ const uint32_t rsa_ek_nv_index = EK_CERT_NV_START_INDEX;
+ const uint32_t ecc_ek_nv_index = EK_CERT_NV_START_INDEX + 1;
+ uint32_t nv_index;
+ NV_DefineSpace_In define_space;
+ TPMA_NV space_attributes;
+ NV_Write_In in;
+
+ /* Clear up structures potentially uszed only partially. */
+ memset(&define_space, 0, sizeof(define_space));
+ memset(&space_attributes, 0, sizeof(space_attributes));
+ memset(&in, 0, sizeof(in));
+
+ /* Indicate that a system reset has occurred, and currently
+ * running with Platform auth.
+ */
+ HierarchyStartup(SU_RESET);
+
+ if (component_type == CROS_PERSO_COMPONENT_TYPE_RSA_CERT)
+ nv_index = rsa_ek_nv_index;
+ else /* P256 certificate. */
+ nv_index = ecc_ek_nv_index;
+
+ /* EK Credential attributes specified in the "TCG PC Client
+ * Platform, TPM Profile (PTP) Specification" document.
+ */
+ /* REQUIRED: Writeable under platform auth. */
+ space_attributes.TPMA_NV_PPWRITE = 1;
+ /* OPTIONAL: Write-once; space must be deleted to be re-written. */
+ space_attributes.TPMA_NV_WRITEDEFINE = 1;
+ /* REQUIRED: Space created with platform auth. */
+ space_attributes.TPMA_NV_PLATFORMCREATE = 1;
+ /* REQUIRED: Readable under empty password? */
+ space_attributes.TPMA_NV_AUTHREAD = 1;
+ /* REQUIRED: Disable dictionary attack protection. */
+ space_attributes.TPMA_NV_NO_DA = 1;
+
+ define_space.authHandle = TPM_RH_PLATFORM;
+ define_space.auth.t.size = 0;
+ define_space.publicInfo.t.size = sizeof(
+ define_space.publicInfo.t.nvPublic);
+ define_space.publicInfo.t.nvPublic.nvIndex = nv_index;
+ define_space.publicInfo.t.nvPublic.nameAlg = TPM_ALG_SHA256;
+ define_space.publicInfo.t.nvPublic.attributes = space_attributes;
+ define_space.publicInfo.t.nvPublic.authPolicy.t.size = 0;
+ define_space.publicInfo.t.nvPublic.dataSize = cert->cert_len;
+
+ /* Define the required space first. */
+ if (TPM2_NV_DefineSpace(&define_space) != TPM_RC_SUCCESS)
+ return 0;
+
+ /* TODO(ngm): call TPM2_NV_WriteLock(nvIndex) on tpm_init();
+ * this prevents delete?
+ */
+
+ in.nvIndex = nv_index;
+ in.authHandle = TPM_RH_PLATFORM;
+ in.data.t.size = cert->cert_len;
+ memcpy(in.data.t.buffer, cert->cert, cert->cert_len);
+ in.offset = 0;
+
+ if (TPM2_NV_Write(&in) != TPM_RC_SUCCESS)
+ return 0;
+ if (NvCommit())
+ return 1;
+ return 0;
+}
+
+static uint32_t hw_key_ladder_step(uint32_t cert)
+{
+ uint32_t itop;
+
+ GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */
+
+ GREG32(KEYMGR, SHA_USE_CERT_INDEX) =
+ (cert << GC_KEYMGR_SHA_USE_CERT_INDEX_LSB) |
+ GC_KEYMGR_SHA_USE_CERT_ENABLE_MASK;
+
+ GREG32(KEYMGR, SHA_CFG_EN) =
+ GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK;
+ GREG32(KEYMGR, SHA_TRIG) =
+ GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK;
+
+ do {
+ itop = GREG32(KEYMGR, SHA_ITOP);
+ } while (!itop);
+
+ GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */
+
+ return !!GREG32(KEYMGR, HKEY_ERR_FLAGS);
+}
+
+
+#define KEYMGR_CERT_0 0
+#define KEYMGR_CERT_3 3
+#define KEYMGR_CERT_4 4
+#define KEYMGR_CERT_5 5
+#define KEYMGR_CERT_7 7
+#define KEYMGR_CERT_15 15
+#define KEYMGR_CERT_20 20
+#define KEYMGR_CERT_25 25
+#define KEYMGR_CERT_26 26
+
+#define K_CROS_FW_MAJOR_VERSION 0
+static const uint8_t k_cr50_max_fw_major_version = 254;
+
+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 */
+ if (hw_key_ladder_step(KEYMGR_CERT_3))
+ return 0;
+
+ /* Cryptographically mix OBS-FBS --> Deposited into ISR1 */
+ if (hw_key_ladder_step(KEYMGR_CERT_4))
+ return 0;
+
+ /* Derive HIK_RT --> Deposited into ISR0 */
+ if (hw_key_ladder_step(KEYMGR_CERT_5))
+ return 0;
+
+ /* Derive BL_HIK --> Deposited into ISR0 */
+ if (hw_key_ladder_step(KEYMGR_CERT_7))
+ return 0;
+
+ /* Generate FRK2 by executing certs 15, 20, 25, and 26 */
+ if (hw_key_ladder_step(KEYMGR_CERT_15))
+ return 0;
+
+ if (hw_key_ladder_step(KEYMGR_CERT_20))
+ return 0;
+
+ for (i = 0; i < k_cr50_max_fw_major_version -
+ K_CROS_FW_MAJOR_VERSION; i++) {
+ if (hw_key_ladder_step(KEYMGR_CERT_25))
+ return 0;
+ }
+ if (hw_key_ladder_step(KEYMGR_CERT_26))
+ return 0;
+ memcpy(frk2, (void *) GREG32_ADDR(KEYMGR, HKEY_FRR0),
+ AES256_BLOCK_CIPHER_KEY_SIZE);
+ return 1;
+}
+
+static void flash_info_read_enable(void)
+{
+ /* Enable R access to INFO. */
+ GREG32(GLOBALSEC, FLASH_REGION7_BASE_ADDR) = FLASH_INFO_MEMORY_BASE +
+ FLASH_INFO_MANUFACTURE_STATE_OFFSET;
+ GREG32(GLOBALSEC, FLASH_REGION7_SIZE) =
+ FLASH_INFO_MANUFACTURE_STATE_SIZE - 1;
+ GREG32(GLOBALSEC, FLASH_REGION7_CTRL) =
+ GC_GLOBALSEC_FLASH_REGION7_CTRL_EN_MASK |
+ GC_GLOBALSEC_FLASH_REGION7_CTRL_RD_EN_MASK;
+}
+
+static void flash_info_read_disable(void)
+{
+ GREG32(GLOBALSEC, FLASH_REGION7_CTRL) = 0;
+}
+
+static void flash_cert_region_enable(void)
+{
+ /* Enable R access to CERT block. */
+ GREG32(GLOBALSEC, FLASH_REGION6_BASE_ADDR) = RO_CERTS_START_ADDR;
+ GREG32(GLOBALSEC, FLASH_REGION6_SIZE) =
+ RO_CERTS_REGION_SIZE - 1;
+ GREG32(GLOBALSEC, FLASH_REGION6_CTRL) =
+ GC_GLOBALSEC_FLASH_REGION6_CTRL_EN_MASK |
+ GC_GLOBALSEC_FLASH_REGION6_CTRL_RD_EN_MASK;
+}
+
+/* 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 get_decrypted_eps(uint8_t eps[PRIMARY_SEED_SIZE])
+{
+ int i;
+ uint8_t frk2[AES256_BLOCK_CIPHER_KEY_SIZE];
+
+ CPRINTF("%s: getting eps\n", __func__);
+ if (!compute_frk2(frk2))
+ return 0;
+
+ /* Setup flash region mapping. */
+ flash_info_read_enable();
+
+ for (i = 0; i < INFO1_EPS_SIZE; i += sizeof(uint32_t)) {
+ uint32_t word;
+
+ if (flash_physical_info_read_word(
+ INFO1_EPS_OFFSET + i, &word) != EC_SUCCESS) {
+ memset(frk2, 0, sizeof(frk2));
+ return 0; /* Flash read INFO1 failed. */
+ }
+ memcpy(eps + i, &word, sizeof(word));
+ }
+
+ /* Remove flash region mapping. */
+ flash_info_read_disable();
+
+ /* One-time-pad decrypt EPS. */
+ for (i = 0; i < PRIMARY_SEED_SIZE; i++)
+ eps[i] ^= frk2[i];
+
+ memset(frk2, 0, sizeof(frk2));
+ return 1;
+}
+
+static int store_eps(const 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 NvCommit();
+}
+
+static void endorsement_complete(void)
+{
+ CPRINTF("%s(): SUCCESS\n", __func__);
+}
+
+static int handle_cert(
+ const struct cros_perso_response_component_info_v0 *cert_info,
+ const struct cros_perso_certificate_response_v0 *cert,
+ const uint8_t *eps)
+{
+
+ /* Write RSA / P256 endorsement certificate. */
+ if (!validate_cert(cert_info, cert, eps))
+ return 0;
+
+ /* TODO(ngm): verify that storage succeeded. */
+ if (!store_cert(cert_info->component_type, cert)) {
+ CPRINTF("%s(): cert storage failed, type: %d\n", __func__,
+ cert_info->component_type);
+ return 0; /* Internal failure. */
+ }
+
+ return 1;
+}
+
+int tpm_endorse(void)
+{
+ struct ro_cert_response {
+ uint8_t key_id[4];
+ uint32_t cert_len;
+ uint8_t cert[0];
+ } __packed;
+
+ struct ro_cert {
+ const struct cros_perso_response_component_info_v0 cert_info;
+ const struct ro_cert_response cert_response;
+ } __packed;
+
+ /* 2-kB RO cert region is setup like so:
+ *
+ * | struct ro_cert | rsa_cert | struct ro_cert | ecc_cert |
+ */
+ const uint8_t *p = (const uint8_t *) RO_CERTS_START_ADDR;
+ const uint32_t *c = (const uint32_t *) RO_CERTS_START_ADDR;
+ const struct ro_cert *rsa_cert;
+ const struct ro_cert *ecc_cert;
+ int result = 0;
+ uint8_t eps[PRIMARY_SEED_SIZE];
+
+ flash_cert_region_enable();
+
+ /* First boot, certs not yet installed. */
+ if (*c == 0xFFFFFFFF)
+ return 0;
+
+ if (!get_decrypted_eps(eps)) {
+ CPRINTF("%s(): failed to read eps\n", __func__);
+ return 0;
+ }
+
+ /* Unpack rsa cert struct. */
+ rsa_cert = (const struct ro_cert *) p;
+ /* Sanity check cert region contents. */
+ if ((2 * sizeof(struct ro_cert)) +
+ rsa_cert->cert_response.cert_len > RO_CERTS_REGION_SIZE)
+ return 0;
+
+ /* Unpack ecc cert struct. */
+ ecc_cert = (const struct ro_cert *) (p + sizeof(struct ro_cert) +
+ rsa_cert->cert_response.cert_len);
+ /* Sanity check cert region contents. */
+ if ((2 * sizeof(struct ro_cert)) +
+ rsa_cert->cert_response.cert_len +
+ ecc_cert->cert_response.cert_len > RO_CERTS_REGION_SIZE)
+ return 0;
+
+ /* Verify expected component types. */
+ if (rsa_cert->cert_info.component_type !=
+ CROS_PERSO_COMPONENT_TYPE_RSA_CERT) {
+ return 0;
+ }
+ if (ecc_cert->cert_info.component_type !=
+ CROS_PERSO_COMPONENT_TYPE_P256_CERT) {
+ return 0;
+ }
+
+ do {
+ if (!handle_cert(
+ &rsa_cert->cert_info,
+ (struct cros_perso_certificate_response_v0 *)
+ &rsa_cert->cert_response, eps)) {
+ CPRINTF("%s: Failed to process RSA cert\n", __func__);
+ break;
+ }
+ CPRINTF("%s: RSA cert install success\n", __func__);
+
+ if (!handle_cert(
+ &ecc_cert->cert_info,
+ (struct cros_perso_certificate_response_v0 *)
+ &ecc_cert->cert_response, eps)) {
+ CPRINTF("%s: Failed to process ECC cert\n", __func__);
+ break;
+ }
+ CPRINTF("%s: ECC cert intsall success\n", __func__);
+
+ /* Copy EPS from INFO1 to flash data region. */
+ if (!store_eps(eps)) {
+ CPRINTF("%s(): eps storage failed\n", __func__);
+ break;
+ }
+
+ /* Mark as endorsed. */
+ endorsement_complete();
+
+ /* Chip has been marked as manufactured. */
+ result = 1;
+ } while (0);
+
+ memset(eps, 0, sizeof(eps));
+ return result;
+}
diff --git a/chip/g/flash.c b/chip/g/flash.c
index d77ad0ad35..6a329756a7 100644
--- a/chip/g/flash.c
+++ b/chip/g/flash.c
@@ -119,6 +119,7 @@ int flash_physical_protect_now(int all)
enum flash_op {
OP_ERASE_BLOCK,
OP_WRITE_BLOCK,
+ OP_READ_BLOCK,
};
static int do_flash_op(enum flash_op op, int is_info_bank,
@@ -180,6 +181,16 @@ static int do_flash_op(enum flash_op op, int is_info_bank,
/* This number is based on the TSMC spec Nmp=Tprog/Tsmp */
max_attempts = 9;
break;
+ case OP_READ_BLOCK:
+ if (!is_info_bank)
+ /* This code path only supports reading from
+ * the INFO bank.
+ */
+ return EC_ERROR_INVAL;
+ opcode = 0x16021765;
+ words = 1;
+ max_attempts = 9;
+ break;
}
/*
@@ -324,6 +335,21 @@ int flash_physical_write(int byte_offset, int num_bytes, const char *data)
return flash_physical_write_internal(byte_offset, 0, num_bytes, data);
}
+int flash_physical_info_read_word(int byte_offset, uint32_t *dst)
+{
+ int ret;
+
+ if (byte_offset % CONFIG_FLASH_WRITE_SIZE)
+ return EC_ERROR_INVAL;
+
+ ret = do_flash_op(OP_READ_BLOCK, 1, byte_offset, 1);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ *dst = GREG32(FLASH, FSH_DOUT_VAL1);
+ return EC_SUCCESS;
+}
+
void flash_info_write_enable(void)
{
/* Enable R/W access to INFO. */
diff --git a/chip/g/flash_info.h b/chip/g/flash_info.h
index 443b64e031..fae622c24b 100644
--- a/chip/g/flash_info.h
+++ b/chip/g/flash_info.h
@@ -9,5 +9,6 @@
void flash_info_write_enable(void);
void flash_info_write_disable(void);
int flash_info_physical_write(int byte_offset, int num_bytes, const char *data);
+int flash_physical_info_read_word(int byte_offset, uint32_t *dst);
#endif /* ! __EC_CHIP_G_FLASH_INFO_H */
diff --git a/common/tpm_registers.c b/common/tpm_registers.c
index 70e57c8d76..29bcf791fa 100644
--- a/common/tpm_registers.c
+++ b/common/tpm_registers.c
@@ -476,6 +476,7 @@ static void tpm_init(void)
*/
TPM_Manufacture(1);
_TPM_Init();
+ tpm_endorse();
}
_plat__SetNvAvail();
diff --git a/include/tpm_manufacture.h b/include/tpm_manufacture.h
index 57eba367f6..f43fd9ec13 100644
--- a/include/tpm_manufacture.h
+++ b/include/tpm_manufacture.h
@@ -13,5 +13,6 @@
/* Returns non-zero if the TPM manufacture steps have been completed. */
int tpm_manufactured(void);
+int tpm_endorse(void);
#endif /* __CROS_EC_TPM_MANUFACTURE_H */