[U-Boot] [PATCH 0/4] [RFC] rsa: Modify rsa lib to use hw acceleration

The rsa-verify functionality is a two step operation involving: 1. Checksum (hash) Calculation over image regions 2. Public Key Modular exponentiation over signature to generate hash
The following patch set modifies the rsa library to use hw acceleration if available in platform.
The first two patches in the series, split the rsa-verify lib into two files: 1. rsa-verify.c - The file parses device tree keys node to fill a keyprop structure. The key prop structure can then be converted to implementation specific formal (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 exponentiation from rsa-verify.c to this file. The file is compiled if "CONFIG_RSA_MOD_EXP_SW" is defined. In general if both CONFIG_FIT_SIGNATURE and CONFIG_RSA are defined, CONFIG_RSA_MOD_EXP_SW gets automatically defined.
Platforms having hardware implementation for rsa_mod_exp can add a define "CONFIG_RSA_MOD_EXP_HW" to their config files. Adding this defined, undefs the CONFIG_RSA_MOD_EXP_SW and hardware implementation of mod_exp gets compiled.
Another option is to add a node in struct "image_sig_algos" in image-sig.c as done in common/sha.c.
#ifdef CONFIG_RSA_HW { "sha1,rsa2048", #ifdef HOST_CC rsa_sign, rsa_add_verify_data, #else NULL, NULL, #endif rsa_verify_hw, &checksum_algos[0], }, #endif.
However the code related with parsing of devicetree for key properties, calculation of hash and comparison of passed hash with signature derived hash would need to be duplicated in the rsa_verify_hw function.
The next set of two patches are related with hash lib support in RSA.
For hash, the infrastructure already exists in common/hash.c. rsa_checksum is modified to use the API's registered with the hash_algo structure. Once HW accelerated support for progressive hash is available, RSA library can easily pick it up.
Ruchika Gupta (4): rsa: Split the rsa-verify crypto/fsl: Add support for RSA Modular Exponentiation hash: Add function to find hash_algo struct with progressive hash rsa: Use checksum algorithms from struct hash_algo
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
common/hash.c | 35 +++-- drivers/crypto/fsl/Makefile | 1 + drivers/crypto/fsl/fsl_rsa.c | 44 ++++++ drivers/crypto/fsl/jobdesc.c | 28 ++++ drivers/crypto/fsl/jobdesc.h | 5 + drivers/crypto/fsl/rsa_caam.h | 27 ++++ include/config_fallbacks.h | 5 + include/hash.h | 15 ++ include/image.h | 2 +- include/u-boot/rsa-checksum.h | 4 +- include/u-boot/rsa-mod-exp.h | 25 ++++ lib/rsa/Makefile | 1 + lib/rsa/rsa-checksum.c | 61 ++++++++- lib/rsa/rsa-mod-exp.c | 308 ++++++++++++++++++++++++++++++++++++++++++ lib/rsa/rsa-verify.c | 307 ++++------------------------------------- tools/Makefile | 2 +- 16 files changed, 576 insertions(+), 294 deletions(-) create mode 100644 drivers/crypto/fsl/fsl_rsa.c create mode 100644 drivers/crypto/fsl/rsa_caam.h create mode 100644 include/u-boot/rsa-mod-exp.h create mode 100644 lib/rsa/rsa-mod-exp.c

Public exponentiation which is required in rsa verify functionality is currently tightly integrated with verification code in rsa_verify.c. Currently this implementation is software based. Some platforms having support of the exponentiation in hardware. To enable the rsa verify functionality to use the Modular exponentiation if present in hardware, the patch-set splits the file into two files:
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 formal (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 exponentiation from rsa-verify.c to this file. The file is compiled if "CONFIG_RSA_MOD_EXP_SW" is defined. In general if both CONFIG_FIT_SIGNATURE and CONFIG_RSA are defined, CONFIG_RSA_MOD_EXP_SW gets automatically defined.
Platforms having hardware implementation for rsa_mod_exp can add a define "CONFIG_RSA_MOD_EXP_HW" to their config files. Adding this defined, undefs the CONFIG_RSA_MOD_EXP_SW and hardware implementation of mod_exp gets compiled.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- include/config_fallbacks.h | 5 + include/u-boot/rsa-mod-exp.h | 25 ++++ lib/rsa/Makefile | 1 + lib/rsa/rsa-mod-exp.c | 308 +++++++++++++++++++++++++++++++++++++++++++ lib/rsa/rsa-verify.c | 307 +++++------------------------------------- tools/Makefile | 2 +- 6 files changed, 370 insertions(+), 278 deletions(-) create mode 100644 include/u-boot/rsa-mod-exp.h create mode 100644 lib/rsa/rsa-mod-exp.c
diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h index ddfe045..d4676b4 100644 --- a/include/config_fallbacks.h +++ b/include/config_fallbacks.h @@ -83,6 +83,11 @@ #define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + 128) #endif
+#if defined(CONFIG_FIT_SIGNATURE) && defined(CONFIG_RSA) && \ + !defined(CONFIG_RSA_MOD_EXP_HW) +#define CONFIG_RSA_MOD_EXP_SW +#endif + #ifndef CONFIG_FIT_SIGNATURE #define CONFIG_IMAGE_FORMAT_LEGACY #endif diff --git a/include/u-boot/rsa-mod-exp.h b/include/u-boot/rsa-mod-exp.h new file mode 100644 index 0000000..577f673 --- /dev/null +++ b/include/u-boot/rsa-mod-exp.h @@ -0,0 +1,25 @@ +/* + * 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 { + const void *rr; + const void *modulus; + const void *public_exponent; + uint32_t n0inv; + int num_bits; + uint32_t exp_len; +}; + +int rsa_mod_exp(const uint8_t *sig, uint32_t sig_len, + struct key_prop *node, uint8_t *out); + +#endif diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile index a5a96cb6..ccc6060 100644 --- a/lib/rsa/Makefile +++ b/lib/rsa/Makefile @@ -8,3 +8,4 @@ #
obj-$(CONFIG_FIT_SIGNATURE) += rsa-verify.o rsa-checksum.o +obj-$(CONFIG_RSA_MOD_EXP_SW) += 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..f69ae1b --- /dev/null +++ b/lib/rsa/rsa-mod-exp.c @@ -0,0 +1,308 @@ +/* + * 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 <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(const uint8_t *sig, uint32_t sig_len, + struct key_prop *prop, uint8_t *out) +{ + struct rsa_public_key key; + int ret; + + if (!prop) { + debug("%s: Skipping invalid prop", __func__); + return -EBADF; + } + if (!prop->n0inv) { + 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[sig_len / sizeof(uint32_t)]; + + memcpy(buf, sig, sig_len); + + ret = pow_mod(&key, buf); + if (ret) + return ret; + + memcpy(out, buf, sig_len); + + return 0; +} diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 4ef19b6..583400f 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -17,230 +17,13 @@ #include "mkimage.h" #include <fdt_support.h> #endif +#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 - * - * @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 int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig, +static int rsa_verify_key(struct key_prop *node, const uint8_t *sig, const uint32_t sig_len, const uint8_t *hash, struct checksum_algo *algo) { @@ -248,10 +31,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 (!node || !sig || !hash || !algo) return -EIO;
- if (sig_len != (key->len * sizeof(uint32_t))) { + if (sig_len != (node->num_bits / 8)) { debug("Signature is of incorrect length %d\n", sig_len); return -EINVAL; } @@ -265,13 +48,13 @@ 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)]; - - memcpy(buf, sig, sig_len); + uint8_t buf[sig_len];
- ret = pow_mod(key, buf); - if (ret) + ret = rsa_mod_exp(sig, sig_len, node, buf); + if (ret) { + debug("Error in Modular exponentation\n"); return ret; + }
padding = algo->rsa_padding; pad_len = algo->pad_len - algo->checksum_len; @@ -291,72 +74,42 @@ static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig, 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]); -} - 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;
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; - } + rsa_verify_key(&prop, sig, sig_len, hash, info->algo->checksum);
return 0; + }
int rsa_verify(struct image_sign_info *info, diff --git a/tools/Makefile b/tools/Makefile index a4216a1..f67cd15 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -60,7 +60,7 @@ 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 \

Hi Ruchika,
On 17 December 2014 at 03:05, Ruchika Gupta ruchika.gupta@freescale.com wrote:
Public exponentiation which is required in rsa verify functionality is currently tightly integrated with verification code in rsa_verify.c. Currently this implementation is software based. Some platforms having support of the exponentiation in hardware. To enable the rsa verify functionality to use the Modular exponentiation if present in hardware, the patch-set splits the file into two files:
- 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 formal (struct rsa_pub_key for sw implementation).
- The parsed device tree node is then passed to a generic
rsa_mod_exp function.
- rsa-mod-exp.c
Move the software specific functions related to exponentiation from rsa-verify.c to this file. The file is compiled if "CONFIG_RSA_MOD_EXP_SW" is defined. In general if both CONFIG_FIT_SIGNATURE and CONFIG_RSA are defined, CONFIG_RSA_MOD_EXP_SW gets automatically defined.
Platforms having hardware implementation for rsa_mod_exp can add a define "CONFIG_RSA_MOD_EXP_HW" to their config files. Adding this defined, undefs the CONFIG_RSA_MOD_EXP_SW and hardware implementation of mod_exp gets compiled.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
I'm going to mostly limit my comments to high level things for this RFC. It's a good idea.
Can you add a patch to move existing RSA CONFIGs to Kconfig, and then use Kconfig for your new options. Then I think your ...EXP_HW and ...EXP_SW become an choice:
1. Software RSA 2. Freescale xxx chip hardware RSA 3. Some other RSA implementation
With my driver model hat on, there really should be a uclass for an exponentiation implementation and an interface that these drivers implement. Since you already have an interface, that should be easy.
I'm not sure about the structures you mention above, but potentially you can have a the driver-specific structure and a uclass structure. The device tree would parse to the latter perhaps.
include/config_fallbacks.h | 5 + include/u-boot/rsa-mod-exp.h | 25 ++++ lib/rsa/Makefile | 1 + lib/rsa/rsa-mod-exp.c | 308 +++++++++++++++++++++++++++++++++++++++++++ lib/rsa/rsa-verify.c | 307 +++++------------------------------------- tools/Makefile | 2 +- 6 files changed, 370 insertions(+), 278 deletions(-) create mode 100644 include/u-boot/rsa-mod-exp.h create mode 100644 lib/rsa/rsa-mod-exp.c
diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h index ddfe045..d4676b4 100644 --- a/include/config_fallbacks.h +++ b/include/config_fallbacks.h @@ -83,6 +83,11 @@ #define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + 128) #endif
+#if defined(CONFIG_FIT_SIGNATURE) && defined(CONFIG_RSA) && \
!defined(CONFIG_RSA_MOD_EXP_HW)
+#define CONFIG_RSA_MOD_EXP_SW +#endif
As above you shouldn't need this
#ifndef CONFIG_FIT_SIGNATURE #define CONFIG_IMAGE_FORMAT_LEGACY #endif diff --git a/include/u-boot/rsa-mod-exp.h b/include/u-boot/rsa-mod-exp.h new file mode 100644 index 0000000..577f673 --- /dev/null +++ b/include/u-boot/rsa-mod-exp.h @@ -0,0 +1,25 @@ +/*
- 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>
Comments here
+struct key_prop {
const void *rr;
const void *modulus;
const void *public_exponent;
uint32_t n0inv;
int num_bits;
uint32_t exp_len;
+};
+int rsa_mod_exp(const uint8_t *sig, uint32_t sig_len,
struct key_prop *node, uint8_t *out);
+#endif diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile index a5a96cb6..ccc6060 100644 --- a/lib/rsa/Makefile +++ b/lib/rsa/Makefile @@ -8,3 +8,4 @@ #
obj-$(CONFIG_FIT_SIGNATURE) += rsa-verify.o rsa-checksum.o +obj-$(CONFIG_RSA_MOD_EXP_SW) += 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..f69ae1b --- /dev/null +++ b/lib/rsa/rsa-mod-exp.c @@ -0,0 +1,308 @@ +/*
- 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 <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;
}
+}
I'm not quite sure what is happening here, but can you please first move the code and then in a separate patch, change it. Maybe I am missing something here, sorry if so.
+/**
- 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(const uint8_t *sig, uint32_t sig_len,
struct key_prop *prop, uint8_t *out)
+{
struct rsa_public_key key;
int ret;
if (!prop) {
debug("%s: Skipping invalid prop", __func__);
return -EBADF;
}
if (!prop->n0inv) {
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[sig_len / sizeof(uint32_t)];
memcpy(buf, sig, sig_len);
ret = pow_mod(&key, buf);
if (ret)
return ret;
memcpy(out, buf, sig_len);
return 0;
+} diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 4ef19b6..583400f 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -17,230 +17,13 @@ #include "mkimage.h" #include <fdt_support.h> #endif +#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
- @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 int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig, +static int rsa_verify_key(struct key_prop *node, const uint8_t *sig, const uint32_t sig_len, const uint8_t *hash, struct checksum_algo *algo) { @@ -248,10 +31,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 (!node || !sig || !hash || !algo) return -EIO;
if (sig_len != (key->len * sizeof(uint32_t))) {
if (sig_len != (node->num_bits / 8)) { debug("Signature is of incorrect length %d\n", sig_len); return -EINVAL; }
@@ -265,13 +48,13 @@ 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)];
memcpy(buf, sig, sig_len);
uint8_t buf[sig_len];
ret = pow_mod(key, buf);
if (ret)
ret = rsa_mod_exp(sig, sig_len, node, buf);
if (ret) {
debug("Error in Modular exponentation\n"); return ret;
} padding = algo->rsa_padding; pad_len = algo->pad_len - algo->checksum_len;
@@ -291,72 +74,42 @@ static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig, 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]);
-}
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; 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;
}
rsa_verify_key(&prop, sig, sig_len, hash, info->algo->checksum); return 0;
}
int rsa_verify(struct image_sign_info *info, diff --git a/tools/Makefile b/tools/Makefile index a4216a1..f67cd15 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -60,7 +60,7 @@ 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

Support added for offloading Modular Exponentiation required in RSA Verify functionality to hardware which depends on CONFIG_RSA_MOD_EXP_HW.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- drivers/crypto/fsl/Makefile | 1 + drivers/crypto/fsl/fsl_rsa.c | 44 +++++++++++++++++++++++++++++++++++++++++++ drivers/crypto/fsl/jobdesc.c | 28 +++++++++++++++++++++++++++ drivers/crypto/fsl/jobdesc.h | 5 +++++ drivers/crypto/fsl/rsa_caam.h | 27 ++++++++++++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 drivers/crypto/fsl/fsl_rsa.c create mode 100644 drivers/crypto/fsl/rsa_caam.h
diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile index 067d0a9..ef36f67 100644 --- a/drivers/crypto/fsl/Makefile +++ b/drivers/crypto/fsl/Makefile @@ -8,4 +8,5 @@
obj-y += sec.o obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o +obj-$(CONFIG_RSA_MOD_EXP_HW) += fsl_rsa.o obj-$(CONFIG_CMD_BLOB) += fsl_blob.o diff --git a/drivers/crypto/fsl/fsl_rsa.c b/drivers/crypto/fsl/fsl_rsa.c new file mode 100644 index 0000000..1100316 --- /dev/null +++ b/drivers/crypto/fsl/fsl_rsa.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/types.h> +#include <malloc.h> +#include "jobdesc.h" +#include "desc.h" +#include "jr.h" +#include "rsa_caam.h" +#include <u-boot/rsa-mod-exp.h> + +int rsa_mod_exp(const uint8_t *sig, uint32_t sig_len, + struct key_prop *prop, uint8_t *out) +{ + uint32_t keylen; + struct pk_in_params pkin; + uint32_t desc[MAX_CAAM_DESCSIZE]; + int ret; + + /* Length in bytes */ + keylen = prop->num_bits / 8; + + pkin.a = sig; + pkin.a_siz = sig_len; + pkin.n = prop->modulus; + pkin.n_siz = keylen; + pkin.e = prop->public_exponent; + pkin.e_siz = prop->exp_len; + + inline_cnstr_jobdesc_pkha_rsaexp(desc, &pkin, out, sig_len); + + ret = run_descriptor_jr(desc); + + if (ret) { + debug("%s: RSA failed to verify: %d\n", __func__, ret); + return ret; + } + + return 0; +} diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c index 1386bae..cc0dced 100644 --- a/drivers/crypto/fsl/jobdesc.c +++ b/drivers/crypto/fsl/jobdesc.c @@ -11,6 +11,7 @@ #include <common.h> #include "desc_constr.h" #include "jobdesc.h" +#include "rsa_caam.h"
#define KEY_BLOB_SIZE 32 #define MAC_SIZE 16 @@ -123,3 +124,30 @@ void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc) append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | OP_ALG_RNG4_SK); } + +/* Change key size to bytes form bits in calling function*/ +void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc, + struct pk_in_params *pkin, uint8_t *out, + uint32_t out_siz) +{ + dma_addr_t dma_addr_e, dma_addr_a, dma_addr_n, dma_addr_out; + + dma_addr_e = virt_to_phys((void *)pkin->e); + dma_addr_a = virt_to_phys((void *)pkin->a); + dma_addr_n = virt_to_phys((void *)pkin->n); + dma_addr_out = virt_to_phys((void *)out); + + init_job_desc(desc, 0); + append_key(desc, dma_addr_e, pkin->e_siz, KEY_DEST_PKHA_E | CLASS_1); + + append_fifo_load(desc, dma_addr_a, + pkin->a_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_A); + + append_fifo_load(desc, dma_addr_n, + pkin->n_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_N); + + append_operation(desc, OP_TYPE_PK | OP_ALG_PK | OP_ALG_PKMODE_MOD_EXPO); + + append_fifo_store(desc, dma_addr_out, out_siz, + LDST_CLASS_1_CCB | FIFOST_TYPE_PKHA_B); +} diff --git a/drivers/crypto/fsl/jobdesc.h b/drivers/crypto/fsl/jobdesc.h index 3cf7226..84b3edd 100644 --- a/drivers/crypto/fsl/jobdesc.h +++ b/drivers/crypto/fsl/jobdesc.h @@ -10,6 +10,7 @@
#include <common.h> #include <asm/io.h> +#include "rsa_caam.h"
#define KEY_IDNFR_SZ_BYTES 16
@@ -26,4 +27,8 @@ void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr, uint32_t out_sz);
void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc); + +void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc, + struct pk_in_params *pkin, uint8_t *out, + uint32_t out_siz); #endif diff --git a/drivers/crypto/fsl/rsa_caam.h b/drivers/crypto/fsl/rsa_caam.h new file mode 100644 index 0000000..d1dc7eb --- /dev/null +++ b/drivers/crypto/fsl/rsa_caam.h @@ -0,0 +1,27 @@ +/* + * Copyright 2014 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __RSA_SEC_H +#define __RSA_SEC_H + +#include <common.h> + +/** + * struct pk_in_params - holder for input to PKHA block in CAAM + * + */ +struct pk_in_params { + const uint8_t *e; /* public exponent as byte array */ + uint32_t e_siz; /* size of e[] in number of bytes */ + const uint8_t *n; /* modulus as byte array */ + uint32_t n_siz; /* size of n[] in number of bytes */ + const uint8_t *a; /* Signature as byte array */ + uint32_t a_siz; /* size of a[] in number of bytes */ + uint8_t *b; /* Result exp. modulus in number of bytes */ + uint32_t b_siz; /* size of b[] in number of bytes */ +}; + +#endif

Hi Ruchika,
On 17 December 2014 at 03:05, Ruchika Gupta ruchika.gupta@freescale.com wrote:
Support added for offloading Modular Exponentiation required in RSA Verify functionality to hardware which depends on CONFIG_RSA_MOD_EXP_HW.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
drivers/crypto/fsl/Makefile | 1 + drivers/crypto/fsl/fsl_rsa.c | 44 +++++++++++++++++++++++++++++++++++++++++++ drivers/crypto/fsl/jobdesc.c | 28 +++++++++++++++++++++++++++ drivers/crypto/fsl/jobdesc.h | 5 +++++ drivers/crypto/fsl/rsa_caam.h | 27 ++++++++++++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 drivers/crypto/fsl/fsl_rsa.c create mode 100644 drivers/crypto/fsl/rsa_caam.h
I have no new comments on this patch apart from what I said on patch 1.
Regards, Simon

Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- common/hash.c | 35 ++++++++++++++++++++++++++--------- include/hash.h | 15 +++++++++++++++ 2 files changed, 41 insertions(+), 9 deletions(-)
diff --git a/common/hash.c b/common/hash.c index 12d6759..87263df 100644 --- a/common/hash.c +++ b/common/hash.c @@ -20,7 +20,7 @@ #include <asm/io.h> #include <asm/errno.h>
-#ifdef CONFIG_CMD_SHA1SUM +#ifdef CONFIG_SHA256 static int hash_init_sha1(struct hash_algo *algo, void **ctxp) { sha1_context *ctx = malloc(sizeof(sha1_context)); @@ -125,12 +125,8 @@ static struct hash_algo hash_algo[] = { CHUNKSZ_SHA256, }, #endif - /* - * This is CONFIG_CMD_SHA1SUM instead of CONFIG_SHA1 since otherwise - * it bloats the code for boards which use SHA1 but not the 'hash' - * or 'sha1sum' commands. - */ -#ifdef CONFIG_CMD_SHA1SUM + +#ifdef CONFIG_SHA1 { "sha1", SHA1_SUM_LEN, @@ -140,7 +136,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha1, hash_finish_sha1, }, -#define MULTI_HASH #endif #ifdef CONFIG_SHA256 { @@ -152,7 +147,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha256, hash_finish_sha256, }, -#define MULTI_HASH #endif { "crc32", @@ -165,6 +159,10 @@ static struct hash_algo hash_algo[] = { }, };
+#if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM) +#define MULTI_HASH +#endif + #if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_CMD_HASH) #define MULTI_HASH #endif @@ -311,6 +309,25 @@ int hash_lookup_algo(const char *algo_name, struct hash_algo **algop) return -EPROTONOSUPPORT; }
+int hash_progressive_lookup_algo(const char *algo_name, + struct hash_algo **algop) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hash_algo); i++) { + if (!strcmp(algo_name, hash_algo[i].name)) { + if (hash_algo[i].hash_init) { + *algop = &hash_algo[i]; + return 0; + } + } + } + + debug("Unknown hash algorithm '%s'\n", algo_name); + return -EPROTONOSUPPORT; +} + + void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output) { int i; diff --git a/include/hash.h b/include/hash.h index d8ec4f0..059f84e 100644 --- a/include/hash.h +++ b/include/hash.h @@ -128,6 +128,21 @@ int hash_block(const char *algo_name, const void *data, unsigned int len, int hash_lookup_algo(const char *algo_name, struct hash_algo **algop);
/** + * hash_progressive_lookup_algo() - Look up the hash_algo struct with progressive + * hash support for an algorithm + * + * The function returns the pointer to the struct or -EPROTONOSUPPORT if the + * algorithm is not available with progressive hash support. + * + * @algo_name: Hash algorithm to look up + * @algop: Pointer to the hash_algo struct if found + * + * @return 0 if ok, -EPROTONOSUPPORT for an unknown algorithm. + */ +int hash_progressive_lookup_algo(const char *algo_name, + struct hash_algo **algop); + +/** * hash_show() - Print out a hash algorithm and value * * You will get a message like this (without a newline at the end):

Hi,
On 17 December 2014 at 03:05, Ruchika Gupta ruchika.gupta@freescale.com wrote:
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
common/hash.c | 35 ++++++++++++++++++++++++++--------- include/hash.h | 15 +++++++++++++++ 2 files changed, 41 insertions(+), 9 deletions(-)
Can you please add a commit message? I think I can see what this is doing, but I'm not sure...
diff --git a/common/hash.c b/common/hash.c index 12d6759..87263df 100644 --- a/common/hash.c +++ b/common/hash.c @@ -20,7 +20,7 @@ #include <asm/io.h> #include <asm/errno.h>
-#ifdef CONFIG_CMD_SHA1SUM +#ifdef CONFIG_SHA256 static int hash_init_sha1(struct hash_algo *algo, void **ctxp) { sha1_context *ctx = malloc(sizeof(sha1_context)); @@ -125,12 +125,8 @@ static struct hash_algo hash_algo[] = { CHUNKSZ_SHA256, }, #endif
/*
* This is CONFIG_CMD_SHA1SUM instead of CONFIG_SHA1 since otherwise
* it bloats the code for boards which use SHA1 but not the 'hash'
* or 'sha1sum' commands.
*/
-#ifdef CONFIG_CMD_SHA1SUM
+#ifdef CONFIG_SHA1 { "sha1", SHA1_SUM_LEN, @@ -140,7 +136,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha1, hash_finish_sha1, }, -#define MULTI_HASH #endif #ifdef CONFIG_SHA256 { @@ -152,7 +147,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha256, hash_finish_sha256, }, -#define MULTI_HASH #endif { "crc32", @@ -165,6 +159,10 @@ static struct hash_algo hash_algo[] = { }, };
+#if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM) +#define MULTI_HASH +#endif
#if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_CMD_HASH) #define MULTI_HASH #endif @@ -311,6 +309,25 @@ int hash_lookup_algo(const char *algo_name, struct hash_algo **algop) return -EPROTONOSUPPORT; }
+int hash_progressive_lookup_algo(const char *algo_name,
struct hash_algo **algop)
+{
int i;
for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
if (!strcmp(algo_name, hash_algo[i].name)) {
if (hash_algo[i].hash_init) {
*algop = &hash_algo[i];
return 0;
}
}
}
debug("Unknown hash algorithm '%s'\n", algo_name);
return -EPROTONOSUPPORT;
+}
void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output) { int i; diff --git a/include/hash.h b/include/hash.h index d8ec4f0..059f84e 100644 --- a/include/hash.h +++ b/include/hash.h @@ -128,6 +128,21 @@ int hash_block(const char *algo_name, const void *data, unsigned int len, int hash_lookup_algo(const char *algo_name, struct hash_algo **algop);
/**
- hash_progressive_lookup_algo() - Look up the hash_algo struct with progressive
hash support for an algorithm
- The function returns the pointer to the struct or -EPROTONOSUPPORT if the
- algorithm is not available with progressive hash support.
- @algo_name: Hash algorithm to look up
- @algop: Pointer to the hash_algo struct if found
- @return 0 if ok, -EPROTONOSUPPORT for an unknown algorithm.
- */
+int hash_progressive_lookup_algo(const char *algo_name,
struct hash_algo **algop);
+/**
- hash_show() - Print out a hash algorithm and value
- You will get a message like this (without a newline at the end):
-- 1.8.1.4
Regards, Simon

Currently the hash functions used in RSA are called directly from the sha1 and sha256 libraries. Change the RSA checksum library to use the progressive hash API's registered with struct hash_algo. This will allow the checksum library to use the support of hardware accelerated progressive hash API's once available.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- include/image.h | 2 +- include/u-boot/rsa-checksum.h | 4 +-- lib/rsa/rsa-checksum.c | 61 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 7 deletions(-)
diff --git a/include/image.h b/include/image.h index af30d60..0067c75 100644 --- a/include/image.h +++ b/include/image.h @@ -926,7 +926,7 @@ struct checksum_algo { #if IMAGE_ENABLE_SIGN const EVP_MD *(*calculate_sign)(void); #endif - void (*calculate)(const struct image_region region[], + int (*calculate)(const struct image_region region[], int region_count, uint8_t *checksum); const uint8_t *rsa_padding; }; diff --git a/include/u-boot/rsa-checksum.h b/include/u-boot/rsa-checksum.h index c996fb3..db55046 100644 --- a/include/u-boot/rsa-checksum.h +++ b/include/u-boot/rsa-checksum.h @@ -16,9 +16,9 @@ extern const uint8_t padding_sha256_rsa4096[]; extern const uint8_t padding_sha256_rsa2048[]; extern const uint8_t padding_sha1_rsa2048[];
-void sha256_calculate(const struct image_region region[], int region_count, +int sha256_calculate(const struct image_region region[], int region_count, uint8_t *checksum); -void sha1_calculate(const struct image_region region[], int region_count, +int sha1_calculate(const struct image_region region[], int region_count, uint8_t *checksum);
#endif diff --git a/lib/rsa/rsa-checksum.c b/lib/rsa/rsa-checksum.c index 8d8b59f..af27c97 100644 --- a/lib/rsa/rsa-checksum.c +++ b/lib/rsa/rsa-checksum.c @@ -10,12 +10,13 @@ #include <asm/byteorder.h> #include <asm/errno.h> #include <asm/unaligned.h> +#include <hash.h> #else #include "fdt_host.h" -#endif -#include <u-boot/rsa.h> #include <u-boot/sha1.h> #include <u-boot/sha256.h> +#endif +#include <u-boot/rsa.h>
/* PKCS 1.5 paddings as described in the RSA PKCS#1 v2.1 standard. */
@@ -136,7 +137,54 @@ const uint8_t padding_sha256_rsa4096[RSA4096_BYTES - SHA256_SUM_LEN] = { 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
-void sha1_calculate(const struct image_region region[], int region_count, +#ifndef USE_HOSTCC +void hash_calculate(struct hash_algo *algo, const struct image_region region[], + int region_count, uint8_t *checksum) +{ + void *ctx; + uint32_t i; + i = 0; + + algo->hash_init(algo, &ctx); + for (i = 0; i < region_count - 1; i++) + algo->hash_update(algo, ctx, region[i].data, region[i].size, 0); + + algo->hash_update(algo, ctx, region[i].data, region[i].size, 1); + algo->hash_finish(algo, ctx, checksum, algo->digest_size); +} + +int sha1_calculate(const struct image_region region[], int region_count, + uint8_t *checksum) +{ + struct hash_algo *algo; + int ret = 0; + + ret = hash_progressive_lookup_algo("sha1", &algo); + if (ret) + return ret; + + hash_calculate(algo, region, region_count, checksum); + + return 0; +} + +int sha256_calculate(const struct image_region region[], int region_count, + uint8_t *checksum) +{ + struct hash_algo *algo; + int ret; + + ret = hash_progressive_lookup_algo("sha256", &algo); + if (ret) + return ret; + + hash_calculate(algo, region, region_count, checksum); + + return 0; +} + +#else +int sha1_calculate(const struct image_region region[], int region_count, uint8_t *checksum) { sha1_context ctx; @@ -147,9 +195,11 @@ void sha1_calculate(const struct image_region region[], int region_count, for (i = 0; i < region_count; i++) sha1_update(&ctx, region[i].data, region[i].size); sha1_finish(&ctx, checksum); + + return 0; }
-void sha256_calculate(const struct image_region region[], int region_count, +int sha256_calculate(const struct image_region region[], int region_count, uint8_t *checksum) { sha256_context ctx; @@ -160,4 +210,7 @@ void sha256_calculate(const struct image_region region[], int region_count, for (i = 0; i < region_count; i++) sha256_update(&ctx, region[i].data, region[i].size); sha256_finish(&ctx, checksum); + + return 0; } +#endif

Hi,
On 17 December 2014 at 03:05, Ruchika Gupta ruchika.gupta@freescale.com wrote:
Currently the hash functions used in RSA are called directly from the sha1 and sha256 libraries. Change the RSA checksum library to use the progressive hash API's registered with struct hash_algo. This will allow the checksum library to use the support of hardware accelerated progressive hash API's once available.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
include/image.h | 2 +- include/u-boot/rsa-checksum.h | 4 +-- lib/rsa/rsa-checksum.c | 61 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 7 deletions(-)
diff --git a/include/image.h b/include/image.h index af30d60..0067c75 100644 --- a/include/image.h +++ b/include/image.h @@ -926,7 +926,7 @@ struct checksum_algo { #if IMAGE_ENABLE_SIGN const EVP_MD *(*calculate_sign)(void); #endif
void (*calculate)(const struct image_region region[],
int (*calculate)(const struct image_region region[], int region_count, uint8_t *checksum); const uint8_t *rsa_padding;
}; diff --git a/include/u-boot/rsa-checksum.h b/include/u-boot/rsa-checksum.h index c996fb3..db55046 100644 --- a/include/u-boot/rsa-checksum.h +++ b/include/u-boot/rsa-checksum.h @@ -16,9 +16,9 @@ extern const uint8_t padding_sha256_rsa4096[]; extern const uint8_t padding_sha256_rsa2048[]; extern const uint8_t padding_sha1_rsa2048[];
-void sha256_calculate(const struct image_region region[], int region_count, +int sha256_calculate(const struct image_region region[], int region_count, uint8_t *checksum); -void sha1_calculate(const struct image_region region[], int region_count, +int sha1_calculate(const struct image_region region[], int region_count, uint8_t *checksum);
I wonder if the algorithm can become a parameter rather than duplicating the code...
#endif diff --git a/lib/rsa/rsa-checksum.c b/lib/rsa/rsa-checksum.c index 8d8b59f..af27c97 100644 --- a/lib/rsa/rsa-checksum.c +++ b/lib/rsa/rsa-checksum.c @@ -10,12 +10,13 @@ #include <asm/byteorder.h> #include <asm/errno.h> #include <asm/unaligned.h> +#include <hash.h> #else #include "fdt_host.h" -#endif -#include <u-boot/rsa.h> #include <u-boot/sha1.h> #include <u-boot/sha256.h> +#endif +#include <u-boot/rsa.h>
/* PKCS 1.5 paddings as described in the RSA PKCS#1 v2.1 standard. */
@@ -136,7 +137,54 @@ const uint8_t padding_sha256_rsa4096[RSA4096_BYTES - SHA256_SUM_LEN] = { 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
-void sha1_calculate(const struct image_region region[], int region_count, +#ifndef USE_HOSTCC +void hash_calculate(struct hash_algo *algo, const struct image_region region[],
int region_count, uint8_t *checksum)
+{
void *ctx;
uint32_t i;
i = 0;
algo->hash_init(algo, &ctx);
for (i = 0; i < region_count - 1; i++)
algo->hash_update(algo, ctx, region[i].data, region[i].size, 0);
algo->hash_update(algo, ctx, region[i].data, region[i].size, 1);
algo->hash_finish(algo, ctx, checksum, algo->digest_size);
+}
+int sha1_calculate(const struct image_region region[], int region_count,
uint8_t *checksum)
+{
struct hash_algo *algo;
int ret = 0;
ret = hash_progressive_lookup_algo("sha1", &algo);
if (ret)
return ret;
hash_calculate(algo, region, region_count, checksum);
return 0;
+}
+int sha256_calculate(const struct image_region region[], int region_count,
uint8_t *checksum)
+{
struct hash_algo *algo;
int ret;
ret = hash_progressive_lookup_algo("sha256", &algo);
if (ret)
return ret;
hash_calculate(algo, region, region_count, checksum);
return 0;
+}
Here is the duplication - these functions are the same but for sha1 and sha256.
+#else +int sha1_calculate(const struct image_region region[], int region_count, uint8_t *checksum) { sha1_context ctx; @@ -147,9 +195,11 @@ void sha1_calculate(const struct image_region region[], int region_count, for (i = 0; i < region_count; i++) sha1_update(&ctx, region[i].data, region[i].size); sha1_finish(&ctx, checksum);
return 0;
}
-void sha256_calculate(const struct image_region region[], int region_count, +int sha256_calculate(const struct image_region region[], int region_count, uint8_t *checksum) { sha256_context ctx; @@ -160,4 +210,7 @@ void sha256_calculate(const struct image_region region[], int region_count, for (i = 0; i < region_count; i++) sha256_update(&ctx, region[i].data, region[i].size); sha256_finish(&ctx, checksum);
return 0;
}
+#endif
1.8.1.4
Regards, Simon
participants (2)
-
Ruchika Gupta
-
Simon Glass