[U-Boot] [PATCH 1/9] [v4] rsa: Split the rsa-verify to separate the modular exponentiation

Simon Glass sjg at chromium.org
Fri Jan 2 23:24:11 CET 2015


Hi Ruchika,

On 30 December 2014 at 02:30, Ruchika Gupta <ruchika.gupta at freescale.com> wrote:
> Public exponentiation which is required in rsa verify functionality is
> tightly integrated with verification code in rsa_verify.c. The patch
> splits the file into twp separating the modular exponentiation.
>
> 1. rsa-verify.c
> - The file parses device tree keys node to fill a keyprop structure.
> The keyprop structure can then be converted to implementation specific
> format.
> (struct rsa_pub_key for sw implementation)
> - The parsed device tree node is then passed to a generic rsa_mod_exp
> function.
>
> 2. rsa-mod-exp.c
> Move the software specific functions related to modular exponentiation
> from rsa-verify.c to this file.
>
> Signed-off-by: Ruchika Gupta <ruchika.gupta at freescale.com>
> CC: Simon Glass <sjg at chromium.org>
> ---
> Changes in v4:
> Modified rsa_mod_exp_sw function to add pointer to output length
>
> Changes in v3:
> Kconfig moved to separate patch. This patch just splits the file now
>
> Changes in v2:
> Addressed few of Simon Glass's comments:
> - Kconfig option added for RSA
> - Comments added for new keyprop struct
>
>  include/u-boot/rsa-mod-exp.h |  49 +++++++
>  lib/rsa/Makefile             |   2 +-
>  lib/rsa/rsa-mod-exp.c        | 309 ++++++++++++++++++++++++++++++++++++++
>  lib/rsa/rsa-verify.c         | 343 +++++++++----------------------------------
>  tools/Makefile               |   3 +-
>  5 files changed, 429 insertions(+), 277 deletions(-)
>  create mode 100644 include/u-boot/rsa-mod-exp.h
>  create mode 100644 lib/rsa/rsa-mod-exp.c
>
> diff --git a/include/u-boot/rsa-mod-exp.h b/include/u-boot/rsa-mod-exp.h
> new file mode 100644
> index 0000000..7b74f3c
> --- /dev/null
> +++ b/include/u-boot/rsa-mod-exp.h
> @@ -0,0 +1,49 @@
> +/*
> + * Copyright (c) 2014, Ruchika Gupta.
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> +*/
> +
> +#ifndef _RSA_MOD_EXP_H
> +#define _RSA_MOD_EXP_H
> +
> +#include <errno.h>
> +#include <image.h>
> +
> +/**
> + * struct key_prop - holder for a public key properties
> + *
> + * The struct has pointers to modulus (Typically called N),
> + * The inverse, R^2, exponent. These can be typecasted and
> + * used as byte arrays or converted to the required format
> + * as per requirement of RSA implementation.
> + */
> +struct key_prop {
> +       const void *rr;         /* R^2 can be treated as byte array */
> +       const void *modulus;    /* modulus as byte array */
> +       const void *public_exponent; /* public exponent as byte array */
> +       uint32_t n0inv;         /* -1 / modulus[0] mod 2^32 */
> +       int num_bits;           /* Key length in bits */
> +       uint32_t exp_len;       /* Exponent length in number of uint8_t */
> +};
> +
> +/**
> + * rsa_mod_exp_sw() - Perform RSA Modular Exponentiation in sw
> + *
> + * Operation: result[] = sig ^ exponent % modulus
> + *
> + * @sig:       RSA PKCS1.5 signature
> + * @sig_len:   Length of signature in number of bytes
> + * @node:      Node with RSA key elements like modulus, exponent, R^2, n0inv
> + * @outp:      Set to an allocated buffer holding the output hash
> + * @out_len:   Set to length of hash(outp) calculated after exponentiation
> + *
> + * This computes exponentiation over the signature. Resulting hash value is
> + * placed in an allocated buffer, the pointer is returned as *outp. The
> + * length of calulated hash is returned via the out_len pointer argument. The
> + * caller should free *outp
> + */
> +int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len,
> +               struct key_prop *node, uint8_t **outp, uint32_t *out_len);
> +
> +#endif
> diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile
> index a5a96cb6..cc25b3c 100644
> --- a/lib/rsa/Makefile
> +++ b/lib/rsa/Makefile
> @@ -7,4 +7,4 @@
>  # SPDX-License-Identifier:     GPL-2.0+
>  #
>
> -obj-$(CONFIG_FIT_SIGNATURE) += rsa-verify.o rsa-checksum.o
> +obj-$(CONFIG_FIT_SIGNATURE) += rsa-verify.o rsa-checksum.o rsa-mod-exp.o
> diff --git a/lib/rsa/rsa-mod-exp.c b/lib/rsa/rsa-mod-exp.c
> new file mode 100644
> index 0000000..af01b74
> --- /dev/null
> +++ b/lib/rsa/rsa-mod-exp.c
> @@ -0,0 +1,309 @@
> +/*
> + * Copyright (c) 2013, Google Inc.
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#ifndef USE_HOSTCC
> +#include <common.h>
> +#include <fdtdec.h>
> +#include <asm/types.h>
> +#include <asm/byteorder.h>
> +#include <asm/errno.h>
> +#include <asm/types.h>
> +#include <asm/unaligned.h>
> +#else
> +#include "fdt_host.h"
> +#include "mkimage.h"
> +#include <fdt_support.h>
> +#endif
> +#include <malloc.h>
> +#include <u-boot/rsa.h>
> +#include <u-boot/rsa-mod-exp.h>
> +
> +#define UINT64_MULT32(v, multby)  (((uint64_t)(v)) * ((uint32_t)(multby)))
> +
> +#define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a)
> +#define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a))
> +
> +/* Default public exponent for backward compatibility */
> +#define RSA_DEFAULT_PUBEXP     65537
> +
> +/**
> + * subtract_modulus() - subtract modulus from the given value
> + *
> + * @key:       Key containing modulus to subtract
> + * @num:       Number to subtract modulus from, as little endian word array
> + */
> +static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[])
> +{
> +       int64_t acc = 0;
> +       uint i;
> +
> +       for (i = 0; i < key->len; i++) {
> +               acc += (uint64_t)num[i] - key->modulus[i];
> +               num[i] = (uint32_t)acc;
> +               acc >>= 32;
> +       }
> +}
> +
> +/**
> + * greater_equal_modulus() - check if a value is >= modulus
> + *
> + * @key:       Key containing modulus to check
> + * @num:       Number to check against modulus, as little endian word array
> + * @return 0 if num < modulus, 1 if num >= modulus
> + */
> +static int greater_equal_modulus(const struct rsa_public_key *key,
> +                                uint32_t num[])
> +{
> +       int i;
> +
> +       for (i = (int)key->len - 1; i >= 0; i--) {
> +               if (num[i] < key->modulus[i])
> +                       return 0;
> +               if (num[i] > key->modulus[i])
> +                       return 1;
> +       }
> +
> +       return 1;  /* equal */
> +}
> +
> +/**
> + * montgomery_mul_add_step() - Perform montgomery multiply-add step
> + *
> + * Operation: montgomery result[] += a * b[] / n0inv % modulus
> + *
> + * @key:       RSA key
> + * @result:    Place to put result, as little endian word array
> + * @a:         Multiplier
> + * @b:         Multiplicand, as little endian word array
> + */
> +static void montgomery_mul_add_step(const struct rsa_public_key *key,
> +               uint32_t result[], const uint32_t a, const uint32_t b[])
> +{
> +       uint64_t acc_a, acc_b;
> +       uint32_t d0;
> +       uint i;
> +
> +       acc_a = (uint64_t)a * b[0] + result[0];
> +       d0 = (uint32_t)acc_a * key->n0inv;
> +       acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a;
> +       for (i = 1; i < key->len; i++) {
> +               acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i];
> +               acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] +
> +                               (uint32_t)acc_a;
> +               result[i - 1] = (uint32_t)acc_b;
> +       }
> +
> +       acc_a = (acc_a >> 32) + (acc_b >> 32);
> +
> +       result[i - 1] = (uint32_t)acc_a;
> +
> +       if (acc_a >> 32)
> +               subtract_modulus(key, result);
> +}
> +
> +/**
> + * montgomery_mul() - Perform montgomery mutitply
> + *
> + * Operation: montgomery result[] = a[] * b[] / n0inv % modulus
> + *
> + * @key:       RSA key
> + * @result:    Place to put result, as little endian word array
> + * @a:         Multiplier, as little endian word array
> + * @b:         Multiplicand, as little endian word array
> + */
> +static void montgomery_mul(const struct rsa_public_key *key,
> +               uint32_t result[], uint32_t a[], const uint32_t b[])
> +{
> +       uint i;
> +
> +       for (i = 0; i < key->len; ++i)
> +               result[i] = 0;
> +       for (i = 0; i < key->len; ++i)
> +               montgomery_mul_add_step(key, result, a[i], b);
> +}
> +
> +/**
> + * num_pub_exponent_bits() - Number of bits in the public exponent
> + *
> + * @key:       RSA key
> + * @num_bits:  Storage for the number of public exponent bits
> + */
> +static int num_public_exponent_bits(const struct rsa_public_key *key,
> +               int *num_bits)
> +{
> +       uint64_t exponent;
> +       int exponent_bits;
> +       const uint max_bits = (sizeof(exponent) * 8);
> +
> +       exponent = key->exponent;
> +       exponent_bits = 0;
> +
> +       if (!exponent) {
> +               *num_bits = exponent_bits;
> +               return 0;
> +       }
> +
> +       for (exponent_bits = 1; exponent_bits < max_bits + 1; ++exponent_bits)
> +               if (!(exponent >>= 1)) {
> +                       *num_bits = exponent_bits;
> +                       return 0;
> +               }
> +
> +       return -EINVAL;
> +}
> +
> +/**
> + * is_public_exponent_bit_set() - Check if a bit in the public exponent is set
> + *
> + * @key:       RSA key
> + * @pos:       The bit position to check
> + */
> +static int is_public_exponent_bit_set(const struct rsa_public_key *key,
> +               int pos)
> +{
> +       return key->exponent & (1ULL << pos);
> +}
> +
> +/**
> + * pow_mod() - in-place public exponentiation
> + *
> + * @key:       RSA key
> + * @inout:     Big-endian word array containing value and result
> + */
> +static int pow_mod(const struct rsa_public_key *key, uint32_t *inout)
> +{
> +       uint32_t *result, *ptr;
> +       uint i;
> +       int j, k;
> +
> +       /* Sanity check for stack size - key->len is in 32-bit words */
> +       if (key->len > RSA_MAX_KEY_BITS / 32) {
> +               debug("RSA key words %u exceeds maximum %d\n", key->len,
> +                     RSA_MAX_KEY_BITS / 32);
> +               return -EINVAL;
> +       }
> +
> +       uint32_t val[key->len], acc[key->len], tmp[key->len];
> +       uint32_t a_scaled[key->len];
> +       result = tmp;  /* Re-use location. */
> +
> +       /* Convert from big endian byte array to little endian word array. */
> +       for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--)
> +               val[i] = get_unaligned_be32(ptr);
> +
> +       if (0 != num_public_exponent_bits(key, &k))
> +               return -EINVAL;
> +
> +       if (k < 2) {
> +               debug("Public exponent is too short (%d bits, minimum 2)\n",
> +                     k);
> +               return -EINVAL;
> +       }
> +
> +       if (!is_public_exponent_bit_set(key, 0)) {
> +               debug("LSB of RSA public exponent must be set.\n");
> +               return -EINVAL;
> +       }
> +
> +       /* the bit at e[k-1] is 1 by definition, so start with: C := M */
> +       montgomery_mul(key, acc, val, key->rr); /* acc = a * RR / R mod n */
> +       /* retain scaled version for intermediate use */
> +       memcpy(a_scaled, acc, key->len * sizeof(a_scaled[0]));
> +
> +       for (j = k - 2; j > 0; --j) {
> +               montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
> +
> +               if (is_public_exponent_bit_set(key, j)) {
> +                       /* acc = tmp * val / R mod n */
> +                       montgomery_mul(key, acc, tmp, a_scaled);
> +               } else {
> +                       /* e[j] == 0, copy tmp back to acc for next operation */
> +                       memcpy(acc, tmp, key->len * sizeof(acc[0]));
> +               }
> +       }
> +
> +       /* the bit at e[0] is always 1 */
> +       montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
> +       montgomery_mul(key, acc, tmp, val); /* acc = tmp * a / R mod M */
> +       memcpy(result, acc, key->len * sizeof(result[0]));
> +
> +       /* Make sure result < mod; result is at most 1x mod too large. */
> +       if (greater_equal_modulus(key, result))
> +               subtract_modulus(key, result);
> +
> +       /* Convert to bigendian byte array */
> +       for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++)
> +               put_unaligned_be32(result[i], ptr);
> +       return 0;
> +}
> +
> +static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
> +{
> +       int i;
> +
> +       for (i = 0; i < len; i++)
> +               dst[i] = fdt32_to_cpu(src[len - 1 - i]);
> +}
> +
> +int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len,
> +               struct key_prop *prop, uint8_t **out, uint32_t *len)
> +{
> +       struct rsa_public_key key;
> +       int ret;
> +
> +       if (!prop) {
> +               debug("%s: Skipping invalid prop", __func__);
> +               return -EBADF;
> +       }
> +       if (!prop->n0inv) {

Sorry I did not notice this in v3, but you should remove this check.
This is a value, not a pointer.

> +               debug("%s: Missing rsa,n0-inverse", __func__);
> +               return -EFAULT;
> +       }
> +       key.n0inv = prop->n0inv;
> +       key.len = prop->num_bits;
> +
> +       if (!prop->public_exponent)
> +               key.exponent = RSA_DEFAULT_PUBEXP;
> +       else
> +               key.exponent =
> +                       fdt64_to_cpu(*((uint64_t *)(prop->public_exponent)));
> +
> +       if (!key.len || !prop->modulus || !prop->rr) {
> +               debug("%s: Missing RSA key info", __func__);
> +               return -EFAULT;
> +       }
> +
> +       /* Sanity check for stack size */
> +       if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) {
> +               debug("RSA key bits %u outside allowed range %d..%d\n",
> +                     key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
> +               return -EFAULT;
> +       }
> +       key.len /= sizeof(uint32_t) * 8;
> +       uint32_t key1[key.len], key2[key.len];
> +
> +       key.modulus = key1;
> +       key.rr = key2;
> +       rsa_convert_big_endian(key.modulus, (uint32_t *)prop->modulus, key.len);
> +       rsa_convert_big_endian(key.rr, (uint32_t *)prop->rr, key.len);
> +       if (!key.modulus || !key.rr) {
> +               debug("%s: Out of memory", __func__);
> +               return -ENOMEM;
> +       }
> +
> +       uint32_t *buf = malloc(sig_len);

Can you declare buf at the top of the function?

Also you need

if (!buf)
   return -ENOMEM;

> +
> +       memcpy(buf, sig, sig_len);
> +
> +       ret = pow_mod(&key, buf);
> +       if (ret)
> +               return ret;
> +
> +       *out = (uint8_t *)buf;
> +       *len = sig_len;

If len is the same as sig_len, why do you need this extra parameter? I
wonder if I put you wrong somewhere? If sig_len is passed in, there is
no need for rsa_mod_exp_sw() to malloc() space - the caller may as
well just supply the buffer as now.

> +
> +       return 0;
> +}
> diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
> index 4ef19b6..1d2e707 100644
> --- a/lib/rsa/rsa-verify.c
> +++ b/lib/rsa/rsa-verify.c
> @@ -17,230 +17,27 @@
>  #include "mkimage.h"
>  #include <fdt_support.h>
>  #endif
> +#include <malloc.h>
> +#include <u-boot/rsa-mod-exp.h>
>  #include <u-boot/rsa.h>
> -#include <u-boot/sha1.h>
> -#include <u-boot/sha256.h>
> -
> -#define UINT64_MULT32(v, multby)  (((uint64_t)(v)) * ((uint32_t)(multby)))
> -
> -#define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a)
> -#define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a))
>
>  /* Default public exponent for backward compatibility */
>  #define RSA_DEFAULT_PUBEXP     65537
>
>  /**
> - * subtract_modulus() - subtract modulus from the given value
> + * rsa_verify_key() - Verify a signature against some data using RSA Key
>   *
> - * @key:       Key containing modulus to subtract
> - * @num:       Number to subtract modulus from, as little endian word array
> - */
> -static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[])
> -{
> -       int64_t acc = 0;
> -       uint i;
> -
> -       for (i = 0; i < key->len; i++) {
> -               acc += (uint64_t)num[i] - key->modulus[i];
> -               num[i] = (uint32_t)acc;
> -               acc >>= 32;
> -       }
> -}
> -
> -/**
> - * greater_equal_modulus() - check if a value is >= modulus
> + * Verify a RSA PKCS1.5 signature against an expected hash using
> + * the RSA Key properties in prop structure.
>   *
> - * @key:       Key containing modulus to check
> - * @num:       Number to check against modulus, as little endian word array
> - * @return 0 if num < modulus, 1 if num >= modulus
> + * @prop:      Specifies 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.
> + * @return 0 if verified, -ve on error
>   */
> -static int greater_equal_modulus(const struct rsa_public_key *key,
> -                                uint32_t num[])
> -{
> -       int i;
> -
> -       for (i = (int)key->len - 1; i >= 0; i--) {
> -               if (num[i] < key->modulus[i])
> -                       return 0;
> -               if (num[i] > key->modulus[i])
> -                       return 1;
> -       }
> -
> -       return 1;  /* equal */
> -}
> -
> -/**
> - * montgomery_mul_add_step() - Perform montgomery multiply-add step
> - *
> - * Operation: montgomery result[] += a * b[] / n0inv % modulus
> - *
> - * @key:       RSA key
> - * @result:    Place to put result, as little endian word array
> - * @a:         Multiplier
> - * @b:         Multiplicand, as little endian word array
> - */
> -static void montgomery_mul_add_step(const struct rsa_public_key *key,
> -               uint32_t result[], const uint32_t a, const uint32_t b[])
> -{
> -       uint64_t acc_a, acc_b;
> -       uint32_t d0;
> -       uint i;
> -
> -       acc_a = (uint64_t)a * b[0] + result[0];
> -       d0 = (uint32_t)acc_a * key->n0inv;
> -       acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a;
> -       for (i = 1; i < key->len; i++) {
> -               acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i];
> -               acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] +
> -                               (uint32_t)acc_a;
> -               result[i - 1] = (uint32_t)acc_b;
> -       }
> -
> -       acc_a = (acc_a >> 32) + (acc_b >> 32);
> -
> -       result[i - 1] = (uint32_t)acc_a;
> -
> -       if (acc_a >> 32)
> -               subtract_modulus(key, result);
> -}
> -
> -/**
> - * montgomery_mul() - Perform montgomery mutitply
> - *
> - * Operation: montgomery result[] = a[] * b[] / n0inv % modulus
> - *
> - * @key:       RSA key
> - * @result:    Place to put result, as little endian word array
> - * @a:         Multiplier, as little endian word array
> - * @b:         Multiplicand, as little endian word array
> - */
> -static void montgomery_mul(const struct rsa_public_key *key,
> -               uint32_t result[], uint32_t a[], const uint32_t b[])
> -{
> -       uint i;
> -
> -       for (i = 0; i < key->len; ++i)
> -               result[i] = 0;
> -       for (i = 0; i < key->len; ++i)
> -               montgomery_mul_add_step(key, result, a[i], b);
> -}
> -
> -/**
> - * num_pub_exponent_bits() - Number of bits in the public exponent
> - *
> - * @key:       RSA key
> - * @num_bits:  Storage for the number of public exponent bits
> - */
> -static int num_public_exponent_bits(const struct rsa_public_key *key,
> -               int *num_bits)
> -{
> -       uint64_t exponent;
> -       int exponent_bits;
> -       const uint max_bits = (sizeof(exponent) * 8);
> -
> -       exponent = key->exponent;
> -       exponent_bits = 0;
> -
> -       if (!exponent) {
> -               *num_bits = exponent_bits;
> -               return 0;
> -       }
> -
> -       for (exponent_bits = 1; exponent_bits < max_bits + 1; ++exponent_bits)
> -               if (!(exponent >>= 1)) {
> -                       *num_bits = exponent_bits;
> -                       return 0;
> -               }
> -
> -       return -EINVAL;
> -}
> -
> -/**
> - * is_public_exponent_bit_set() - Check if a bit in the public exponent is set
> - *
> - * @key:       RSA key
> - * @pos:       The bit position to check
> - */
> -static int is_public_exponent_bit_set(const struct rsa_public_key *key,
> -               int pos)
> -{
> -       return key->exponent & (1ULL << pos);
> -}
> -
> -/**
> - * pow_mod() - in-place public exponentiation
> - *
> - * @key:       RSA key
> - * @inout:     Big-endian word array containing value and result
> - */
> -static int pow_mod(const struct rsa_public_key *key, uint32_t *inout)
> -{
> -       uint32_t *result, *ptr;
> -       uint i;
> -       int j, k;
> -
> -       /* Sanity check for stack size - key->len is in 32-bit words */
> -       if (key->len > RSA_MAX_KEY_BITS / 32) {
> -               debug("RSA key words %u exceeds maximum %d\n", key->len,
> -                     RSA_MAX_KEY_BITS / 32);
> -               return -EINVAL;
> -       }
> -
> -       uint32_t val[key->len], acc[key->len], tmp[key->len];
> -       uint32_t a_scaled[key->len];
> -       result = tmp;  /* Re-use location. */
> -
> -       /* Convert from big endian byte array to little endian word array. */
> -       for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--)
> -               val[i] = get_unaligned_be32(ptr);
> -
> -       if (0 != num_public_exponent_bits(key, &k))
> -               return -EINVAL;
> -
> -       if (k < 2) {
> -               debug("Public exponent is too short (%d bits, minimum 2)\n",
> -                     k);
> -               return -EINVAL;
> -       }
> -
> -       if (!is_public_exponent_bit_set(key, 0)) {
> -               debug("LSB of RSA public exponent must be set.\n");
> -               return -EINVAL;
> -       }
> -
> -       /* the bit at e[k-1] is 1 by definition, so start with: C := M */
> -       montgomery_mul(key, acc, val, key->rr); /* acc = a * RR / R mod n */
> -       /* retain scaled version for intermediate use */
> -       memcpy(a_scaled, acc, key->len * sizeof(a_scaled[0]));
> -
> -       for (j = k - 2; j > 0; --j) {
> -               montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
> -
> -               if (is_public_exponent_bit_set(key, j)) {
> -                       /* acc = tmp * val / R mod n */
> -                       montgomery_mul(key, acc, tmp, a_scaled);
> -               } else {
> -                       /* e[j] == 0, copy tmp back to acc for next operation */
> -                       memcpy(acc, tmp, key->len * sizeof(acc[0]));
> -               }
> -       }
> -
> -       /* the bit at e[0] is always 1 */
> -       montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
> -       montgomery_mul(key, acc, tmp, val); /* acc = tmp * a / R mod M */
> -       memcpy(result, acc, key->len * sizeof(result[0]));
> -
> -       /* Make sure result < mod; result is at most 1x mod too large. */
> -       if (greater_equal_modulus(key, result))
> -               subtract_modulus(key, result);
> -
> -       /* Convert to bigendian byte array */
> -       for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++)
> -               put_unaligned_be32(result[i], ptr);
> -       return 0;
> -}
> -
> -static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig,
> +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)
>  {
> @@ -248,10 +45,10 @@ static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig,
>         int pad_len;
>         int ret;
>
> -       if (!key || !sig || !hash || !algo)
> +       if (!prop || !sig || !hash || !algo)
>                 return -EIO;
>
> -       if (sig_len != (key->len * sizeof(uint32_t))) {
> +       if (sig_len != (prop->num_bits / 8)) {
>                 debug("Signature is of incorrect length %d\n", sig_len);
>                 return -EINVAL;
>         }
> @@ -265,13 +62,20 @@ static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig,
>                 return -EINVAL;
>         }
>
> -       uint32_t buf[sig_len / sizeof(uint32_t)];
> +       uint8_t *buf;
> +       uint32_t buf_len;

Again please put declarations at the top. As per above comment perhaps
you can revert this chunk anyway. (and the next two)

>
> -       memcpy(buf, sig, sig_len);
> -
> -       ret = pow_mod(key, buf);
> -       if (ret)
> +       ret = rsa_mod_exp_sw(sig, sig_len, prop, &buf, &buf_len);
> +       if (ret) {
> +               debug("Error in Modular exponentation\n");
>                 return ret;
> +       }
> +
> +       if (buf_len != sig_len) {
> +               debug("In RSAVerify(): hash length not same as sig len\n");
> +               free(buf);
> +               return -EINVAL;
> +       }

This check doesn't achieve anything really. If ret == 0, then buf_len
== sig_len.

>
>         padding = algo->rsa_padding;
>         pad_len = algo->pad_len - algo->checksum_len;
> @@ -279,84 +83,73 @@ static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig,
>         /* Check pkcs1.5 padding bytes. */
>         if (memcmp(buf, padding, pad_len)) {
>                 debug("In RSAVerify(): Padding check failed!\n");
> +               free(buf);
>                 return -EINVAL;
>         }
>
>         /* Check hash. */
> -       if (memcmp((uint8_t *)buf + pad_len, hash, sig_len - pad_len)) {
> +       if (memcmp(buf + pad_len, hash, sig_len - pad_len)) {
>                 debug("In RSAVerify(): Hash check failed!\n");
> +               free(buf);
>                 return -EACCES;
>         }
>
> -       return 0;
> -}
> -
> -static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
> -{
> -       int i;
> +       free(buf);
>
> -       for (i = 0; i < len; i++)
> -               dst[i] = fdt32_to_cpu(src[len - 1 - i]);
> +       return 0;
>  }
>
> +/**
> + * rsa_verify_with_keynode() - Verify a signature against some data using
> + * information in node with prperties of RSA Key like modulus, exponent etc.
> + *
> + * Parse sign-node and fill a key_prop structure with properties of the
> + * key.  Verify a RSA PKCS1.5 signature against an expected hash using
> + * the properties parsed
> + *
> + * @info:      Specifies key and FIT information
> + * @hash:      Pointer to the expected hash
> + * @sig:       Signature
> + * @sig_len:   Number of bytes in signature
> + * @node:      Node having the RSA Key properties
> + * @return 0 if verified, -ve on error
> + */
>  static int rsa_verify_with_keynode(struct image_sign_info *info,
> -               const void *hash, uint8_t *sig, uint sig_len, int node)
> +                                  const void *hash, uint8_t *sig,
> +                                  uint sig_len, int node)
>  {
>         const void *blob = info->fdt_blob;
> -       struct rsa_public_key key;
> -       const void *modulus, *rr;
> -       const uint64_t *public_exponent;
> +       struct key_prop prop;
>         int length;
> -       int ret;
> +       int ret = 0;
>
>         if (node < 0) {
>                 debug("%s: Skipping invalid node", __func__);
>                 return -EBADF;
>         }
> -       if (!fdt_getprop(blob, node, "rsa,n0-inverse", NULL)) {
> -               debug("%s: Missing rsa,n0-inverse", __func__);
> -               return -EFAULT;
> -       }
> -       key.len = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
> -       key.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
> -       public_exponent = fdt_getprop(blob, node, "rsa,exponent", &length);
> -       if (!public_exponent || length < sizeof(*public_exponent))
> -               key.exponent = RSA_DEFAULT_PUBEXP;
> -       else
> -               key.exponent = fdt64_to_cpu(*public_exponent);
> -       modulus = fdt_getprop(blob, node, "rsa,modulus", NULL);
> -       rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
> -       if (!key.len || !modulus || !rr) {
> -               debug("%s: Missing RSA key info", __func__);
> -               return -EFAULT;
> -       }
>
> -       /* Sanity check for stack size */
> -       if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) {
> -               debug("RSA key bits %u outside allowed range %d..%d\n",
> -                     key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
> +       prop.num_bits = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
> +
> +       prop.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
> +
> +       prop.public_exponent = fdt_getprop(blob, node, "rsa,exponent", &length);
> +       if (!prop.public_exponent || length < sizeof(uint64_t))
> +               prop.public_exponent = NULL;
> +
> +       prop.exp_len = sizeof(uint64_t);
> +
> +       prop.modulus = fdt_getprop(blob, node, "rsa,modulus", NULL);
> +
> +       prop.rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
> +
> +       if (!prop.num_bits || !prop.modulus) {
> +               debug("%s: Missing RSA key info", __func__);
>                 return -EFAULT;
>         }
> -       key.len /= sizeof(uint32_t) * 8;
> -       uint32_t key1[key.len], key2[key.len];
> -
> -       key.modulus = key1;
> -       key.rr = key2;
> -       rsa_convert_big_endian(key.modulus, modulus, key.len);
> -       rsa_convert_big_endian(key.rr, rr, key.len);
> -       if (!key.modulus || !key.rr) {
> -               debug("%s: Out of memory", __func__);
> -               return -ENOMEM;
> -       }
>
> -       debug("key length %d\n", key.len);
> -       ret = rsa_verify_key(&key, sig, sig_len, hash, info->algo->checksum);
> -       if (ret) {
> -               printf("%s: RSA failed to verify: %d\n", __func__, ret);
> -               return ret;
> -       }
> +       ret = rsa_verify_key(&prop, sig, sig_len, hash, info->algo->checksum);
>
> -       return 0;
> +       return ret;
>  }
>
>  int rsa_verify(struct image_sign_info *info,
> diff --git a/tools/Makefile b/tools/Makefile
> index a4216a1..0b981da 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -60,7 +60,8 @@ FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := common/image-sig.o
>  LIBFDT_OBJS := $(addprefix lib/libfdt/, \
>                         fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o)
>  RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \
> -                                       rsa-sign.o rsa-verify.o rsa-checksum.o)
> +                                       rsa-sign.o rsa-verify.o rsa-checksum.o \
> +                                       rsa-mod-exp.o)
>
>  # common objs for dumpimage and mkimage
>  dumpimage-mkimage-objs := aisimage.o \
> --
> 1.8.1.4
>

Regards,
Simon


More information about the U-Boot mailing list