[PATCH v4 1/3] binman: Add support for externally encrypted blobs

christian.taedcke-oss at weidmueller.com christian.taedcke-oss at weidmueller.com
Mon Jul 10 11:25:52 CEST 2023


From: Christian Taedcke <christian.taedcke at weidmueller.com>

This adds a new etype encrypted that is derived from collection.

It creates a new cipher node in the related image similar to the
cipher node used by u-boot, see boot/image-cipher.c.

Signed-off-by: Christian Taedcke <christian.taedcke at weidmueller.com>
---

(no changes since v3)

Changes in v3:
- rebase on u-boot-dm/mkim-working
- update doc for functions ObtainContents and ProcessContents
- update entries.rst

Changes in v2:
- add entry documentation
- remove global /cipher node
- replace key-name-hint with key-source property

 tools/binman/entries.rst        |  88 ++++++++++++++++++
 tools/binman/etype/encrypted.py | 157 ++++++++++++++++++++++++++++++++
 2 files changed, 245 insertions(+)
 create mode 100644 tools/binman/etype/encrypted.py

diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index b55f424620..d4bc5de1d3 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -468,6 +468,94 @@ updating the EC on startup via software sync.
 
 
 
+.. _etype_encrypted:
+
+Entry: encrypted: Externally built encrypted binary blob
+--------------------------------------------------------
+
+This entry provides the functionality to include information about how to
+decrypt an encrypted binary. This information is added to the
+resulting device tree by adding a new cipher node in the entry's parent
+node (i.e. the binary).
+
+The key that must be used to decrypt the binary is either directly embedded
+in the device tree or indirectly by specifying a key source. The key source
+can be used as an id of a key that is stored in an external device.
+
+Using an embedded key
+~~~~~~~~~~~~~~~~~~~~~
+
+This is an example using an embedded key::
+
+    encrypted_blob: blob-ext {
+        filename = "encrypted-blob.bin";
+    };
+
+    encrypted {
+        content = <&encrypted_blob>;
+        algo = "aes256-gcm";
+        iv-filename = "encrypted-blob.bin.iv";
+        key-filename = "encrypted-blob.bin.key";
+    };
+
+This entry generates the following device tree structure form the example
+above::
+
+    data = [...]
+    cipher {
+        algo = "aes256-gcm";
+        key = <0x...>;
+        iv = <0x...>;
+    };
+
+The data property is generated by the blob-ext etype, the cipher node and
+its content is generated by this etype.
+
+Using an external key
+~~~~~~~~~~~~~~~~~~~~~
+
+Instead of embedding the key itself into the device tree, it is also
+possible to address an externally stored key by specifying a 'key-source'
+instead of the 'key'::
+
+    encrypted_blob: blob-ext {
+        filename = "encrypted-blob.bin";
+    };
+
+    encrypted {
+        content = <&encrypted_blob>;
+        algo = "aes256-gcm";
+        iv-filename = "encrypted-blob.bin.iv";
+        key-source = "external-key-id";
+    };
+
+This entry generates the following device tree structure form the example
+above::
+
+    data = [...]
+    cipher {
+        algo = "aes256-gcm";
+        key-source = "external-key-id";
+        iv = <0x...>;
+    };
+
+Properties
+~~~~~~~~~~
+
+In addition to the inherited 'collection' for Properties / Entry arguments:
+    - algo: The encryption algorithm. Currently no algorithm is supported
+            out-of-the-box. Certain algorithms will be added in future
+            patches.
+    - iv-filename: The name of the file containing the initialization
+                   vector (in short iv). See
+                   https://en.wikipedia.org/wiki/Initialization_vector
+    - key-filename: The name of the file containing the key. Either
+                    key-filename or key-source must be provided.
+    - key-source: The key that should be used. Either key-filename or
+                  key-source must be provided.
+
+
+
 .. _etype_fdtmap:
 
 Entry: fdtmap: An entry which contains an FDT map
diff --git a/tools/binman/etype/encrypted.py b/tools/binman/etype/encrypted.py
new file mode 100644
index 0000000000..7638cfbe7f
--- /dev/null
+++ b/tools/binman/etype/encrypted.py
@@ -0,0 +1,157 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2023 Weidmüller Interface GmbH & Co. KG
+# Written by Christian Taedcke <christian.taedcke at weidmueller.com>
+#
+# Entry-type module for cipher information of encrypted blobs/binaries
+#
+
+from binman.etype.collection import Entry_collection
+from dtoc import fdt_util
+from u_boot_pylib import tools
+
+# This is imported if needed
+state = None
+
+
+class Entry_encrypted(Entry_collection):
+    """Externally built encrypted binary blob
+
+    This entry provides the functionality to include information about how to
+    decrypt an encrypted binary. This information is added to the
+    resulting device tree by adding a new cipher node in the entry's parent
+    node (i.e. the binary).
+
+    The key that must be used to decrypt the binary is either directly embedded
+    in the device tree or indirectly by specifying a key source. The key source
+    can be used as an id of a key that is stored in an external device.
+
+    Using an embedded key
+    ~~~~~~~~~~~~~~~~~~~~~
+
+    This is an example using an embedded key::
+
+        encrypted_blob: blob-ext {
+            filename = "encrypted-blob.bin";
+        };
+
+        encrypted {
+            content = <&encrypted_blob>;
+            algo = "aes256-gcm";
+            iv-filename = "encrypted-blob.bin.iv";
+            key-filename = "encrypted-blob.bin.key";
+        };
+
+    This entry generates the following device tree structure form the example
+    above::
+
+        data = [...]
+        cipher {
+            algo = "aes256-gcm";
+            key = <0x...>;
+            iv = <0x...>;
+        };
+
+    The data property is generated by the blob-ext etype, the cipher node and
+    its content is generated by this etype.
+
+    Using an external key
+    ~~~~~~~~~~~~~~~~~~~~~
+
+    Instead of embedding the key itself into the device tree, it is also
+    possible to address an externally stored key by specifying a 'key-source'
+    instead of the 'key'::
+
+        encrypted_blob: blob-ext {
+            filename = "encrypted-blob.bin";
+        };
+
+        encrypted {
+            content = <&encrypted_blob>;
+            algo = "aes256-gcm";
+            iv-filename = "encrypted-blob.bin.iv";
+            key-source = "external-key-id";
+        };
+
+    This entry generates the following device tree structure form the example
+    above::
+
+        data = [...]
+        cipher {
+            algo = "aes256-gcm";
+            key-source = "external-key-id";
+            iv = <0x...>;
+        };
+
+    Properties
+    ~~~~~~~~~~
+
+    In addition to the inherited 'collection' for Properties / Entry arguments:
+        - algo: The encryption algorithm. Currently no algorithm is supported
+                out-of-the-box. Certain algorithms will be added in future
+                patches.
+        - iv-filename: The name of the file containing the initialization
+                       vector (in short iv). See
+                       https://en.wikipedia.org/wiki/Initialization_vector
+        - key-filename: The name of the file containing the key. Either
+                        key-filename or key-source must be provided.
+        - key-source: The key that should be used. Either key-filename or
+                      key-source must be provided.
+    """
+
+    def __init__(self, section, etype, node):
+        # Put this here to allow entry-docs and help to work without libfdt
+        global state
+        from binman import state
+
+        super().__init__(section, etype, node)
+        self.required_props = ['algo', 'iv-filename']
+        self._algo = None
+        self._iv_filename = None
+        self._key_name_hint = None
+        self._key_filename = None
+
+    def ReadNode(self):
+        super().ReadNode()
+
+        self._algo = fdt_util.GetString(self._node, 'algo')
+        self._iv_filename = fdt_util.GetString(self._node, 'iv-filename')
+        self._key_filename = fdt_util.GetString(self._node, 'key-filename')
+        self._key_source = fdt_util.GetString(self._node, 'key-source')
+
+        if self._key_filename is None and self._key_source is None:
+            self.Raise("Provide either 'key-filename' or 'key-source'")
+
+    def gen_entries(self):
+        super().gen_entries()
+
+        iv_filename = tools.get_input_filename(self._iv_filename)
+        iv = tools.read_file(iv_filename, binary=True)
+
+        cipher_node = state.AddSubnode(self._node.parent, "cipher")
+        cipher_node.AddString("algo", self._algo)
+        cipher_node.AddData("iv", iv)
+
+        if self._key_filename:
+            key_filename = tools.get_input_filename(self._key_filename)
+            key = tools.read_file(key_filename, binary=True)
+            cipher_node.AddData("key", key)
+
+        if self._key_source:
+            cipher_node.AddString("key-source", self._key_source)
+
+    def ObtainContents(self):
+        """Set to empty contents
+
+        Ensure that linked content is not added to the device tree again from
+        this entry.
+        """
+        self.SetContents(b'')
+        return True
+
+    def ProcessContents(self):
+        """Set to empty contents
+
+        Ensure that linked content is not added to the device tree again from
+        this entry.
+        """
+        return self.ProcessContentsUpdate(b'')
-- 
2.34.1



More information about the U-Boot mailing list