vboot2: Add support for modexp acceleration

Add vb2ex_hwcrypto_modexp support to accelerate only calculation part of
RSA and we can handle the rest. Instead of relying on opaque hardware
accleration for all RSA verification process, this will enable us to
maintain our security level while enhancing overall speed of
verification.

BRANCH=zork
BUG=b:169157796
TEST=make runtests

Signed-off-by: Kangheui Won <khwon@chromium.org>
Change-Id: I6f9fc919c4215964158815a58a9f1b338c2a76a4
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2444809
Reviewed-by: Julius Werner <jwerner@chromium.org>
diff --git a/firmware/2lib/2rsa.c b/firmware/2lib/2rsa.c
index 1a23d02..962558d 100644
--- a/firmware/2lib/2rsa.c
+++ b/firmware/2lib/2rsa.c
@@ -342,7 +342,7 @@
 	int sig_size;
 	int pad_size;
 	int exp;
-	vb2_error_t rv;
+	vb2_error_t rv = VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
 
 	if (!key || !sig || !digest)
 		return VB2_ERROR_RSA_VERIFY_PARAM;
@@ -367,7 +367,22 @@
 		return VB2_ERROR_RSA_VERIFY_WORKBUF;
 	}
 
-	modpow(key, sig, workbuf32, exp);
+	if (key->allow_hwcrypto) {
+		rv = vb2ex_hwcrypto_modexp(key, sig, workbuf32, exp);
+
+		if (rv == VB2_SUCCESS)
+			VB2_DEBUG("Using HW modexp engine for sig_alg %d\n",
+					key->sig_alg);
+		else
+			VB2_DEBUG("HW modexp for sig_alg %d not supported, using SW\n",
+					key->sig_alg);
+	} else {
+		VB2_DEBUG("HW modexp forbidden, using SW\n");
+	}
+
+	if (rv != VB2_SUCCESS) {
+		modpow(key, sig, workbuf32, exp);
+	}
 
 	vb2_workbuf_free(&wblocal, 3 * key_bytes);
 
diff --git a/firmware/2lib/2stub_hwcrypto.c b/firmware/2lib/2stub_hwcrypto.c
index 542a5ed..56272ad 100644
--- a/firmware/2lib/2stub_hwcrypto.c
+++ b/firmware/2lib/2stub_hwcrypto.c
@@ -34,3 +34,8 @@
 	return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
 }
 
+__attribute__((weak))
+vb2_error_t vb2ex_hwcrypto_modexp(const struct vb2_public_key *key,
+				  uint8_t *inout, uint32_t *workbuf32, int exp) {
+	return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
+}
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h
index 6b95204..67b5074 100644
--- a/firmware/2lib/include/2api.h
+++ b/firmware/2lib/include/2api.h
@@ -966,6 +966,20 @@
 					     const uint8_t *sig,
 					     const uint8_t *digest);
 
+/**
+ * Calculate modexp using hardware crypto engine.
+ *
+ * @param key		Key to use in signing
+ * @param inout		Input and output big-endian byte array
+ * @param workbuf32	Work buffer; caller must verify this is
+ *			(3 * key->arrsize) elements long.
+ * @param exp		RSA public exponent: either 65537 (F4) or 3
+ * @return VB2_SUCCESS or HWCRYPTO_UNSUPPORTED.
+ */
+vb2_error_t vb2ex_hwcrypto_modexp(const struct vb2_public_key *key,
+				  uint8_t *inout,
+				  uint32_t *workbuf32, int exp);
+
 /*
  * Abort vboot flow due to a failed assertion or broken assumption.
  *
diff --git a/tests/vb20_rsa_padding_tests.c b/tests/vb20_rsa_padding_tests.c
index 8a0d58a..03a38ee 100644
--- a/tests/vb20_rsa_padding_tests.c
+++ b/tests/vb20_rsa_padding_tests.c
@@ -14,6 +14,14 @@
 #include "test_common.h"
 #include "vb2_common.h"
 
+vb2_error_t hwcrypto_modexp_return_value = VB2_SUCCESS;
+vb2_error_t vb2ex_hwcrypto_modexp(const struct vb2_public_key *key,
+				  uint8_t *inout,
+				  uint32_t *workbuf32, int exp) {
+	return hwcrypto_modexp_return_value;
+}
+
+
 /**
  * Test valid and invalid signatures.
  */
@@ -67,6 +75,20 @@
 	TEST_EQ(vb2_rsa_verify_digest(key, NULL, test_message_sha1_hash, &wb),
 		VB2_ERROR_RSA_VERIFY_PARAM, "vb2_rsa_verify_digest() bad arg");
 
+	key->allow_hwcrypto = 1;
+	memcpy(sig, signatures[0], sizeof(sig));
+	vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
+	hwcrypto_modexp_return_value = VB2_SUCCESS;
+	TEST_NEQ(vb2_rsa_verify_digest(key, sig, test_message_sha1_hash, &wb),
+		VB2_SUCCESS, "vb2_rsa_verify_digest() hwcrypto modexp fails");
+
+	memcpy(sig, signatures[0], sizeof(sig));
+	vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
+	hwcrypto_modexp_return_value = VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
+	TEST_SUCC(vb2_rsa_verify_digest(key, sig, test_message_sha1_hash, &wb),
+		"vb2_rsa_verify_digest() hwcrypto modexp fallback to sw");
+	key->allow_hwcrypto = 0;
+
 	memcpy(sig, signatures[0], sizeof(sig));
 	vb2_workbuf_init(&wb, workbuf, sizeof(sig) * 3 - 1);
 	TEST_EQ(vb2_rsa_verify_digest(key, sig, test_message_sha1_hash, &wb),