vboot2: Add host lib support for bare hash keys

And use them in the other vboot2 unit tests.

BUG=chromium:423882
BRANCH=none
TEST=VBOOT2=1 make runtests

Change-Id: I0c3590649a0acf792e41e295ca4279ccba17a41f
Reviewed-on: https://chromium-review.googlesource.com/231345
Tested-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Commit-Queue: Randall Spangler <rspangler@chromium.org>
diff --git a/Makefile b/Makefile
index 30047b5..08eaa5b 100644
--- a/Makefile
+++ b/Makefile
@@ -988,6 +988,7 @@
 ${BUILD}/utility/signature_digest_utility: LDLIBS += ${CRYPTO_LIBS}
 
 ${BUILD}/host/linktest/main: LDLIBS += ${CRYPTO_LIBS}
+${BUILD}/tests/vb2_common_tests: LDLIBS += ${CRYPTO_LIBS}
 ${BUILD}/tests/vb2_common2_tests: LDLIBS += ${CRYPTO_LIBS}
 ${BUILD}/tests/vb2_common3_tests: LDLIBS += ${CRYPTO_LIBS}
 ${BUILD}/tests/vb2_host_key_tests: LDLIBS += ${CRYPTO_LIBS}
diff --git a/firmware/2lib/2packed_key2.c b/firmware/2lib/2packed_key2.c
index 91000df..a67664b 100644
--- a/firmware/2lib/2packed_key2.c
+++ b/firmware/2lib/2packed_key2.c
@@ -81,20 +81,22 @@
 		return VB2_ERROR_UNPACK_KEY_STRUCT_VERSION;
 
 	/* Copy key algorithms */
-	key->sig_alg = pkey->sig_alg;
-	sig_size = vb2_rsa_sig_size(key->sig_alg);
-	if (!sig_size)
-		return VB2_ERROR_UNPACK_KEY_SIG_ALGORITHM;
-
 	key->hash_alg = pkey->hash_alg;
 	if (!vb2_digest_size(key->hash_alg))
 		return VB2_ERROR_UNPACK_KEY_HASH_ALGORITHM;
 
-	rv = vb2_unpack_key2_data(key,
-				  (const uint8_t *)pkey + pkey->key_offset,
-				  pkey->key_size);
-	if (rv)
-		return rv;
+	key->sig_alg = pkey->sig_alg;
+	if (key->sig_alg != VB2_SIG_NONE) {
+		sig_size = vb2_rsa_sig_size(key->sig_alg);
+		if (!sig_size)
+			return VB2_ERROR_UNPACK_KEY_SIG_ALGORITHM;
+		rv = vb2_unpack_key2_data(
+				key,
+				(const uint8_t *)pkey + pkey->key_offset,
+				pkey->key_size);
+		if (rv)
+			return rv;
+	}
 
 	/* Key description */
 	if (pkey->c.desc_size)
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index deae914..f12f2c1 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -510,6 +510,9 @@
 	/* Unable to set description in vb2_private_key_unpack() */
 	VB2_ERROR_UNPACK_PRIVATE_KEY_DESC,
 
+	/* Bad bare hash key in vb2_private_key_unpack() */
+	VB2_ERROR_UNPACK_PRIVATE_KEY_HASH,
+
 	/* Unable to create RSA data in vb2_private_key_write() */
 	VB2_ERROR_PRIVATE_KEY_WRITE_RSA,
 
@@ -519,6 +522,9 @@
 	/* Unable to write file in vb2_private_key_write() */
 	VB2_ERROR_PRIVATE_KEY_WRITE_FILE,
 
+	/* Bad algorithm in vb2_private_key_hash() */
+	VB2_ERROR_PRIVATE_KEY_HASH,
+
 	/* Unable to determine key size in vb2_public_key_alloc() */
 	VB2_ERROR_PUBLIC_KEY_ALLOC_SIZE,
 
@@ -549,6 +555,9 @@
 	/* Unable to determine key size in vb2_public_key_pack() */
 	VB2_ERROR_PUBLIC_KEY_PACK_SIZE,
 
+	/* Bad hash algorithm in vb2_publc_key_hash() */
+	VB2_ERROR_PUBLIC_KEY_HASH,
+
         /**********************************************************************
 	 * Highest non-zero error generated inside vboot library.  Note that
 	 * error codes passed through vboot when it calls external APIs may
diff --git a/host/lib/host_key2.c b/host/lib/host_key2.c
index eb252ef..8f761f6 100644
--- a/host/lib/host_key2.c
+++ b/host/lib/host_key2.c
@@ -14,6 +14,7 @@
 #include "2sysincludes.h"
 #include "2common.h"
 #include "2rsa.h"
+#include "2sha.h"
 #include "host_common.h"
 #include "host_key2.h"
 #include "host_misc.h"
@@ -82,11 +83,19 @@
 	key->guid = pkey->guid;
 
 	/* Unpack RSA key */
-	start = (const unsigned char *)(buf + pkey->key_offset);
-	key->rsa_private_key = d2i_RSAPrivateKey(0, &start, pkey->key_size);
-	if (!key->rsa_private_key) {
-		free(key);
-		return VB2_ERROR_UNPACK_PRIVATE_KEY_RSA;
+	if (pkey->sig_alg == VB2_SIG_NONE) {
+		if (pkey->key_size != 0) {
+			free(key);
+			return VB2_ERROR_UNPACK_PRIVATE_KEY_HASH;
+		}
+	} else {
+		start = (const unsigned char *)(buf + pkey->key_offset);
+		key->rsa_private_key = d2i_RSAPrivateKey(0, &start,
+							 pkey->key_size);
+		if (!key->rsa_private_key) {
+			free(key);
+			return VB2_ERROR_UNPACK_PRIVATE_KEY_RSA;
+		}
 	}
 
 	/* Key description */
@@ -184,7 +193,7 @@
 	};
 	uint8_t *buf;
 	uint8_t *rsabuf = NULL;
-	int rsalen;
+	int rsalen = 0;
 	int rv;
 
 	memcpy(&pkey.guid, &key->guid, sizeof(pkey.guid));
@@ -192,10 +201,12 @@
 	if (key->desc)
 		pkey.c.desc_size = roundup32(strlen(key->desc) + 1);
 
-	/* Pack RSA key */
-	rsalen = i2d_RSAPrivateKey(key->rsa_private_key, &rsabuf);
-	if (rsalen <= 0)
-		return VB2_ERROR_PRIVATE_KEY_WRITE_RSA;
+	if (key->sig_alg != VB2_SIG_NONE) {
+		/* Pack RSA key */
+		rsalen = i2d_RSAPrivateKey(key->rsa_private_key, &rsabuf);
+		if (rsalen <= 0 || !rsabuf)
+			return VB2_ERROR_PRIVATE_KEY_WRITE_RSA;
+	}
 
 	pkey.key_offset = pkey.c.fixed_size + pkey.c.desc_size;
 	pkey.key_size = roundup32(rsalen);
@@ -215,8 +226,10 @@
 	if (key->desc)
 		strcpy((char *)buf + pkey.c.fixed_size, key->desc);
 
-	memcpy(buf + pkey.key_offset, rsabuf, rsalen);
-	free(rsabuf);
+	if (rsabuf) {
+		memcpy(buf + pkey.key_offset, rsabuf, rsalen);
+		free(rsabuf);
+	}
 
 	rv = vb2_write_object(filename, buf);
 	free(buf);
@@ -224,6 +237,56 @@
 	return rv ? VB2_ERROR_PRIVATE_KEY_WRITE_FILE : VB2_SUCCESS;
 }
 
+int vb2_private_key_hash(const struct vb2_private_key **key_ptr,
+			 enum vb2_hash_algorithm hash_alg)
+{
+	*key_ptr = NULL;
+
+	switch (hash_alg) {
+#if VB2_SUPPORT_SHA1
+	case VB2_HASH_SHA1:
+		{
+			static const struct vb2_private_key key = {
+				.hash_alg = VB2_HASH_SHA1,
+				.sig_alg = VB2_SIG_NONE,
+				.desc = "Unsigned SHA1",
+				.guid = VB2_GUID_NONE_SHA1,
+			};
+			*key_ptr = &key;
+			return VB2_SUCCESS;
+		}
+#endif
+#if VB2_SUPPORT_SHA256
+	case VB2_HASH_SHA256:
+		{
+			static const struct vb2_private_key key = {
+				.hash_alg = VB2_HASH_SHA256,
+				.sig_alg = VB2_SIG_NONE,
+				.desc = "Unsigned SHA-256",
+				.guid = VB2_GUID_NONE_SHA256,
+			};
+			*key_ptr = &key;
+			return VB2_SUCCESS;
+		}
+#endif
+#if VB2_SUPPORT_SHA512
+	case VB2_HASH_SHA512:
+		{
+			static const struct vb2_private_key key = {
+				.hash_alg = VB2_HASH_SHA512,
+				.sig_alg = VB2_SIG_NONE,
+				.desc = "Unsigned SHA-512",
+				.guid = VB2_GUID_NONE_SHA512,
+			};
+			*key_ptr = &key;
+			return VB2_SUCCESS;
+		}
+#endif
+	default:
+		return VB2_ERROR_PRIVATE_KEY_HASH;
+	}
+}
+
 /**
  * Allocate a public key buffer of sufficient size for the signature algorithm.
  *
@@ -347,11 +410,11 @@
 
 	*key_ptr = NULL;
 
-	if (!vb2_read_file(filename, &buf, &size))
+	if (vb2_read_file(filename, &buf, &size))
 		return VB2_ERROR_READ_PACKED_KEY_DATA;
 
 	/* Sanity check: make sure key unpacks properly */
-	if (!vb2_unpack_key(&key, buf, size))
+	if (vb2_unpack_key2(&key, buf, size))
 		return VB2_ERROR_READ_PACKED_KEY;
 
 	*key_ptr = (struct vb2_packed_key2 *)buf;
@@ -375,14 +438,16 @@
 	/* Calculate sizes and offsets */
 	key.c.fixed_size = sizeof(key);
 
-	if (pubk->desc)
+	if (pubk->desc && *pubk->desc)
 		key.c.desc_size = roundup32(strlen(pubk->desc) + 1);
 
 	key.key_offset = key.c.fixed_size + key.c.desc_size;
 
-	key.key_size = vb2_packed_key_size(pubk->sig_alg);
-	if (!key.key_size)
-		return VB2_ERROR_PUBLIC_KEY_PACK_SIZE;
+	if (pubk->sig_alg != VB2_SIG_NONE) {
+		key.key_size = vb2_packed_key_size(pubk->sig_alg);
+		if (!key.key_size)
+			return VB2_ERROR_PUBLIC_KEY_PACK_SIZE;
+	}
 
 	key.c.total_size = key.key_offset + key.key_size;
 
@@ -400,20 +465,51 @@
 	memcpy(buf, &key, sizeof(key));
 
 	/* strcpy() is safe because we allocated above based on strlen() */
-	if (pubk->desc) {
+	if (pubk->desc && *pubk->desc) {
 		strcpy((char *)(buf + key.c.fixed_size), pubk->desc);
 		buf[key.c.fixed_size + key.c.desc_size - 1] = 0;
 	}
 
-	/* Re-pack the key arrays */
-	buf32 = (uint32_t *)(buf + key.key_offset);
-	buf32[0] = pubk->arrsize;
-	buf32[1] = pubk->n0inv;
-	memcpy(buf32 + 2, pubk->n, pubk->arrsize * sizeof(uint32_t));
-	memcpy(buf32 + 2 + pubk->arrsize, pubk->rr,
-	       pubk->arrsize * sizeof(uint32_t));
+	if (pubk->sig_alg != VB2_SIG_NONE) {
+		/* Re-pack the key arrays */
+		buf32 = (uint32_t *)(buf + key.key_offset);
+		buf32[0] = pubk->arrsize;
+		buf32[1] = pubk->n0inv;
+		memcpy(buf32 + 2, pubk->n, pubk->arrsize * sizeof(uint32_t));
+		memcpy(buf32 + 2 + pubk->arrsize, pubk->rr,
+		       pubk->arrsize * sizeof(uint32_t));
+	}
 
 	*key_ptr = (struct vb2_packed_key2 *)buf;
 
 	return VB2_SUCCESS;
 }
+
+int vb2_public_key_hash(struct vb2_public_key *key,
+			enum vb2_hash_algorithm hash_alg)
+{
+	switch (hash_alg) {
+#if VB2_SUPPORT_SHA1
+	case VB2_HASH_SHA1:
+		key->desc = "Unsigned SHA1";
+		break;
+#endif
+#if VB2_SUPPORT_SHA256
+	case VB2_HASH_SHA256:
+		key->desc = "Unsigned SHA-256";
+		break;
+#endif
+#if VB2_SUPPORT_SHA512
+	case VB2_HASH_SHA512:
+		key->desc = "Unsigned SHA-512";
+		break;
+#endif
+	default:
+		return VB2_ERROR_PUBLIC_KEY_HASH;
+	}
+
+	key->sig_alg = VB2_SIG_NONE;
+	key->hash_alg = hash_alg;
+	key->guid = vb2_hash_guid(hash_alg);
+	return VB2_SUCCESS;
+}
diff --git a/host/lib/host_misc2.c b/host/lib/host_misc2.c
index 88b58f5..71a2067 100644
--- a/host/lib/host_misc2.c
+++ b/host/lib/host_misc2.c
@@ -10,6 +10,7 @@
 
 #include "2sysincludes.h"
 #include "2common.h"
+#include "2sha.h"
 #include "host_common.h"
 
 int vb2_read_file(const char *filename, uint8_t **data_ptr, uint32_t *size_ptr)
diff --git a/host/lib/include/host_key2.h b/host/lib/include/host_key2.h
index 08f55a3..813ae60 100644
--- a/host/lib/include/host_key2.h
+++ b/host/lib/include/host_key2.h
@@ -84,6 +84,17 @@
 			  const char *filename);
 
 /**
+ * Get a private key for an unsigned hash
+ *
+ * @param key_ptr	Destination for pointer to key.  The key is statically
+ *			allocated and must not be freed.
+ * @param hash_alg	Hash algorithm to use
+ * @return VB2_SUCCESS, or non-zero error code if error.
+ */
+int vb2_private_key_hash(const struct vb2_private_key **key_ptr,
+			 enum vb2_hash_algorithm hash_alg);
+
+/**
  * Free a public key allocated by one of the functions below.
  *
  * Note that this should ONLY be called for public keys allocated via one
@@ -141,4 +152,15 @@
 int vb2_public_key_pack(struct vb2_packed_key2 **key_ptr,
 			const struct vb2_public_key *pubk);
 
+/**
+ * Get a public key for an unsigned hash.
+ *
+ * @param key		Destination for key data.
+ * @param hash_alg	Hash algorithm to use
+ * @return VB2_SUCCESS, or non-zero error code if error.
+ */
+int vb2_public_key_hash(struct vb2_public_key *key,
+			enum vb2_hash_algorithm hash_alg);
+
+
 #endif  /* VBOOT_REFERENCE_HOST_KEY2_H_ */
diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c
index d8a714b..37996ae 100644
--- a/tests/vb2_common_tests.c
+++ b/tests/vb2_common_tests.c
@@ -8,6 +8,7 @@
 #include "2sysincludes.h"
 #include "2common.h"
 #include "2rsa.h"
+#include "host_key2.h"
 #include "vb2_convert_structs.h"
 #include "vboot_struct.h"  /* For old struct sizes */
 
@@ -452,16 +453,15 @@
 static void test_verify_hash(void)
 {
 	struct vb2_signature2 *sig;
-	struct vb2_public_key pubk = {
-		.sig_alg = VB2_SIG_NONE,
-		.hash_alg = VB2_HASH_SHA256,
-		.guid = vb2_hash_guid(VB2_HASH_SHA256)
-	};
+	struct vb2_public_key pubk;
 	uint8_t workbuf[VB2_VERIFY_DATA_WORKBUF_BYTES];
 	struct vb2_workbuf wb;
 
 	vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
 
+	TEST_SUCC(vb2_public_key_hash(&pubk, VB2_HASH_SHA256),
+		  "create hash key");
+
 	/* Create the signature */
 	sig = vb2_create_hash_sig(test_data, sizeof(test_data), pubk.hash_alg);
 	TEST_PTR_NEQ(sig, NULL, "create hash sig");
@@ -483,6 +483,7 @@
 static void test_verify_keyblock(void)
 {
 	const char desc[16] = "test keyblock";
+	struct vb2_public_key pubk, pubk2, pubk_not_present;
 	struct vb2_signature2 *sig;
 	struct vb2_keyblock2 *kbuf;
 	uint32_t buf_size;
@@ -491,21 +492,12 @@
 	uint8_t workbuf[VB2_KEY_BLOCK_VERIFY_WORKBUF_BYTES];
 	struct vb2_workbuf wb;
 
-	const struct vb2_public_key pubk = {
-		.sig_alg = VB2_SIG_NONE,
-		.hash_alg = VB2_HASH_SHA256,
-		.guid = vb2_hash_guid(VB2_HASH_SHA256)
-	};
-	const struct vb2_public_key pubk2 = {
-		.sig_alg = VB2_SIG_NONE,
-		.hash_alg = VB2_HASH_SHA512,
-		.guid = vb2_hash_guid(VB2_HASH_SHA512)
-	};
-	const struct vb2_public_key pubk_not_present = {
-		.sig_alg = VB2_SIG_NONE,
-		.hash_alg = VB2_HASH_SHA1,
-		.guid = vb2_hash_guid(VB2_HASH_SHA1)
-	};
+	TEST_SUCC(vb2_public_key_hash(&pubk, VB2_HASH_SHA256),
+		  "create hash key 1");
+	TEST_SUCC(vb2_public_key_hash(&pubk2, VB2_HASH_SHA512),
+		  "create hash key 2");
+	TEST_SUCC(vb2_public_key_hash(&pubk_not_present, VB2_HASH_SHA1),
+		  "create hash key 3");
 
 	/*
 	 * Test packed key only needs to initialize the fields used by keyblock
@@ -663,6 +655,7 @@
 static void test_verify_fw_preamble(void)
 {
 	const char desc[16] = "test preamble";
+	struct vb2_public_key pubk;
 	struct vb2_signature2 *sig;
 	struct vb2_fw_preamble2 *pre;
 	uint32_t buf_size;
@@ -678,11 +671,8 @@
 	 * bare hash here saves us from needing to have a private key to do
 	 * this test.
 	 */
-	const struct vb2_public_key pubk = {
-		.sig_alg = VB2_SIG_NONE,
-		.hash_alg = VB2_HASH_SHA256,
-		.guid = vb2_hash_guid(VB2_HASH_SHA256)
-	};
+	TEST_SUCC(vb2_public_key_hash(&pubk, VB2_HASH_SHA256),
+		  "create hash key");
 
 	struct vb2_fw_preamble2 fp = {
 		.c.magic = VB2_MAGIC_FW_PREAMBLE2,
diff --git a/tests/vb2_host_key_tests.c b/tests/vb2_host_key_tests.c
index 9a56351..15e0b37 100644
--- a/tests/vb2_host_key_tests.c
+++ b/tests/vb2_host_key_tests.c
@@ -33,6 +33,7 @@
 			      const char *pemfile)
 {
 	struct vb2_private_key *key, *k2;
+	const struct vb2_private_key *ckey;
 	struct vb2_packed_private_key2 *pkey;
 	const char *testfile = "test.vbprik2";
 	const char *notapem = "not_a_pem";
@@ -136,11 +137,31 @@
 		VB2_ERROR_UNPACK_PRIVATE_KEY_RSA,
 		"Unpack private key bad rsa data");
 
+	memcpy(buf, buf2, bufsize);
+	pkey->sig_alg = VB2_SIG_NONE;
+	TEST_EQ(vb2_private_key_unpack(&k2, buf, bufsize),
+		VB2_ERROR_UNPACK_PRIVATE_KEY_HASH,
+		"Unpack private key hash but has data");
+
 	free(buf);
 	free(buf2);
 	unlink(testfile);
 
-	vb2_private_key_free(key);
+	TEST_EQ(vb2_private_key_hash(&ckey, VB2_HASH_INVALID),
+		VB2_ERROR_PRIVATE_KEY_HASH,
+		"Hash key invalid");
+	TEST_PTR_EQ(ckey, NULL, "  key_ptr");
+
+	TEST_SUCC(vb2_private_key_hash(&ckey, combo->hash_alg), "Hash key");
+	TEST_PTR_NEQ(ckey, NULL, "  key_ptr");
+	TEST_EQ(ckey->hash_alg, combo->hash_alg, "  hash_alg");
+	TEST_EQ(ckey->sig_alg, VB2_SIG_NONE, "  sig_alg");
+	TEST_EQ(memcmp(&ckey->guid, vb2_hash_guid(combo->hash_alg),
+		       sizeof(ckey->guid)), 0, "  guid");
+
+	TEST_SUCC(vb2_private_key_write(ckey, testfile), "Write hash key");
+	TEST_SUCC(vb2_private_key_read(&key, testfile), "Read hash key");
+	unlink(testfile);
 }
 
 static void public_key_tests(const struct alg_combo *combo,
@@ -213,13 +234,47 @@
 		"  n");
 	TEST_EQ(memcmp(key->rr, k2.rr, key->arrsize * sizeof(uint32_t)), 0,
 		"  rr");
+
+	TEST_SUCC(vb2_write_object(testfile, pkey), "Write packed key");
 	free(pkey);
 
+	TEST_SUCC(vb2_packed_key2_read(&pkey, testfile), "Read packed key");
+	TEST_PTR_NEQ(pkey, NULL, "  key_ptr");
+	unlink(testfile);
+
+	pkey->hash_alg = VB2_HASH_INVALID;
+	TEST_SUCC(vb2_write_object(testfile, pkey), "Write bad packed key");
+	free(pkey);
+
+	TEST_EQ(vb2_packed_key2_read(&pkey, testfile),
+		VB2_ERROR_READ_PACKED_KEY, "Read bad packed key");
+	TEST_PTR_EQ(pkey, NULL, "  key_ptr");
+	unlink(testfile);
+
+	TEST_EQ(vb2_packed_key2_read(&pkey, testfile),
+		VB2_ERROR_READ_PACKED_KEY_DATA, "Read missing packed key");
+
 	key->sig_alg = VB2_SIG_INVALID;
 	TEST_EQ(vb2_public_key_pack(&pkey, key),
 		VB2_ERROR_PUBLIC_KEY_PACK_SIZE,
 		"Pack invalid sig alg");
 	vb2_public_key_free(key);
+
+	TEST_EQ(vb2_public_key_hash(&k2, VB2_HASH_INVALID),
+		VB2_ERROR_PUBLIC_KEY_HASH,
+		"Hash key invalid");
+
+	TEST_SUCC(vb2_public_key_hash(&k2, combo->hash_alg), "Hash key");
+	TEST_EQ(k2.hash_alg, combo->hash_alg, "  hash_alg");
+	TEST_EQ(k2.sig_alg, VB2_SIG_NONE, "  sig_alg");
+	TEST_EQ(memcmp(k2.guid, vb2_hash_guid(combo->hash_alg),
+		       sizeof(*k2.guid)), 0, "  guid");
+
+	TEST_SUCC(vb2_public_key_pack(&pkey, &k2), "Pack public hash key");
+	TEST_PTR_NEQ(pkey, NULL, "  key_ptr");
+	TEST_SUCC(vb2_unpack_key2(&k2, (uint8_t *)pkey, pkey->c.total_size),
+		  "Unpack public hash key");
+	free(pkey);
 }
 
 static int test_algorithm(const struct alg_combo *combo, const char *keys_dir)