
Separate out the SHA1 code from the rsa-sign.c and rsa-verify.c . Each file now has a function which does the correct hashing operation instead of having the SHA-1 hashing operation hard-coded in the rest of the code. This makes adding a new hashing operating much easier and cleaner.
Signed-off-by: Marek Vasut marex@denx.de --- lib/rsa/rsa-sign.c | 45 ++++++++++++++++++++++++-- lib/rsa/rsa-verify.c | 89 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 110 insertions(+), 24 deletions(-)
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c index 549130e..4e11720 100644 --- a/lib/rsa/rsa-sign.c +++ b/lib/rsa/rsa-sign.c @@ -15,6 +15,11 @@ #include <openssl/ssl.h> #include <openssl/evp.h>
+enum rsa_hash_type { + RSA_HASH_SHA1, + RSA_HASH_UNKNOWN, +}; + #if OPENSSL_VERSION_NUMBER >= 0x10000000L #define HAVE_ERR_REMOVE_THREAD_STATE #endif @@ -159,7 +164,19 @@ static void rsa_remove(void) EVP_cleanup(); }
-static int rsa_sign_with_key(RSA *rsa, const struct image_region region[], +static const EVP_MD *rsa_sign_get_hash(enum rsa_hash_type hash) +{ + switch (hash) { + case RSA_HASH_SHA1: + return EVP_sha1(); + default: /* This must never happen. */ + rsa_err("Invalid hash type!\n"); + exit(1); + }; +} + +static int rsa_sign_with_key(RSA *rsa, enum rsa_hash_type hash, + const struct image_region region[], int region_count, uint8_t **sigp, uint *sig_size) { EVP_PKEY *key; @@ -192,7 +209,7 @@ static int rsa_sign_with_key(RSA *rsa, const struct image_region region[], goto err_create; } EVP_MD_CTX_init(context); - if (!EVP_SignInit(context, EVP_sha1())) { + if (!EVP_SignInit(context, rsa_sign_get_hash(hash))) { ret = rsa_err("Signer setup failed"); goto err_sign; } @@ -228,12 +245,34 @@ err_set: return ret; }
+static enum rsa_hash_type rsa_get_sha_type(struct image_sign_info *info) +{ + char *pos; + unsigned int hash_str_len; + + pos = strstr(info->algo->name, ","); + if (!pos) + return -EINVAL; + + hash_str_len = pos - info->algo->name; + + if (!strncmp(info->algo->name, "sha1", hash_str_len)) + return RSA_HASH_SHA1; + else + return RSA_HASH_UNKNOWN; +} + int rsa_sign(struct image_sign_info *info, const struct image_region region[], int region_count, uint8_t **sigp, uint *sig_len) { RSA *rsa; int ret; + enum rsa_hash_type hash; + + hash = rsa_get_sha_type(info); + if (hash == RSA_HASH_UNKNOWN) + return -EINVAL;
ret = rsa_init(); if (ret) @@ -242,7 +281,7 @@ int rsa_sign(struct image_sign_info *info, ret = rsa_get_priv_key(info->keydir, info->keyname, &rsa); if (ret) goto err_priv; - ret = rsa_sign_with_key(rsa, region, region_count, sigp, sig_len); + ret = rsa_sign_with_key(rsa, hash, region, region_count, sigp, sig_len); if (ret) goto err_sign;
diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 02cc4e3..9617f8d 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -6,6 +6,7 @@
#include <common.h> #include <fdtdec.h> +#include <malloc.h> #include <rsa.h> #include <sha1.h> #include <asm/byteorder.h> @@ -209,10 +210,9 @@ static int pow_mod(const struct rsa_public_key *key, uint32_t *inout) }
static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig, - const uint32_t sig_len, const uint8_t *hash) + const uint32_t sig_len, const uint8_t *hash, + const uint8_t *padding, int pad_len) { - const uint8_t *padding; - int pad_len; int ret;
if (!key || !sig || !hash) @@ -238,10 +238,6 @@ static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig, if (ret) return ret;
- /* Determine padding to use depending on the signature type. */ - padding = padding_sha1_rsa2048; - pad_len = RSA2048_BYTES - SHA1_SUM_LEN; - /* Check pkcs1.5 padding bytes. */ if (memcmp(buf, padding, pad_len)) { debug("In RSAVerify(): Padding check failed!\n"); @@ -266,7 +262,8 @@ static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len) }
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 uint8_t *padding, int pad_len) { const void *blob = info->fdt_blob; struct rsa_public_key key; @@ -309,7 +306,7 @@ static int rsa_verify_with_keynode(struct image_sign_info *info, }
debug("key length %d\n", key.len); - ret = rsa_verify_key(&key, sig, sig_len, hash); + ret = rsa_verify_key(&key, sig, sig_len, hash, padding, pad_len); if (ret) { printf("%s: RSA failed to verify: %d\n", __func__, ret); return ret; @@ -318,17 +315,64 @@ static int rsa_verify_with_keynode(struct image_sign_info *info, return 0; }
+static int +rsa_compute_hash_sha1(const struct image_region region[], int region_count, + uint8_t **out_hash) +{ + sha1_context ctx; + int i; + uint8_t *hash; + + hash = calloc(1, SHA1_SUM_LEN); + if (!hash) + return -ENOMEM; + + sha1_starts(&ctx); + for (i = 0; i < region_count; i++) + sha1_update(&ctx, region[i].data, region[i].size); + sha1_finish(&ctx, hash); + + *out_hash = hash; + + return 0; +} + +static int rsa_compute_hash(struct image_sign_info *info, + const struct image_region region[], int region_count, + uint8_t **out_hash, const uint8_t **padding, + int *pad_len) +{ + int len, ret; + const uint8_t *pad; + + if (!strcmp(info->algo->name, "sha1,rsa2048")) { + pad = padding_sha1_rsa2048; + len = RSA2048_BYTES - SHA1_SUM_LEN; + ret = rsa_compute_hash_sha1(region, region_count, out_hash); + } else { + ret = -EINVAL; + } + + if (!ret) { + *padding = pad; + *pad_len = len; + } + + return ret; +} + int rsa_verify(struct image_sign_info *info, const struct image_region region[], int region_count, uint8_t *sig, uint sig_len) { const void *blob = info->fdt_blob; - uint8_t hash[SHA1_SUM_LEN]; + uint8_t *hash = NULL; int ndepth, noffset; int sig_node, node; char name[100]; - sha1_context ctx; - int ret, i; + const uint8_t *padding; + int pad_len; + int ret;
sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME); if (sig_node < 0) { @@ -336,25 +380,26 @@ int rsa_verify(struct image_sign_info *info, return -ENOENT; }
- sha1_starts(&ctx); - for (i = 0; i < region_count; i++) - sha1_update(&ctx, region[i].data, region[i].size); - sha1_finish(&ctx, hash); + ret = rsa_compute_hash(info, region, region_count, &hash, + &padding, &pad_len); + if (ret) + return ret;
/* See if we must use a particular key */ if (info->required_keynode != -1) { ret = rsa_verify_with_keynode(info, hash, sig, sig_len, - info->required_keynode); + info->required_keynode, padding, pad_len); if (!ret) - return ret; + goto exit; }
/* Look for a key that matches our hint */ snprintf(name, sizeof(name), "key-%s", info->keyname); node = fdt_subnode_offset(blob, sig_node, name); - ret = rsa_verify_with_keynode(info, hash, sig, sig_len, node); + ret = rsa_verify_with_keynode(info, hash, sig, sig_len, node, + padding, pad_len); if (!ret) - return ret; + goto exit;
/* No luck, so try each of the keys in turn */ for (ndepth = 0, noffset = fdt_next_node(info->fit, sig_node, &ndepth); @@ -362,11 +407,13 @@ int rsa_verify(struct image_sign_info *info, noffset = fdt_next_node(info->fit, noffset, &ndepth)) { if (ndepth == 1 && noffset != node) { ret = rsa_verify_with_keynode(info, hash, sig, sig_len, - noffset); + noffset, padding, pad_len); if (!ret) break; } }
+exit: + free(hash); return ret; }