vboot: add support for HW accel in kernel verification

Add support for using HW hashing acceleration in kernel verification.

BUG=b:162551138
BRANCH=zork
TEST=CC=x86_64-pc-linux-gnu-clang make runtests

Signed-off-by: Kangheui Won <khwon@chromium.org>
Change-Id: Ia03ff7f49bd18393c0daeab72348414fa059e0cd
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2639456
Reviewed-by: Raul E Rangel <rrangel@chromium.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
diff --git a/firmware/2lib/2common.c b/firmware/2lib/2common.c
index a88bc2e..8267f8c 100644
--- a/firmware/2lib/2common.c
+++ b/firmware/2lib/2common.c
@@ -190,9 +190,9 @@
 			    const struct vb2_workbuf *wb)
 {
 	struct vb2_workbuf wblocal = *wb;
-	struct vb2_digest_context *dc;
 	uint8_t *digest;
 	uint32_t digest_size;
+	vb2_error_t rv;
 
 	if (sig->data_size > size) {
 		VB2_DEBUG("Data buffer smaller than length of signed data.\n");
@@ -208,16 +208,26 @@
 	if (!digest)
 		return VB2_ERROR_VDATA_WORKBUF_DIGEST;
 
-	/* Hashing requires temp space for the context */
-	dc = vb2_workbuf_alloc(&wblocal, sizeof(*dc));
-	if (!dc)
-		return VB2_ERROR_VDATA_WORKBUF_HASHING;
-
-	VB2_TRY(vb2_digest_init(dc, key->hash_alg));
-	VB2_TRY(vb2_digest_extend(dc, data, sig->data_size));
-	VB2_TRY(vb2_digest_finalize(dc, digest, digest_size));
-
-	vb2_workbuf_free(&wblocal, sizeof(*dc));
+	if (key->allow_hwcrypto) {
+		rv = vb2ex_hwcrypto_digest_init(key->hash_alg, sig->data_size);
+		if (rv == VB2_SUCCESS) {
+			VB2_DEBUG("Using HW crypto engine for hash_alg %d\n", key->hash_alg);
+			VB2_TRY(vb2ex_hwcrypto_digest_extend(data, sig->data_size));
+			VB2_TRY(vb2ex_hwcrypto_digest_finalize(digest, digest_size));
+		} else if (rv == VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED) {
+			VB2_DEBUG("HW crypto for hash_alg %d not supported, using SW\n",
+				  key->hash_alg);
+			VB2_TRY(vb2_digest_buffer(data, sig->data_size, key->hash_alg,
+						  digest, digest_size));
+		} else {
+			VB2_DEBUG("HW crypto init error : %d\n", rv);
+			return rv;
+		}
+	} else {
+		VB2_DEBUG("HW crypto forbidden by TPM flag, using SW\n");
+		VB2_TRY(vb2_digest_buffer(data, sig->data_size, key->hash_alg,
+					  digest, digest_size));
+	}
 
 	return vb2_verify_digest(key, sig, digest, &wblocal);
 }
diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c
index 495b360..470f19e 100644
--- a/firmware/lib/vboot_kernel.c
+++ b/firmware/lib/vboot_kernel.c
@@ -137,6 +137,9 @@
 		return VB2_ERROR_VBLOCK_KERNEL_SUBKEY;
 	}
 
+	if (vb2_hwcrypto_allowed(ctx))
+		kernel_subkey2.allow_hwcrypto = 1;
+
 	/* Verify the keyblock. */
 	int keyblock_valid = 1;  /* Assume valid */
 	struct vb2_keyblock *keyblock = get_keyblock(kbuf);
@@ -412,6 +415,9 @@
 		return VB2_ERROR_LOAD_PARTITION_DATA_KEY;
 	}
 
+	if (vb2_hwcrypto_allowed(ctx))
+		data_key.allow_hwcrypto = 1;
+
 	/* Verify kernel data */
 	if (VB2_SUCCESS != vb2_verify_data(kernbuf, kernbuf_size,
 					   &preamble->body_signature,
diff --git a/tests/vb2_common2_tests.c b/tests/vb2_common2_tests.c
index b1666ab..3f06289 100644
--- a/tests/vb2_common2_tests.c
+++ b/tests/vb2_common2_tests.c
@@ -20,25 +20,52 @@
 static const uint8_t test_data[] = "This is some test data to sign.";
 static const uint32_t test_size = sizeof(test_data);
 
-static enum {
+static enum hwcrypto_state {
 	HWCRYPTO_OK,
 	HWCRYPTO_NOTSUPPORTED,
 	HWCRYPTO_ERROR,
-} hwcrypto_state;
+	HWCRYPTO_ABORT,
+} hwcrypto_state_rsa, hwcrypto_state_digest;
 
-vb2_error_t vb2ex_hwcrypto_rsa_verify_digest(const struct vb2_public_key *key,
-					     const uint8_t *sig, const uint8_t *digest)
+static vb2_error_t hwcrypto_mock(enum hwcrypto_state *state)
 {
-	switch (hwcrypto_state) {
+	switch (*state) {
 		case HWCRYPTO_OK:
 			return VB2_SUCCESS;
 		case HWCRYPTO_NOTSUPPORTED:
 			return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
 		case HWCRYPTO_ERROR:
-			return VB2_ERROR_RSA_VERIFY_DIGEST;
+			return VB2_ERROR_MOCK;
+		case HWCRYPTO_ABORT:
+			vb2ex_abort();
+			/* shouldn't reach here but added for compiler */
+			return VB2_ERROR_MOCK;
 	}
 }
 
+vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
+				       uint32_t data_size)
+{
+	return hwcrypto_mock(&hwcrypto_state_digest);
+}
+
+vb2_error_t vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
+{
+	return hwcrypto_mock(&hwcrypto_state_digest);
+}
+
+vb2_error_t vb2ex_hwcrypto_digest_finalize(uint8_t *digest,
+					   uint32_t digest_size)
+{
+	return hwcrypto_mock(&hwcrypto_state_digest);
+}
+
+vb2_error_t vb2ex_hwcrypto_rsa_verify_digest(const struct vb2_public_key *key,
+					     const uint8_t *sig, const uint8_t *digest)
+{
+	return hwcrypto_mock(&hwcrypto_state_rsa);
+}
+
 
 static void test_unpack_key(const struct vb2_packed_key *key1)
 {
@@ -109,6 +136,9 @@
 	uint32_t sig_total_size = sig->sig_offset + sig->sig_size;
 	struct vb2_signature *sig2;
 
+	hwcrypto_state_rsa = HWCRYPTO_ABORT;
+	hwcrypto_state_digest = HWCRYPTO_ABORT;
+
 	vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
 
 	/* Allocate signature copy for tests */
@@ -155,18 +185,57 @@
 
 	pubk.allow_hwcrypto = 1;
 
-	hwcrypto_state = HWCRYPTO_OK;
+	hwcrypto_state_digest = HWCRYPTO_OK;
+	hwcrypto_state_rsa = HWCRYPTO_OK;
 	memcpy(sig2, sig, sig_total_size);
 	vb2_signature_data_mutable(sig2)[0] ^= 0x5A;
 	TEST_EQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
 		0, "vb2_verify_data() hwcrypto ok");
 
-	hwcrypto_state = HWCRYPTO_ERROR;
+	hwcrypto_state_rsa = HWCRYPTO_ERROR;
 	memcpy(sig2, sig, sig_total_size);
 	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
 		0, "vb2_verify_data() hwcrypto error");
 
-	hwcrypto_state = HWCRYPTO_NOTSUPPORTED;
+	hwcrypto_state_rsa = HWCRYPTO_NOTSUPPORTED;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_EQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto fallback ok");
+
+	memcpy(sig2, sig, sig_total_size);
+	sig2->sig_size -= 16;
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto fallback error");
+
+	hwcrypto_state_digest = HWCRYPTO_ERROR;
+	hwcrypto_state_rsa = HWCRYPTO_OK;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto error");
+
+	hwcrypto_state_rsa = HWCRYPTO_ERROR;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto error");
+
+	hwcrypto_state_rsa = HWCRYPTO_NOTSUPPORTED;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto fallback error");
+
+	hwcrypto_state_digest = HWCRYPTO_NOTSUPPORTED;
+	hwcrypto_state_rsa = HWCRYPTO_OK;
+	memcpy(sig2, sig, sig_total_size);
+	vb2_signature_data_mutable(sig2)[0] ^= 0x5A;
+	TEST_EQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto ok");
+
+	hwcrypto_state_rsa = HWCRYPTO_ERROR;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto error");
+
+	hwcrypto_state_rsa = HWCRYPTO_NOTSUPPORTED;
 	memcpy(sig2, sig, sig_total_size);
 	TEST_EQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
 		0, "vb2_verify_data() hwcrypto fallback ok");
diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c
index 87056ad..e86837b 100644
--- a/tests/vboot_kernel_tests.c
+++ b/tests/vboot_kernel_tests.c
@@ -175,7 +175,12 @@
 	fwmp = (struct vb2_secdata_fwmp *)ctx->secdata_fwmp;
 	memcpy(&fwmp->dev_key_hash, mock_digest, sizeof(fwmp->dev_key_hash));
 
-	// TODO: more workbuf fields - flags, secdata_firmware, secdata_kernel
+	// TODO: more workbuf fields - flags, secdata_firmware
+
+	vb2api_secdata_kernel_create(ctx);
+	vb2_secdata_kernel_init(ctx);
+	vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS,
+			VB2_SECDATA_KERNEL_FLAG_HWCRYPTO_ALLOWED);
 }
 
 /* Mocks */
diff --git a/tests/verify_kernel.c b/tests/verify_kernel.c
index 9aaad72..fe68a1b 100644
--- a/tests/verify_kernel.c
+++ b/tests/verify_kernel.c
@@ -10,6 +10,7 @@
 #include "2common.h"
 #include "2misc.h"
 #include "2nvstorage.h"
+#include "2secdata.h"
 #include "host_common.h"
 #include "util_misc.h"
 #include "vboot_api.h"
@@ -124,6 +125,11 @@
 	 * dev mode.  So just use defaults for nv storage.
 	 */
 	vb2_nv_init(ctx);
+	/* We need to init kernel secdata for
+	 * VB2_SECDATA_KERNEL_FLAG_HWCRYPTO_ALLOWED.
+	 */
+	vb2api_secdata_kernel_create(ctx);
+	vb2_secdata_kernel_init(ctx);
 
 	/* Try loading kernel */
 	rv = LoadKernel(ctx, &params);