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

From: Christian Taedcke christian.taedcke@weidmueller.com
This series adds the functionality to handle externally encrypted blobs to binman. It includes the functionality itself and the corresponding unit tests.
The following block shows an example on how to use this functionality. In the device tree that is parsed by binman a new node encrypted is used:
/ { binman { filename = "u-boot.itb"; fit { ... images { some-bitstream { ... image_bitstream: blob-ext { filename = "bitstream.bin"; }; encrypted { content = <&image_bitstream>; algo = "aes256-gcm"; iv-filename = "bitstream.bin.iv"; key-filename = "bitstream.bin.key"; }; ...
This results in an generated fit image containing the following information:
\ { images { ... some-bitstream { ... data = [...] cipher { algo = "aes256-gcm"; key = <0x...>; iv = <0x...>; }; }; ...
Changes in v4: - fix failing test testEncryptedKeyFile
Changes in v3: - rebase on u-boot-dm/mkim-working - remove unnecessary test testEncryptedNoContent - update doc for functions ObtainContents and ProcessContents - update entries.rst - wrap some lines at 80 cols
Changes in v2: - adapt tests for changed entry implementation - add entry documentation - remove global /cipher node - replace key-name-hint with key-source property
Christian Taedcke (3): binman: Add support for externally encrypted blobs binman: Allow cipher node as special section binman: Add tests for etype encrypted
tools/binman/entries.rst | 88 ++++++++++ tools/binman/etype/encrypted.py | 157 ++++++++++++++++++ tools/binman/etype/section.py | 2 +- tools/binman/ftest.py | 53 ++++++ tools/binman/test/291_encrypted_no_algo.dts | 19 +++ .../test/292_encrypted_invalid_iv_file.dts | 23 +++ .../binman/test/293_encrypted_missing_key.dts | 28 ++++ .../binman/test/294_encrypted_key_source.dts | 29 ++++ tools/binman/test/295_encrypted_key_file.dts | 29 ++++ 9 files changed, 427 insertions(+), 1 deletion(-) create mode 100644 tools/binman/etype/encrypted.py create mode 100644 tools/binman/test/291_encrypted_no_algo.dts create mode 100644 tools/binman/test/292_encrypted_invalid_iv_file.dts create mode 100644 tools/binman/test/293_encrypted_missing_key.dts create mode 100644 tools/binman/test/294_encrypted_key_source.dts create mode 100644 tools/binman/test/295_encrypted_key_file.dts

From: Christian Taedcke christian.taedcke@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@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@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'')

Hi Christian,
On 2023-07-10 11:25, christian.taedcke-oss@weidmueller.com wrote:
From: Christian Taedcke christian.taedcke@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@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?
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.
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"); };
Regards, Jonas
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@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'')

Hello Jonas,
Am 10.07.2023 um 12:48 schrieb Jonas Karlman:
Hi Christian,
On 2023-07-10 11:25, christian.taedcke-oss@weidmueller.com wrote:
From: Christian Taedcke christian.taedcke@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@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@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'')

Hello Jonas,
On 10.07.2023 12:48, Jonas Karlman wrote:
Hi Christian,
On 2023-07-10 11:25, christian.taedcke-oss@weidmueller.com wrote:
From: Christian Taedcke christian.taedcke@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@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?
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.
I tried renaming the etype to cipher, but this leads to further complications. After renaming the etype to cipher, the node cipher in the device tree has basically two different states/meanings. Initially it contains the input to binman, so binman passes the node and its properties to the etype, so the etype can evaluate it. After this is done the cipher node contains new, different properties that should not be evaluated by binman again, but simply written out to the generated device tree. But since binman does not simply parse the device tree once and writes out the result, i get an error when binman tries to pass the generated cipher node (containing the new properties that should end up in the resulting device tree) to the cipher etype again.
So in the next version of the patch series i would keep the etype name encrypted.
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"); };
Regards, Jonas
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@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'')
Regards, Christian

Hi Christian,
On Tue, 11 Jul 2023 at 08:58, Taedcke, Christian christian.taedcke-oss@weidmueller.com wrote:
Hello Jonas,
On 10.07.2023 12:48, Jonas Karlman wrote:
Hi Christian,
On 2023-07-10 11:25, christian.taedcke-oss@weidmueller.com wrote:
From: Christian Taedcke christian.taedcke@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@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?
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.
I tried renaming the etype to cipher, but this leads to further complications. After renaming the etype to cipher, the node cipher in the device tree has basically two different states/meanings. Initially it contains the input to binman, so binman passes the node and its properties to the etype, so the etype can evaluate it. After this is done the cipher node contains new, different properties that should not be evaluated by binman again, but simply written out to the generated device tree. But since binman does not simply parse the device tree once and writes out the result, i get an error when binman tries to pass the generated cipher node (containing the new properties that should end up in the resulting device tree) to the cipher etype again.
So in the next version of the patch series i would keep the etype name encrypted.
Could you please post the error you get? Binman should not process the nodes more than once. I might be able to fix it.
Regards, Simon

Hello Simon,
thank you for your help so far.
On 11.07.2023 17:01, Simon Glass wrote:
Hi Christian,
On Tue, 11 Jul 2023 at 08:58, Taedcke, Christian christian.taedcke-oss@weidmueller.com wrote:
Hello Jonas,
On 10.07.2023 12:48, Jonas Karlman wrote:
Hi Christian,
On 2023-07-10 11:25, christian.taedcke-oss@weidmueller.com wrote:
From: Christian Taedcke christian.taedcke@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@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?
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.
I tried renaming the etype to cipher, but this leads to further complications. After renaming the etype to cipher, the node cipher in the device tree has basically two different states/meanings. Initially it contains the input to binman, so binman passes the node and its properties to the etype, so the etype can evaluate it. After this is done the cipher node contains new, different properties that should not be evaluated by binman again, but simply written out to the generated device tree. But since binman does not simply parse the device tree once and writes out the result, i get an error when binman tries to pass the generated cipher node (containing the new properties that should end up in the resulting device tree) to the cipher etype again.
So in the next version of the patch series i would keep the etype name encrypted.
Could you please post the error you get? Binman should not process the nodes more than once. I might be able to fix it.
I misinterpreted my issue. So my etype is not processed twice.
But i am not able to replace the cipher node or the content of the cipher node. When i try to get the binman output in the unit test, i always get the original cipher node, not the one that i am trying to create in my etype.
The unit test looks like this: data = self._DoReadFileDtb('295_cipher_key_file.dts')[0] dtb = fdt.Fdt.FromData(data) dtb.Scan() node = dtb.GetNode('/images/u-boot/cipher')
Is this the correct sequence for the unit test?
In the new cipher etype, i tried 2 approaches, none of them worked for me:
1. Delete all properties from the current node (self._node) and add the new properties. To delete the properties i used: props = list(self._node.props) for prop in props: self._node.DeleteProp(prop)
2. Delete the current cipher node completely and create a new one. parent = self._node.parent self._node.purge() cipher_node = state.AddSubnode(parent, "cipher")
I tried this in the etype method "def gen_entries(self)" and also in "def ProcessFdt(self, fdt)"
How can i replace the initial cipher node that is read from the dts file with a new cipher node that is created in the etype?
Regards, Simon
Regards, Christian

Hi Christian,
On Wed, 12 Jul 2023 at 03:20, Taedcke, Christian christian.taedcke-oss@weidmueller.com wrote:
Hello Simon,
thank you for your help so far.
On 11.07.2023 17:01, Simon Glass wrote:
Hi Christian,
On Tue, 11 Jul 2023 at 08:58, Taedcke, Christian christian.taedcke-oss@weidmueller.com wrote:
Hello Jonas,
On 10.07.2023 12:48, Jonas Karlman wrote:
Hi Christian,
On 2023-07-10 11:25, christian.taedcke-oss@weidmueller.com wrote:
From: Christian Taedcke christian.taedcke@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@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?
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.
I tried renaming the etype to cipher, but this leads to further complications. After renaming the etype to cipher, the node cipher in the device tree has basically two different states/meanings. Initially it contains the input to binman, so binman passes the node and its properties to the etype, so the etype can evaluate it. After this is done the cipher node contains new, different properties that should not be evaluated by binman again, but simply written out to the generated device tree. But since binman does not simply parse the device tree once and writes out the result, i get an error when binman tries to pass the generated cipher node (containing the new properties that should end up in the resulting device tree) to the cipher etype again.
So in the next version of the patch series i would keep the etype name encrypted.
Could you please post the error you get? Binman should not process the nodes more than once. I might be able to fix it.
I misinterpreted my issue. So my etype is not processed twice.
But i am not able to replace the cipher node or the content of the cipher node. When i try to get the binman output in the unit test, i always get the original cipher node, not the one that i am trying to create in my etype.
The unit test looks like this: data = self._DoReadFileDtb('295_cipher_key_file.dts')[0] dtb = fdt.Fdt.FromData(data) dtb.Scan() node = dtb.GetNode('/images/u-boot/cipher')
Is this the correct sequence for the unit test?
You should be aware that Binman fakes almost all data in tests, by default. For example the 'u-boot' entry results in contents of '1234'. This is for easy inspection and debugging.
If you use _DoReadFileRealDtb() it will avoid that.
In the new cipher etype, i tried 2 approaches, none of them worked for me:
- Delete all properties from the current node (self._node) and add the
new properties. To delete the properties i used: props = list(self._node.props) for prop in props: self._node.DeleteProp(prop)
- Delete the current cipher node completely and create a new one. parent = self._node.parent self._node.purge() cipher_node = state.AddSubnode(parent, "cipher")
I tried this in the etype method "def gen_entries(self)" and also in "def ProcessFdt(self, fdt)"
How can i replace the initial cipher node that is read from the dts file with a new cipher node that is created in the etype?
You should only need to add the new properties, as with 2. The purge should not be necessary unless you are deleting things, etc.
Regards, Simon

From: Christian Taedcke christian.taedcke@weidmueller.com
The new encrypted etype generates a cipher node in the device tree that should not be evaluated by binman, but still be kept in the output device tree.
Signed-off-by: Christian Taedcke christian.taedcke@weidmueller.com ---
(no changes since v3)
Changes in v3: - rebase on u-boot-dm/mkim-working
tools/binman/etype/section.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index 7c4d312c16..fb49e85a76 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -179,7 +179,7 @@ class Entry_section(Entry): Returns: bool: True if the node is a special one, else False """ - start_list = ('hash', 'signature', 'template') + start_list = ('cipher', 'hash', 'signature', 'template') return any(node.name.startswith(name) for name in start_list)
def ReadNode(self):

On Mon, 10 Jul 2023 at 03:26, christian.taedcke-oss@weidmueller.com wrote:
From: Christian Taedcke christian.taedcke@weidmueller.com
The new encrypted etype generates a cipher node in the device tree that should not be evaluated by binman, but still be kept in the output device tree.
Signed-off-by: Christian Taedcke christian.taedcke@weidmueller.com
(no changes since v3)
Changes in v3:
- rebase on u-boot-dm/mkim-working
tools/binman/etype/section.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
As a follow-up if you have time - can you add a list of the special nodes to the docs?

From: Christian Taedcke christian.taedcke@weidmueller.com
Add tests to reach 100% code coverage for the added etype encrypted.
Signed-off-by: Christian Taedcke christian.taedcke@weidmueller.com ---
Changes in v4: - fix failing test testEncryptedKeyFile
Changes in v3: - rebase on u-boot-dm/mkim-working - remove unnecessary test testEncryptedNoContent - wrap some lines at 80 cols
Changes in v2: - adapt tests for changed entry implementation
tools/binman/ftest.py | 53 +++++++++++++++++++ tools/binman/test/291_encrypted_no_algo.dts | 19 +++++++ .../test/292_encrypted_invalid_iv_file.dts | 23 ++++++++ .../binman/test/293_encrypted_missing_key.dts | 28 ++++++++++ .../binman/test/294_encrypted_key_source.dts | 29 ++++++++++ tools/binman/test/295_encrypted_key_file.dts | 29 ++++++++++ 6 files changed, 181 insertions(+) create mode 100644 tools/binman/test/291_encrypted_no_algo.dts create mode 100644 tools/binman/test/292_encrypted_invalid_iv_file.dts create mode 100644 tools/binman/test/293_encrypted_missing_key.dts create mode 100644 tools/binman/test/294_encrypted_key_source.dts create mode 100644 tools/binman/test/295_encrypted_key_file.dts
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index e53181afb7..c1ace9a401 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -94,6 +94,8 @@ ROCKCHIP_TPL_DATA = b'rockchip-tpl' TEST_FDT1_DATA = b'fdt1' TEST_FDT2_DATA = b'test-fdt2' ENV_DATA = b'var1=1\nvar2="2"' +ENCRYPTED_IV_DATA = b'123456' +ENCRYPTED_KEY_DATA = b'abcde' PRE_LOAD_MAGIC = b'UBSH' PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big') PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big') @@ -226,6 +228,10 @@ class TestFunctional(unittest.TestCase): # Newer OP_TEE file in v1 binary format cls.make_tee_bin('tee.bin')
+ # test files for encrypted tests + TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA) + TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA) + cls.comp_bintools = {} for name in COMP_BINTOOLS: cls.comp_bintools[name] = bintool.Bintool.create(name) @@ -6884,6 +6890,53 @@ fdt fdtmap Extract the devicetree blob from the fdtmap # Move to next spl_data = content[:0x18]
+ def testEncryptedNoAlgo(self): + with self.assertRaises(ValueError) as e: + self._DoReadFileDtb('291_encrypted_no_algo.dts') + self.assertIn( + "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename", + str(e.exception)) + + def testEncryptedInvalidIvfile(self): + with self.assertRaises(ValueError) as e: + self._DoReadFileDtb('292_encrypted_invalid_iv_file.dts') + self.assertIn("Filename 'invalid-iv-file' not found in input path", + str(e.exception)) + + def testEncryptedMissingKey(self): + with self.assertRaises(ValueError) as e: + self._DoReadFileDtb('293_encrypted_missing_key.dts') + self.assertIn( + "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'", + str(e.exception)) + + def testEncryptedKeySource(self): + data = self._DoReadFileDtb('294_encrypted_key_source.dts')[0] + + dtb = fdt.Fdt.FromData(data) + dtb.Scan() + + node = dtb.GetNode('/images/u-boot/cipher') + self.assertEqual('algo-name', node.props['algo'].value) + self.assertEqual('key-source-value', node.props['key-source'].value) + self.assertEqual(ENCRYPTED_IV_DATA, + tools.to_bytes(''.join(node.props['iv'].value))) + self.assertNotIn('key', node.props) + + def testEncryptedKeyFile(self): + data = self._DoReadFileDtb('295_encrypted_key_file.dts')[0] + + dtb = fdt.Fdt.FromData(data) + dtb.Scan() + + node = dtb.GetNode('/images/u-boot/cipher') + self.assertEqual('algo-name', node.props['algo'].value) + self.assertEqual(ENCRYPTED_IV_DATA, + tools.to_bytes(''.join(node.props['iv'].value))) + self.assertEqual(ENCRYPTED_KEY_DATA, + tools.to_bytes(''.join(node.props['key'].value))) + self.assertNotIn('key-source', node.props) +
if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/291_encrypted_no_algo.dts b/tools/binman/test/291_encrypted_no_algo.dts new file mode 100644 index 0000000000..71975c0116 --- /dev/null +++ b/tools/binman/test/291_encrypted_no_algo.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + fit { + images { + u-boot { + encrypted { + content = <&data>; + }; + + data: data { + }; + }; + }; + }; + }; +}; diff --git a/tools/binman/test/292_encrypted_invalid_iv_file.dts b/tools/binman/test/292_encrypted_invalid_iv_file.dts new file mode 100644 index 0000000000..1764d5e503 --- /dev/null +++ b/tools/binman/test/292_encrypted_invalid_iv_file.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + fit { + images { + u-boot { + blob: blob { + filename = "blobfile"; + }; + + encrypted { + content = <&blob>; + algo = "some-algo"; + key-source = "key"; + iv-filename = "invalid-iv-file"; + }; + }; + }; + }; + }; +}; diff --git a/tools/binman/test/293_encrypted_missing_key.dts b/tools/binman/test/293_encrypted_missing_key.dts new file mode 100644 index 0000000000..9d342d6f45 --- /dev/null +++ b/tools/binman/test/293_encrypted_missing_key.dts @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + fit { + description = "test desc"; + + images { + u-boot { + blob: blob { + filename = "blobfile"; + }; + + encrypted { + content = <&blob>; + algo = "algo-name"; + iv-filename = "encrypted-file.iv"; + }; + }; + }; + }; + }; +}; diff --git a/tools/binman/test/294_encrypted_key_source.dts b/tools/binman/test/294_encrypted_key_source.dts new file mode 100644 index 0000000000..d2529b9c3a --- /dev/null +++ b/tools/binman/test/294_encrypted_key_source.dts @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + fit { + description = "test desc"; + + images { + u-boot { + blob: blob { + filename = "blobfile"; + }; + + encrypted { + content = <&blob>; + algo = "algo-name"; + key-source = "key-source-value"; + iv-filename = "encrypted-file.iv"; + }; + }; + }; + }; + }; +}; diff --git a/tools/binman/test/295_encrypted_key_file.dts b/tools/binman/test/295_encrypted_key_file.dts new file mode 100644 index 0000000000..71f1ab47b1 --- /dev/null +++ b/tools/binman/test/295_encrypted_key_file.dts @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + fit { + description = "test desc"; + + images { + u-boot { + blob: blob { + filename = "blobfile"; + }; + + encrypted { + content = <&blob>; + algo = "algo-name"; + iv-filename = "encrypted-file.iv"; + key-filename = "encrypted-file.key"; + }; + }; + }; + }; + }; +};

Hi Christian,
On Mon, 10 Jul 2023 at 03:26, christian.taedcke-oss@weidmueller.com wrote:
From: Christian Taedcke christian.taedcke@weidmueller.com
Add tests to reach 100% code coverage for the added etype encrypted.
Signed-off-by: Christian Taedcke christian.taedcke@weidmueller.com
Changes in v4:
- fix failing test testEncryptedKeyFile
Changes in v3:
- rebase on u-boot-dm/mkim-working
- remove unnecessary test testEncryptedNoContent
- wrap some lines at 80 cols
Changes in v2:
- adapt tests for changed entry implementation
tools/binman/ftest.py | 53 +++++++++++++++++++ tools/binman/test/291_encrypted_no_algo.dts | 19 +++++++ .../test/292_encrypted_invalid_iv_file.dts | 23 ++++++++ .../binman/test/293_encrypted_missing_key.dts | 28 ++++++++++ .../binman/test/294_encrypted_key_source.dts | 29 ++++++++++ tools/binman/test/295_encrypted_key_file.dts | 29 ++++++++++ 6 files changed, 181 insertions(+) create mode 100644 tools/binman/test/291_encrypted_no_algo.dts create mode 100644 tools/binman/test/292_encrypted_invalid_iv_file.dts create mode 100644 tools/binman/test/293_encrypted_missing_key.dts create mode 100644 tools/binman/test/294_encrypted_key_source.dts create mode 100644 tools/binman/test/295_encrypted_key_file.dts
nit below:
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index e53181afb7..c1ace9a401 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -94,6 +94,8 @@ ROCKCHIP_TPL_DATA = b'rockchip-tpl' TEST_FDT1_DATA = b'fdt1' TEST_FDT2_DATA = b'test-fdt2' ENV_DATA = b'var1=1\nvar2="2"' +ENCRYPTED_IV_DATA = b'123456' +ENCRYPTED_KEY_DATA = b'abcde' PRE_LOAD_MAGIC = b'UBSH' PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big') PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big') @@ -226,6 +228,10 @@ class TestFunctional(unittest.TestCase): # Newer OP_TEE file in v1 binary format cls.make_tee_bin('tee.bin')
# test files for encrypted tests
TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
cls.comp_bintools = {} for name in COMP_BINTOOLS: cls.comp_bintools[name] = bintool.Bintool.create(name)
@@ -6884,6 +6890,53 @@ fdt fdtmap Extract the devicetree blob from the fdtmap # Move to next spl_data = content[:0x18]
- def testEncryptedNoAlgo(self):
with self.assertRaises(ValueError) as e:
self._DoReadFileDtb('291_encrypted_no_algo.dts')
self.assertIn(
"Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
str(e.exception))
- def testEncryptedInvalidIvfile(self):
Please can you add a one-line comment to all of these function?
with self.assertRaises(ValueError) as e:
self._DoReadFileDtb('292_encrypted_invalid_iv_file.dts')
self.assertIn("Filename 'invalid-iv-file' not found in input path",
str(e.exception))
- def testEncryptedMissingKey(self):
with self.assertRaises(ValueError) as e:
self._DoReadFileDtb('293_encrypted_missing_key.dts')
self.assertIn(
"Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
str(e.exception))
- def testEncryptedKeySource(self):
data = self._DoReadFileDtb('294_encrypted_key_source.dts')[0]
dtb = fdt.Fdt.FromData(data)
dtb.Scan()
node = dtb.GetNode('/images/u-boot/cipher')
self.assertEqual('algo-name', node.props['algo'].value)
self.assertEqual('key-source-value', node.props['key-source'].value)
self.assertEqual(ENCRYPTED_IV_DATA,
tools.to_bytes(''.join(node.props['iv'].value)))
self.assertNotIn('key', node.props)
- def testEncryptedKeyFile(self):
data = self._DoReadFileDtb('295_encrypted_key_file.dts')[0]
dtb = fdt.Fdt.FromData(data)
dtb.Scan()
node = dtb.GetNode('/images/u-boot/cipher')
self.assertEqual('algo-name', node.props['algo'].value)
self.assertEqual(ENCRYPTED_IV_DATA,
tools.to_bytes(''.join(node.props['iv'].value)))
self.assertEqual(ENCRYPTED_KEY_DATA,
tools.to_bytes(''.join(node.props['key'].value)))
self.assertNotIn('key-source', node.props)
[..]
Regards, Simon
participants (4)
-
christian.taedcke-oss@weidmueller.com
-
Jonas Karlman
-
Simon Glass
-
Taedcke, Christian