diff mbox series

[5/8] lib: crypto: add pkcs7_digest()

Message ID 20200609051401.18192-6-takahiro.akashi@linaro.org
State Superseded
Headers show
Series efi_loader: secure boot: support intermediate certificates in signature | expand

Commit Message

AKASHI Takahiro June 9, 2020, 5:13 a.m. UTC
This function was nullified when the file, pkcs7_verify.c, was imported
because it calls further linux-specific interfaces inside, hence that
could lead to more files being imported from linux.

We need this function in pkcs7_verify_one() and so simply re-implement it
here instead of re-using the code.

Signed-off-by: AKASHI Takahiro <takahiro.akashi at linaro.org>
---
 lib/crypto/pkcs7_verify.c | 84 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 81 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/lib/crypto/pkcs7_verify.c b/lib/crypto/pkcs7_verify.c
index 1e8600f7faca..8b5cd7a443ae 100644
--- a/lib/crypto/pkcs7_verify.c
+++ b/lib/crypto/pkcs7_verify.c
@@ -17,7 +17,10 @@ 
 #include <linux/err.h>
 #endif
 #include <linux/asn1.h>
-#ifndef __UBOOT__
+#ifdef __UBOOT__
+#include <image.h>
+#include <u-boot/rsa-checksum.h>
+#else
 #include <crypto/hash.h>
 #include <crypto/hash_info.h>
 #endif
@@ -35,9 +38,84 @@ 
 static int pkcs7_digest(struct pkcs7_message *pkcs7,
 			struct pkcs7_signed_info *sinfo)
 {
-	return 0;
+	struct public_key_signature *sig = sinfo->sig;
+	struct image_region regions[2];
+	int ret = 0;
+
+	/* The digest was calculated already. */
+	if (sig->digest)
+		return 0;
+
+	if (!sinfo->sig->hash_algo)
+		return -ENOPKG;
+	if (!strcmp(sinfo->sig->hash_algo, "sha256"))
+		sig->digest_size = SHA256_SUM_LEN;
+	else if (!strcmp(sinfo->sig->hash_algo, "sha1"))
+		sig->digest_size = SHA1_SUM_LEN;
+	else
+		return -ENOPKG;
+
+	sig->digest = calloc(1, sig->digest_size);
+	if (!sig->digest) {
+		pr_warn("Sig %u: Out of memory\n", sinfo->index);
+		return -ENOMEM;
+	}
+
+	regions[0].data = pkcs7->data;
+	regions[0].size = pkcs7->data_len;
+
+	/* Digest the message [RFC2315 9.3] */
+	hash_calculate(sinfo->sig->hash_algo, regions, 1, sig->digest);
+
+	/* However, if there are authenticated attributes, there must be a
+	 * message digest attribute amongst them which corresponds to the
+	 * digest we just calculated.
+	 */
+	if (sinfo->authattrs) {
+		u8 tag;
+
+		if (!sinfo->msgdigest) {
+			pr_warn("Sig %u: No messageDigest\n", sinfo->index);
+			ret = -EKEYREJECTED;
+			goto error;
+		}
+
+		if (sinfo->msgdigest_len != sig->digest_size) {
+			pr_debug("Sig %u: Invalid digest size (%u)\n",
+				 sinfo->index, sinfo->msgdigest_len);
+			ret = -EBADMSG;
+			goto error;
+		}
+
+		if (memcmp(sig->digest, sinfo->msgdigest,
+			   sinfo->msgdigest_len) != 0) {
+			pr_debug("Sig %u: Message digest doesn't match\n",
+				 sinfo->index);
+			ret = -EKEYREJECTED;
+			goto error;
+		}
+
+		/* We then calculate anew, using the authenticated attributes
+		 * as the contents of the digest instead.  Note that we need to
+		 * convert the attributes from a CONT.0 into a SET before we
+		 * hash it.
+		 */
+		memset(sig->digest, 0, sig->digest_size);
+
+		tag = 0x31;
+		regions[0].data = &tag;
+		regions[0].size = 1;
+		regions[1].data = sinfo->authattrs;
+		regions[1].size = sinfo->authattrs_len;
+
+		hash_calculate(sinfo->sig->hash_algo, regions, 2, sig->digest);
+
+		ret = 0;
+	}
+error:
+	return ret;
 }
-#else
+#else /* !__UBOOT__ */
 static int pkcs7_digest(struct pkcs7_message *pkcs7,
 			struct pkcs7_signed_info *sinfo)
 {