From patchwork Wed Nov 14 12:51:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philippe REYNES X-Patchwork-Id: 997694 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=softathome.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 42w4D76lnnz9s8J for ; Wed, 14 Nov 2018 23:53:11 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 88043C22094; Wed, 14 Nov 2018 12:52:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=KHOP_BIG_TO_CC autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 44CA4C220A6; Wed, 14 Nov 2018 12:51:25 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id D7A1BC22094; Wed, 14 Nov 2018 12:51:21 +0000 (UTC) Received: from vrout10.yaziba.net (vrout10-bl2.yaziba.net [185.56.204.56]) by lists.denx.de (Postfix) with ESMTPS id 72C33C2208E for ; Wed, 14 Nov 2018 12:51:21 +0000 (UTC) Received: from mtaout10.int.yaziba.net (mtaout10.int.yaziba.net [10.4.20.36]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by vrout10.yaziba.net (mx10.yaziba.net) with ESMTPS id 6362252015; Wed, 14 Nov 2018 13:51:20 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mtaout10.int.yaziba.net (Postfix) with ESMTP id A7AE0160320; Wed, 14 Nov 2018 13:51:19 +0100 (CET) X-Virus-Scanned: amavisd-new at Received: from mtaout10.int.yaziba.net ([127.0.0.1]) by localhost (mtaout10.int.yaziba.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZXP6RKuZ4xfd; Wed, 14 Nov 2018 13:51:19 +0100 (CET) Received: from sahnlpt0333.softathome.com (unknown [149.6.166.170]) by mtaout10.int.yaziba.net (Postfix) with ESMTPSA id 6F222160304; Wed, 14 Nov 2018 13:51:19 +0100 (CET) From: Philippe Reynes To: sjg@chromium.org, michal.simek@xilinx.com, joe.hershberger@ni.com, marex@denx.de, yamada.masahiro@socionext.com, aford173@gmail.com, woods.technical@gmail.com, alex.kiernan@gmail.com, jun.nie@linaro.org, lokeshvutla@ti.com, peng.fan@nxp.com, andre.przywara@arm.com, keguang.zhang@gmail.com, teddy.reed@gmail.com, philipp.tomsich@theobroma-systems.com, rick@andestech.com, bin.chen@linaro.org, nomble@palism.com, jsg@jsg.id.au, swarren@nvidia.com, paul.burton@mips.com Date: Wed, 14 Nov 2018 13:51:01 +0100 Message-Id: <1542199865-26068-3-git-send-email-philippe.reynes@softathome.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1542199865-26068-1-git-send-email-philippe.reynes@softathome.com> References: <1542199865-26068-1-git-send-email-philippe.reynes@softathome.com> X-DRWEB-SCAN: ok X-CLAMAV-SCAN: ok X-VRSPAM-SCORE: 0 X-VRSPAM-STATE: legit X-VRSPAM-CAUSE: gggruggvucftvghtrhhoucdtuddrgedtkedrleefgdeghecutefuodetggdotefrucfrrhhofhhilhgvmecuggftfghnshhusghstghrihgsvgenuceurghilhhouhhtmecufedttdenucenucfjughrpefhvffufffkofgjfhestddtredtredttdenucfhrhhomheprfhhihhlihhpphgvucftvgihnhgvshcuoehphhhilhhiphhpvgdrrhgvhihnvghssehsohhfthgrthhhohhmvgdrtghomheqnecuffhomhgrihhnpehivghtfhdrohhrghenucfkphepudegledriedrudeiiedrudejtdenucfrrghrrghmpehmohguvgepshhmthhpohhuth X-VRSPAM-EXTCAUSE: mhhouggvpehsmhhtphhouhht Cc: u-boot@lists.denx.de Subject: [U-Boot] [PATCH V4 3/7] rsa: add support of padding pss X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" We add the support of the padding pss for rsa signature. This new padding is often recommended instead of pkcs-1.5. Signed-off-by: Philippe Reynes Reviewed-by: Simon Glass --- Kconfig | 8 +++ common/image-sig.c | 6 ++ include/image.h | 1 + include/u-boot/rsa.h | 15 ++++ lib/rsa/rsa-sign.c | 10 +++ lib/rsa/rsa-verify.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 230 insertions(+) Changelog: v4: - remove Reviewed-by Clement Peron (added by mistake) v3: - no change v2: - add a Kconfig option (thanks Simon Glass) - some code cleaning (thanks Simon Glass) diff --git a/Kconfig b/Kconfig index dca9bb4..3120553 100644 --- a/Kconfig +++ b/Kconfig @@ -290,6 +290,14 @@ config FIT_SIGNATURE_MAX_SIZE device memory. Assure this size does not extend past expected storage space. +config FIT_ENABLE_RSASSA_PSS_SUPPORT + bool "Support rsassa-pss signature scheme of FIT image contents" + depends on FIT_SIGNATURE + default n + help + Enable this to support the pss padding algorithm as described + in the rfc8017 (https://tools.ietf.org/html/rfc8017). + config FIT_VERBOSE bool "Show verbose messages when FIT images fail" help diff --git a/common/image-sig.c b/common/image-sig.c index b7ca657..f5ce3b2 100644 --- a/common/image-sig.c +++ b/common/image-sig.c @@ -76,6 +76,12 @@ struct padding_algo padding_algos[] = { .name = "pkcs-1.5", .verify = padding_pkcs_15_verify, }, +#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT + { + .name = "pss", + .verify = padding_pss_verify, + } +#endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */ }; struct checksum_algo *image_get_checksum_algo(const char *full_name) diff --git a/include/image.h b/include/image.h index 7fed0ae..f4c5a15 100644 --- a/include/image.h +++ b/include/image.h @@ -30,6 +30,7 @@ struct fdt_region; #define IMAGE_ENABLE_FIT 1 #define IMAGE_ENABLE_OF_LIBFDT 1 #define CONFIG_FIT_VERBOSE 1 /* enable fit_format_{error,warning}() */ +#define CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT 1 #define CONFIG_FIT_ENABLE_SHA256_SUPPORT #define CONFIG_SHA1 #define CONFIG_SHA256 diff --git a/include/u-boot/rsa.h b/include/u-boot/rsa.h index 16b4c4c..2d3024d 100644 --- a/include/u-boot/rsa.h +++ b/include/u-boot/rsa.h @@ -101,6 +101,12 @@ int rsa_verify(struct image_sign_info *info, int padding_pkcs_15_verify(struct image_sign_info *info, uint8_t *msg, int msg_len, const uint8_t *hash, int hash_len); + +#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT +int padding_pss_verify(struct image_sign_info *info, + uint8_t *msg, int msg_len, + const uint8_t *hash, int hash_len); +#endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */ #else static inline int rsa_verify(struct image_sign_info *info, const struct image_region region[], int region_count, @@ -115,6 +121,15 @@ static inline int padding_pkcs_15_verify(struct image_sign_info *info, { return -ENXIO; } + +#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT +static inline int padding_pss_verify(struct image_sign_info *info, + uint8_t *msg, int msg_len, + const uint8_t *hash, int hash_len) +{ + return -ENXIO; +} +#endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */ #endif #define RSA_DEFAULT_PADDING_NAME "pkcs-1.5" diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c index 6aa0e2a..fb5e07b 100644 --- a/lib/rsa/rsa-sign.c +++ b/lib/rsa/rsa-sign.c @@ -438,6 +438,16 @@ static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo, goto err_sign; } +#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT + if (padding_algo && !strcmp(padding_algo->name, "pss")) { + if (EVP_PKEY_CTX_set_rsa_padding(ckey, + RSA_PKCS1_PSS_PADDING) <= 0) { + ret = rsa_err("Signer padding setup failed"); + goto err_sign; + } + } +#endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */ + for (i = 0; i < region_count; i++) { if (!EVP_DigestSignUpdate(context, region[i].data, region[i].size)) { diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 279a9ba..9734f6d 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -80,6 +80,196 @@ int padding_pkcs_15_verify(struct image_sign_info *info, return 0; } +#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT +static void u32_i2osp(uint32_t val, uint8_t *buf) +{ + buf[0] = (uint8_t)((val >> 24) & 0xff); + buf[1] = (uint8_t)((val >> 16) & 0xff); + buf[2] = (uint8_t)((val >> 8) & 0xff); + buf[3] = (uint8_t)((val >> 0) & 0xff); +} + +/** + * mask_generation_function1() - generate an octet string + * + * Generate an octet string used to check rsa signature. + * It use an input octet string and a hash function. + * + * @checksum: A Hash function + * @seed: Specifies an input variable octet string + * @seed_len: Size of the input octet string + * @output: Specifies the output octet string + * @output_len: Size of the output octet string + * @return 0 if the octet string was correctly generated, others on error + */ +static int mask_generation_function1(struct checksum_algo *checksum, + uint8_t *seed, int seed_len, + uint8_t *output, int output_len) +{ + struct image_region region[2]; + int ret = 0, i, i_output = 0, region_count = 2; + uint32_t counter = 0; + uint8_t buf_counter[4], *tmp; + int hash_len = checksum->checksum_len; + + memset(output, 0, output_len); + + region[0].data = seed; + region[0].size = seed_len; + region[1].data = &buf_counter[0]; + region[1].size = 4; + + tmp = malloc(hash_len); + if (!tmp) { + debug("%s: can't allocate array tmp\n", __func__); + ret = -ENOMEM; + goto out; + } + + while (i_output < output_len) { + u32_i2osp(counter, &buf_counter[0]); + + ret = checksum->calculate(checksum->name, + region, region_count, + tmp); + if (ret < 0) { + debug("%s: Error in checksum calculation\n", __func__); + goto out; + } + + i = 0; + while ((i_output < output_len) && (i < hash_len)) { + output[i_output] = tmp[i]; + i_output++; + i++; + } + + counter++; + } + +out: + free(tmp); + + return ret; +} + +static int compute_hash_prime(struct checksum_algo *checksum, + uint8_t *pad, int pad_len, + uint8_t *hash, int hash_len, + uint8_t *salt, int salt_len, + uint8_t *hprime) +{ + struct image_region region[3]; + int ret, region_count = 3; + + region[0].data = pad; + region[0].size = pad_len; + region[1].data = hash; + region[1].size = hash_len; + region[2].data = salt; + region[2].size = salt_len; + + ret = checksum->calculate(checksum->name, region, region_count, hprime); + if (ret < 0) { + debug("%s: Error in checksum calculation\n", __func__); + goto out; + } + +out: + return ret; +} + +int padding_pss_verify(struct image_sign_info *info, + uint8_t *msg, int msg_len, + const uint8_t *hash, int hash_len) +{ + uint8_t *masked_db = NULL; + int masked_db_len = msg_len - hash_len - 1; + uint8_t *h = NULL, *hprime = NULL; + int h_len = hash_len; + uint8_t *db_mask = NULL; + int db_mask_len = masked_db_len; + uint8_t *db = NULL, *salt = NULL; + int db_len = masked_db_len, salt_len = msg_len - hash_len - 2; + uint8_t pad_zero[8] = { 0 }; + int ret, i, leftmost_bits = 1; + uint8_t leftmost_mask; + struct checksum_algo *checksum = info->checksum; + + /* first, allocate everything */ + masked_db = malloc(masked_db_len); + h = malloc(h_len); + db_mask = malloc(db_mask_len); + db = malloc(db_len); + salt = malloc(salt_len); + hprime = malloc(hash_len); + if (!masked_db || !h || !db_mask || !db || !salt || !hprime) { + printf("%s: can't allocate some buffer\n", __func__); + ret = -ENOMEM; + goto out; + } + + /* step 4: check if the last byte is 0xbc */ + if (msg[msg_len - 1] != 0xbc) { + printf("%s: invalid pss padding (0xbc is missing)\n", __func__); + ret = -EINVAL; + goto out; + } + + /* step 5 */ + memcpy(masked_db, msg, masked_db_len); + memcpy(h, msg + masked_db_len, h_len); + + /* step 6 */ + leftmost_mask = (0xff >> (8 - leftmost_bits)) << (8 - leftmost_bits); + if (masked_db[0] & leftmost_mask) { + printf("%s: invalid pss padding ", __func__); + printf("(leftmost bit of maskedDB not zero)\n"); + ret = -EINVAL; + goto out; + } + + /* step 7 */ + mask_generation_function1(checksum, h, h_len, db_mask, db_mask_len); + + /* step 8 */ + for (i = 0; i < db_len; i++) + db[i] = masked_db[i] ^ db_mask[i]; + + /* step 9 */ + db[0] &= 0xff >> leftmost_bits; + + /* step 10 */ + if (db[0] != 0x01) { + printf("%s: invalid pss padding ", __func__); + printf("(leftmost byte of db isn't 0x01)\n"); + ret = EINVAL; + goto out; + } + + /* step 11 */ + memcpy(salt, &db[1], salt_len); + + /* step 12 & 13 */ + compute_hash_prime(checksum, pad_zero, 8, + (uint8_t *)hash, hash_len, + salt, salt_len, hprime); + + /* step 14 */ + ret = memcmp(h, hprime, hash_len); + +out: + free(hprime); + free(salt); + free(db); + free(db_mask); + free(h); + free(masked_db); + + return ret; +} +#endif + /** * rsa_verify_key() - Verify a signature against some data using RSA Key *