From patchwork Fri Sep 6 07:08:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1158808 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=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="DQcWF69U"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 46PpWV5jdlz9sN1 for ; Fri, 6 Sep 2019 17:06:30 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 7210BC21E0D; Fri, 6 Sep 2019 07:06:11 +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=RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, T_DKIM_INVALID 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 40414C21E2C; Fri, 6 Sep 2019 07:06:09 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id E6FACC21DB6; Fri, 6 Sep 2019 07:05:58 +0000 (UTC) Received: from mail-pf1-f193.google.com (mail-pf1-f193.google.com [209.85.210.193]) by lists.denx.de (Postfix) with ESMTPS id 1E3F5C21DD9 for ; Fri, 6 Sep 2019 07:05:52 +0000 (UTC) Received: by mail-pf1-f193.google.com with SMTP id b13so3725682pfo.8 for ; Fri, 06 Sep 2019 00:05:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=g/0ECfLbrvV58d6yNrpEiHKip4PLcpUTpVbf3aVjip4=; b=DQcWF69US7R71eEPUioUenaErcSRzd1dKzeP3ube9RwTRCUG2/zTEWZTHStHSiPCmO ir74inoxZZHfhWuE3M2w6d7180xKOpJNslWRIATmZNZn6X6YlS7yEMUlqE3/YIrH7/vc oXzn95+qXN+ZLpP1F07j5VV1MhtOdqzcr/dwBdgrJrDIj9VbD3Q59JUzpFb6UJUq0Cxy SqD+iP06DSDOYCOchqzuFLa1HlT5IDgS9kFSXsw1UrphjvLm/Th5SOpBkzJzIPfuPLEz w+kUgHFweYTiKmmyFJ7GsmczmnqMwd2ma3Dho7tPdSeB1H13AY4dfBtcOQKx50KP4ksJ 8WYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=g/0ECfLbrvV58d6yNrpEiHKip4PLcpUTpVbf3aVjip4=; b=CUSJWjw/Atv9ZHtpuAOqRsxu2SD2lA0bjU5UvML6/7/lenJcHA01gwCJx/zb/mZ7kh cBJsuopTRXC+8wdIHtsieREFyIlxcZ8k+hZUC9VpRRAta0edxDAOITWKBUnpyjsvtN+b pV68SDG/TrBc4Sm6XjWTy0xo0us3buAFsaa/x0CifGnAVHVCLOTgTsMo/bQkqBJbsgfi oKJrZnE9jh7Vkr8twOQtHXMaBptb+hlQG8NidkmiyxZzZCjgSIefETM8aLoADYc+9VAT +ELa9ZxuxSrcdR+FNUC3ZLBhBM3rkdLnJWq8jShCk447z8YjRYRcZEXQlEfnQjOAJoAm N9BA== X-Gm-Message-State: APjAAAXsqE8ZdwA4JCBwy5l6PYhS/KaYNxuV8WzLJPu6rUzh0UyIeg8M X4/mEbV48JEHjchfvbZ8x2xyww== X-Google-Smtp-Source: APXvYqzL3R1uGEJCW/ucKcp/OPhiTZqBvkMbJT+rv4p7OHuKYgyWyYdjpOpSkr3RWOVuMuFClIThvA== X-Received: by 2002:a63:f04:: with SMTP id e4mr6514664pgl.38.1567753550119; Fri, 06 Sep 2019 00:05:50 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id em21sm3664395pjb.31.2019.09.06.00.05.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 06 Sep 2019 00:05:49 -0700 (PDT) From: AKASHI Takahiro To: trini@konsulko.com, sjg@chromium.org, xypron.glpk@gmx.de, agraf@csgraf.de Date: Fri, 6 Sep 2019 16:08:06 +0900 Message-Id: <20190906070808.1198-2-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190906070808.1198-1-takahiro.akashi@linaro.org> References: <20190906070808.1198-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 Cc: u-boot@lists.denx.de Subject: [U-Boot] [RFC 1/3] lib: rsa: decouple rsa from FIT image verification 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: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Introduce new configuration, CONFIG_RSA_VERIFY which will decouple building RSA functions from FIT verification and allow for adding a RSA-based signature verification for other file formats, in particular PE file for UEFI secure boot. Signed-off-by: AKASHI Takahiro --- lib/rsa/Kconfig | 7 +++++++ lib/rsa/Makefile | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/rsa/Kconfig b/lib/rsa/Kconfig index 2b33f323bccc..338c8124da59 100644 --- a/lib/rsa/Kconfig +++ b/lib/rsa/Kconfig @@ -1,5 +1,6 @@ config RSA bool "Use RSA Library" + select RSA_VERIFY select RSA_FREESCALE_EXP if FSL_CAAM && !ARCH_MX7 && !ARCH_MX6 && !ARCH_MX5 select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP help @@ -17,6 +18,12 @@ if RSA config SPL_RSA bool "Use RSA Library within SPL" + select RSA_VERIFY + +config RSA_VERIFY + bool + help + Add RSA signature verification support. config RSA_SOFTWARE_EXP bool "Enable driver for RSA Modular Exponentiation in software" diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile index a51c6e1685fb..226d8f3514a9 100644 --- a/lib/rsa/Makefile +++ b/lib/rsa/Makefile @@ -5,5 +5,5 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_$(SPL_)FIT_SIGNATURE) += rsa-verify.o rsa-checksum.o +obj-$(CONFIG_RSA_VERIFY) += rsa-verify.o rsa-checksum.o obj-$(CONFIG_RSA_SOFTWARE_EXP) += rsa-mod-exp.o From patchwork Fri Sep 6 07:08:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1158809 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=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="gB59Wnw1"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 46PpWz6Skfz9sN1 for ; Fri, 6 Sep 2019 17:06:55 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 965D7C21E0B; Fri, 6 Sep 2019 07:06:23 +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=RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, T_DKIM_INVALID 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 66921C21C6A; Fri, 6 Sep 2019 07:06:10 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 2645DC21DB6; Fri, 6 Sep 2019 07:05:59 +0000 (UTC) Received: from mail-pl1-f195.google.com (mail-pl1-f195.google.com [209.85.214.195]) by lists.denx.de (Postfix) with ESMTPS id E2DFDC21E50 for ; Fri, 6 Sep 2019 07:05:54 +0000 (UTC) Received: by mail-pl1-f195.google.com with SMTP id x3so2651896plr.12 for ; Fri, 06 Sep 2019 00:05:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=LSLRdeZL1mMOFkKjnKaIayp9hb6Bi8yv1D8aoDHaOp4=; b=gB59Wnw18UZWb7RkKTFK02B57vyr/y560uf4EtWu0bENKsDYDezssBc+YeR0ymZhWQ MDRFR+L3XI8oUU/XwK8b4f9pFwN0Pq5NX01IpwYFcwzqJ/bc/gprqXHwbwbnNXpA450U qx0u12Y3CF9Ceu+l5Di5aLp1Z/54ZPEXyn7dHtbq20bKfGuv57I3Q5aH2KKeS92GKog7 w7sIRgg18H+ArnMb9NjVH4nJUWVcQs35kJn19jMIzZlG9plCH+4pLWdQ8fLJUUCHVGPK RcYmm117Qjh6ydzX/SSDhPbVovNLkA3DIOoAS1eQcVYm6xvRjut+285v6zTO/m6Ln9Is INdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=LSLRdeZL1mMOFkKjnKaIayp9hb6Bi8yv1D8aoDHaOp4=; b=tzDW4TGRRTFzIDk4bpnlKxX9UV7ug1O34qxEcKJoq/cQ0Jk77UV9czZA/8EGyB8R+w cYQWeEn/k53Thkx0+WU9SrPd0+E8X8jCNs4fe8so5lupjoDGBm4BiHTRgpiWlIy6xr9k n1grseoXNJC1bg9U45wbGGTswOOQBGALz2MHZ9ohjLjNxfCgYAf6EdY2wBoxjeMz+3Qn KuVPDB6f2W13f1/CztBQmq2Qbi3vn4HQw8u34Jg+ZvqVRx0SyO/TFBI9LLyWaSiCb+RT KecoIGczsNzo8526Jti82C3Hoa7tEUiKIBBNeq039opdKJGzQeedap+JUpnHGhEW6/Jh GBvA== X-Gm-Message-State: APjAAAXKDmfpNgFZ5DN/a1Cvn8X6Zls3vNn+B3KTaI4S5aRD2gYGoWK0 y70We7bWAk3uXS2U7K248kzaCw== X-Google-Smtp-Source: APXvYqxYC0u/7SAWUQM1vGWBHpnnjaiE92VcuIwic4B6LST9L54+BA7hYaRuKVEqPkc8wpcjooggbg== X-Received: by 2002:a17:902:a507:: with SMTP id s7mr7744708plq.66.1567753553213; Fri, 06 Sep 2019 00:05:53 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id r185sm7276931pfr.68.2019.09.06.00.05.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 06 Sep 2019 00:05:52 -0700 (PDT) From: AKASHI Takahiro To: trini@konsulko.com, sjg@chromium.org, xypron.glpk@gmx.de, agraf@csgraf.de Date: Fri, 6 Sep 2019 16:08:07 +0900 Message-Id: <20190906070808.1198-3-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190906070808.1198-1-takahiro.akashi@linaro.org> References: <20190906070808.1198-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 Cc: u-boot@lists.denx.de Subject: [U-Boot] [RFC 2/3] lib: rsa: generate additional parameters for public key 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: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" In the current implementation of FIT_SIGNATURE, five parameters for a RSA public key are required while only two of them are essential. (See rsa-mod-exp.h and uImage.FIT/signature.txt) This is a result of considering relatively limited computer power and resources on embedded systems, while such a assumption may not be quite practical for other use cases. In this patch, added is a function, rsa_gen_key_prop(), which will generate additional parameters for other uses, in particular UEFI secure boot, on the fly. Note: the current code uses some "big number" routines from BearSSL for the calculation. Signed-off-by: AKASHI Takahiro --- include/u-boot/rsa-mod-exp.h | 3 + lib/rsa/Makefile | 2 +- lib/rsa/rsa-keyprop.c | 631 +++++++++++++++++++++++++++++++++++ 3 files changed, 635 insertions(+), 1 deletion(-) create mode 100644 lib/rsa/rsa-keyprop.c diff --git a/include/u-boot/rsa-mod-exp.h b/include/u-boot/rsa-mod-exp.h index 8a428c4b6a1a..ca189292d869 100644 --- a/include/u-boot/rsa-mod-exp.h +++ b/include/u-boot/rsa-mod-exp.h @@ -26,6 +26,9 @@ struct key_prop { uint32_t exp_len; /* Exponent length in number of uint8_t */ }; +struct key_prop *rsa_gen_key_prop(const void *key, uint32_t keylen); +void rsa_free_key_prop(struct key_prop *prop); + /** * rsa_mod_exp_sw() - Perform RSA Modular Exponentiation in sw * diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile index 226d8f3514a9..d66eef74c514 100644 --- a/lib/rsa/Makefile +++ b/lib/rsa/Makefile @@ -5,5 +5,5 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_RSA_VERIFY) += rsa-verify.o rsa-checksum.o +obj-$(CONFIG_RSA_VERIFY) += rsa-verify.o rsa-checksum.o rsa-keyprop.o obj-$(CONFIG_RSA_SOFTWARE_EXP) += rsa-mod-exp.o diff --git a/lib/rsa/rsa-keyprop.c b/lib/rsa/rsa-keyprop.c new file mode 100644 index 000000000000..e650a931dff9 --- /dev/null +++ b/lib/rsa/rsa-keyprop.c @@ -0,0 +1,631 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * RSA library - generate parameters for a public key + * + * Copyright (c) 2019 Linaro Limited + * Author: AKASHI Takahiro + * + * Big number routines in this file come from BearSSL. + * See the original copyright below. + * + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include + +#include +#include +#include +#include + +/* stripped version of src/inner.h */ + +static inline unsigned +br_dec16be(const void *src) +{ +#if 0 /* BR_BE_UNALIGNED */ + return ((const br_union_u16 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return ((unsigned)buf[0] << 8) | (unsigned)buf[1]; +#endif +} + +static inline uint32_t +br_dec32be(const void *src) +{ +#if 0 /* BR_BE_UNALIGNED */ + return ((const br_union_u32 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return ((uint32_t)buf[0] << 24) + | ((uint32_t)buf[1] << 16) + | ((uint32_t)buf[2] << 8) + | (uint32_t)buf[3]; +#endif +} + +static inline void +br_enc32be(void *dst, uint32_t x) +{ +#if 0 /* BR_BE_UNALIGNED */ + ((br_union_u32 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + buf[0] = (unsigned char)(x >> 24); + buf[1] = (unsigned char)(x >> 16); + buf[2] = (unsigned char)(x >> 8); + buf[3] = (unsigned char)x; +#endif +} + +static inline uint32_t +NOT(uint32_t ctl) +{ + return ctl ^ 1; +} + +static inline uint32_t +MUX(uint32_t ctl, uint32_t x, uint32_t y) +{ + return y ^ (-ctl & (x ^ y)); +} + +static inline uint32_t +EQ(uint32_t x, uint32_t y) +{ + uint32_t q; + + q = x ^ y; + return NOT((q | -q) >> 31); +} + +static inline uint32_t +NEQ(uint32_t x, uint32_t y) +{ + uint32_t q; + + q = x ^ y; + return (q | -q) >> 31; +} + +static inline uint32_t +GT(uint32_t x, uint32_t y) +{ + /* + * If both x < 2^31 and x < 2^31, then y-x will have its high + * bit set if x > y, cleared otherwise. + * + * If either x >= 2^31 or y >= 2^31 (but not both), then the + * result is the high bit of x. + * + * If both x >= 2^31 and y >= 2^31, then we can virtually + * subtract 2^31 from both, and we are back to the first case. + * Since (y-2^31)-(x-2^31) = y-x, the subtraction is already + * fine. + */ + uint32_t z; + + z = y - x; + return (z ^ ((x ^ y) & (x ^ z))) >> 31; +} + +static inline uint32_t +BIT_LENGTH(uint32_t x) +{ + uint32_t k, c; + + k = NEQ(x, 0); + c = GT(x, 0xFFFF); x = MUX(c, x >> 16, x); k += c << 4; + c = GT(x, 0x00FF); x = MUX(c, x >> 8, x); k += c << 3; + c = GT(x, 0x000F); x = MUX(c, x >> 4, x); k += c << 2; + c = GT(x, 0x0003); x = MUX(c, x >> 2, x); k += c << 1; + k += GT(x, 0x0001); + return k; +} + +#define GE(x, y) NOT(GT(y, x)) +#define LT(x, y) GT(y, x) +#define MUL(x, y) ((uint64_t)(x) * (uint64_t)(y)) + +static inline uint32_t +br_i32_word(const uint32_t *a, uint32_t off) +{ + size_t u; + unsigned j; + + u = (size_t)(off >> 5) + 1; + j = (unsigned)off & 31; + if (j == 0) { + return a[u]; + } else { + return (a[u] >> j) | (a[u + 1] << (32 - j)); + } +} + +/* src/int/i32_bitlen.c */ + +static uint32_t +br_i32_bit_length(uint32_t *x, size_t xlen) +{ + uint32_t tw, twk; + + tw = 0; + twk = 0; + while (xlen -- > 0) { + uint32_t w, c; + + c = EQ(tw, 0); + w = x[xlen]; + tw = MUX(c, w, tw); + twk = MUX(c, (uint32_t)xlen, twk); + } + return (twk << 5) + BIT_LENGTH(tw); +} + +/* src/int/i32_decode.c */ + +static void +br_i32_decode(uint32_t *x, const void *src, size_t len) +{ + const unsigned char *buf; + size_t u, v; + + buf = src; + u = len; + v = 1; + for (;;) { + if (u < 4) { + uint32_t w; + + if (u < 2) { + if (u == 0) { + break; + } else { + w = buf[0]; + } + } else { + if (u == 2) { + w = br_dec16be(buf); + } else { + w = ((uint32_t)buf[0] << 16) + | br_dec16be(buf + 1); + } + } + x[v ++] = w; + break; + } else { + u -= 4; + x[v ++] = br_dec32be(buf + u); + } + } + x[0] = br_i32_bit_length(x + 1, v - 1); +} + +/* src/int/i32_encode.c */ + +static void +br_i32_encode(void *dst, size_t len, const uint32_t *x) +{ + unsigned char *buf; + size_t k; + + buf = dst; + + /* + * Compute the announced size of x in bytes; extra bytes are + * filled with zeros. + */ + k = (x[0] + 7) >> 3; + while (len > k) { + *buf ++ = 0; + len --; + } + + /* + * Now we use k as index within x[]. That index starts at 1; + * we initialize it to the topmost complete word, and process + * any remaining incomplete word. + */ + k = (len + 3) >> 2; + switch (len & 3) { + case 3: + *buf ++ = x[k] >> 16; + /* fall through */ + case 2: + *buf ++ = x[k] >> 8; + /* fall through */ + case 1: + *buf ++ = x[k]; + k --; + } + + /* + * Encode all complete words. + */ + while (k > 0) { + br_enc32be(buf, x[k]); + k --; + buf += 4; + } +} + +/* src/int/i32_ninv32.c */ + +static uint32_t +br_i32_ninv32(uint32_t x) +{ + uint32_t y; + + y = 2 - x; + y *= 2 - y * x; + y *= 2 - y * x; + y *= 2 - y * x; + y *= 2 - y * x; + return MUX(x & 1, -y, 0); +} + +/* src/int/i32_add.c */ + +static uint32_t +br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; + + cc = 0; + m = (a[0] + 63) >> 5; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; + + aw = a[u]; + bw = b[u]; + naw = aw + bw + cc; + + /* + * Carry is 1 if naw < aw. Carry is also 1 if naw == aw + * AND the carry was already 1. + */ + cc = (cc & EQ(naw, aw)) | LT(naw, aw); + a[u] = MUX(ctl, naw, aw); + } + return cc; +} + +/* src/int/i32_sub.c */ + +static uint32_t +br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; + + cc = 0; + m = (a[0] + 63) >> 5; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; + + aw = a[u]; + bw = b[u]; + naw = aw - bw - cc; + + /* + * Carry is 1 if naw > aw. Carry is 1 also if naw == aw + * AND the carry was already 1. + */ + cc = (cc & EQ(naw, aw)) | GT(naw, aw); + a[u] = MUX(ctl, naw, aw); + } + return cc; +} + +/* src/int/i32_div32.c */ + +static uint32_t +br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r) +{ + /* TODO: optimize this */ + uint32_t q; + uint32_t ch, cf; + int k; + + q = 0; + ch = EQ(hi, d); + hi = MUX(ch, 0, hi); + for (k = 31; k > 0; k --) { + int j; + uint32_t w, ctl, hi2, lo2; + + j = 32 - k; + w = (hi << j) | (lo >> k); + ctl = GE(w, d) | (hi >> k); + hi2 = (w - d) >> j; + lo2 = lo - (d << k); + hi = MUX(ctl, hi2, hi); + lo = MUX(ctl, lo2, lo); + q |= ctl << k; + } + cf = GE(lo, d) | hi; + q |= cf; + *r = MUX(cf, lo - d, lo); + return q; +} + +static inline uint32_t +br_rem(uint32_t hi, uint32_t lo, uint32_t d) +{ + uint32_t r; + + br_divrem(hi, lo, d, &r); + return r; +} + +static inline uint32_t +br_div(uint32_t hi, uint32_t lo, uint32_t d) +{ + uint32_t r; + + return br_divrem(hi, lo, d, &r); +} + +/* src/int/i32_muladd.c */ + +static void +br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m) +{ + uint32_t m_bitlen; + size_t u, mlen; + uint32_t a0, a1, b0, hi, g, q, tb; + uint32_t chf, clow, under, over; + uint64_t cc; + + /* + * We can test on the modulus bit length since we accept to + * leak that length. + */ + m_bitlen = m[0]; + if (m_bitlen == 0) { + return; + } + if (m_bitlen <= 32) { + x[1] = br_rem(x[1], z, m[1]); + return; + } + mlen = (m_bitlen + 31) >> 5; + + /* + * Principle: we estimate the quotient (x*2^32+z)/m by + * doing a 64/32 division with the high words. + * + * Let: + * w = 2^32 + * a = (w*a0 + a1) * w^N + a2 + * b = b0 * w^N + b2 + * such that: + * 0 <= a0 < w + * 0 <= a1 < w + * 0 <= a2 < w^N + * w/2 <= b0 < w + * 0 <= b2 < w^N + * a < w*b + * I.e. the two top words of a are a0:a1, the top word of b is + * b0, we ensured that b0 is "full" (high bit set), and a is + * such that the quotient q = a/b fits on one word (0 <= q < w). + * + * If a = b*q + r (with 0 <= r < q), we can estimate q by + * doing an Euclidean division on the top words: + * a0*w+a1 = b0*u + v (with 0 <= v < w) + * Then the following holds: + * 0 <= u <= w + * u-2 <= q <= u + */ + a0 = br_i32_word(x, m_bitlen - 32); + hi = x[mlen]; + memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); + x[1] = z; + a1 = br_i32_word(x, m_bitlen - 32); + b0 = br_i32_word(m, m_bitlen - 32); + + /* + * We estimate a divisor q. If the quotient returned by br_div() + * is g: + * -- If a0 == b0 then g == 0; we want q = 0xFFFFFFFF. + * -- Otherwise: + * -- if g == 0 then we set q = 0; + * -- otherwise, we set q = g - 1. + * The properties described above then ensure that the true + * quotient is q-1, q or q+1. + */ + g = br_div(a0, a1, b0); + q = MUX(EQ(a0, b0), 0xFFFFFFFF, MUX(EQ(g, 0), 0, g - 1)); + + /* + * We subtract q*m from x (with the extra high word of value 'hi'). + * Since q may be off by 1 (in either direction), we may have to + * add or subtract m afterwards. + * + * The 'tb' flag will be true (1) at the end of the loop if the + * result is greater than or equal to the modulus (not counting + * 'hi' or the carry). + */ + cc = 0; + tb = 1; + for (u = 1; u <= mlen; u ++) { + uint32_t mw, zw, xw, nxw; + uint64_t zl; + + mw = m[u]; + zl = MUL(mw, q) + cc; + cc = (uint32_t)(zl >> 32); + zw = (uint32_t)zl; + xw = x[u]; + nxw = xw - zw; + cc += (uint64_t)GT(nxw, xw); + x[u] = nxw; + tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw)); + } + + /* + * If we underestimated q, then either cc < hi (one extra bit + * beyond the top array word), or cc == hi and tb is true (no + * extra bit, but the result is not lower than the modulus). In + * these cases we must subtract m once. + * + * Otherwise, we may have overestimated, which will show as + * cc > hi (thus a negative result). Correction is adding m once. + */ + chf = (uint32_t)(cc >> 32); + clow = (uint32_t)cc; + over = chf | GT(clow, hi); + under = ~over & (tb | (~chf & LT(clow, hi))); + br_i32_add(x, m, over); + br_i32_sub(x, m, under); +} + +/* src/int/i32_reduce.c */ + +static void +br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m) +{ + uint32_t m_bitlen, a_bitlen; + size_t mlen, alen, u; + + m_bitlen = m[0]; + mlen = (m_bitlen + 31) >> 5; + + x[0] = m_bitlen; + if (m_bitlen == 0) { + return; + } + + /* + * If the source is shorter, then simply copy all words from a[] + * and zero out the upper words. + */ + a_bitlen = a[0]; + alen = (a_bitlen + 31) >> 5; + if (a_bitlen < m_bitlen) { + memcpy(x + 1, a + 1, alen * sizeof *a); + for (u = alen; u < mlen; u ++) { + x[u + 1] = 0; + } + return; + } + + /* + * The source length is at least equal to that of the modulus. + * We must thus copy N-1 words, and input the remaining words + * one by one. + */ + memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a); + x[mlen] = 0; + for (u = 1 + alen - mlen; u > 0; u --) { + br_i32_muladd_small(x, a[u], m); + } +} + +void rsa_free_key_prop(struct key_prop *prop) +{ + if (!prop) + return; + + free((void *)prop->modulus); + free((void *)prop->public_exponent); + free((void *)prop->rr); + + free(prop); +} + +struct key_prop *rsa_gen_key_prop(const void *key, uint32_t keylen) +{ + struct key_prop *prop; + struct rsa_key rsa_key; +#define BR_MAX_RSA_SIZE 4096 + uint32_t *n, *rr, *rrtmp; + int rlen, i, ret; + + prop = calloc(sizeof(*prop), 1); + if (!prop) + return NULL; + n = calloc(sizeof(uint32_t), 1 + (BR_MAX_RSA_SIZE >> 5)); + rr = calloc(sizeof(uint32_t), 1 + (BR_MAX_RSA_SIZE >> 5)); + rrtmp = calloc(sizeof(uint32_t), 1 + (BR_MAX_RSA_SIZE >> 5)); + if (!n || !rr || !rrtmp) + return NULL; + + ret = rsa_parse_pub_key(&rsa_key, key, keylen); + if (ret) + goto err; + + /* modulus */ + /* removing leading 0's */ + for (i = 0; i < rsa_key.n_sz && !rsa_key.n[i]; i++) + ; + prop->num_bits = (rsa_key.n_sz - i) * 8; + prop->modulus = malloc(rsa_key.n_sz - i); + if (!prop->modulus) + goto err; + memcpy((void *)prop->modulus, &rsa_key.n[i], rsa_key.n_sz - i); + + /* exponent */ + /* FIXME: fdt64 expected, not rsa_key.e_sz. See rsa_mod_exp_sw() */ + prop->public_exponent = calloc(1, sizeof(uint64_t)); + if (!prop->public_exponent) + goto err; + memcpy((void *)prop->public_exponent + sizeof(uint64_t) - rsa_key.e_sz, + rsa_key.e, rsa_key.e_sz); + prop->exp_len = rsa_key.e_sz; + + /* n0 inverse */ + br_i32_decode(n, &rsa_key.n[i], rsa_key.n_sz - i); + prop->n0inv = br_i32_ninv32(n[1]); + + /* R^2 mod n; R = 2^(num_bits) */ + rlen = prop->num_bits * 2; /* #bits of R^2 = (2^num_bits)^2 */ + rr[0] = 0; + *(uint8_t *)&rr[0] = (1 << (rlen % 8)); + for (i = 1; i < (((rlen + 31) >> 5) + 1); i++) + rr[i] = 0; + br_i32_decode(rrtmp, rr, ((rlen + 7) >> 3) + 1); + br_i32_reduce(rr, rrtmp, n); + + rlen = (prop->num_bits + 7) >> 3; /* #bytes of R^2 mod n */ + prop->rr = malloc(rlen); + if (!prop->rr) + goto err; + br_i32_encode((void *)prop->rr, rlen, rr); + + return prop; + +err: + free(n); + free(rr); + free(rrtmp); + rsa_free_key_prop(prop); + return NULL; +} From patchwork Fri Sep 6 07:08:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1158810 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=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="kHcznoF6"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 46PpXH5M91z9sN1 for ; Fri, 6 Sep 2019 17:07:11 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 72B47C21E2C; Fri, 6 Sep 2019 07:06:50 +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=RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, T_DKIM_INVALID 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 4BD3FC21E0F; Fri, 6 Sep 2019 07:06:13 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 873BFC21E02; Fri, 6 Sep 2019 07:06:00 +0000 (UTC) Received: from mail-pf1-f195.google.com (mail-pf1-f195.google.com [209.85.210.195]) by lists.denx.de (Postfix) with ESMTPS id 5F165C21E44 for ; Fri, 6 Sep 2019 07:05:57 +0000 (UTC) Received: by mail-pf1-f195.google.com with SMTP id w22so3730352pfi.9 for ; Fri, 06 Sep 2019 00:05:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2Ypo4JOWwwvXgZnHmnJ4eHGjvLcVMR4Sjs4txMK9FL8=; b=kHcznoF638gvlYuGymoTjTvAaXvGysosOU+fg+ZOzzDUiNGrxYfJNbBqsoJ1/uwSd6 JpUrL+3SG4Y3jVgwROiXoUCNQCjj/lI3siRZdcp8LHRWa6SJJLFfGT5QXnVtbvwa69gu unpU65/6dNXVDGapYV2ohl82y5BvwvbqoPnrinMdel2bFtY5rHnqaM37M5O0Rny0IBXb pB79Vq9yhA7qHeP/bHeF5ELa9eLIPgPB6mawU6XFgucgyAh8TIFNLt79yQsSkeVggxDc +pTL8CjVzxEl5Kb/+iSpOs/v/GXAeTDzeJyGDHC89F5RTJFTxQMwapVRtV7H3+dWmdmx oXBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2Ypo4JOWwwvXgZnHmnJ4eHGjvLcVMR4Sjs4txMK9FL8=; b=FvLFcIYy7G5xF5TFUkd4M46cWGvYnvykA2VF1RJ+spUVo+UHvNCIHDa9WppRqWmuSz GOA052iugw45tfVi9OH4xsxaDp0oiD3XaBFD4MZLpKLFacxV8x/R49FPakOn4OiZT5pL SpFohSosBkOg6qFG77/CDLHBK9C1SaDAd92SEB5IV0eh4Ah48ECnG1Vwq65VRWwWirZ6 /bRYMiU7gHhLI7+t/ncymgp6+1QpJUfQLuQd5WziThlrZaXqi8G3KrSBmKn40sPjwr0r Hyq3B0dRuBkInCNbZTqI85Iu+GlWVDx4LcfrgmIFWZquwJGneykiOIy5JMeeMRk7ssv6 fjDw== X-Gm-Message-State: APjAAAXXc935GEGlBzhgXP2Hm7aRilcQahQw9dJ8X4fNjmNYKjvjZa/G mbHQoU+gMbS0ZccGviluzsp1VQ== X-Google-Smtp-Source: APXvYqz6+rfKTbUs84Vh5igxUJP7DLjvFEBCiG55Tv4Kd95d8Ig1xx7q0Ul50B4eSjklLrHI1f5//g== X-Received: by 2002:a62:8745:: with SMTP id i66mr8670054pfe.259.1567753555996; Fri, 06 Sep 2019 00:05:55 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id z25sm4829385pfa.91.2019.09.06.00.05.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 06 Sep 2019 00:05:55 -0700 (PDT) From: AKASHI Takahiro To: trini@konsulko.com, sjg@chromium.org, xypron.glpk@gmx.de, agraf@csgraf.de Date: Fri, 6 Sep 2019 16:08:08 +0900 Message-Id: <20190906070808.1198-4-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190906070808.1198-1-takahiro.akashi@linaro.org> References: <20190906070808.1198-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 Cc: u-boot@lists.denx.de Subject: [U-Boot] [RFC 3/3] lib: rsa: add rsa_verify_with_pkey() 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: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" This function, and hence rsa_verify(), will perform RSA verification with two essential parameters for a RSA public key in contract of rsa_verify_with_keynode(), which requires additional three parameters stored in FIT image. It will be used in implementing UEFI secure boot, i.e. image authentication and variable authentication. Signed-off-by: AKASHI Takahiro --- lib/rsa/Kconfig | 7 +++++ lib/rsa/Makefile | 3 ++- lib/rsa/rsa-verify.c | 63 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/lib/rsa/Kconfig b/lib/rsa/Kconfig index 338c8124da59..3c1986a26f8c 100644 --- a/lib/rsa/Kconfig +++ b/lib/rsa/Kconfig @@ -25,6 +25,13 @@ config RSA_VERIFY help Add RSA signature verification support. +config RSA_VERIFY_WITH_PKEY + bool "Execute RSA verification without key parameters from FDT" + depends on RSA + help + This options enables RSA signature verification without + using public key parameters which is embedded control FDT. + config RSA_SOFTWARE_EXP bool "Enable driver for RSA Modular Exponentiation in software" depends on DM diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile index d66eef74c514..fd4592fd6a8a 100644 --- a/lib/rsa/Makefile +++ b/lib/rsa/Makefile @@ -5,5 +5,6 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_RSA_VERIFY) += rsa-verify.o rsa-checksum.o rsa-keyprop.o +obj-$(CONFIG_RSA_VERIFY) += rsa-verify.o rsa-checksum.o +obj-$(CONFIG_RSA_VERIFY_WITH_PKEY) += rsa-keyprop.o obj-$(CONFIG_RSA_SOFTWARE_EXP) += rsa-mod-exp.o diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 287fcc4d234d..80eabff3e940 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -17,9 +17,14 @@ #include "mkimage.h" #include #endif +#include #include #include +#ifndef __UBOOT__ /* for host tools */ +#undef CONFIG_RSA_VERIFY_WITH_PKEY +#endif + /* Default public exponent for backward compatibility */ #define RSA_DEFAULT_PUBEXP 65537 @@ -342,6 +347,34 @@ static int rsa_verify_key(struct image_sign_info *info, return 0; } +#ifdef CONFIG_RSA_VERIFY_WITH_PKEY +/** + * rsa_verify_with_pkey() + * + */ +static int rsa_verify_with_pkey(struct image_sign_info *info, + const void *hash, uint8_t *sig, uint sig_len) +{ + struct key_prop *prop; + int ret; + + /* Public key is self-described to fill key_prop */ + prop = rsa_gen_key_prop(info->key, info->keylen); + if (!prop) { + debug("Generating necessary parameter for decoding failed\n"); + return -EACCES; + } + + ret = rsa_verify_key(info, prop, sig, sig_len, hash, + info->crypto->key_len); + + rsa_free_key_prop(prop); + + return ret; +} +#endif + +#if CONFIG_IS_ENABLED(FIT_SIGNATURE) /** * rsa_verify_with_keynode() - Verify a signature against some data using * information in node with prperties of RSA Key like modulus, exponent etc. @@ -395,18 +428,21 @@ static int rsa_verify_with_keynode(struct image_sign_info *info, return ret; } +#endif 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; /* Reserve memory for maximum checksum-length */ uint8_t hash[info->crypto->key_len]; + int ret = -EACCES; +#if CONFIG_IS_ENABLED(FIT_SIGNATURE) + const void *blob = info->fdt_blob; int ndepth, noffset; int sig_node, node; char name[100]; - int ret; +#endif /* * Verify that the checksum-length does not exceed the @@ -419,12 +455,6 @@ int rsa_verify(struct image_sign_info *info, return -EINVAL; } - sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME); - if (sig_node < 0) { - debug("%s: No signature node found\n", __func__); - return -ENOENT; - } - /* Calculate checksum with checksum-algorithm */ ret = info->checksum->calculate(info->checksum->name, region, region_count, hash); @@ -433,6 +463,22 @@ int rsa_verify(struct image_sign_info *info, return -EINVAL; } +#ifdef CONFIG_RSA_VERIFY_WITH_PKEY + if (!info->fdt_blob) { + /* don't rely on fdt properties */ + ret = rsa_verify_with_pkey(info, hash, sig, sig_len); + + return ret; + } +#endif + +#if CONFIG_IS_ENABLED(FIT_SIGNATURE) + sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME); + if (sig_node < 0) { + debug("%s: No signature node found\n", __func__); + return -ENOENT; + } + /* See if we must use a particular key */ if (info->required_keynode != -1) { ret = rsa_verify_with_keynode(info, hash, sig, sig_len, @@ -459,6 +505,7 @@ int rsa_verify(struct image_sign_info *info, break; } } +#endif return ret; }