[PATCH v4 1/3] binman: Add support for externally encrypted blobs
Taedcke, Christian
christian.taedcke-oss at weidmueller.com
Mon Jul 10 14:33:53 CEST 2023
Hello Jonas,
Am 10.07.2023 um 12:48 schrieb Jonas Karlman:
> Hi Christian,
>
> On 2023-07-10 11:25, christian.taedcke-oss at weidmueller.com wrote:
>> 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>;
>
> Why is this content reference needed?
Now it is not used at all in the code. It is only some kind of
documentation that shows which data is encrypted. It was used in a
previous patch to determine the size of the encrypted data.
I will remove this in the next version of the patch.
>
> It does not look like this content is used by the etype and if the etype
> intends to encrypt the content this etype should probably be a section
> and wrap content nodes instead of referencing it.
>
> If the content is not intended to be encrypted by this etype the name
> of the etype is misleading, cipher may be a better name if the intended
> use is to produce a cipher node for an already encrypted blob.
This etype is not meant to encrypt the data. Because of this i named the
etype encrypted and not encrypt. But i can rename the etype to cipher,
since it only adds a cipher node into the generated device tree.
>
> Also look like something like the following could be added without an
> etype and just the IsSpecialSubnode patch. An etype may be more
> convenient.
>
> cipher {
> algo = "aes256-gcm";
> key = /incbin/("/path/to/encrypted-blob.bin.key");
> iv = /incbin/("/path/to/encrypted-blob.bin.iv");
> };
You are right, with the removal of the global /cipher node in v2, it
would be possible to do this without implementing a new etype. The
benfit of the etype is that there is a check, that the required
properties are set. In addition the search directory for the provided
binaries can be controlled via the environment variable BINMAN_INDIRS
instead of providing the search path to dtc.
I would prefer to keep the etype.
>
> Regards,
> Jonas
>
Regards,
Christian
>> + 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'')
>
More information about the U-Boot
mailing list