[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