platform: msm_shared: Validate the decrypted signature

For a successful boot image authentication, the RSA decrypt api returns the
size of ASN1 encoded signature (PKCS#1 magic + sha256), compare the size
returned by RSA decrypt API with size of ASN1 if they match the signature is
valid otherwise fail with an error. This check avoids vulnerability due to
trailing data placed at the end of digest.

Change-Id: Ib7077efce6369a253b09a0def8e53d035ee345b8
diff --git a/platform/msm_shared/boot_verifier.c b/platform/msm_shared/boot_verifier.c
index 2d90f40..43b12fa 100644
--- a/platform/msm_shared/boot_verifier.c
+++ b/platform/msm_shared/boot_verifier.c
@@ -44,6 +44,9 @@
 #include <secapp_loader.h>
 #include <target.h>
 
+#define ASN1_ENCODED_SHA256_SIZE 0x33
+#define ASN1_ENCODED_SHA256_OFFSET 0x13
+
 static KEYSTORE *oem_keystore;
 static KEYSTORE *user_keystore;
 static uint32_t dev_boot_state = RED;
@@ -130,52 +133,25 @@
 	return len;
 }
 
-static int verify_digest(unsigned char* input, unsigned char *digest, int hash_size)
-{
-	int ret = -1;
-	X509_SIG *sig = NULL;
-	uint32_t len = read_der_message_length(input);
-	if(!len)
-	{
-		dprintf(CRITICAL, "boot_verifier: Signature length is invalid.\n");
-		return ret;
-	}
-
-	sig = d2i_X509_SIG(NULL, (const unsigned char **) &input, len);
-	if(sig == NULL)
-	{
-		dprintf(CRITICAL, "boot_verifier: Reading digest failed\n");
-		return ret;
-	}
-
-	if(sig->digest->length != SHA256_SIZE)
-	{
-		dprintf(CRITICAL, "boot_verifier: Digest length error.\n");
-		goto verify_digest_error;
-	}
-
-	if(memcmp(sig->digest->data, digest, hash_size) == 0)
-		ret = 0;
-
-verify_digest_error:
-	if(sig != NULL)
-		X509_SIG_free(sig);
-
-	return ret;
-}
-
 static int add_attribute_to_img(unsigned char *ptr, AUTH_ATTR *input)
 {
 	return i2d_AUTH_ATTR(input, &ptr);
 }
 
-static bool boot_verify_compare_sha256(unsigned char *image_ptr,
+bool boot_verify_compare_sha256(unsigned char *image_ptr,
 		unsigned int image_size, unsigned char *signature_ptr, RSA *rsa)
 {
 	int ret = -1;
 	bool auth = false;
 	unsigned char *plain_text = NULL;
-	unsigned int digest[8];
+
+	/* The magic numbers here are drawn from the PKCS#1 standard and are the ASN.1
+	 *encoding of the SHA256 object identifier that is required for a PKCS#1
+	* signature.*/
+	uint8_t digest[ASN1_ENCODED_SHA256_SIZE] = {0x30, 0x31, 0x30, 0x0d, 0x06,
+												0x09, 0x60, 0x86, 0x48, 0x01,
+												0x65, 0x03, 0x04, 0x02, 0x01,
+												0x05, 0x00, 0x04, 0x20};
 
 	plain_text = (unsigned char *)calloc(sizeof(char), SIGNATURE_SIZE);
 	if (plain_text == NULL) {
@@ -183,22 +159,34 @@
 		goto cleanup;
 	}
 
-	/* Calculate SHA256sum */
+	/* Calculate SHA256 of image and place it into the ASN.1 structure*/
 	image_find_digest(image_ptr, image_size, CRYPTO_AUTH_ALG_SHA256,
-			(unsigned char *)&digest);
+			digest + ASN1_ENCODED_SHA256_OFFSET);
 
-	/* Find digest from the image */
+	/* Find digest from the image. This performs the PKCS#1 padding checks up to
+	 * but not including the ASN.1 OID and hash function check. The return value
+	 * is not positive for a failure or the length of the part after the padding */
 	ret = image_decrypt_signature_rsa(signature_ptr, plain_text, rsa);
 
-	dprintf(SPEW, "boot_verifier: Return of RSA_public_decrypt = %d\n",
+	/* Make sure the length returned from rsa decrypt is same as x509 signature format
+	 * otherwise the signature is invalid and we fail
+	 */
+	if (ret != ASN1_ENCODED_SHA256_SIZE)
+	{
+		dprintf(CRITICAL, "boot_verifier: Signature decrypt failed! Signature invalid = %d\n",
 			ret);
+		goto cleanup;
+	}
+	/* So plain_text contains the ASN.1 encoded hash from the signature and
+	* digest contains the value that this should be for the image that we're
+	* verifying, so compare them.*/
 
-	ret = verify_digest(plain_text, (unsigned char*)digest, SHA256_SIZE);
+	ret = memcmp(plain_text, digest, ASN1_ENCODED_SHA256_SIZE);
 	if(ret == 0)
 	{
 		auth = true;
 #ifdef TZ_SAVE_KERNEL_HASH
-		save_kernel_hash((unsigned char *) &digest, CRYPTO_AUTH_ALG_SHA256);
+		save_kernel_hash((unsigned char *) digest + ASN1_ENCODED_SHA256_OFFSET, CRYPTO_AUTH_ALG_SHA256);
 #endif
 	}
 
@@ -627,3 +615,9 @@
 
 	return false;
 }
+
+KEYSTORE *boot_gerity_get_oem_keystore()
+{
+	read_oem_keystore();
+	return oem_keystore;
+}
diff --git a/platform/msm_shared/include/boot_verifier.h b/platform/msm_shared/include/boot_verifier.h
index 07fb923..62968fc 100644
--- a/platform/msm_shared/include/boot_verifier.h
+++ b/platform/msm_shared/include/boot_verifier.h
@@ -178,4 +178,7 @@
 /* Function to send root of trust to trust zone */
 bool send_rot_command(uint32_t is_unlocked);
 unsigned char* get_boot_fingerprint(unsigned int* buf_size);
+bool boot_verify_compare_sha256(unsigned char *image_ptr,
+		unsigned int image_size, unsigned char *signature_ptr, RSA *rsa);
+KEYSTORE *boot_gerity_get_oem_keystore();
 #endif