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

Marek Vasut marex at denx.de
Thu Feb 6 04:47:05 CET 2014


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 at 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



More information about the U-Boot mailing list