add vb2api_get_pcr_digest

this api allows firmware to get the digest indicating boot mode status.

BUG=chromium:451609
TEST=VBOOT2=1 make run2tests
BRANCH=tot

Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org>
Change-Id: Idca7bc5f6aed947689ad7cf219805aad35047c7d
Reviewed-on: https://chromium-review.googlesource.com/244542
diff --git a/Makefile b/Makefile
index ed4ccf4..ddae955 100644
--- a/Makefile
+++ b/Makefile
@@ -307,7 +307,8 @@
 	firmware/2lib/2sha1.c \
 	firmware/2lib/2sha256.c \
 	firmware/2lib/2sha512.c \
-	firmware/2lib/2sha_utility.c
+	firmware/2lib/2sha_utility.c \
+	firmware/2lib/2tpm_bootmode.c
 
 FWLIB20_SRCS = \
 	firmware/lib20/api.c \
diff --git a/firmware/2lib/2api.c b/firmware/2lib/2api.c
index 1a616d5..70cb8a3 100644
--- a/firmware/2lib/2api.c
+++ b/firmware/2lib/2api.c
@@ -14,6 +14,7 @@
 #include "2secdata.h"
 #include "2sha.h"
 #include "2rsa.h"
+#include "2tpm_bootmode.h"
 
 int vb2api_secdata_check(const struct vb2_context *ctx)
 {
@@ -123,3 +124,33 @@
 	else
 		return vb2_digest_extend(dc, buf, size);
 }
+
+int vb2api_get_pcr_digest(struct vb2_context *ctx,
+			  enum vb2_pcr_digest which_digest,
+			  uint8_t *dest,
+			  uint32_t *dest_size)
+{
+	const uint8_t *digest;
+	uint32_t digest_size;
+
+	switch (which_digest) {
+	case BOOT_MODE_PCR:
+		digest = vb2_get_boot_state_digest(ctx);
+		digest_size = VB2_SHA1_DIGEST_SIZE;
+		break;
+	case HWID_DIGEST_PCR:
+		digest = vb2_get_sd(ctx)->gbb_hwid_digest;
+		digest_size = VB2_GBB_HWID_DIGEST_SIZE;
+		break;
+	default:
+		return VB2_ERROR_API_PCR_DIGEST;
+	}
+
+	if (digest == NULL || *dest_size < digest_size)
+		return VB2_ERROR_API_PCR_DIGEST_BUF;
+
+	memcpy(dest, digest, digest_size);
+	*dest_size = digest_size;
+
+	return VB2_SUCCESS;
+}
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c
index 5dc0014..5fc7604 100644
--- a/firmware/2lib/2misc.c
+++ b/firmware/2lib/2misc.c
@@ -196,6 +196,7 @@
 	sd->gbb_flags = gbb->flags;
 	sd->gbb_rootkey_offset = gbb->rootkey_offset;
 	sd->gbb_rootkey_size = gbb->rootkey_size;
+	memcpy(sd->gbb_hwid_digest, gbb->hwid_digest, VB2_GBB_HWID_DIGEST_SIZE);
 
 	return VB2_SUCCESS;
 }
diff --git a/firmware/2lib/2tpm_bootmode.c b/firmware/2lib/2tpm_bootmode.c
new file mode 100644
index 0000000..6903fe8
--- /dev/null
+++ b/firmware/2lib/2tpm_bootmode.c
@@ -0,0 +1,54 @@
+/* Copyright 2015 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.
+ *
+ * Functions for updating the TPM state with the status of boot path.
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2sha.h"
+#include "2tpm_bootmode.h"
+
+/*
+ * Input digests for PCR extend.
+ * These are calculated as:
+ *    SHA1("|Developer_Mode||Recovery_Mode||Keyblock_Mode|").
+ * Developer_Mode can be 0 or 1.
+ * Recovery_Mode can be 0 or 1.
+ * Keyblock flags are defined in 2struct.h and assumed always 0 in recovery mode
+ * or 7 in non-recovery mode.
+ *
+ * We map them to Keyblock_Mode as follows:
+ *   -----------------------------------------
+ *   Keyblock Flags            | Keyblock Mode
+ *   -----------------------------------------
+ *   0 recovery mode           |     0
+ *   7 Normal-signed firmware  |     1
+ */
+
+const uint8_t kBootStateSHA1Digests[][VB2_SHA1_DIGEST_SIZE] = {
+	/* SHA1(0x00|0x00|0x01) */
+	{0x25, 0x47, 0xcc, 0x73, 0x6e, 0x95, 0x1f, 0xa4, 0x91, 0x98, 0x53, 0xc4,
+			0x3a, 0xe8, 0x90, 0x86, 0x1a, 0x3b, 0x32, 0x64},
+
+	/* SHA1(0x01|0x00|0x01) */
+	{0xc4, 0x2a, 0xc1, 0xc4, 0x6f, 0x1d, 0x4e, 0x21, 0x1c, 0x73, 0x5c, 0xc7,
+			0xdf, 0xad, 0x4f, 0xf8, 0x39, 0x11, 0x10, 0xe9},
+
+	/* SHA1(0x00|0x01|0x00) */
+	{0x62, 0x57, 0x18, 0x91, 0x21, 0x5b, 0x4e, 0xfc, 0x1c, 0xea, 0xb7, 0x44,
+			0xce, 0x59, 0xdd, 0x0b, 0x66, 0xea, 0x6f, 0x73},
+
+	/* SHA1(0x01|0x01|0x00) */
+	{0x47, 0xec, 0x8d, 0x98, 0x36, 0x64, 0x33, 0xdc, 0x00, 0x2e, 0x77, 0x21,
+			0xc9, 0xe3, 0x7d, 0x50, 0x67, 0x54, 0x79, 0x37},
+};
+
+const uint8_t *vb2_get_boot_state_digest(struct vb2_context *ctx)
+{
+	int index = (ctx->flags & VB2_CONTEXT_RECOVERY_MODE ? 2 : 0) +
+			(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE ? 1 : 0);
+
+	return kBootStateSHA1Digests[index];
+}
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h
index 9db5019..69f4dde 100644
--- a/firmware/2lib/include/2api.h
+++ b/firmware/2lib/include/2api.h
@@ -42,6 +42,9 @@
  */
 #define VB2_WORKBUF_RECOMMENDED_SIZE (12 * 1024)
 
+/* Recommended buffer size for vb2api_get_pcr_digest */
+#define VB2_PCR_DIGEST_RECOMMENDED_SIZE 32
+
 /* Flags for vb2_context.
  *
  * Unless otherwise noted, flags are set by verified boot and may be read (but
@@ -160,6 +163,15 @@
 	VB2_RES_FW_VBLOCK,
 };
 
+/* Digest ID for vbapi_get_pcr_digest() */
+enum vb2_pcr_digest {
+	/* Digest based on current developer and recovery mode flags */
+	BOOT_MODE_PCR,
+
+	/* SHA-256 hash digest of HWID, from GBB */
+	HWID_DIGEST_PCR,
+};
+
 /******************************************************************************
  * APIs provided by verified boot.
  *
@@ -338,6 +350,22 @@
  */
 int vb2api_check_hash(struct vb2_context *ctx);
 
+/**
+ * Get a PCR digest
+ *
+ * @param ctx		Vboot context
+ * @param which_digest	PCR index of the digest
+ * @param dest		Destination where the digest is copied.
+ * 			Recommended size is VB2_PCR_DIGEST_RECOMMENDED_SIZE.
+ * @param dest_size	IN: size of the buffer pointed by dest
+ * 			OUT: size of the copied digest
+ * @return VB2_SUCCESS, or error code on error
+ */
+int vb2api_get_pcr_digest(struct vb2_context *ctx,
+			  enum vb2_pcr_digest which_digest,
+			  uint8_t *dest,
+			  uint32_t *dest_size);
+
 /*****************************************************************************/
 /* APIs provided by the caller to verified boot */
 
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index 53e0102..e89897f 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -423,6 +423,12 @@
 	/* Siganature mismatch in vb2api_check_hash() */
 	VB2_ERROR_API_CHECK_HASH_SIG,
 
+	/* Invalid enum vb2_pcr_digest requested to vb2api_get_pcr_digest */
+	VB2_ERROR_API_PCR_DIGEST,
+
+	/* Buffer size for the digest is too small for vb2api_get_pcr_digest */
+	VB2_ERROR_API_PCR_DIGEST_BUF,
+
         /**********************************************************************
 	 * Errors which may be generated by implementations of vb2ex functions.
 	 * Implementation may also return its own specific errors, which should
diff --git a/firmware/2lib/include/2struct.h b/firmware/2lib/include/2struct.h
index 5e2757b..95cf73c 100644
--- a/firmware/2lib/include/2struct.h
+++ b/firmware/2lib/include/2struct.h
@@ -21,6 +21,7 @@
 #define VB2_KEY_BLOCK_FLAG_DEVELOPER_1  0x02 /* Developer switch on */
 #define VB2_KEY_BLOCK_FLAG_RECOVERY_0   0x04 /* Not recovery mode */
 #define VB2_KEY_BLOCK_FLAG_RECOVERY_1   0x08 /* Recovery mode */
+#define VB2_GBB_HWID_DIGEST_SIZE	32
 
 /****************************************************************************/
 
@@ -103,6 +104,9 @@
 	uint32_t gbb_rootkey_offset;
 	uint32_t gbb_rootkey_size;
 
+	/* HWID digest from GBB header */
+	uint8_t gbb_hwid_digest[VB2_GBB_HWID_DIGEST_SIZE];
+
 	/* Offset of preamble from start of vblock */
 	uint32_t vblock_preamble_offset;
 
@@ -231,7 +235,7 @@
 	uint32_t recovery_key_size;
 
 	/* Added in version 1.2 */
-	uint8_t  hwid_digest[32];	/* SHA-256 of HWID */
+	uint8_t  hwid_digest[VB2_GBB_HWID_DIGEST_SIZE];	/* SHA-256 of HWID */
 
 	/* Pad to match EXPECETED_VB2_GBB_HEADER_SIZE.  Initialize to 0. */
 	uint8_t  pad[48];
diff --git a/firmware/2lib/include/2tpm_bootmode.h b/firmware/2lib/include/2tpm_bootmode.h
new file mode 100644
index 0000000..63f247d
--- /dev/null
+++ b/firmware/2lib/include/2tpm_bootmode.h
@@ -0,0 +1,21 @@
+/* Copyright 2015 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.
+ *
+ * Functions for updating the TPM state with the status of boot path.
+ */
+
+#ifndef VBOOT_REFERENCE_2TPM_BOOTMODE_H_
+#define VBOOT_REFERENCE_2TPM_BOOTMODE_H_
+
+#include "2api.h"
+
+/**
+ * Return digest indicating the boot state
+ *
+ * @param ctx		Vboot context
+ * @return		Pointer to sha1 digest of size VB2_SHA1_DIGEST_SIZE
+ */
+const uint8_t *vb2_get_boot_state_digest(struct vb2_context *ctx);
+
+#endif  /* VBOOT_REFERENCE_2TPM_BOOTMODE_H_ */
diff --git a/tests/vb2_api_tests.c b/tests/vb2_api_tests.c
index a68b6c5..2978c3f 100644
--- a/tests/vb2_api_tests.c
+++ b/tests/vb2_api_tests.c
@@ -26,6 +26,12 @@
 const int mock_body_size = sizeof(mock_body);
 const int mock_algorithm = VB2_ALG_RSA2048_SHA256;
 const int mock_hash_alg = VB2_HASH_SHA256;
+static const uint8_t mock_hwid_digest[VB2_GBB_HWID_DIGEST_SIZE] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
 
 /* Mocked function data */
 
@@ -59,6 +65,9 @@
 	retval_vb2_check_dev_switch = VB2_SUCCESS;
 	retval_vb2_check_tpm_clear = VB2_SUCCESS;
 	retval_vb2_select_fw_slot = VB2_SUCCESS;
+
+	memcpy(sd->gbb_hwid_digest, mock_hwid_digest,
+	       sizeof(sd->gbb_hwid_digest));
 };
 
 /* Mocked functions */
@@ -166,11 +175,52 @@
 		VB2_RECOVERY_FW_SLOT, "  recovery reason");
 }
 
+static void get_pcr_digest_tests(void)
+{
+	uint8_t digest[VB2_PCR_DIGEST_RECOMMENDED_SIZE];
+	uint8_t digest_org[VB2_PCR_DIGEST_RECOMMENDED_SIZE];
+	uint32_t digest_size;
+
+	reset_common_data(FOR_MISC);
+	memset(digest_org, 0, sizeof(digest_org));
+
+	digest_size = sizeof(digest);
+	memset(digest, 0, sizeof(digest));
+	TEST_SUCC(vb2api_get_pcr_digest(
+			&cc, BOOT_MODE_PCR, digest, &digest_size),
+		  "BOOT_MODE_PCR");
+	TEST_EQ(digest_size, VB2_SHA1_DIGEST_SIZE, "BOOT_MODE_PCR digest size");
+	TEST_TRUE(memcmp(digest, digest_org, digest_size),
+		  "BOOT_MODE_PCR digest");
+
+	digest_size = sizeof(digest);
+	memset(digest, 0, sizeof(digest));
+	TEST_SUCC(vb2api_get_pcr_digest(
+			&cc, HWID_DIGEST_PCR, digest, &digest_size),
+		  "HWID_DIGEST_PCR");
+	TEST_EQ(digest_size, VB2_GBB_HWID_DIGEST_SIZE,
+		"HWID_DIGEST_PCR digest size");
+	TEST_FALSE(memcmp(digest, mock_hwid_digest, digest_size),
+		   "HWID_DIGEST_PCR digest");
+
+	digest_size = 1;
+	TEST_EQ(vb2api_get_pcr_digest(&cc, BOOT_MODE_PCR, digest, &digest_size),
+		VB2_ERROR_API_PCR_DIGEST_BUF,
+		"BOOT_MODE_PCR buffer too small");
+
+	TEST_EQ(vb2api_get_pcr_digest(
+			&cc, HWID_DIGEST_PCR + 1, digest, &digest_size),
+		VB2_ERROR_API_PCR_DIGEST,
+		"invalid enum vb2_pcr_digest");
+}
+
 int main(int argc, char* argv[])
 {
 	misc_tests();
 	phase1_tests();
 	phase2_tests();
 
+	get_pcr_digest_tests();
+
 	return gTestSuccess ? 0 : 255;
 }