lib: crypto: add pkcs7_digest()
authorAKASHI Takahiro <takahiro.akashi@linaro.org>
Tue, 21 Jul 2020 10:35:20 +0000 (19:35 +0900)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Wed, 22 Jul 2020 10:36:29 +0000 (12:36 +0200)
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@linaro.org>
lib/crypto/pkcs7_verify.c

index 192e39b..706358f 100644 (file)
 
 #define pr_fmt(fmt) "PKCS7: "fmt
 #ifdef __UBOOT__
+#include <image.h>
 #include <string.h>
 #include <linux/bitops.h>
 #include <linux/compat.h>
 #include <linux/asn1.h>
+#include <u-boot/rsa-checksum.h>
 #include <crypto/public_key.h>
 #include <crypto/pkcs7_parser.h>
 #else
 #endif
 
 /*
- * Digest the relevant parts of the PKCS#7 data
+ * pkcs7_digest - Digest the relevant parts of the PKCS#7 data
+ * @pkcs7:     PKCS7 Signed Data
+ * @sinfo:     PKCS7 Signed Info
+ *
+ * Digest the relevant parts of the PKCS#7 data, @pkcs7, using signature
+ * information in @sinfo. But if there are authentication attributes,
+ * i.e. signed image case, the digest must be calculated against
+ * the authentication attributes.
+ *
+ * Return:     0 - on success, non-zero error code - otherwise
  */
 #ifdef __UBOOT__
 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)
 {