[PATCH RFC v2 05/11] ti: etype: x509: Add etype for x509 certificate for K3 devices

Neha Malcom Francis n-francis at ti.com
Fri May 6 06:37:53 CEST 2022


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 at 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 at 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 at 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



More information about the U-Boot mailing list