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

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@freescale.com CC: Simon Glass sjg@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) { + 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); + + memcpy(buf, sig, sig_len); + + ret = pow_mod(&key, buf); + if (ret) + return ret; + + *out = (uint8_t *)buf; + *len = sig_len; + + 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;
- 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; + }
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 \

For FIT signature based approach to work, RSA library needs to be selected. The FIT_SIGNATURE option in Kconfig is modified to automatically select RSA. Selecting RSA compiles the RSA library required for image verification.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- Changes in v4: Expanded CONFIG_RSA with documentation link
Changes in v3: New patch created for adding Kconfig option for FIT signature
Kconfig | 3 ++- lib/Kconfig | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/Kconfig b/Kconfig index 153ee2b..c2d7cb9 100644 --- a/Kconfig +++ b/Kconfig @@ -116,8 +116,9 @@ config FIT_VERBOSE depends on FIT
config FIT_SIGNATURE - bool "Enabel signature verification of FIT uImages" + bool "Enable signature verification of FIT uImages" depends on FIT + select RSA help This option enables signature verification of FIT uImages, using a hash signed and verified using RSA. diff --git a/lib/Kconfig b/lib/Kconfig index 8460439..2455f7a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -27,4 +27,11 @@ config SYS_HZ get_timer() must operate in milliseconds and this option must be set to 1000.
+config RSA + bool "Use RSA Library" + help + RSA support.This enables the RSA algorithm used for FIT image + verification in U-Boot. + See doc/uImage.FIT/signature.txt for more details. + endmenu

Hi Ruchika,
On 30 December 2014 at 02:30, Ruchika Gupta ruchika.gupta@freescale.com wrote:
For FIT signature based approach to work, RSA library needs to be selected. The FIT_SIGNATURE option in Kconfig is modified to automatically select RSA. Selecting RSA compiles the RSA library required for image verification.
Please word-wrap this.
Assuming you fix the two nits:
Acked-by: Simon Glass sjg@chromium.org
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: Expanded CONFIG_RSA with documentation link
Changes in v3: New patch created for adding Kconfig option for FIT signature
Kconfig | 3 ++- lib/Kconfig | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/Kconfig b/Kconfig index 153ee2b..c2d7cb9 100644 --- a/Kconfig +++ b/Kconfig @@ -116,8 +116,9 @@ config FIT_VERBOSE depends on FIT
config FIT_SIGNATURE
bool "Enabel signature verification of FIT uImages"
bool "Enable signature verification of FIT uImages" depends on FIT
select RSA help This option enables signature verification of FIT uImages, using a hash signed and verified using RSA.
diff --git a/lib/Kconfig b/lib/Kconfig index 8460439..2455f7a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -27,4 +27,11 @@ config SYS_HZ get_timer() must operate in milliseconds and this option must be set to 1000.
+config RSA
bool "Use RSA Library"
help
RSA support.This enables the RSA algorithm used for FIT image
Space after '.'
verification in U-Boot.
See doc/uImage.FIT/signature.txt for more details.
endmenu
1.8.1.4
Regards, Simon

Add a new rsa uclass for performing modular exponentiation and implement the software driver basing on this uclass.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- Changes in v4: Removed Kconfig option for DM_RSA Corrected driver name for sw rsa driver Updated the rsa_mod_exp operation to have output length
Changes in v3: New patch with driver model for RSA UCLASS
drivers/crypto/Makefile | 1 + drivers/crypto/rsa/Makefile | 7 +++++++ drivers/crypto/rsa/rsa_sw.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/crypto/rsa/rsa_uclass.c | 31 +++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/u-boot/rsa-mod-exp.h | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 drivers/crypto/rsa/Makefile create mode 100644 drivers/crypto/rsa/rsa_sw.c create mode 100644 drivers/crypto/rsa/rsa_uclass.c
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 7b79237..a2f30fc 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -6,4 +6,5 @@ #
obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o +obj-y += rsa/ obj-y += fsl/ diff --git a/drivers/crypto/rsa/Makefile b/drivers/crypto/rsa/Makefile new file mode 100644 index 0000000..927c5bd --- /dev/null +++ b/drivers/crypto/rsa/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2014 Freescale Semiconductor, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_RSA) += rsa_uclass.o rsa_sw.o diff --git a/drivers/crypto/rsa/rsa_sw.c b/drivers/crypto/rsa/rsa_sw.c new file mode 100644 index 0000000..3dcd512 --- /dev/null +++ b/drivers/crypto/rsa/rsa_sw.c @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2014 Freescale Semiconductor, Inc. + * Author: Ruchika Gupta ruchika.gupta@freescale.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <common.h> +#include <dm.h> +#include <u-boot/rsa-mod-exp.h> + +int mod_exp_sw(struct udevice *dev, const uint8_t *sig, uint32_t sig_len, + struct key_prop *prop, uint8_t **outp, uint32_t *out_len) +{ + int ret = 0; + + ret = rsa_mod_exp_sw(sig, sig_len, prop, outp, out_len); + if (ret) { + debug("%s: RSA failed to verify: %d\n", __func__, ret); + return ret; + } + + return 0; +} + +static const struct rsa_ops rsa_ops_sw = { + .mod_exp = mod_exp_sw, +}; + +U_BOOT_DRIVER(rsa_sw) = { + .name = "rsa_sw", + .id = UCLASS_RSA, + .ops = &rsa_ops_sw, +}; + +U_BOOT_DEVICE(rsa_sw) = { + .name = "rsa_sw", +}; diff --git a/drivers/crypto/rsa/rsa_uclass.c b/drivers/crypto/rsa/rsa_uclass.c new file mode 100644 index 0000000..4d52dcc --- /dev/null +++ b/drivers/crypto/rsa/rsa_uclass.c @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2014 Freescale Semiconductor, Inc + * Author: Ruchika Gupta ruchika.gupta@freescale.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <u-boot/rsa-mod-exp.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <asm/io.h> +#include <linux/list.h> + +int rsa_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len, + struct key_prop *node, uint8_t **out, uint32_t *out_len) +{ + const struct rsa_ops *ops = device_get_ops(dev); + + if (!ops->mod_exp) + return -ENOSYS; + + return ops->mod_exp(dev, sig, sig_len, node, out, out_len); +} + +UCLASS_DRIVER(rsa) = { + .id = UCLASS_RSA, + .name = "rsa", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index f17c3c2..823e43c 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -33,6 +33,7 @@ enum uclass_id { UCLASS_I2C, /* I2C bus */ UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ + UCLASS_RSA, /* RSA Mod Exp device */
UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/u-boot/rsa-mod-exp.h b/include/u-boot/rsa-mod-exp.h index 7b74f3c..417e468 100644 --- a/include/u-boot/rsa-mod-exp.h +++ b/include/u-boot/rsa-mod-exp.h @@ -46,4 +46,41 @@ struct key_prop { int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len, struct key_prop *node, uint8_t **outp, uint32_t *out_len);
+int rsa_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len, + struct key_prop *node, uint8_t **outp, uint32_t *out_len); + +/** + * struct struct rsa_ops - Driver model for RSA operations + * + * The uclass interface is implemented by all crypto devices which use + * driver model. + */ +struct rsa_ops { + /** + * Perform Modular Exponentiation + * + * Operation: out[] = sig ^ exponent % modulus + * + * @dev: RSA Device + * @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 + * + * Returns: 0 if exponentiation is successful, or a negative value + * if it wasn't. + */ + int (*mod_exp)(struct udevice *dev, const uint8_t *sig, + uint32_t sig_len, struct key_prop *node, + uint8_t **outp, uint32_t *len); +}; + #endif

Hi Ruchika,
On 30 December 2014 at 02:30, Ruchika Gupta ruchika.gupta@freescale.com wrote:
Add a new rsa uclass for performing modular exponentiation and implement the software driver basing on this uclass.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: Removed Kconfig option for DM_RSA Corrected driver name for sw rsa driver Updated the rsa_mod_exp operation to have output length
Changes in v3: New patch with driver model for RSA UCLASS
drivers/crypto/Makefile | 1 + drivers/crypto/rsa/Makefile | 7 +++++++ drivers/crypto/rsa/rsa_sw.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/crypto/rsa/rsa_uclass.c | 31 +++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/u-boot/rsa-mod-exp.h | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 drivers/crypto/rsa/Makefile create mode 100644 drivers/crypto/rsa/rsa_sw.c create mode 100644 drivers/crypto/rsa/rsa_uclass.c
Again I'm a bit worried we are going off into the weeds.
Is this an RSA driver or a modular exponentiation driver? It seems like the latter to me. If so, the uclass should be UCLASS_MOD_EXP, not UCLASS_RSA, and the files and directories should be renames also. Some hardware will implement the entire RSA algorithm, which would be a true RSA uclass. Here I think you are only doing part of it.
Other than that rename the code looks fine.
Minor point: again I don't see the value of returning the same value as sig_len, so you may as well drop those last two args to mod_exp() - unless I am missing something.
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 7b79237..a2f30fc 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -6,4 +6,5 @@ #
obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o +obj-y += rsa/ obj-y += fsl/ diff --git a/drivers/crypto/rsa/Makefile b/drivers/crypto/rsa/Makefile new file mode 100644 index 0000000..927c5bd --- /dev/null +++ b/drivers/crypto/rsa/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2014 Freescale Semiconductor, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_RSA) += rsa_uclass.o rsa_sw.o diff --git a/drivers/crypto/rsa/rsa_sw.c b/drivers/crypto/rsa/rsa_sw.c new file mode 100644 index 0000000..3dcd512 --- /dev/null +++ b/drivers/crypto/rsa/rsa_sw.c @@ -0,0 +1,39 @@ +/*
- (C) Copyright 2014 Freescale Semiconductor, Inc.
- Author: Ruchika Gupta ruchika.gupta@freescale.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <config.h> +#include <common.h> +#include <dm.h> +#include <u-boot/rsa-mod-exp.h>
+int mod_exp_sw(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
struct key_prop *prop, uint8_t **outp, uint32_t *out_len)
+{
int ret = 0;
ret = rsa_mod_exp_sw(sig, sig_len, prop, outp, out_len);
if (ret) {
debug("%s: RSA failed to verify: %d\n", __func__, ret);
return ret;
}
return 0;
+}
+static const struct rsa_ops rsa_ops_sw = {
.mod_exp = mod_exp_sw,
+};
+U_BOOT_DRIVER(rsa_sw) = {
.name = "rsa_sw",
.id = UCLASS_RSA,
.ops = &rsa_ops_sw,
+};
+U_BOOT_DEVICE(rsa_sw) = {
.name = "rsa_sw",
+}; diff --git a/drivers/crypto/rsa/rsa_uclass.c b/drivers/crypto/rsa/rsa_uclass.c new file mode 100644 index 0000000..4d52dcc --- /dev/null +++ b/drivers/crypto/rsa/rsa_uclass.c @@ -0,0 +1,31 @@ +/*
- (C) Copyright 2014 Freescale Semiconductor, Inc
- Author: Ruchika Gupta ruchika.gupta@freescale.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <u-boot/rsa-mod-exp.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <asm/io.h> +#include <linux/list.h>
+int rsa_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
struct key_prop *node, uint8_t **out, uint32_t *out_len)
+{
const struct rsa_ops *ops = device_get_ops(dev);
if (!ops->mod_exp)
return -ENOSYS;
return ops->mod_exp(dev, sig, sig_len, node, out, out_len);
+}
+UCLASS_DRIVER(rsa) = {
.id = UCLASS_RSA,
.name = "rsa",
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index f17c3c2..823e43c 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -33,6 +33,7 @@ enum uclass_id { UCLASS_I2C, /* I2C bus */ UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */
UCLASS_RSA, /* RSA Mod Exp device */ UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/u-boot/rsa-mod-exp.h b/include/u-boot/rsa-mod-exp.h index 7b74f3c..417e468 100644 --- a/include/u-boot/rsa-mod-exp.h +++ b/include/u-boot/rsa-mod-exp.h @@ -46,4 +46,41 @@ struct key_prop { int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len, struct key_prop *node, uint8_t **outp, uint32_t *out_len);
+int rsa_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
struct key_prop *node, uint8_t **outp, uint32_t *out_len);
+/**
- struct struct rsa_ops - Driver model for RSA operations
- The uclass interface is implemented by all crypto devices which use
- driver model.
- */
+struct rsa_ops {
/**
* Perform Modular Exponentiation
*
* Operation: out[] = sig ^ exponent % modulus
*
* @dev: RSA Device
* @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
*
* Returns: 0 if exponentiation is successful, or a negative value
* if it wasn't.
*/
int (*mod_exp)(struct udevice *dev, const uint8_t *sig,
uint32_t sig_len, struct key_prop *node,
uint8_t **outp, uint32_t *len);
+};
#endif
1.8.1.4

For the platforms which use,CONFIG_FIT_SIGNATURE, the required configs are moved to the platform's defconfig file. Selecting CONFIG_FIT_SIGNATURE using defconfig automatically resolves the dependencies for signature verification. The RSA library gets automatically selected and user does not have to define CONFIG_RSA manually.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org Acked-by: Simon Glass sjg@chromium.org
--- Changes in v4: No changes
Changes in v3: New patch
configs/ids8313_defconfig | 2 ++ configs/sandbox_defconfig | 3 +++ configs/zynq_microzed_defconfig | 3 +++ configs/zynq_zc70x_defconfig | 3 +++ configs/zynq_zc770_xm010_defconfig | 3 +++ configs/zynq_zc770_xm012_defconfig | 3 +++ configs/zynq_zc770_xm013_defconfig | 3 +++ configs/zynq_zed_defconfig | 3 +++ configs/zynq_zybo_defconfig | 3 +++ include/configs/am335x_evm.h | 4 ++-- include/configs/ids8313.h | 3 --- include/configs/sandbox.h | 3 --- include/configs/zynq-common.h | 6 ------ 13 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/configs/ids8313_defconfig b/configs/ids8313_defconfig index 1c665aa..8479cd4 100644 --- a/configs/ids8313_defconfig +++ b/configs/ids8313_defconfig @@ -1,4 +1,6 @@ CONFIG_SYS_EXTRA_OPTIONS="SYS_TEXT_BASE=0xFFF00000" CONFIG_PPC=y CONFIG_MPC83xx=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y CONFIG_TARGET_IDS8313=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 47d8400..0111f25 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -1,3 +1,6 @@ CONFIG_OF_CONTROL=y CONFIG_OF_HOSTFILE=y +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y CONFIG_DEFAULT_DEVICE_TREE="sandbox" diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig index 9588849..b9a6fe5 100644 --- a/configs/zynq_microzed_defconfig +++ b/configs/zynq_microzed_defconfig @@ -3,4 +3,7 @@ CONFIG_SPL=y +S:CONFIG_ZYNQ=y +S:CONFIG_TARGET_ZYNQ_MICROZED=y CONFIG_OF_CONTROL=y +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y CONFIG_DEFAULT_DEVICE_TREE="zynq-microzed" diff --git a/configs/zynq_zc70x_defconfig b/configs/zynq_zc70x_defconfig index cf50730..dc8aa84 100644 --- a/configs/zynq_zc70x_defconfig +++ b/configs/zynq_zc70x_defconfig @@ -4,3 +4,6 @@ CONFIG_SPL=y +S:CONFIG_TARGET_ZYNQ_ZC70X=y CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="zynq-zc702" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y diff --git a/configs/zynq_zc770_xm010_defconfig b/configs/zynq_zc770_xm010_defconfig index 8bb405d..2f5fa8c 100644 --- a/configs/zynq_zc770_xm010_defconfig +++ b/configs/zynq_zc770_xm010_defconfig @@ -5,3 +5,6 @@ CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM010" +S:CONFIG_TARGET_ZYNQ_ZC770=y CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm010" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y diff --git a/configs/zynq_zc770_xm012_defconfig b/configs/zynq_zc770_xm012_defconfig index 0ba5da5..a92d495 100644 --- a/configs/zynq_zc770_xm012_defconfig +++ b/configs/zynq_zc770_xm012_defconfig @@ -5,3 +5,6 @@ CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM012" +S:CONFIG_TARGET_ZYNQ_ZC770=y CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm012" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y diff --git a/configs/zynq_zc770_xm013_defconfig b/configs/zynq_zc770_xm013_defconfig index 13f8112..3a02f75 100644 --- a/configs/zynq_zc770_xm013_defconfig +++ b/configs/zynq_zc770_xm013_defconfig @@ -5,3 +5,6 @@ CONFIG_SYS_EXTRA_OPTIONS="ZC770_XM013" +S:CONFIG_TARGET_ZYNQ_ZC770=y CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm013" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y diff --git a/configs/zynq_zed_defconfig b/configs/zynq_zed_defconfig index eb057fa..1d816f6 100644 --- a/configs/zynq_zed_defconfig +++ b/configs/zynq_zed_defconfig @@ -4,3 +4,6 @@ CONFIG_SPL=y +S:CONFIG_TARGET_ZYNQ_ZED=y CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="zynq-zed" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y diff --git a/configs/zynq_zybo_defconfig b/configs/zynq_zybo_defconfig index 12311cd..9183629 100644 --- a/configs/zynq_zybo_defconfig +++ b/configs/zynq_zybo_defconfig @@ -4,3 +4,6 @@ CONFIG_SPL=y +S:CONFIG_TARGET_ZYNQ_ZYBO=y CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="zynq-zybo" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index 560e3bf..cc36985 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -23,8 +23,8 @@ # define CONFIG_TIMESTAMP # define CONFIG_LZO # ifdef CONFIG_ENABLE_VBOOT -# define CONFIG_FIT_SIGNATURE -# define CONFIG_RSA +# define CONFIG_FIT_SIGNATURE +# define CONFIG_RSA # endif #endif
diff --git a/include/configs/ids8313.h b/include/configs/ids8313.h index f084834..2384864 100644 --- a/include/configs/ids8313.h +++ b/include/configs/ids8313.h @@ -575,12 +575,9 @@
#define CONFIG_VERSION_VARIABLE
-#define CONFIG_FIT -#define CONFIG_FIT_SIGNATURE #define CONFIG_IMAGE_FORMAT_LEGACY #define CONFIG_CMD_FDT #define CONFIG_CMD_HASH -#define CONFIG_RSA #define CONFIG_SHA1 #define CONFIG_SHA256
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 657f751..6fd29b9 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -41,9 +41,6 @@
#define CONFIG_OF_LIBFDT #define CONFIG_LMB -#define CONFIG_FIT -#define CONFIG_FIT_SIGNATURE -#define CONFIG_RSA #define CONFIG_CMD_FDT #define CONFIG_ANDROID_BOOT_IMAGE
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h index 87b4fff..3894517 100644 --- a/include/configs/zynq-common.h +++ b/include/configs/zynq-common.h @@ -219,17 +219,11 @@ #define CONFIG_OF_LIBFDT
/* FIT support */ -#define CONFIG_FIT -#define CONFIG_FIT_VERBOSE 1 /* enable fit_format_{error,warning}() */ #define CONFIG_IMAGE_FORMAT_LEGACY /* enable also legacy image format */
/* FDT support */ #define CONFIG_DISPLAY_BOARDINFO_LATE
-/* RSA support */ -#define CONFIG_FIT_SIGNATURE -#define CONFIG_RSA - /* Extend size of kernel image for uncompression */ #define CONFIG_SYS_BOOTM_LEN (60 * 1024 * 1024)

Modify rsa_verify to use the rsa driver of DM library .The tools will continue to use the same RSA sw library.
CONFIG_RSA is now dependent on CONFIG_DM. All configurations which enable FIT based signatures have been modified to enable CONFIG_DM by default.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- Changes in v4: Make CONFIG_RSA always depenedent on Driver Model. Add CONFIG_DM in defconfigs of the platforms which enable CONFIG_FIT_SIGNATURE
Changes in v3: New patch
README | 7 ++++++- configs/ids8313_defconfig | 1 + configs/sandbox_defconfig | 1 + configs/zynq_microzed_defconfig | 1 + configs/zynq_zc70x_defconfig | 1 + configs/zynq_zc770_xm010_defconfig | 1 + configs/zynq_zc770_xm012_defconfig | 1 + configs/zynq_zc770_xm013_defconfig | 1 + configs/zynq_zed_defconfig | 1 + configs/zynq_zybo_defconfig | 1 + include/configs/am335x_evm.h | 3 +++ include/configs/sandbox.h | 1 - lib/Kconfig | 5 ++++- lib/rsa/rsa-verify.c | 19 +++++++++++++++++++ 14 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/README b/README index 4ca04d0..1d7978f 100644 --- a/README +++ b/README @@ -3173,8 +3173,13 @@ CBFS (Coreboot Filesystem) support This enables the RSA algorithm used for FIT image verification in U-Boot. See doc/uImage.FIT/signature.txt for more information.
+ The Modular Exponentiation algorithm in RSA is implemented using + driver model. So CONFIG_DM needs to be enabled by default for this + library to function. + The signing part is build into mkimage regardless of this - option. + option. The software based modular exponentiation is built into + mkimage irrespective of this option.
- bootcount support: CONFIG_BOOTCOUNT_LIMIT diff --git a/configs/ids8313_defconfig b/configs/ids8313_defconfig index 8479cd4..0950ec8 100644 --- a/configs/ids8313_defconfig +++ b/configs/ids8313_defconfig @@ -4,3 +4,4 @@ CONFIG_MPC83xx=y CONFIG_FIT=y CONFIG_FIT_SIGNATURE=y CONFIG_TARGET_IDS8313=y +CONFIG_DM=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 0111f25..660063e 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -3,4 +3,5 @@ CONFIG_OF_HOSTFILE=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y CONFIG_DEFAULT_DEVICE_TREE="sandbox" diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig index b9a6fe5..8b985fe 100644 --- a/configs/zynq_microzed_defconfig +++ b/configs/zynq_microzed_defconfig @@ -6,4 +6,5 @@ CONFIG_OF_CONTROL=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y CONFIG_DEFAULT_DEVICE_TREE="zynq-microzed" diff --git a/configs/zynq_zc70x_defconfig b/configs/zynq_zc70x_defconfig index dc8aa84..cceb321 100644 --- a/configs/zynq_zc70x_defconfig +++ b/configs/zynq_zc70x_defconfig @@ -7,3 +7,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc702" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zc770_xm010_defconfig b/configs/zynq_zc770_xm010_defconfig index 2f5fa8c..2935c0d 100644 --- a/configs/zynq_zc770_xm010_defconfig +++ b/configs/zynq_zc770_xm010_defconfig @@ -8,3 +8,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm010" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zc770_xm012_defconfig b/configs/zynq_zc770_xm012_defconfig index a92d495..0401739 100644 --- a/configs/zynq_zc770_xm012_defconfig +++ b/configs/zynq_zc770_xm012_defconfig @@ -8,3 +8,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm012" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zc770_xm013_defconfig b/configs/zynq_zc770_xm013_defconfig index 3a02f75..a95970a 100644 --- a/configs/zynq_zc770_xm013_defconfig +++ b/configs/zynq_zc770_xm013_defconfig @@ -8,3 +8,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm013" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zed_defconfig b/configs/zynq_zed_defconfig index 1d816f6..0fbc41a 100644 --- a/configs/zynq_zed_defconfig +++ b/configs/zynq_zed_defconfig @@ -7,3 +7,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zed" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zybo_defconfig b/configs/zynq_zybo_defconfig index 9183629..4e66760 100644 --- a/configs/zynq_zybo_defconfig +++ b/configs/zynq_zybo_defconfig @@ -7,3 +7,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zybo" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index cc36985..1eb0ce7 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -24,6 +24,9 @@ # define CONFIG_LZO # ifdef CONFIG_ENABLE_VBOOT # define CONFIG_FIT_SIGNATURE +#ifndef CONFIG_DM +#define CONFIG_DM +#endif # define CONFIG_RSA # endif #endif diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 6fd29b9..e9d3f32 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -23,7 +23,6 @@
#define CONFIG_BOOTSTAGE #define CONFIG_BOOTSTAGE_REPORT -#define CONFIG_DM #define CONFIG_CMD_DEMO #define CONFIG_CMD_DM #define CONFIG_DM_DEMO diff --git a/lib/Kconfig b/lib/Kconfig index 2455f7a..f317f81 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -29,9 +29,12 @@ config SYS_HZ
config RSA bool "Use RSA Library" + depends on DM help RSA support.This enables the RSA algorithm used for FIT image - verification in U-Boot. + verification in U-Boot. RSA support for Modular exponentiation + is implemented as a driver model. Driver Model should be enabled + to select this option. See doc/uImage.FIT/signature.txt for more details.
endmenu diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 1d2e707..af915d3 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -12,6 +12,7 @@ #include <asm/errno.h> #include <asm/types.h> #include <asm/unaligned.h> +#include <dm.h> #else #include "fdt_host.h" #include "mkimage.h" @@ -44,6 +45,9 @@ static int rsa_verify_key(struct key_prop *prop, const uint8_t *sig, const uint8_t *padding; int pad_len; int ret; +#if !defined(USE_HOSTCC) + struct udevice *rsa_dev; +#endif
if (!prop || !sig || !hash || !algo) return -EIO; @@ -65,11 +69,26 @@ static int rsa_verify_key(struct key_prop *prop, const uint8_t *sig, uint8_t *buf; uint32_t buf_len;
+#if !defined(USE_HOSTCC) + ret = uclass_get_device(UCLASS_RSA, 0, &rsa_dev); + if (!ret) { + ret = rsa_mod_exp(rsa_dev, sig, sig_len, prop, &buf, + &buf_len); + if (ret) { + debug("Error in Modular exponentation\n"); + return ret; + } + } else { + printf("RSA: Can't find Mod Exp implemnetation\n"); + return -EINVAL; + } +#else ret = rsa_mod_exp_sw(sig, sig_len, prop, &buf, &buf_len); if (ret) { debug("Error in Modular exponentation\n"); return ret; } +#endif
if (buf_len != sig_len) { debug("In RSAVerify(): hash length not same as sig len\n");

Hi Ruchika,
On 30 December 2014 at 02:30, Ruchika Gupta ruchika.gupta@freescale.com wrote:
Modify rsa_verify to use the rsa driver of DM library .The tools will continue to use the same RSA sw library.
CONFIG_RSA is now dependent on CONFIG_DM. All configurations which enable FIT based signatures have been modified to enable CONFIG_DM by default.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: Make CONFIG_RSA always depenedent on Driver Model. Add CONFIG_DM in defconfigs of the platforms which enable CONFIG_FIT_SIGNATURE
Changes in v3: New patch
README | 7 ++++++- configs/ids8313_defconfig | 1 + configs/sandbox_defconfig | 1 + configs/zynq_microzed_defconfig | 1 + configs/zynq_zc70x_defconfig | 1 + configs/zynq_zc770_xm010_defconfig | 1 + configs/zynq_zc770_xm012_defconfig | 1 + configs/zynq_zc770_xm013_defconfig | 1 + configs/zynq_zed_defconfig | 1 + configs/zynq_zybo_defconfig | 1 + include/configs/am335x_evm.h | 3 +++ include/configs/sandbox.h | 1 - lib/Kconfig | 5 ++++- lib/rsa/rsa-verify.c | 19 +++++++++++++++++++ 14 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/README b/README index 4ca04d0..1d7978f 100644 --- a/README +++ b/README @@ -3173,8 +3173,13 @@ CBFS (Coreboot Filesystem) support This enables the RSA algorithm used for FIT image verification in U-Boot. See doc/uImage.FIT/signature.txt for more information.
The Modular Exponentiation algorithm in RSA is implemented using
driver model. So CONFIG_DM needs to be enabled by default for this
library to function.
The signing part is build into mkimage regardless of this
option.
option. The software based modular exponentiation is built into
mkimage irrespective of this option.
Just to avoid confusion, I think your addition here to the README is good.
- bootcount support: CONFIG_BOOTCOUNT_LIMIT
diff --git a/configs/ids8313_defconfig b/configs/ids8313_defconfig index 8479cd4..0950ec8 100644 --- a/configs/ids8313_defconfig +++ b/configs/ids8313_defconfig @@ -4,3 +4,4 @@ CONFIG_MPC83xx=y CONFIG_FIT=y CONFIG_FIT_SIGNATURE=y CONFIG_TARGET_IDS8313=y +CONFIG_DM=y
Eek I suspect this might cause a problem, but by the time this merges, DM support for PPC should be merged, so OK.
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 0111f25..660063e 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -3,4 +3,5 @@ CONFIG_OF_HOSTFILE=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y CONFIG_DEFAULT_DEVICE_TREE="sandbox" diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig index b9a6fe5..8b985fe 100644 --- a/configs/zynq_microzed_defconfig +++ b/configs/zynq_microzed_defconfig @@ -6,4 +6,5 @@ CONFIG_OF_CONTROL=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y CONFIG_DEFAULT_DEVICE_TREE="zynq-microzed" diff --git a/configs/zynq_zc70x_defconfig b/configs/zynq_zc70x_defconfig index dc8aa84..cceb321 100644 --- a/configs/zynq_zc70x_defconfig +++ b/configs/zynq_zc70x_defconfig @@ -7,3 +7,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc702" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zc770_xm010_defconfig b/configs/zynq_zc770_xm010_defconfig index 2f5fa8c..2935c0d 100644 --- a/configs/zynq_zc770_xm010_defconfig +++ b/configs/zynq_zc770_xm010_defconfig @@ -8,3 +8,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm010" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zc770_xm012_defconfig b/configs/zynq_zc770_xm012_defconfig index a92d495..0401739 100644 --- a/configs/zynq_zc770_xm012_defconfig +++ b/configs/zynq_zc770_xm012_defconfig @@ -8,3 +8,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm012" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zc770_xm013_defconfig b/configs/zynq_zc770_xm013_defconfig index 3a02f75..a95970a 100644 --- a/configs/zynq_zc770_xm013_defconfig +++ b/configs/zynq_zc770_xm013_defconfig @@ -8,3 +8,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm013" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zed_defconfig b/configs/zynq_zed_defconfig index 1d816f6..0fbc41a 100644 --- a/configs/zynq_zed_defconfig +++ b/configs/zynq_zed_defconfig @@ -7,3 +7,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zed" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/configs/zynq_zybo_defconfig b/configs/zynq_zybo_defconfig index 9183629..4e66760 100644 --- a/configs/zynq_zybo_defconfig +++ b/configs/zynq_zybo_defconfig @@ -7,3 +7,4 @@ CONFIG_DEFAULT_DEVICE_TREE="zynq-zybo" CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y +CONFIG_DM=y diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index cc36985..1eb0ce7 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -24,6 +24,9 @@ # define CONFIG_LZO # ifdef CONFIG_ENABLE_VBOOT # define CONFIG_FIT_SIGNATURE +#ifndef CONFIG_DM +#define CONFIG_DM +#endif # define CONFIG_RSA # endif
Since you have moved CONFIG_FIT_SIGNATURE to Kconfig you can remove all of this and just add your options to configs/am335x_boneblack_vboot_defconfig instead. That is the only config which enables vboot.
#endif diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 6fd29b9..e9d3f32 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -23,7 +23,6 @@
#define CONFIG_BOOTSTAGE #define CONFIG_BOOTSTAGE_REPORT -#define CONFIG_DM #define CONFIG_CMD_DEMO #define CONFIG_CMD_DM #define CONFIG_DM_DEMO diff --git a/lib/Kconfig b/lib/Kconfig index 2455f7a..f317f81 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -29,9 +29,12 @@ config SYS_HZ
config RSA bool "Use RSA Library"
depends on DM help RSA support.This enables the RSA algorithm used for FIT image
verification in U-Boot.
verification in U-Boot. RSA support for Modular exponentiation
is implemented as a driver model. Driver Model should be enabled
to select this option.
I think you should drop this change. The fact that it depends on DM will be obvious from the depends line, and you won't see the option unless DM is enabled anyway.
See doc/uImage.FIT/signature.txt for more details.
endmenu diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 1d2e707..af915d3 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -12,6 +12,7 @@ #include <asm/errno.h> #include <asm/types.h> #include <asm/unaligned.h> +#include <dm.h> #else #include "fdt_host.h" #include "mkimage.h" @@ -44,6 +45,9 @@ static int rsa_verify_key(struct key_prop *prop, const uint8_t *sig, const uint8_t *padding; int pad_len; int ret; +#if !defined(USE_HOSTCC)
struct udevice *rsa_dev;
+#endif
if (!prop || !sig || !hash || !algo) return -EIO;
@@ -65,11 +69,26 @@ static int rsa_verify_key(struct key_prop *prop, const uint8_t *sig, uint8_t *buf; uint32_t buf_len;
+#if !defined(USE_HOSTCC)
ret = uclass_get_device(UCLASS_RSA, 0, &rsa_dev);
if (!ret) {
ret = rsa_mod_exp(rsa_dev, sig, sig_len, prop, &buf,
&buf_len);
if (ret) {
debug("Error in Modular exponentation\n");
return ret;
}
} else {
printf("RSA: Can't find Mod Exp implemnetation\n");
return -EINVAL;
}
+#else ret = rsa_mod_exp_sw(sig, sig_len, prop, &buf, &buf_len); if (ret) { debug("Error in Modular exponentation\n"); return ret; } +#endif
Please can you refactor to reduce duplication? Something like this (excuse formatting):
+#if !defined(USE_HOSTCC)
ret = uclass_get_device(UCLASS_RSA, 0, &rsa_dev);
if (ret)
printf("RSA: Can't find Mod Exp implemnetation\n"); - fix typo here!
return -EINVAL;
}
+ ret = rsa_mod_exp(rsa_dev, sig, sig_len, prop, &buf,
&buf_len);
+#else ret = rsa_mod_exp_sw(sig, sig_len, prop, &buf, &buf_len);
#endif
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");
-- 1.8.1.4
Regards, Simon

Driver added for RSA Modular Exponentiation using Freescale Hardware Accelerator CAAM. The driver used uclass rsa.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- Changes in v4: Modified for the changes in op function of rsa class mod_exp
Changes in v3: Moved to integrate with RSA UCLASS
drivers/crypto/Kconfig | 1 + drivers/crypto/fsl/Kconfig | 6 ++++ drivers/crypto/fsl/Makefile | 1 + drivers/crypto/fsl/fsl_rsa.c | 69 +++++++++++++++++++++++++++++++++++++++++++ drivers/crypto/fsl/jobdesc.c | 28 ++++++++++++++++++ drivers/crypto/fsl/jobdesc.h | 5 ++++ drivers/crypto/fsl/rsa_caam.h | 28 ++++++++++++++++++ 7 files changed, 138 insertions(+) create mode 100644 drivers/crypto/fsl/Kconfig create mode 100644 drivers/crypto/fsl/fsl_rsa.c create mode 100644 drivers/crypto/fsl/rsa_caam.h
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index e69de29..bd26a2b 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -0,0 +1 @@ +source drivers/crypto/fsl/Kconfig diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig new file mode 100644 index 0000000..86b2f2f --- /dev/null +++ b/drivers/crypto/fsl/Kconfig @@ -0,0 +1,6 @@ +config FSL_CAAM + bool "Freescale Crypto Driver Support" + help + Enables the Freescale's Cryptographic Accelerator and Assurance + Module (CAAM), also known as the SEC version 4 (SEC4). The driver uses + Job Ring as interface to communicate with CAAM. diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile index cb13d2e..db3c010 100644 --- a/drivers/crypto/fsl/Makefile +++ b/drivers/crypto/fsl/Makefile @@ -8,3 +8,4 @@
obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o obj-$(CONFIG_CMD_BLOB) += fsl_blob.o +obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o diff --git a/drivers/crypto/fsl/fsl_rsa.c b/drivers/crypto/fsl/fsl_rsa.c new file mode 100644 index 0000000..21156b2 --- /dev/null +++ b/drivers/crypto/fsl/fsl_rsa.c @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2014 Freescale Semiconductor, Inc. + * Author: Ruchika Gupta ruchika.gupta@freescale.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <common.h> +#include <dm.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 fsl_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len, + struct key_prop *prop, uint8_t **outp, uint32_t *out_len) +{ + uint32_t keylen; + struct pk_in_params pkin; + uint32_t desc[MAX_CAAM_DESCSIZE]; + int ret; + + /* Length in bytes */ + keylen = prop->num_bits / 8; + + *outp = malloc(sig_len); + if (!*outp) { + debug("%s: Out of malloc space\n", __func__); + return -EFAULT; + } + + printf("HW\n"); + 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, *outp, sig_len); + + ret = run_descriptor_jr(desc); + if (ret) { + debug("%s: RSA failed to verify: %d\n", __func__, ret); + return -EFAULT; + } + + *out_len = sig_len; + + return 0; +} + +static const struct rsa_ops fsl_rsa_ops = { + .mod_exp = fsl_mod_exp, +}; + +U_BOOT_DRIVER(fsl_rsa) = { + .name = "fsl_rsa", + .id = UCLASS_RSA, + .ops = &fsl_rsa_ops, +}; + +U_BOOT_DEVICE(fsl_rsa) = { + .name = "fsl_rsa", +}; 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..4ff87ef --- /dev/null +++ b/drivers/crypto/fsl/rsa_caam.h @@ -0,0 +1,28 @@ +/* + * Copyright 2014 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __RSA_CAAM_H +#define __RSA_CAAM_H + +#include <common.h> + +/** + * struct pk_in_params - holder for input to PKHA block in CAAM + * These parameters are required to perform Modular Exponentiation + * using 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

Kconfig option added for devices which support RSA Verification. 1. RSA_SOFTWARE_EXP Enables driver for supporting RSA Modular Exponentiation in Software 2. RSA_FREESCALE_EXP Enables driver for supporting RSA Modular Exponentiation using Freescale specific driver
The above drivers use RSA uclass
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- Changes in v4: Introduced 2 options when CONFIG_RSA is selected: RSA_SOFTWARE_EXP RSA_FREESCALE_EXP
Removed RSA_HW. Changes the name pf RSA_SW to RSA_SOFTWARE_EXP
Changes in v3: New patch
lib/Kconfig | 10 +--------- lib/rsa/Kconfig | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 lib/rsa/Kconfig
diff --git a/lib/Kconfig b/lib/Kconfig index f317f81..a1f30a2 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -27,14 +27,6 @@ config SYS_HZ get_timer() must operate in milliseconds and this option must be set to 1000.
-config RSA - bool "Use RSA Library" - depends on DM - help - RSA support.This enables the RSA algorithm used for FIT image - verification in U-Boot. RSA support for Modular exponentiation - is implemented as a driver model. Driver Model should be enabled - to select this option. - See doc/uImage.FIT/signature.txt for more details. +source lib/rsa/Kconfig
endmenu diff --git a/lib/rsa/Kconfig b/lib/rsa/Kconfig new file mode 100644 index 0000000..14155b9 --- /dev/null +++ b/lib/rsa/Kconfig @@ -0,0 +1,30 @@ +config RSA + bool "Use RSA Library" + depends on DM + select RSA_FREESCALE_EXP if FSL_CAAM + select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP + help + RSA support.This enables the RSA algorithm used for FIT image + verification in U-Boot. RSA support for Modular exponentiation + is implemented as a driver model. Driver Model should be enabled + to select this option. + See doc/uImage.FIT/signature.txt for more details. + +if RSA +config RSA_SOFTWARE_EXP + bool "Enable driver for RSA Modular Exponentiation in software" + depends on DM && RSA + help + Enables driver for modular exponentiation in software. This is a RSA + algorithm used in FIT image verification. It required RSA Key as + input. + See doc/uImage.FIT/signature.txt for more details. + +config RSA_FREESCALE_EXP + bool "Enable RSA Modular Exponentiation with FSL crypto accelerator" + depends on DM && RSA && FSL_CAAM + help + Enables driver for RSA modular exponentiation using Freescale cryptographic + accelerator - CAAM. + +endif

Hi Ruchika,
On 30 December 2014 at 02:30, Ruchika Gupta ruchika.gupta@freescale.com wrote:
Kconfig option added for devices which support RSA Verification.
- RSA_SOFTWARE_EXP
Enables driver for supporting RSA Modular Exponentiation in Software 2. RSA_FREESCALE_EXP Enables driver for supporting RSA Modular Exponentiation using Freescale specific driver
The above drivers use RSA uclass
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: Introduced 2 options when CONFIG_RSA is selected: RSA_SOFTWARE_EXP RSA_FREESCALE_EXP
Removed RSA_HW. Changes the name pf RSA_SW to RSA_SOFTWARE_EXP
Changes in v3: New patch
lib/Kconfig | 10 +--------- lib/rsa/Kconfig | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 lib/rsa/Kconfig
diff --git a/lib/Kconfig b/lib/Kconfig index f317f81..a1f30a2 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -27,14 +27,6 @@ config SYS_HZ get_timer() must operate in milliseconds and this option must be set to 1000.
-config RSA
bool "Use RSA Library"
depends on DM
help
RSA support.This enables the RSA algorithm used for FIT image
verification in U-Boot. RSA support for Modular exponentiation
is implemented as a driver model. Driver Model should be enabled
to select this option.
See doc/uImage.FIT/signature.txt for more details.
+source lib/rsa/Kconfig
endmenu diff --git a/lib/rsa/Kconfig b/lib/rsa/Kconfig new file mode 100644 index 0000000..14155b9 --- /dev/null +++ b/lib/rsa/Kconfig @@ -0,0 +1,30 @@ +config RSA
bool "Use RSA Library"
depends on DM
select RSA_FREESCALE_EXP if FSL_CAAM
select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP
help
RSA support.This enables the RSA algorithm used for FIT image
verification in U-Boot. RSA support for Modular exponentiation
is implemented as a driver model. Driver Model should be enabled
to select this option.
See doc/uImage.FIT/signature.txt for more details.
+if RSA +config RSA_SOFTWARE_EXP
bool "Enable driver for RSA Modular Exponentiation in software"
depends on DM && RSA
help
Enables driver for modular exponentiation in software. This is a RSA
algorithm used in FIT image verification. It required RSA Key as
input.
See doc/uImage.FIT/signature.txt for more details.
+config RSA_FREESCALE_EXP
Just for clarify, I think these names are fine, it's the naming of the uclass that I think should change. Perhaps UCLASS_MOD_EXP or UCLASS_RSA_MOD_EXP?
bool "Enable RSA Modular Exponentiation with FSL crypto accelerator"
depends on DM && RSA && FSL_CAAM
help
Enables driver for RSA modular exponentiation using Freescale cryptographic
accelerator - CAAM.
+endif
1.8.1.4
Regards, Simon

Hi Simon,
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Saturday, January 03, 2015 3:54 AM To: Gupta Ruchika-R66431 Cc: U-Boot Mailing List; Sun York-R58495 Subject: Re: [PATCH 7/9] [v4] lib/rsa: Add Kconfig for devices supporting RSA Modular Exponentiation
Hi Ruchika,
On 30 December 2014 at 02:30, Ruchika Gupta ruchika.gupta@freescale.com wrote:
Kconfig option added for devices which support RSA Verification.
- RSA_SOFTWARE_EXP
Enables driver for supporting RSA Modular Exponentiation in Software 2. RSA_FREESCALE_EXP Enables driver for supporting RSA Modular Exponentiation using Freescale specific driver
The above drivers use RSA uclass
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: Introduced 2 options when CONFIG_RSA is selected: RSA_SOFTWARE_EXP RSA_FREESCALE_EXP
Removed RSA_HW. Changes the name pf RSA_SW to RSA_SOFTWARE_EXP
Changes in v3: New patch
lib/Kconfig | 10 +--------- lib/rsa/Kconfig | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 lib/rsa/Kconfig
diff --git a/lib/Kconfig b/lib/Kconfig index f317f81..a1f30a2 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -27,14 +27,6 @@ config SYS_HZ get_timer() must operate in milliseconds and this option must be set to 1000.
-config RSA
bool "Use RSA Library"
depends on DM
help
RSA support.This enables the RSA algorithm used for FIT image
verification in U-Boot. RSA support for Modular exponentiation
is implemented as a driver model. Driver Model should be enabled
to select this option.
See doc/uImage.FIT/signature.txt for more details.
+source lib/rsa/Kconfig
endmenu diff --git a/lib/rsa/Kconfig b/lib/rsa/Kconfig new file mode 100644 index 0000000..14155b9 --- /dev/null +++ b/lib/rsa/Kconfig @@ -0,0 +1,30 @@ +config RSA
bool "Use RSA Library"
depends on DM
select RSA_FREESCALE_EXP if FSL_CAAM
select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP
help
RSA support.This enables the RSA algorithm used for FIT image
verification in U-Boot. RSA support for Modular exponentiation
is implemented as a driver model. Driver Model should be enabled
to select this option.
See doc/uImage.FIT/signature.txt for more details.
+if RSA +config RSA_SOFTWARE_EXP
bool "Enable driver for RSA Modular Exponentiation in software"
depends on DM && RSA
help
Enables driver for modular exponentiation in software. This is a
RSA
algorithm used in FIT image verification. It required RSA Key as
input.
See doc/uImage.FIT/signature.txt for more details.
+config RSA_FREESCALE_EXP
Just for clarify, I think these names are fine, it's the naming of the uclass that I think should change. Perhaps UCLASS_MOD_EXP or UCLASS_RSA_MOD_EXP?
I will change it in next version of patches.
bool "Enable RSA Modular Exponentiation with FSL crypto
accelerator"
depends on DM && RSA && FSL_CAAM
help
Enables driver for RSA modular exponentiation using Freescale
cryptographic
accelerator - CAAM.
+endif
1.8.1.4
Regards, Simon
Regards, Ruchika

The hash_algo structure has some implementations in which progressive hash API's are not defined. These are basically the hardware based implementations of SHA. An API is added to find the algo which has progressive hash API's defined. This can then be integrated with RSA checksum library which uses Progressive Hash API's.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- Changes in v4: Few cosmetic changes. Currently I have not replaced CONFIG_SHA1 with CONFIG_CMD_SHA1SUM. Waiting for reply from Simon and Denx for the same.
Changes in v3 : Corrected ifdef for SHA1
Changes in v2 : Added commit message
common/hash.c | 33 ++++++++++++++++++++++++--------- include/hash.h | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/common/hash.c b/common/hash.c index 12d6759..ea1ec60 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_SHA1 static int hash_init_sha1(struct hash_algo *algo, void **ctxp) { sha1_context *ctx = malloc(sizeof(sha1_context)); @@ -125,12 +125,7 @@ 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 +135,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha1, hash_finish_sha1, }, -#define MULTI_HASH #endif #ifdef CONFIG_SHA256 { @@ -152,7 +146,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha256, hash_finish_sha256, }, -#define MULTI_HASH #endif { "crc32", @@ -165,6 +158,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 +308,24 @@ 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..c0a7ebc 100644 --- a/include/hash.h +++ b/include/hash.h @@ -128,6 +128,20 @@ 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 hash_algo for prog. hash support + * + * 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 Ruchika,
On 30 December 2014 at 02:30, Ruchika Gupta ruchika.gupta@freescale.com wrote:
The hash_algo structure has some implementations in which progressive hash API's are not defined. These are basically the hardware based implementations of SHA. An API is added to find the algo which has progressive hash API's defined. This can then be integrated with RSA checksum library which uses Progressive Hash API's.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: Few cosmetic changes. Currently I have not replaced CONFIG_SHA1 with CONFIG_CMD_SHA1SUM. Waiting for reply from Simon and Denx for the same.
./tools/buildman/buildman -b try-rsa MPC8308RDB boards.cfg is up to date. Nothing to do. Building 10 commits for 1 boards (1 thread, 32 jobs per thread) 10 0 0 /10 MPC8308RDB (try-rsa=458103: asc) u> ./tools/buildman/buildman -b try-rsa MPC8308RDB -sS boards.cfg is up to date. Nothing to do. Summary of 10 commits for 1 boards (1 thread, 32 jobs per thread) 01: Merge branch 'master' of git://git.denx.de/u-boot-usb 02: rsa: Split the rsa-verify to separate the modular exponentiation 03: FIT: Modify option FIT_SIGNATURE in Kconfig 04: DM: crypto/rsa: Add rsa Modular Exponentiation DM driver 05: configs: Move CONFIG_FIT_SIGNATURE to defconfig 06: lib/rsa: Modify rsa to use DM driver 07: DM: crypto/fsl - Add Freescale rsa DM driver 08: lib/rsa: Add Kconfig for devices supporting RSA Modular Exponentiation 09: hash: Add function to find hash_algo struct with progressive hash powerpc: (for 1/1 boards) all +208.0 data +28.0 text +180.0 10: rsa: Use checksum algorithms from struct hash_algo (no errors to report) (try-rsa=458103: asc) u>
So this adds 180 bytes of code space. I really don't think that is a big problem, so I think this patch is fine. I'll Wolfgang chime in if he disagrees.
Changes in v3 : Corrected ifdef for SHA1
Changes in v2 : Added commit message
common/hash.c | 33 ++++++++++++++++++++++++--------- include/hash.h | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/common/hash.c b/common/hash.c index 12d6759..ea1ec60 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_SHA1 static int hash_init_sha1(struct hash_algo *algo, void **ctxp) { sha1_context *ctx = malloc(sizeof(sha1_context)); @@ -125,12 +125,7 @@ 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 +135,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha1, hash_finish_sha1, }, -#define MULTI_HASH #endif #ifdef CONFIG_SHA256 { @@ -152,7 +146,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha256, hash_finish_sha256, }, -#define MULTI_HASH #endif { "crc32", @@ -165,6 +158,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 +308,24 @@ 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;
}
}
}
Can't you just call hash_lookup_algo() and then check for hash_init?
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..c0a7ebc 100644 --- a/include/hash.h +++ b/include/hash.h @@ -128,6 +128,20 @@ 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 hash_algo for prog. hash support
- 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

Hi Simon,
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Saturday, January 03, 2015 3:54 AM To: Gupta Ruchika-R66431 Cc: U-Boot Mailing List; Sun York-R58495; Wolfgang Denk Subject: Re: [PATCH 8/9] [v4] hash: Add function to find hash_algo struct with progressive hash
Hi Ruchika,
On 30 December 2014 at 02:30, Ruchika Gupta ruchika.gupta@freescale.com wrote:
The hash_algo structure has some implementations in which progressive hash API's are not defined. These are basically the hardware based implementations of SHA. An API is added to find the algo which has progressive hash API's defined. This can then be integrated with RSA checksum library which uses Progressive Hash API's.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: Few cosmetic changes. Currently I have not replaced CONFIG_SHA1 with
CONFIG_CMD_SHA1SUM.
Waiting for reply from Simon and Denx for the same.
./tools/buildman/buildman -b try-rsa MPC8308RDB boards.cfg is up to date. Nothing to do. Building 10 commits for 1 boards (1 thread, 32 jobs per thread) 10 0 0 /10 MPC8308RDB (try-rsa=458103: asc) u> ./tools/buildman/buildman -b try-rsa MPC8308RDB -sS boards.cfg is up to date. Nothing to do. Summary of 10 commits for 1 boards (1 thread, 32 jobs per thread) 01: Merge branch 'master' of git://git.denx.de/u-boot-usb 02: rsa: Split the rsa-verify to separate the modular exponentiation 03: FIT: Modify option FIT_SIGNATURE in Kconfig 04: DM: crypto/rsa: Add rsa Modular Exponentiation DM driver 05: configs: Move CONFIG_FIT_SIGNATURE to defconfig 06: lib/rsa: Modify rsa to use DM driver 07: DM: crypto/fsl - Add Freescale rsa DM driver 08: lib/rsa: Add Kconfig for devices supporting RSA Modular Exponentiation 09: hash: Add function to find hash_algo struct with progressive hash powerpc: (for 1/1 boards) all +208.0 data +28.0 text +180.0 10: rsa: Use checksum algorithms from struct hash_algo (no errors to report) (try-rsa=458103: asc) u>
So this adds 180 bytes of code space. I really don't think that is a big problem, so I think this patch is fine. I'll Wolfgang chime in if he disagrees.
Changes in v3 : Corrected ifdef for SHA1
Changes in v2 : Added commit message
common/hash.c | 33 ++++++++++++++++++++++++--------- include/hash.h | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/common/hash.c b/common/hash.c index 12d6759..ea1ec60 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_SHA1 static int hash_init_sha1(struct hash_algo *algo, void **ctxp) { sha1_context *ctx = malloc(sizeof(sha1_context)); @@ -125,12 +125,7 @@ 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 +135,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha1, hash_finish_sha1, }, -#define MULTI_HASH #endif #ifdef CONFIG_SHA256 { @@ -152,7 +146,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha256, hash_finish_sha256, }, -#define MULTI_HASH #endif { "crc32", @@ -165,6 +158,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 +308,24 @@ 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;
}
}
}
Can't you just call hash_lookup_algo() and then check for hash_init?
Hash_lookup_algo always searches from the start of hash_algo[]. So what you have suggested above wouldn't work.
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..c0a7ebc 100644 --- a/include/hash.h +++ b/include/hash.h @@ -128,6 +128,20 @@ 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 hash_algo for prog. hash
+support
- 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
Regards, Ruchika

Hi Ruchika,
On 6 January 2015 at 02:38, Ruchika Gupta ruchika.gupta@freescale.com wrote:
Hi Simon,
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Saturday, January 03, 2015 3:54 AM To: Gupta Ruchika-R66431 Cc: U-Boot Mailing List; Sun York-R58495; Wolfgang Denk Subject: Re: [PATCH 8/9] [v4] hash: Add function to find hash_algo struct with progressive hash
Hi Ruchika,
On 30 December 2014 at 02:30, Ruchika Gupta ruchika.gupta@freescale.com wrote:
The hash_algo structure has some implementations in which progressive hash API's are not defined. These are basically the hardware based implementations of SHA. An API is added to find the algo which has progressive hash API's defined. This can then be integrated with RSA checksum library which uses Progressive Hash API's.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: Few cosmetic changes. Currently I have not replaced CONFIG_SHA1 with
CONFIG_CMD_SHA1SUM.
Waiting for reply from Simon and Denx for the same.
./tools/buildman/buildman -b try-rsa MPC8308RDB boards.cfg is up to date. Nothing to do. Building 10 commits for 1 boards (1 thread, 32 jobs per thread) 10 0 0 /10 MPC8308RDB (try-rsa=458103: asc) u> ./tools/buildman/buildman -b try-rsa MPC8308RDB -sS boards.cfg is up to date. Nothing to do. Summary of 10 commits for 1 boards (1 thread, 32 jobs per thread) 01: Merge branch 'master' of git://git.denx.de/u-boot-usb 02: rsa: Split the rsa-verify to separate the modular exponentiation 03: FIT: Modify option FIT_SIGNATURE in Kconfig 04: DM: crypto/rsa: Add rsa Modular Exponentiation DM driver 05: configs: Move CONFIG_FIT_SIGNATURE to defconfig 06: lib/rsa: Modify rsa to use DM driver 07: DM: crypto/fsl - Add Freescale rsa DM driver 08: lib/rsa: Add Kconfig for devices supporting RSA Modular Exponentiation 09: hash: Add function to find hash_algo struct with progressive hash powerpc: (for 1/1 boards) all +208.0 data +28.0 text +180.0 10: rsa: Use checksum algorithms from struct hash_algo (no errors to report) (try-rsa=458103: asc) u>
So this adds 180 bytes of code space. I really don't think that is a big problem, so I think this patch is fine. I'll Wolfgang chime in if he disagrees.
Changes in v3 : Corrected ifdef for SHA1
Changes in v2 : Added commit message
common/hash.c | 33 ++++++++++++++++++++++++--------- include/hash.h | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/common/hash.c b/common/hash.c index 12d6759..ea1ec60 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_SHA1 static int hash_init_sha1(struct hash_algo *algo, void **ctxp) { sha1_context *ctx = malloc(sizeof(sha1_context)); @@ -125,12 +125,7 @@ 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 +135,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha1, hash_finish_sha1, }, -#define MULTI_HASH #endif #ifdef CONFIG_SHA256 { @@ -152,7 +146,6 @@ static struct hash_algo hash_algo[] = { hash_update_sha256, hash_finish_sha256, }, -#define MULTI_HASH #endif { "crc32", @@ -165,6 +158,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 +308,24 @@ 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;
}
}
}
Can't you just call hash_lookup_algo() and then check for hash_init?
Hash_lookup_algo always searches from the start of hash_algo[]. So what you have suggested above wouldn't work.
OK I don't fully understand that, but let's go with what you have for this series.
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 hardware accelerated progressive hash API's once available.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org --- Changes in v4: No changes in this patch. Still under discussion
Changes in v3: Modified rsa-verify to check for return from checksum function
Changes in v2: Added generic function hash_calculate. Pass an additional argument as name of algorithm.
common/image-sig.c | 6 ++--- include/image.h | 5 ++-- include/u-boot/rsa-checksum.h | 17 ++++++++++---- lib/rsa/rsa-checksum.c | 53 +++++++++++++++++++++++++++++++++++++++---- lib/rsa/rsa-verify.c | 7 +++++- 5 files changed, 74 insertions(+), 14 deletions(-)
diff --git a/common/image-sig.c b/common/image-sig.c index 8601eda..2c9f0cd 100644 --- a/common/image-sig.c +++ b/common/image-sig.c @@ -38,7 +38,7 @@ struct checksum_algo checksum_algos[] = { #if IMAGE_ENABLE_SIGN EVP_sha1, #endif - sha1_calculate, + hash_calculate, padding_sha1_rsa2048, }, { @@ -48,7 +48,7 @@ struct checksum_algo checksum_algos[] = { #if IMAGE_ENABLE_SIGN EVP_sha256, #endif - sha256_calculate, + hash_calculate, padding_sha256_rsa2048, }, { @@ -58,7 +58,7 @@ struct checksum_algo checksum_algos[] = { #if IMAGE_ENABLE_SIGN EVP_sha256, #endif - sha256_calculate, + hash_calculate, padding_sha256_rsa4096, }
diff --git a/include/image.h b/include/image.h index af30d60..ec55f23 100644 --- a/include/image.h +++ b/include/image.h @@ -926,8 +926,9 @@ struct checksum_algo { #if IMAGE_ENABLE_SIGN const EVP_MD *(*calculate_sign)(void); #endif - void (*calculate)(const struct image_region region[], - int region_count, uint8_t *checksum); + int (*calculate)(const char *name, + 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..3c69d85 100644 --- a/include/u-boot/rsa-checksum.h +++ b/include/u-boot/rsa-checksum.h @@ -16,9 +16,18 @@ 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, - uint8_t *checksum); -void sha1_calculate(const struct image_region region[], int region_count, - uint8_t *checksum); +/** + * hash_calculate() - Calculate hash over the data + * + * @name: Name of algorithm to be used for hash calculation + * @region: Array having info of regions over which hash needs to be calculated + * @region_count: Number of regions in the region array + * @checksum: Buffer contanining the output hash + * + * @return 0 if OK, < 0 if error + */ +int hash_calculate(const char *name, + 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..7f1909a 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,33 @@ 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 +int hash_calculate(const char *name, + const struct image_region region[], + int region_count, uint8_t *checksum) +{ + struct hash_algo *algo; + int ret = 0; + void *ctx; + uint32_t i; + i = 0; + + ret = hash_progressive_lookup_algo(name, &algo); + if (ret) + return ret; + + 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); + + return 0; +} + +#else +int sha1_calculate(const struct image_region region[], int region_count, uint8_t *checksum) { sha1_context ctx; @@ -147,9 +174,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 +189,20 @@ 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; } + +int hash_calculate(const char *name, + const struct image_region region[], int region_count, + uint8_t *checksum) +{ + if (!strcmp(name, "sha1")) + sha1_calculate(region, region_count, checksum); + + if (!strcmp(name, "sha256")) + sha256_calculate(region, region_count, checksum); + + return 0; +} +#endif diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index af915d3..cf5acdf 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -201,7 +201,12 @@ int rsa_verify(struct image_sign_info *info, }
/* Calculate checksum with checksum-algorithm */ - info->algo->checksum->calculate(region, region_count, hash); + ret = info->algo->checksum->calculate(info->algo->checksum->name, + region, region_count, hash); + if (ret < 0) { + debug("%s: Error in checksum calculation\n", __func__); + return -EINVAL; + }
/* See if we must use a particular key */ if (info->required_keynode != -1) {

Hi Ruchika,
On 30 December 2014 at 02:30, 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 hardware accelerated progressive hash API's once available.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: No changes in this patch. Still under discussion
Changes in v3: Modified rsa-verify to check for return from checksum function
Changes in v2: Added generic function hash_calculate. Pass an additional argument as name of algorithm.
common/image-sig.c | 6 ++--- include/image.h | 5 ++-- include/u-boot/rsa-checksum.h | 17 ++++++++++---- lib/rsa/rsa-checksum.c | 53 +++++++++++++++++++++++++++++++++++++++---- lib/rsa/rsa-verify.c | 7 +++++- 5 files changed, 74 insertions(+), 14 deletions(-)
diff --git a/common/image-sig.c b/common/image-sig.c index 8601eda..2c9f0cd 100644 --- a/common/image-sig.c +++ b/common/image-sig.c @@ -38,7 +38,7 @@ struct checksum_algo checksum_algos[] = { #if IMAGE_ENABLE_SIGN EVP_sha1, #endif
sha1_calculate,
hash_calculate, padding_sha1_rsa2048, }, {
@@ -48,7 +48,7 @@ struct checksum_algo checksum_algos[] = { #if IMAGE_ENABLE_SIGN EVP_sha256, #endif
sha256_calculate,
hash_calculate, padding_sha256_rsa2048, }, {
@@ -58,7 +58,7 @@ struct checksum_algo checksum_algos[] = { #if IMAGE_ENABLE_SIGN EVP_sha256, #endif
sha256_calculate,
hash_calculate, padding_sha256_rsa4096, }
diff --git a/include/image.h b/include/image.h index af30d60..ec55f23 100644 --- a/include/image.h +++ b/include/image.h @@ -926,8 +926,9 @@ struct checksum_algo { #if IMAGE_ENABLE_SIGN const EVP_MD *(*calculate_sign)(void); #endif
void (*calculate)(const struct image_region region[],
int region_count, uint8_t *checksum);
int (*calculate)(const char *name,
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..3c69d85 100644 --- a/include/u-boot/rsa-checksum.h +++ b/include/u-boot/rsa-checksum.h @@ -16,9 +16,18 @@ 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,
uint8_t *checksum);
-void sha1_calculate(const struct image_region region[], int region_count,
uint8_t *checksum);
+/**
- hash_calculate() - Calculate hash over the data
- @name: Name of algorithm to be used for hash calculation
- @region: Array having info of regions over which hash needs to be calculated
- @region_count: Number of regions in the region array
- @checksum: Buffer contanining the output hash
- @return 0 if OK, < 0 if error
- */
+int hash_calculate(const char *name,
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..7f1909a 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,33 @@ 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 +int hash_calculate(const char *name,
const struct image_region region[],
int region_count, uint8_t *checksum)
+{
struct hash_algo *algo;
int ret = 0;
void *ctx;
uint32_t i;
i = 0;
ret = hash_progressive_lookup_algo(name, &algo);
if (ret)
return ret;
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);
Shouldn't you have error checking on these calls?
return 0;
+}
+#else
It seems odd to duplicate this code. I'll email you a WIP patch to correct this. Perhaps you could tidy it up and attach it to your series? Then I think you can remove this #else part.
+int sha1_calculate(const struct image_region region[], int region_count, uint8_t *checksum) { sha1_context ctx; @@ -147,9 +174,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 +189,20 @@ 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;
}
+int hash_calculate(const char *name,
const struct image_region region[], int region_count,
uint8_t *checksum)
+{
if (!strcmp(name, "sha1"))
sha1_calculate(region, region_count, checksum);
if (!strcmp(name, "sha256"))
sha256_calculate(region, region_count, checksum);
return 0;
+} +#endif diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index af915d3..cf5acdf 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -201,7 +201,12 @@ int rsa_verify(struct image_sign_info *info, }
/* Calculate checksum with checksum-algorithm */
info->algo->checksum->calculate(region, region_count, hash);
ret = info->algo->checksum->calculate(info->algo->checksum->name,
region, region_count, hash);
if (ret < 0) {
debug("%s: Error in checksum calculation\n", __func__);
return -EINVAL;
} /* See if we must use a particular key */ if (info->required_keynode != -1) {
-- 1.8.1.4
Regards, Simon

Hi Simon,
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Saturday, January 03, 2015 3:55 AM To: Gupta Ruchika-R66431 Cc: U-Boot Mailing List; Sun York-R58495 Subject: Re: [PATCH 9/9] [v4] rsa: Use checksum algorithms from struct hash_algo
Hi Ruchika,
On 30 December 2014 at 02:30, 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 hardware accelerated progressive hash
API's once available.
Signed-off-by: Ruchika Gupta ruchika.gupta@freescale.com CC: Simon Glass sjg@chromium.org
Changes in v4: No changes in this patch. Still under discussion
Changes in v3: Modified rsa-verify to check for return from checksum function
Changes in v2: Added generic function hash_calculate. Pass an additional argument as name of algorithm.
common/image-sig.c | 6 ++--- include/image.h | 5 ++-- include/u-boot/rsa-checksum.h | 17 ++++++++++---- lib/rsa/rsa-checksum.c | 53
+++++++++++++++++++++++++++++++++++++++----
lib/rsa/rsa-verify.c | 7 +++++- 5 files changed, 74 insertions(+), 14 deletions(-)
diff --git a/common/image-sig.c b/common/image-sig.c index 8601eda..2c9f0cd 100644 --- a/common/image-sig.c +++ b/common/image-sig.c @@ -38,7 +38,7 @@ struct checksum_algo checksum_algos[] = { #if IMAGE_ENABLE_SIGN EVP_sha1, #endif
sha1_calculate,
hash_calculate, padding_sha1_rsa2048, }, {
@@ -48,7 +48,7 @@ struct checksum_algo checksum_algos[] = { #if IMAGE_ENABLE_SIGN EVP_sha256, #endif
sha256_calculate,
hash_calculate, padding_sha256_rsa2048, }, {
@@ -58,7 +58,7 @@ struct checksum_algo checksum_algos[] = { #if IMAGE_ENABLE_SIGN EVP_sha256, #endif
sha256_calculate,
hash_calculate, padding_sha256_rsa4096, }
diff --git a/include/image.h b/include/image.h index af30d60..ec55f23 100644 --- a/include/image.h +++ b/include/image.h @@ -926,8 +926,9 @@ struct checksum_algo { #if IMAGE_ENABLE_SIGN const EVP_MD *(*calculate_sign)(void); #endif
void (*calculate)(const struct image_region region[],
int region_count, uint8_t *checksum);
int (*calculate)(const char *name,
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..3c69d85 100644 --- a/include/u-boot/rsa-checksum.h +++ b/include/u-boot/rsa-checksum.h @@ -16,9 +16,18 @@ 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,
uint8_t *checksum);
-void sha1_calculate(const struct image_region region[], int region_count,
uint8_t *checksum);
+/**
- hash_calculate() - Calculate hash over the data
- @name: Name of algorithm to be used for hash calculation
- @region: Array having info of regions over which hash needs to be
+calculated
- @region_count: Number of regions in the region array
- @checksum: Buffer contanining the output hash
- @return 0 if OK, < 0 if error
- */
+int hash_calculate(const char *name,
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..7f1909a 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,33 @@ 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 +int hash_calculate(const char *name,
const struct image_region region[],
int region_count, uint8_t *checksum) {
struct hash_algo *algo;
int ret = 0;
void *ctx;
uint32_t i;
i = 0;
ret = hash_progressive_lookup_algo(name, &algo);
if (ret)
return ret;
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);
Shouldn't you have error checking on these calls?
I will add the checks
return 0;
+}
+#else
It seems odd to duplicate this code. I'll email you a WIP patch to correct this. Perhaps you could tidy it up and attach it to your series? Then I think you can remove this #else part.
I will try the WIP patch to see I this can be corrected.
+int sha1_calculate(const struct image_region region[], int +region_count, uint8_t *checksum) { sha1_context ctx; @@ -147,9 +174,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 +189,20 @@ 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;
}
+int hash_calculate(const char *name,
const struct image_region region[], int region_count,
uint8_t *checksum)
+{
if (!strcmp(name, "sha1"))
sha1_calculate(region, region_count, checksum);
if (!strcmp(name, "sha256"))
sha256_calculate(region, region_count, checksum);
return 0;
+} +#endif diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index af915d3..cf5acdf 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -201,7 +201,12 @@ int rsa_verify(struct image_sign_info *info, }
/* Calculate checksum with checksum-algorithm */
info->algo->checksum->calculate(region, region_count, hash);
ret = info->algo->checksum->calculate(info->algo->checksum->name,
region, region_count, hash);
if (ret < 0) {
debug("%s: Error in checksum calculation\n", __func__);
return -EINVAL;
} /* See if we must use a particular key */ if (info->required_keynode != -1) {
-- 1.8.1.4
Regards, Simon
Regards, Ruchika

Hi Ruchika,
On 30 December 2014 at 02:30, Ruchika Gupta ruchika.gupta@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.
- 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.
- 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@freescale.com CC: Simon Glass sjg@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
participants (2)
-
Ruchika Gupta
-
Simon Glass