u-boot.lists.denx.de archive mirror
 help / color / mirror / Atom feed
From: Neha Malcom Francis <n-francis@ti.com>
To: <u-boot@lists.denx.de>
Cc: <n-francis@ti.com>
Subject: [PATCH RFC v2 05/11] ti: etype: x509: Add etype for x509 certificate for K3 devices
Date: Fri, 6 May 2022 10:07:53 +0530	[thread overview]
Message-ID: <20220506043759.8193-6-n-francis@ti.com> (raw)
In-Reply-To: <20220506043759.8193-1-n-francis@ti.com>

K3 devices x509 certificate added to certain binaries that allows ROM to
validate the integrity of the image. Etype that generates an x509
certificate depending on boot flow added.

Signed-off-by: Neha Malcom Francis <n-francis@ti.com>
---
 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
+------------------------------------------------
+
+Properties / Entry arguments:
+        - content: Phandle of binary to sign
+        - output: Name of the final output file
+        - 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 <sjg@chromium.org>
+#
+
+# 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)
+
+
+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)])
+
 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
-- 
2.17.1


  parent reply	other threads:[~2022-05-06  4:38 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-06  4:37 [PATCH RFC v2 00/11] Integration of sysfw, tispl and tiboot3 Neha Malcom Francis
2022-05-06  4:37 ` [PATCH RFC v2 01/11] j721e_evm: schema: yaml: Add general schema and J721E board config files Neha Malcom Francis
2022-05-06  4:37 ` [PATCH RFC v2 02/11] ti: tools: config: Add board config class to generate config binaries Neha Malcom Francis
2022-05-06  4:37 ` [PATCH RFC v2 03/11] ti: etype: sysfw: Add entry type for sysfw Neha Malcom Francis
2022-05-31  8:44   ` Roger Quadros
2022-06-01  5:58     ` Neha Malcom Francis
2022-06-01  7:29       ` Neha Malcom Francis
2022-06-01  9:26       ` Roger Quadros
2022-05-06  4:37 ` [PATCH RFC v2 04/11] ti: etype: dm: Add entry type for TI DM Neha Malcom Francis
2022-05-06  4:37 ` Neha Malcom Francis [this message]
2022-05-31  9:20   ` [PATCH RFC v2 05/11] ti: etype: x509: Add etype for x509 certificate for K3 devices Roger Quadros
2022-06-01  6:02     ` Neha Malcom Francis
2022-06-01  9:24       ` Roger Quadros
2022-06-01  9:48         ` Neha Malcom Francis
2022-06-01 10:48           ` Roger Quadros
2022-06-02  4:09             ` Neha Malcom Francis
2022-05-06  4:37 ` [PATCH RFC v2 06/11] ti: sysfw: Add support for packaging sysfw.itb Neha Malcom Francis
2022-05-06  4:37 ` [PATCH RFC v2 07/11] ti: tiboot3.bin: Remove tiboot3.bin target from makefile Neha Malcom Francis
2022-05-31 10:51   ` Roger Quadros
2022-05-06  4:37 ` [PATCH RFC v2 08/11] ti: tispl.bin: Removed script that packages tispl.bin Neha Malcom Francis
2022-05-31 10:53   ` Roger Quadros
2022-05-06  4:37 ` [PATCH RFC v2 09/11] ti: x509: Remove shell script used for signing Neha Malcom Francis
2022-05-31 10:54   ` Roger Quadros
2022-05-06  4:37 ` [PATCH RFC v2 10/11] ti: dtsi: j721e: Use binman to package sysfw.itb and tiboot3.bin Neha Malcom Francis
2022-05-06  4:37 ` [PATCH RFC v2 11/11] ti: dtsi: j721e: Use binman to package tispl.bin Neha Malcom Francis
2022-05-31 11:02   ` Roger Quadros
2022-06-01  6:08     ` Neha Malcom Francis
2022-06-01  9:23       ` Roger Quadros
2022-06-01 10:42         ` Neha Malcom Francis
2022-06-01 10:55           ` Roger Quadros
2022-06-01 12:47             ` Andrew Davis
2022-06-03  8:49               ` Roger Quadros
2022-05-10 20:05 ` [PATCH RFC v2 00/11] Integration of sysfw, tispl and tiboot3 Tom Rini
2022-05-11 18:56   ` Alper Nebi Yasak
2022-05-31  8:21 ` Roger Quadros
2022-06-01  5:54   ` Neha Malcom Francis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220506043759.8193-6-n-francis@ti.com \
    --to=n-francis@ti.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).