From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C49E2C433EF for ; Tue, 31 May 2022 09:20:51 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 0CAC982A57; Tue, 31 May 2022 11:20:49 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=kernel.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.b="df7977Y9"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 97A3B82125; Tue, 31 May 2022 11:20:47 +0200 (CEST) Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 6F41B82125 for ; Tue, 31 May 2022 11:20:43 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=kernel.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=rogerq@kernel.org Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id A159761291; Tue, 31 May 2022 09:20:41 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 50B07C385A9; Tue, 31 May 2022 09:20:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1653988841; bh=BUTX+jH4OTE4n967+hEtMR86SNueX2towOLVxoj7FgM=; h=Date:Subject:To:References:From:In-Reply-To:From; b=df7977Y9DfN/Vpe9GgbEBhtu3EXP636bSD+tHWRZVr9z/tiGIUEciHfpef/FnZW+h OlhaR+Gg87zh/XbX3AUGhOq+l8GyPB3fi9de5LvK6XGTwH29omyNtxZSfhaZ1ekRUc ok+RPlspNwFmf9dAHVbATRGlk8pqpAnhtkcAxWhpWtlRAgKg4eFp/KOT7CS7QvQB5D kP8KIT9676J2qV/9SxoQJfXctjtv10bLIZb6QsYqdIuAnNL/BAEJDlayn0t3PBocbm ICKkGwP5gaWUyqdglVvK41A55PtvzEUgMCD4uxGeUlvUo08bq/qbwipkA6rIzu6ofJ YriaaDxaJ2KuQ== Message-ID: Date: Tue, 31 May 2022 12:20:37 +0300 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.7.0 Subject: Re: [PATCH RFC v2 05/11] ti: etype: x509: Add etype for x509 certificate for K3 devices Content-Language: en-US To: Neha Malcom Francis , u-boot@lists.denx.de References: <20220506043759.8193-1-n-francis@ti.com> <20220506043759.8193-6-n-francis@ti.com> From: Roger Quadros In-Reply-To: <20220506043759.8193-6-n-francis@ti.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit 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.5 at phobos.denx.de X-Virus-Status: Clean On 06/05/2022 07:37, Neha Malcom Francis wrote: > K3 devices x509 certificate added to certain binaries that allows ROM to what binaries? > validate the integrity of the image. Etype that generates an x509 > certificate depending on boot flow added. Could you please explain in more detail as to what exactly is happening here. What do you mean by "depending on boot flow"? > > Signed-off-by: Neha Malcom Francis > --- > tools/binman/entries.rst | 15 ++ > tools/binman/etype/x509_cert.py | 248 ++++++++++++++++++++++++++++ > tools/binman/ftest.py | 7 + > tools/binman/test/232_x509_cert.dts | 18 ++ > tools/k3_gen_x509_cert.sh | 10 +- > 5 files changed, 293 insertions(+), 5 deletions(-) > create mode 100644 tools/binman/etype/x509_cert.py > create mode 100644 tools/binman/test/232_x509_cert.dts > > diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst > index 0c6d82fce8..dfa281e49f 100644 > --- a/tools/binman/entries.rst > +++ b/tools/binman/entries.rst > @@ -1890,6 +1890,21 @@ and kernel are genuine. > > > > +Entry: x509cert: x509 certificate for K3 devices > +------------------------------------------------ > + x509 is a generic standard. Can this be made usable by other vendors as well or is it very specific to TI? If this is TI specific then I'd suggest a "ti-" prefix to the entry name. > +Properties / Entry arguments: > + - content: Phandle of binary to sign > + - output: Name of the final output file why do you need output property? > + - key_file: File with key inside it. If not provided, script generates RSA degenerate key > + - core: Target core ID on which image would be running > + - load: Target load address of the binary in hex > + > + Output files: > + - certificate.bin: Signed certificate binary > + > + > + > Entry: x86-reset16: x86 16-bit reset code for U-Boot > ---------------------------------------------------- > > diff --git a/tools/binman/etype/x509_cert.py b/tools/binman/etype/x509_cert.py > new file mode 100644 > index 0000000000..0009973155 > --- /dev/null > +++ b/tools/binman/etype/x509_cert.py > @@ -0,0 +1,248 @@ > +# SPDX-License-Identifier: GPL-2.0+ > +# Copyright (c) 2018 Google, Inc > +# Written by Simon Glass > +# > + > +# Support for a x509 certificate for signing K3 devices > + > +import os > +from collections import OrderedDict > +from subprocess import Popen, PIPE > +from sys import stderr, stdout > + > +import asn1 > +from Crypto.PublicKey import RSA > +from cryptography.hazmat.backends import default_backend > +from cryptography.hazmat.primitives import serialization > + > +from binman.etype.collection import Entry_collection > +from dtoc import fdt_util > +from patman import tools > + > +temp_x509 = "x509-temp.cert" > +cert = "certificate.bin" > +rand_key = "eckey.pem" > +bootcore_opts = 0 > +bootcore = 0 > +debug_type = 0 > + > + > +class Entry_x509_cert(Entry_collection): > + """ An entry which contains a x509 certificate > + > + Properties / Entry arguments: > + - content: Phandle of binary to sign > + - key_file: File with key inside it. If not provided, script generates RSA degenerate key > + - core: Target core ID on which image would be running > + - load: Target load address of the binary in hex > + > + Output files: > + - certificate.bin: Signed certificate binary""" > + > + def __init__(self, section, etype, node): > + super().__init__(section, etype, node) > + self.key_file = fdt_util.GetString(self._node, 'key-file', "") > + self.core = fdt_util.GetInt(self._node, 'core', 0) > + self.load_addr = fdt_util.GetInt(self._node, 'load', 0x41c00000) > + > + def ReadNode(self): > + super().ReadNode() > + if self.key_file == "": > + self.degen_key = True > + else: > + self.degen_key = False > + > + def _CreateCertificate(self): > + """Create certificate for legacy boot flow""" > + if self.degen_key == True: > + gen_degen_key() > + self.key_file = rand_key > + > + sha_val = get_sha_val("intermediate-sysfw.bin") > + bin_size = get_file_size("intermediate-sysfw.bin") > + addr = "%08x" % self.load_addr > + if self.core == 0: > + cert_type = 2 > + elif self.core == 16: > + cert_type = 1 > + else: > + cert_type = 2 > + debug_type = 0 > + > + gen_template() > + gen_cert(bin_size, sha_val, cert_type, bootcore_opts, > + self.core, addr, debug_type, self.key_file) > + > + return tools.read_file("certificate.bin") > + > + def ObtainContents(self): > + self.image = self.GetContents(False) > + if self.image is None: > + return False > + f = open("intermediate-sysfw.bin", "wb") > + f.write(self.image) > + f.close() > + self.SetContents(self._CreateCertificate()) > + return True > + > + def ProcessContents(self): > + data = self._CreateCertificate() > + return self.ProcessContentsUpdate(data) Why do you need _CreateCertificate() and ProcessContents()? Just have one ObtainContents() and try to get rid of all the intermediate files. > + > + > +def get_sha_val(binary_file): > + process = Popen(['openssl', 'dgst', '-sha512', '-hex', > + binary_file], stdout=PIPE, stderr=PIPE) > + stdout, stderr = process.communicate() > + sha_val = stdout.split()[1] > + return sha_val > + > + > +def get_file_size(binary_file): > + return os.path.getsize(binary_file) > + > + > +def gen_degen_template(): > + with open("degen-template.txt", 'w+', encoding='utf-8') as f: > + degen_temp = """ > +asn1=SEQUENCE:rsa_key > + > +[rsa_key] > +version=INTEGER:0 > +modulus=INTEGER:0xDEGEN_MODULUS > +pubExp=INTEGER:1 > +privExp=INTEGER:1 > +p=INTEGER:0xDEGEN_P > +q=INTEGER:0xDEGEN_Q > +e1=INTEGER:1 > +e2=INTEGER:1 > +coeff=INTEGER:0xDEGEN_COEFF""" > + f.write(degen_temp) > + > + > +def gen_template(): > + """Generate x509 Template""" > + with open("x509-template.txt", "w+", encoding='utf-8') as f: > + x509template = """ > +[ req ] > +distinguished_name = req_distinguished_name > +x509_extensions = v3_ca > +prompt = no > +dirstring_type = nobmp > + > +[ req_distinguished_name ] > +C = US > +ST = TX > +L = Dallas > +O = Texas Instruments Incorporated > +OU = Processors > +CN = TI support > +emailAddress = support@ti.com > + > +[ v3_ca ] > +basicConstraints = CA:true > +1.3.6.1.4.1.294.1.1 = ASN1:SEQUENCE:boot_seq > +1.3.6.1.4.1.294.1.2 = ASN1:SEQUENCE:image_integrity > +1.3.6.1.4.1.294.1.3 = ASN1:SEQUENCE:swrv > +# 1.3.6.1.4.1.294.1.4 = ASN1:SEQUENCE:encryption > +1.3.6.1.4.1.294.1.8 = ASN1:SEQUENCE:debug > + > +[ boot_seq ] > +certType = INTEGER:TEST_CERT_TYPE > +bootCore = INTEGER:TEST_BOOT_CORE > +bootCoreOpts = INTEGER:TEST_BOOT_CORE_OPTS > +destAddr = FORMAT:HEX,OCT:TEST_BOOT_ADDR > +imageSize = INTEGER:TEST_IMAGE_LENGTH > + > +[ image_integrity ] > +shaType = OID:2.16.840.1.101.3.4.2.3 > +shaValue = FORMAT:HEX,OCT:TEST_IMAGE_SHA_VAL > + > +[ swrv ] > +swrv = INTEGER:0 > + > +# [ encryption ] > +# initalVector = FORMAT:HEX,OCT:TEST_IMAGE_ENC_IV > +# randomString = FORMAT:HEX,OCT:TEST_IMAGE_ENC_RS > +# iterationCnt = INTEGER:TEST_IMAGE_KEY_DERIVE_INDEX > +# salt = FORMAT:HEX,OCT:TEST_IMAGE_KEY_DERIVE_SALT > + > +[ debug ] > +debugUID = FORMAT:HEX,OCT:0000000000000000000000000000000000000000000000000000000000000000 > +debugType = INTEGER:TEST_DEBUG_TYPE > +coreDbgEn = INTEGER:0 > +coreDbgSecEn = INTEGER:0""" > + f.write(x509template) > + > + > +def parse_key(inp_key, section): > + parsed_key = "" > + section_true = False > + with open(inp_key, 'r') as file: > + for line in file: > + if section in line: > + section_true = True > + elif section_true: > + if " " not in line: > + break > + else: > + parsed_key += line.replace(":", "").replace(" ", "") > + return parsed_key.replace("\n", "") > + > + > +def gen_degen_key(): > + """Generate a 4096 bit RSA key""" > + try: > + # generates 1024 bit PEM encoded RSA key in PKCS#1 format > + private_key = RSA.generate(1024) > + f = open('key.pem', 'wb') > + f.write(private_key.exportKey('PEM')) > + f.close() > + except: > + raise(Exception) > + > + try: > + process = Popen(['openssl', 'rsa', '-in', 'key.pem', > + '-text', '-out', 'key.txt'], stdout=PIPE, stderr=PIPE) > + stdout, stderr = process.communicate() > + except: > + raise(stderr) > + > + DEGEN_MODULUS = parse_key("key.txt", "modulus") > + DEGEN_P = parse_key("key.txt", "prime1") > + DEGEN_Q = parse_key("key.txt", "prime2") > + DEGEN_COEFF = parse_key("key.txt", "coefficient") > + > + gen_degen_template() > + > + with open("degen-template.txt", 'r') as file_input: > + with open("degenerateKey.txt", 'w') as file_output: > + for line in file_input: > + s = line.replace("DEGEN_MODULUS", DEGEN_MODULUS).replace( > + "DEGEN_P", DEGEN_P).replace("DEGEN_Q", DEGEN_Q).replace("DEGEN_COEFF", DEGEN_COEFF) > + file_output.write(s) > + > + try: > + process = Popen(['openssl', 'asn1parse', '-genconf', 'degenerateKey.txt', > + '-out', 'degenerateKey.der'], stdout=PIPE, stderr=PIPE) > + stdout, stderr = process.communicate() > + except: > + raise(stderr) > + > + try: > + process = Popen(['openssl', 'rsa', '-in', 'degenerateKey.der', > + '-inform', 'DER', '-outform', 'PEM', '-out', rand_key]) > + stdout, stderr = process.communicate() > + except: > + raise(stderr) > + > + > +def gen_cert(bin_size, sha_val, cert_type, bootcore_opts, bootcore, addr, debug_type, key): > + with open(temp_x509, "w") as output_file: > + with open("x509-template.txt", "r") as input_file: > + for line in input_file: > + output_file.write(line.replace("TEST_IMAGE_LENGTH", str(bin_size)).replace("TEST_IMAGE_SHA_VAL", sha_val.decode("utf-8")).replace("TEST_CERT_TYPE", str(cert_type)).replace( > + "TEST_BOOT_CORE_OPTS", str(bootcore_opts)).replace("TEST_BOOT_CORE", str(bootcore)).replace("TEST_BOOT_ADDR", str(addr)).replace("TEST_DEBUG_TYPE", str(debug_type))) > + process = Popen(['openssl', 'req', '-new', '-x509', '-key', key, '-nodes', '-outform', > + 'DER', '-out', cert, '-config', temp_x509, '-sha512'], stdout=PIPE, stderr=PIPE) > + stdout, stderr = process.communicate() > diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py > index 5ff294a386..d8ee592250 100644 > --- a/tools/binman/ftest.py > +++ b/tools/binman/ftest.py > @@ -96,6 +96,7 @@ ENV_DATA = b'var1=1\nvar2="2"' > PRE_LOAD_MAGIC = b'UBSH' > PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big') > PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big') > +X509_DATA = b'filetobesigned' > > # Subdirectory of the input dir to use to put test FDTs > TEST_FDT_SUBDIR = 'fdts' > @@ -200,6 +201,7 @@ class TestFunctional(unittest.TestCase): > TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA) > TestFunctional._MakeInputFile('sysfw.bin', TI_SYSFW_DATA) > TestFunctional._MakeInputFile('scp.bin', SCP_DATA) > + TestFunctional._MakeInputFile('tosign.bin', X509_DATA) > > # Add a few .dtb files for testing > TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR, > @@ -5537,5 +5539,10 @@ fdt fdtmap Extract the devicetree blob from the fdtmap > data = self._DoReadFile('232_ti_sysfw.dts') > self.assertEqual(TI_SYSFW_DATA, data[:len(TI_SYSFW_DATA)]) > > + def testX509Cert(self): > + """Test an image with the default x509 certificate header""" > + data = self._DoReadFile('232_x509_cert.dts') > + self.assertEqual(X509_DATA, data[938:938 + len(X509_DATA)]) what is 938? Isn't it easier to just assert that _DoReadFile('232_x509_cert.dts') is greater than len(X509_DATA)? > + > if __name__ == "__main__": > unittest.main() > diff --git a/tools/binman/test/232_x509_cert.dts b/tools/binman/test/232_x509_cert.dts > new file mode 100644 > index 0000000000..f768568ca7 > --- /dev/null > +++ b/tools/binman/test/232_x509_cert.dts > @@ -0,0 +1,18 @@ > +// SPDX-License-Identifier: GPL-2.0+ > + > +/dts-v1/; > + > +/ { > + #address-cells = <1>; > + #size-cells = <1>; > + > + binman { > + x509-cert { > + content = <&image>; > + }; > + > + image: blob-ext { > + filename = "tosign.bin"; > + }; > + }; > +}; > diff --git a/tools/k3_gen_x509_cert.sh b/tools/k3_gen_x509_cert.sh > index 298cec1313..b6ef5a2de3 100755 > --- a/tools/k3_gen_x509_cert.sh > +++ b/tools/k3_gen_x509_cert.sh > @@ -109,7 +109,7 @@ gen_degen_key() { > openssl asn1parse -genconf degenerateKey.txt -out degenerateKey.der >>/dev/null 2>&1 > openssl rsa -in degenerateKey.der -inform DER -outform PEM -out $RAND_KEY >>/dev/null 2>&1 > KEY=$RAND_KEY > - rm key.pem key.txt degen-template.txt degenerateKey.txt degenerateKey.der > + #rm key.pem key.txt degen-template.txt degenerateKey.txt degenerateKey.der > } > > declare -A options_help > @@ -246,7 +246,7 @@ gen_cert > cat $CERT $BIN > $OUTPUT > > # Remove all intermediate files > -rm $TEMP_X509 $CERT x509-template.txt > -if [ "$KEY" == "$RAND_KEY" ]; then > - rm $RAND_KEY > -fi > +#rm $TEMP_X509 $CERT x509-template.txt > +#if [ "$KEY" == "$RAND_KEY" ]; then > +# rm $RAND_KEY > +#fi Why these changes? Maybe you should include them within "ifndef CONFIG_BINMAN ... endif" to avoid breaking platforms not using BINMAN. cheers, -roger