[U-Boot] [PATCH 2/3] fit: rsa: Add groundwork to support other hashes

Marek Vasut
2014-02-06T03:47:05Z

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;
}
--
1.8.5.3