From patchwork Thu Feb 6 03:47:05 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 317329 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id E70D02C009C for ; Thu, 6 Feb 2014 14:47:20 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8B7634B8B9; Thu, 6 Feb 2014 04:47:19 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 4ZIjKUT+M+ch; Thu, 6 Feb 2014 04:47:19 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id CE5194B8E4; Thu, 6 Feb 2014 04:47:16 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 9A0244B8E4 for ; Thu, 6 Feb 2014 04:47:14 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id kl-OWqdiu6yR for ; Thu, 6 Feb 2014 04:47:11 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-out.m-online.net (mail-out.m-online.net [212.18.0.10]) by theia.denx.de (Postfix) with ESMTPS id 473CB4B8B9 for ; Thu, 6 Feb 2014 04:47:09 +0100 (CET) Received: from frontend1.mail.m-online.net (frontend1.mail.intern.m-online.net [192.168.8.180]) by mail-out.m-online.net (Postfix) with ESMTP id 3fKQZ555hPz3hhn3; Thu, 6 Feb 2014 04:47:09 +0100 (CET) X-Auth-Info: oZYsd3FOSCbPt3DWrrGPIxVB36C+dWsPVkjikqjWCgw= Received: from chi.lan (unknown [195.140.253.167]) by smtp-auth.mnet-online.de (Postfix) with ESMTPA id 3fKQZ5490fzbbj1; Thu, 6 Feb 2014 04:47:09 +0100 (CET) From: Marek Vasut To: u-boot@lists.denx.de Date: Thu, 6 Feb 2014 04:47:05 +0100 Message-Id: <1391658426-24799-2-git-send-email-marex@denx.de> X-Mailer: git-send-email 1.8.5.3 In-Reply-To: <1391658426-24799-1-git-send-email-marex@denx.de> References: <1391658426-24799-1-git-send-email-marex@denx.de> Cc: Marek Vasut Subject: [U-Boot] [PATCH 2/3] fit: rsa: Add groundwork to support other hashes X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 --- 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 #include +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 #include +#include #include #include #include @@ -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; }