]> git.sur5r.net Git - u-boot/blobdiff - lib/rsa/rsa-verify.c
Merge git://git.denx.de/u-boot-marvell
[u-boot] / lib / rsa / rsa-verify.c
index f8bc086fd77c0a7049795f864be82b6bcf95b53d..bc833543788b42660b81658cea3a954beb207822 100644 (file)
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (c) 2013, Google Inc.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #ifndef USE_HOSTCC
@@ -9,9 +8,10 @@
 #include <fdtdec.h>
 #include <asm/types.h>
 #include <asm/byteorder.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <asm/types.h>
 #include <asm/unaligned.h>
+#include <dm.h>
 #else
 #include "fdt_host.h"
 #include "mkimage.h"
 /* Default public exponent for backward compatibility */
 #define RSA_DEFAULT_PUBEXP     65537
 
+/**
+ * rsa_verify_padding() - Verify RSA message padding is valid
+ *
+ * Verify a RSA message's padding is consistent with PKCS1.5
+ * padding as described in the RSA PKCS#1 v2.1 standard.
+ *
+ * @msg:       Padded message
+ * @pad_len:   Number of expected padding bytes
+ * @algo:      Checksum algo structure having information on DER encoding etc.
+ * @return 0 on success, != 0 on failure
+ */
+static int rsa_verify_padding(const uint8_t *msg, const int pad_len,
+                             struct checksum_algo *algo)
+{
+       int ff_len;
+       int ret;
+
+       /* first byte must be 0x00 */
+       ret = *msg++;
+       /* second byte must be 0x01 */
+       ret |= *msg++ ^ 0x01;
+       /* next ff_len bytes must be 0xff */
+       ff_len = pad_len - algo->der_len - 3;
+       ret |= *msg ^ 0xff;
+       ret |= memcmp(msg, msg+1, ff_len-1);
+       msg += ff_len;
+       /* next byte must be 0x00 */
+       ret |= *msg++;
+       /* next der_len bytes must match der_prefix */
+       ret |= memcmp(msg, algo->der_prefix, algo->der_len);
+
+       return ret;
+}
+
 /**
  * rsa_verify_key() - Verify a signature against some data using RSA Key
  *
  * @sig:       Signature
  * @sig_len:   Number of bytes in signature
  * @hash:      Pointer to the expected hash
- * @algo:      Checksum algo structure having information on RSA padding etc.
+ * @key_len:   Number of bytes in rsa key
+ * @algo:      Checksum algo structure having information on DER encoding etc.
  * @return 0 if verified, -ve on error
  */
 static int rsa_verify_key(struct key_prop *prop, const uint8_t *sig,
                          const uint32_t sig_len, const uint8_t *hash,
-                         struct checksum_algo *algo)
+                         const uint32_t key_len, struct checksum_algo *algo)
 {
-       const uint8_t *padding;
        int pad_len;
        int ret;
+#if !defined(USE_HOSTCC)
+       struct udevice *mod_exp_dev;
+#endif
 
        if (!prop || !sig || !hash || !algo)
                return -EIO;
@@ -63,17 +100,27 @@ static int rsa_verify_key(struct key_prop *prop, const uint8_t *sig,
 
        uint8_t buf[sig_len];
 
+#if !defined(USE_HOSTCC)
+       ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev);
+       if (ret) {
+               printf("RSA: Can't find Modular Exp implementation\n");
+               return -EINVAL;
+       }
+
+       ret = rsa_mod_exp(mod_exp_dev, sig, sig_len, prop, buf);
+#else
        ret = rsa_mod_exp_sw(sig, sig_len, prop, buf);
+#endif
        if (ret) {
                debug("Error in Modular exponentation\n");
                return ret;
        }
 
-       padding = algo->rsa_padding;
-       pad_len = algo->pad_len - algo->checksum_len;
+       pad_len = key_len - algo->checksum_len;
 
        /* Check pkcs1.5 padding bytes. */
-       if (memcmp(buf, padding, pad_len)) {
+       ret = rsa_verify_padding(buf, pad_len, algo);
+       if (ret) {
                debug("In RSAVerify(): Padding check failed!\n");
                return -EINVAL;
        }
@@ -135,7 +182,8 @@ static int rsa_verify_with_keynode(struct image_sign_info *info,
                return -EFAULT;
        }
 
-       ret = rsa_verify_key(&prop, sig, sig_len, hash, info->algo->checksum);
+       ret = rsa_verify_key(&prop, sig, sig_len, hash,
+                            info->crypto->key_len, info->checksum);
 
        return ret;
 }
@@ -146,7 +194,7 @@ int rsa_verify(struct image_sign_info *info,
 {
        const void *blob = info->fdt_blob;
        /* Reserve memory for maximum checksum-length */
-       uint8_t hash[info->algo->checksum->pad_len];
+       uint8_t hash[info->crypto->key_len];
        int ndepth, noffset;
        int sig_node, node;
        char name[100];
@@ -156,10 +204,10 @@ int rsa_verify(struct image_sign_info *info,
         * Verify that the checksum-length does not exceed the
         * rsa-signature-length
         */
-       if (info->algo->checksum->checksum_len >
-           info->algo->checksum->pad_len) {
+       if (info->checksum->checksum_len >
+           info->crypto->key_len) {
                debug("%s: invlaid checksum-algorithm %s for %s\n",
-                     __func__, info->algo->checksum->name, info->algo->name);
+                     __func__, info->checksum->name, info->crypto->name);
                return -EINVAL;
        }
 
@@ -170,7 +218,12 @@ int rsa_verify(struct image_sign_info *info,
        }
 
        /* Calculate checksum with checksum-algorithm */
-       info->algo->checksum->calculate(region, region_count, hash);
+       ret = info->checksum->calculate(info->checksum->name,
+                                       region, region_count, hash);
+       if (ret < 0) {
+               debug("%s: Error in checksum calculation\n", __func__);
+               return -EINVAL;
+       }
 
        /* See if we must use a particular key */
        if (info->required_keynode != -1) {