From patchwork Sat Jun 24 13:41:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 695735 Delivered-To: patch@linaro.org Received: by 2002:adf:e885:0:0:0:0:0 with SMTP id d5csp2551753wrm; Sat, 24 Jun 2023 13:50:09 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7qutpZfA9GoCFEglxUmqedPeeuA2IrE0R7cAb6Ja5Y4OnSol9GNifm65floRCbG8MGh/kB X-Received: by 2002:a05:6214:5298:b0:61b:65f4:2a15 with SMTP id kj24-20020a056214529800b0061b65f42a15mr25458471qvb.12.1687639809700; Sat, 24 Jun 2023 13:50:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687639809; cv=none; d=google.com; s=arc-20160816; b=csAW9veXSXZVjBpfyWDfw39hxszXOCCtCsRsylcUsybUw71WJ9msWQHKc3nCJPBGAY SPcK7kENFvCs3AlLYUhWYM036xcIXZZMV8ajm/FcLJbQTQpygSJEcfqzIUAgY0J/6RRT 9vOAJnTqZN7bXWliKftxeWQIUB+E6TD8PG8dPAjl2j5eP65J4SASHED+YwPJw6LGO8kf YV7zq+/L5XWPMYoAURDBXKUJT/LPIcy5Zc8VRHxXmJuUi7e/6oGguQF2twgox9qHLNBS tM/PwaGkJas6OEFlgeY7t+s0y/gzRB4ZcqJO9GLp+KOnrCxT9aFOEIKzx2lWYuaJAfa9 5skg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from; bh=tNwxd38QXNqa1z120DLzXJhF+Ty4XHvdC8DT1iz3oX4=; fh=lu5TYXXCc9HXOnqxAkmvhXm+orfKNM3ataUOg5fXk40=; b=zeIfHyJwrd5U5WDDNj4iuJAcTBLEvDA7W5feyfeipaAQBgEd9OWbxy1spIpJJ3M7CD CzPQXVVI+r2hoVRuJsBtE2xqG9atcZEygiYFLE+c+HxbAmYHZgx/cGFpKtx1paRm8kUQ Xx7VXfA1+oU9NgRMULSgCvxS+J1jMtaJCFYJeMR3v66NXwGMVCTeuHl7wdshNN1XuQh7 IK1v1wwFab0uEaZEvMlYt77GqyLrlpxgSeuPvUwgbFVG1BTZzXLIInuWp5e/2XT0egpw 1d9NVw1uKUTLNjmoqTUUC7ZFRLJmHD90j1lwXGtH7Ac2TQeNy3TGzFiJBOkO7n5eXk/C y5Fw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [85.214.62.61]) by mx.google.com with ESMTPS id ib13-20020a0562141c8d00b00631e69834e9si892180qvb.195.2023.06.24.13.50.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 24 Jun 2023 13:50:09 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 4E8DC85F9A; Sat, 24 Jun 2023 22:49:26 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id 4A6FC85F0A; Sat, 24 Jun 2023 22:49:13 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.2 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_SOFTFAIL,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id 8850685F9A for ; Sat, 24 Jun 2023 22:49:01 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=fail smtp.mailfrom=sughosh.ganu@linaro.org Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id CA123AB6; Sat, 24 Jun 2023 06:42:38 -0700 (PDT) Received: from a076522.blr.arm.com (unknown [10.162.46.7]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id EB1FD3F663; Sat, 24 Jun 2023 06:41:51 -0700 (PDT) From: Sughosh Ganu To: u-boot@lists.denx.de Cc: Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Michal Simek , Takahiro Akashi , Malte Schmidt , Tom Rini , Sughosh Ganu Subject: [PATCH v2 2/8] capsule: authenticate: Embed capsule public key in platform's dtb Date: Sat, 24 Jun 2023 19:11:12 +0530 Message-Id: <20230624134118.944567-3-sughosh.ganu@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230624134118.944567-1-sughosh.ganu@linaro.org> References: <20230624134118.944567-1-sughosh.ganu@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 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" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean The EFI capsule authentication logic in u-boot expects the public key in the form of an EFI Signature List(ESL) to be provided as part of the platform's dtb. Currently, the embedding of the ESL file into the dtb needs to be done manually. Use the fdt_add_pubkey tool from binman for embedding the ESL. The capsule update feature is supported for both raw and FIT images. Embedding of the ESL for raw images needs to be done through a binman entry, fdt-esl-embed. For the FIT image, a couple of properties have been added to the fit node which facilitate embedding the ESL into all the DTB's that are packaged into the FIT image. The path to the ESL file is specified through the CONFIG_EFI_CAPSULE_ESL_FILE symbol. Signed-off-by: Sughosh Ganu --- Changes since V1: * Achieve the embedding of the ESL into the DTB through binman * Add an entry type fdt-esl-embed for embedding the ESL for raw images. * Add logic in binman's fit entry type for embedding the ESL into all the DTB's which are part of the FIT image. * Add corresponding documentation entries in binman for the above changes. lib/efi_loader/Kconfig | 11 ++++ tools/binman/btool/fdt_add_pubkey.py | 73 +++++++++++++++++++++++++ tools/binman/entries.rst | 49 +++++++++++++++++ tools/binman/etype/fdt_esl_embed.py | 80 ++++++++++++++++++++++++++++ tools/binman/etype/fit.py | 31 +++++++++++ 5 files changed, 244 insertions(+) create mode 100644 tools/binman/btool/fdt_add_pubkey.py create mode 100644 tools/binman/etype/fdt_esl_embed.py diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index c5835e6ef6..1326a1d109 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -234,6 +234,17 @@ config EFI_CAPSULE_MAX Select the max capsule index value used for capsule report variables. This value is used to create CapsuleMax variable. +config EFI_CAPSULE_ESL_FILE + string "Path to the EFI Signature List File" + default "" + depends on EFI_CAPSULE_AUTHENTICATE + help + Provides the absolute path to the EFI Signature List + file which will be embedded in the platform's device + tree and used for capsule authentication at the time + of capsule update. + + config EFI_DEVICE_PATH_TO_TEXT bool "Device path to text protocol" default y diff --git a/tools/binman/btool/fdt_add_pubkey.py b/tools/binman/btool/fdt_add_pubkey.py new file mode 100644 index 0000000000..071ad166ff --- /dev/null +++ b/tools/binman/btool/fdt_add_pubkey.py @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2023 Linaro Limited +# +"""Bintool implementation for fdt_add_pubkey tool + +fdt_add_pubkey is a tool used for embedding a public key +into the DTB file. + +Currently, this is being used for embedding the EFI Signature +List(ESL) file into the DTB provided. The contents of the ESL +file get added as a property, capsule-key under the signature +node. + +The following are the command line options to be provided to the tool. +Options: + -a Cryptographic algorithm. Optional parameter, default value: sha1,rsa2048 + -e EFI Signature List(ESL) file to embed into the FDT + -k Directory with public key. Optional parameter, default value: . + -n Public key name. Optional parameter, default value: key + -r Required: If present this indicates that the key must be verified for the image / configuration to be considered valid. + FDT blob file for adding of the public key. Required parameter. + +""" + +from binman import bintool + +class Bintoolfdt_add_pubkey(bintool.Bintool): + """Handles the 'fdt_add_pubkey' tool + + This bintool supports running the fdt_add_pubkey tool for + embedding the public key into the dtb file provided. + + Currently, this is being used for embedding the EFI Signature + List(ESL) file into the DTB provided. + """ + def __init__(self, name): + super().__init__(name, 'Tool for generating adding pubkey to platform dtb') + + def add_esl(self, esl_fname, dtb_fname): + """Add an ESL public key into the DTB + + Args: + esl_fname: Path to the ESL file + dtb_name: Path to the DTB file + + Returns: + None + """ + args = [ + f'-e', + esl_fname, + dtb_fname + ] + + self.run_cmd(*args) + + def fetch(self, method): + """Fetch handler for fdt_add_pubkey + + This builds the tool from source + + Returns: + tuple: + str: Filename of fetched file to copy to a suitable directory + str: Name of temp directory to remove, or None + """ + if method != bintool.FETCH_BUILD: + return None + result = self.build_from_git( + 'https://source.denx.de/u-boot/u-boot.git', + 'tools', + 'tools/fdt_add_pubkey') + return result diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index b71af801fd..b89bb2cc1d 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -518,6 +518,38 @@ without the fdtmap header, so it can be viewed with `fdtdump`. +.. _etype_fdt_esl_embed: + +Entry: fdt_esl_embed: An entry for embedding ESL contents into the DTB +---------------------------------------------------------------------- + +Properties / Entry Arguments: + - esl-file: Path to the ESL file. Usually specified + through the CONFIG_EFI_CAPSULE_ESL_FILE Kconfig + symbol. Mandatory property. + - dtb: A list of DTB file names into which the ESL + needs to be embedded. Provided as a string list, + similar to the compatible property. At least one + DTB file needs to be specified. Mandatory property. + - concat: An optional property which specifies the + files which need to be concatenated, along with + the third file into which the result needs to be + put into. + E.g. concat = "./u-boot-nodtb.bin", "./u-boot.dtb", "./u-boot.bin"; + The above concatenates u-boot-nodtb.bin and the + u-boot.dtb files, and puts the result into + u-boot.bin. + +This entry is used for embedding a public key in the form of an +EFI Signature List(ESL) file into the DTB. The public key is +used for authenticating capsules prior to capsule update. + +Once the dtb file has been updated by embedding the ESL, the concat +property allows regenerating the u-boot.bin comprising of the +u-boot-nodtb.bin and the updated dtb. + + + .. _etype_files: Entry: files: A set of files arranged in a section @@ -615,6 +647,23 @@ The top-level 'fit' node supports the following special properties: `of-list` meaning that `-a of-list="dtb1 dtb2..."` should be passed to binman. + In addition to the above properties, a couple of properties exist for embedding + the EFI Signature List(ESL) public key file into the DTB's that are put into + the FIT image. + + The capsule update functionality is supported for the FIT and raw image types. + For the FIT image with capsule updates enabled along with capsule + authentication, it requires the the devicetree with the ESL public key. + Embedding the ESL into the DTBs is being done through a couple of additional + properties + + embed-esl + A boolean property which specifies that the ESL needs to be embedded + into all the DTB's that are put on the FIT image. + esl-file + Path to the ESL file that is to be embedded into the DTB's. + + Substitutions ~~~~~~~~~~~~~ diff --git a/tools/binman/etype/fdt_esl_embed.py b/tools/binman/etype/fdt_esl_embed.py new file mode 100644 index 0000000000..708ab138fd --- /dev/null +++ b/tools/binman/etype/fdt_esl_embed.py @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Linaro Limited +# +# Entry-type module for Embedding ESL into FDTs +# + +from binman.entry import Entry +from dtoc import fdt_util +from u_boot_pylib import tools +from u_boot_pylib import tout + +class Entry_fdt_esl_embed(Entry): + """Entry for embedding the ESL file into devicetree(s) + + This is an entry for embedding the EFI Signature List(ESL) + file into one or multiple devicetrees. + + The ESL is a public key which is inserted as a property + under the signature node in the DTB. One or more dtb files + can be specified under the fdt-esl-embed node to embed the + ESL file. + + Properties / Entry arguments: + - esl-file: Path to the ESL file. Usually specified + through the CONFIG_EFI_CAPSULE_ESL_FILE Kconfig + symbol. Mandatory property. + - dtb: A list of DTB file names into which the ESL + needs to be embedded. Provided as a string list, + similar to the compatible property. At least one + DTB file needs to be specified. Mandatory property. + - concat: An optional property which specifies the + files which need to be concatenated, along with + the third file into which the result needs to be + put into. + E.g. concat = "./u-boot-nodtb.bin", "./u-boot.dtb", "./u-boot.bin"; + The above concatenates u-boot-nodtb.bin and the + u-boot.dtb files, and puts the result into + u-boot.bin. + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + self.dtbs = [] + + def ReadNode(self): + super().ReadNode() + + self.esl = fdt_util.GetString(self._node, 'esl-file') + self.dtbs = fdt_util.GetStringList(self._node, 'dtb') + self.concat = fdt_util.GetStringList(self._node, 'concat') + + if not self.esl: + self.Raise('Path to the ESL file needs to be provided') + if not self.dtbs: + self.Raise('At least one DTB needs to be provided') + + def dtb_embed_esl(self): + for dtb in self.dtbs: + self.fdt_add_pubkey.add_esl(self.esl, + tools.get_input_filename(dtb)) + + def concat_binaries(self): + bins = self.concat + bin0_fname = tools.get_input_filename(bins[0]) + bin1_fname = tools.get_input_filename(bins[1]) + bin2_fname = tools.get_input_filename(bins[2]) + with open(bin0_fname, 'rb') as fd1, open(bin1_fname, 'rb') as fd2, open(bin2_fname, 'wb') as fd3: + bin1 = fd1.read() + bin2 = fd2.read() + bin1 += bin2 + + fd3.write(bin1) + + def ObtainContents(self): + self.dtb_embed_esl() + + if self.concat: + self.concat_binaries() + + def AddBintools(self, btools): + self.fdt_add_pubkey = self.AddBintool(btools, 'fdt_add_pubkey') diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py index c395706ece..a745d83b6f 100644 --- a/tools/binman/etype/fit.py +++ b/tools/binman/etype/fit.py @@ -20,6 +20,7 @@ OPERATIONS = { 'gen-fdt-nodes': OP_GEN_FDT_NODES, 'split-elf': OP_SPLIT_ELF, } +esl_embed_done = False class Entry_fit(Entry_section): @@ -81,6 +82,22 @@ class Entry_fit(Entry_section): `of-list` meaning that `-a of-list="dtb1 dtb2..."` should be passed to binman. + In addition to the above properties, a couple of properties exist for embedding + the EFI Signature List(ESL) public key file into the DTB's that are put into + the FIT image. + + The capsule update functionality is supported for the FIT and raw image types. + For the FIT image with capsule updates enabled along with capsule + authentication, it requires the the devicetree with the ESL public key. + Embedding the ESL into the DTBs is being done through a couple of additional + properties + + embed-esl + A boolean property which specifies that the ESL needs to be embedded + into all the DTB's that are put on the FIT image. + esl-file + Path to the ESL file that is to be embedded into the DTB's. + Substitutions ~~~~~~~~~~~~~ @@ -363,6 +380,9 @@ class Entry_fit(Entry_section): self._fdts = fdts.split() self._fit_default_dt = self.GetEntryArgsOrProps([EntryArg('default-dt', str)])[0] + self.embed_esl = fdt_util.GetBool(self._node, 'embed-esl') + if self.embed_esl: + self.esl = fdt_util.GetString(self._node, 'esl-file') def _get_operation(self, base_node, node): """Get the operation referenced by a subnode @@ -434,6 +454,15 @@ class Entry_fit(Entry_section): Returns: bytes: Contents of the section """ + + global esl_embed_done + + if self.embed_esl and not esl_embed_done: + for dtb in self._fdts: + self.fdt_add_pubkey.add_esl(self.esl, + tools.get_input_filename(dtb + '.dtb')) + esl_embed_done = True + data = self._build_input() uniq = self.GetUniqueName() input_fname = tools.get_output_filename(f'{uniq}.itb') @@ -825,6 +854,8 @@ class Entry_fit(Entry_section): def AddBintools(self, btools): super().AddBintools(btools) self.mkimage = self.AddBintool(btools, 'mkimage') + if self.embed_esl: + self.fdt_add_pubkey = self.AddBintool(btools, 'fdt_add_pubkey') def CheckMissing(self, missing_list): # We must use our private entry list for this since generator nodes