mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
tools: binman: add support for pre-load header
Adds the support of the pre-load header with the image signature to binman. Reviewed-by: Simon Glass <sjg@chromium.org> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
This commit is contained in:
parent
d12c1be903
commit
b1c5093008
11 changed files with 439 additions and 0 deletions
|
@ -1155,6 +1155,44 @@ placed at offset 'RESET_VECTOR_ADDRESS - 0xffc'.
|
|||
|
||||
|
||||
|
||||
Entry: pre-load: Pre load image header
|
||||
--------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- key-path: Path of the directory that store key (provided by the environment variable KEY_PATH)
|
||||
- content: List of phandles to entries to sign
|
||||
- algo-name: Hash and signature algo to use for the signature
|
||||
- padding-name: Name of the padding (pkcs-1.5 or pss)
|
||||
- key-name: Filename of the private key to sign
|
||||
- header-size: Total size of the header
|
||||
- version: Version of the header
|
||||
|
||||
This entry creates a pre-load header that contains a global
|
||||
image signature.
|
||||
|
||||
For example, this creates an image with a pre-load header and a binary::
|
||||
|
||||
binman {
|
||||
image2 {
|
||||
filename = "sandbox.bin";
|
||||
|
||||
pre-load {
|
||||
content = <&image>;
|
||||
algo-name = "sha256,rsa2048";
|
||||
padding-name = "pss";
|
||||
key-name = "private.pem";
|
||||
header-size = <4096>;
|
||||
version = <1>;
|
||||
};
|
||||
|
||||
image: blob-ext {
|
||||
filename = "sandbox.itb";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
Entry: scp: System Control Processor (SCP) firmware blob
|
||||
--------------------------------------------------------
|
||||
|
||||
|
|
162
tools/binman/etype/pre_load.py
Normal file
162
tools/binman/etype/pre_load.py
Normal file
|
@ -0,0 +1,162 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2022 Softathome
|
||||
# Written by Philippe Reynes <philippe.reynes@softathome.com>
|
||||
#
|
||||
# Entry-type for the global header
|
||||
#
|
||||
|
||||
import os
|
||||
import struct
|
||||
from dtoc import fdt_util
|
||||
from patman import tools
|
||||
|
||||
from binman.entry import Entry
|
||||
from binman.etype.collection import Entry_collection
|
||||
from binman.entry import EntryArg
|
||||
|
||||
from Cryptodome.Hash import SHA256, SHA384, SHA512
|
||||
from Cryptodome.PublicKey import RSA
|
||||
from Cryptodome.Signature import pkcs1_15
|
||||
from Cryptodome.Signature import pss
|
||||
|
||||
PRE_LOAD_MAGIC = b'UBSH'
|
||||
|
||||
RSAS = {
|
||||
'rsa1024': 1024 / 8,
|
||||
'rsa2048': 2048 / 8,
|
||||
'rsa4096': 4096 / 8
|
||||
}
|
||||
|
||||
SHAS = {
|
||||
'sha256': SHA256,
|
||||
'sha384': SHA384,
|
||||
'sha512': SHA512
|
||||
}
|
||||
|
||||
class Entry_pre_load(Entry_collection):
|
||||
"""Pre load image header
|
||||
|
||||
Properties / Entry arguments:
|
||||
- pre-load-key-path: Path of the directory that store key (provided by the environment variable PRE_LOAD_KEY_PATH)
|
||||
- content: List of phandles to entries to sign
|
||||
- algo-name: Hash and signature algo to use for the signature
|
||||
- padding-name: Name of the padding (pkcs-1.5 or pss)
|
||||
- key-name: Filename of the private key to sign
|
||||
- header-size: Total size of the header
|
||||
- version: Version of the header
|
||||
|
||||
This entry creates a pre-load header that contains a global
|
||||
image signature.
|
||||
|
||||
For example, this creates an image with a pre-load header and a binary::
|
||||
|
||||
binman {
|
||||
image2 {
|
||||
filename = "sandbox.bin";
|
||||
|
||||
pre-load {
|
||||
content = <&image>;
|
||||
algo-name = "sha256,rsa2048";
|
||||
padding-name = "pss";
|
||||
key-name = "private.pem";
|
||||
header-size = <4096>;
|
||||
version = <1>;
|
||||
};
|
||||
|
||||
image: blob-ext {
|
||||
filename = "sandbox.itb";
|
||||
};
|
||||
};
|
||||
};
|
||||
"""
|
||||
|
||||
def __init__(self, section, etype, node):
|
||||
super().__init__(section, etype, node)
|
||||
self.algo_name = fdt_util.GetString(self._node, 'algo-name')
|
||||
self.padding_name = fdt_util.GetString(self._node, 'padding-name')
|
||||
self.key_name = fdt_util.GetString(self._node, 'key-name')
|
||||
self.header_size = fdt_util.GetInt(self._node, 'header-size')
|
||||
self.version = fdt_util.GetInt(self._node, 'version')
|
||||
|
||||
def ReadNode(self):
|
||||
super().ReadNode()
|
||||
self.key_path, = self.GetEntryArgsOrProps([EntryArg('pre-load-key-path', str)])
|
||||
if self.key_path is None:
|
||||
self.key_path = ''
|
||||
|
||||
def _CreateHeader(self):
|
||||
"""Create a pre load header"""
|
||||
hash_name, sign_name = self.algo_name.split(',')
|
||||
padding_name = self.padding_name
|
||||
key_name = os.path.join(self.key_path, self.key_name)
|
||||
|
||||
# Check hash and signature name/type
|
||||
if hash_name not in SHAS:
|
||||
self.Raise(hash_name + " is not supported")
|
||||
if sign_name not in RSAS:
|
||||
self.Raise(sign_name + " is not supported")
|
||||
|
||||
# Read the key
|
||||
with open(key_name, 'rb') as pem:
|
||||
key = RSA.import_key(pem.read())
|
||||
|
||||
# Check if the key has the expected size
|
||||
if key.size_in_bytes() != RSAS[sign_name]:
|
||||
self.Raise("The key " + self.key_name + " don't have the expected size")
|
||||
|
||||
# Compute the hash
|
||||
hash_image = SHAS[hash_name].new()
|
||||
hash_image.update(self.image)
|
||||
|
||||
# Compute the signature
|
||||
if padding_name is None:
|
||||
padding_name = "pkcs-1.5"
|
||||
if padding_name == "pss":
|
||||
salt_len = key.size_in_bytes() - hash_image.digest_size - 2
|
||||
padding = pss
|
||||
padding_args = {'salt_bytes': salt_len}
|
||||
elif padding_name == "pkcs-1.5":
|
||||
padding = pkcs1_15
|
||||
padding_args = {}
|
||||
else:
|
||||
self.Raise(padding_name + " is not supported")
|
||||
|
||||
sig = padding.new(key, **padding_args).sign(hash_image)
|
||||
|
||||
hash_sig = SHA256.new()
|
||||
hash_sig.update(sig)
|
||||
|
||||
version = self.version
|
||||
header_size = self.header_size
|
||||
image_size = len(self.image)
|
||||
ofs_img_sig = 64 + len(sig)
|
||||
flags = 0
|
||||
reserved0 = 0
|
||||
reserved1 = 0
|
||||
|
||||
first_header = struct.pack('>4sIIIIIII32s', PRE_LOAD_MAGIC,
|
||||
version, header_size, image_size,
|
||||
ofs_img_sig, flags, reserved0,
|
||||
reserved1, hash_sig.digest())
|
||||
|
||||
hash_first_header = SHAS[hash_name].new()
|
||||
hash_first_header.update(first_header)
|
||||
sig_first_header = padding.new(key, **padding_args).sign(hash_first_header)
|
||||
|
||||
data = first_header + sig_first_header + sig
|
||||
pad = bytearray(self.header_size - len(data))
|
||||
|
||||
return data + pad
|
||||
|
||||
def ObtainContents(self):
|
||||
"""Obtain a placeholder for the header contents"""
|
||||
# wait that the image is available
|
||||
self.image = self.GetContents(False)
|
||||
if self.image is None:
|
||||
return False
|
||||
self.SetContents(self._CreateHeader())
|
||||
return True
|
||||
|
||||
def ProcessContents(self):
|
||||
data = self._CreateHeader()
|
||||
return self.ProcessContentsUpdate(data)
|
|
@ -91,6 +91,9 @@ SCP_DATA = b'scp'
|
|||
TEST_FDT1_DATA = b'fdt1'
|
||||
TEST_FDT2_DATA = b'test-fdt2'
|
||||
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')
|
||||
|
||||
# Subdirectory of the input dir to use to put test FDTs
|
||||
TEST_FDT_SUBDIR = 'fdts'
|
||||
|
@ -5471,6 +5474,54 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
|
|||
err,
|
||||
"Image '.*' is missing external blobs and is non-functional: .*")
|
||||
|
||||
def testPreLoad(self):
|
||||
"""Test an image with a pre-load header"""
|
||||
entry_args = {
|
||||
'pre-load-key-path': '.',
|
||||
}
|
||||
data, _, _, _ = self._DoReadFileDtb('225_pre_load.dts',
|
||||
entry_args=entry_args)
|
||||
self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
|
||||
self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
|
||||
self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
|
||||
data = self._DoReadFile('225_pre_load.dts')
|
||||
self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
|
||||
self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
|
||||
self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
|
||||
|
||||
def testPreLoadPkcs(self):
|
||||
"""Test an image with a pre-load header with padding pkcs"""
|
||||
data = self._DoReadFile('226_pre_load_pkcs.dts')
|
||||
self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
|
||||
self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
|
||||
self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
|
||||
|
||||
def testPreLoadPss(self):
|
||||
"""Test an image with a pre-load header with padding pss"""
|
||||
data = self._DoReadFile('227_pre_load_pss.dts')
|
||||
self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
|
||||
self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
|
||||
self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
|
||||
|
||||
def testPreLoadInvalidPadding(self):
|
||||
"""Test an image with a pre-load header with an invalid padding"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
data = self._DoReadFile('228_pre_load_invalid_padding.dts')
|
||||
|
||||
def testPreLoadInvalidSha(self):
|
||||
"""Test an image with a pre-load header with an invalid hash"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
data = self._DoReadFile('229_pre_load_invalid_sha.dts')
|
||||
|
||||
def testPreLoadInvalidAlgo(self):
|
||||
"""Test an image with a pre-load header with an invalid algo"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
data = self._DoReadFile('230_pre_load_invalid_algo.dts')
|
||||
|
||||
def testPreLoadInvalidKey(self):
|
||||
"""Test an image with a pre-load header with an invalid key"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
data = self._DoReadFile('231_pre_load_invalid_key.dts')
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
28
tools/binman/test/225_dev.key
Normal file
28
tools/binman/test/225_dev.key
Normal file
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDYngNWUvXYRXX/
|
||||
WEUI7k164fcpv1srXz+u+5Y3Yhouw3kPs+ffvYyHAPfjF7aUIAgezKk/4o7AvsxE
|
||||
Rdih3T+0deAd/q/yuqN4Adzt6ImnsO/EqdtYl3Yh+Vck9xWhLd3SAw1++GfSmNMT
|
||||
gxlcc/z6z+bIh2tJNtPtRSNNHMmvYYOkBmkfwcjbMXD+fe4vBwYjVrIize+l7Yuv
|
||||
1qN2nFlq56pFi8Lj5vOvFyNhZHRvwcpWdUdkx39beNUfwrGhgewOeWngTcY75n7S
|
||||
FY45TBR1G2PR90CQvyDinCi9Mm0u5s+1WASQWPblovfD6CPbHQu4GZm+FAs7yUvr
|
||||
hA7VCyNxAgMBAAECggEAUbq0uaJNfc8faTtNuMPo2d9eGRNI+8FRTt0/3R+Xj2NT
|
||||
TvhrGUD0P4++96Df012OkshXZ3I8uD6E5ZGQ3emTeqwq5kZM7oE64jGZwO3G2k1o
|
||||
+cO4reFfwgvItHrBX3HlyrI6KljhG1Vr9mW1cOuWXK+KfMiTUylrpo86dYLSGeg3
|
||||
7ZlsOPArr4eof/A0iPryQZX6X5POf7k/e9qRFYsOkoRQO8pBL3J4rIKwBl3uBN3K
|
||||
+FY40vCkd8JyTo2DNfHeIe1XYA9fG2ahjD2qMsw10TUsRRMd5yhonEcJ7VzGzy8m
|
||||
MnuMDAr7CwbbLkKi4UfZUl6YDkojqerwLOrxikBqkQKBgQD6sS6asDgwiq5MtstE
|
||||
4/PxMrVEsCdkrU+jjQN749qIt/41a6lbp0Pr6aUKKKGs0QbcnCtlpp7qmhvymBcW
|
||||
hlqxk2wokKMChv4WLXjZS3DGcOdMglc81y2F+252bToN8vwUfm6DPp9/GKtejA0a
|
||||
GP57GeHxoVO7vfDX1F/vZRogRQKBgQDdNCLWOlGWvnKjfgNZHgX+Ou6ZgTSAzy+/
|
||||
hRsZPlY5nwO5iD7YkIKvqBdOmfyjlUpHWk2uAcT9pfgzYygvyBRaoQhAYBGkHItt
|
||||
slaMxnLd+09wWufoCbgJvFn+wVQxBLcA5PXB98ws0Dq8ZYuo6AOuoRivsSO4lblK
|
||||
MW0guBJXPQKBgQDGjf0ukbH/aGfC5Oi8SJvWhuYhYC/jQo2YKUEAKCjXLnuOThZW
|
||||
PHXEbUrFcAcVfH0l0B9jJIQrpiHKlAF9Wq6MhQoeWuhxQQAQCrXzzRemZJgd9gIo
|
||||
cvlgbBNCgyJ/F9vmU3kuRDRJkv1wJhbee7tbPtXA7pkGUttl5pSRZI87zQKBgQC/
|
||||
0ZkwCox72xTQP9MpcYai6nnDta5Q0NnIC+Xu4wakmwcA2WweIlqhdnMXnyLcu/YY
|
||||
n+9iqHgpuMXd0eukW62C1cexA13o4TPrYU36b5BmfKprdPlLVzo3fxTPfNjEVSFY
|
||||
7jNLC9YLOlrkym3sf53Jzjr5B/RA+d0ewHOwfs6wxQKBgFSyfjx5wtdHK4fO+Z1+
|
||||
q3bxouZryM/4CiPCFuw4+aZmRHPmufuNCvfXdF+IH8dM0E9ObwKZAe/aMP/Y+Abx
|
||||
Wz9Vm4CP6g7k3DU3INEygyjmIQQDKQ9lFdDnsP9ESzrPbaGxZhc4x2lo7qmeW1BR
|
||||
/RuiAofleFkT4s+EhLrfE/v5
|
||||
-----END PRIVATE KEY-----
|
22
tools/binman/test/225_pre_load.dts
Normal file
22
tools/binman/test/225_pre_load.dts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pre-load {
|
||||
content = <&image>;
|
||||
algo-name = "sha256,rsa2048";
|
||||
key-name = "tools/binman/test/225_dev.key";
|
||||
header-size = <4096>;
|
||||
version = <0x11223344>;
|
||||
};
|
||||
|
||||
image: blob-ext {
|
||||
filename = "refcode.bin";
|
||||
};
|
||||
};
|
||||
};
|
23
tools/binman/test/226_pre_load_pkcs.dts
Normal file
23
tools/binman/test/226_pre_load_pkcs.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pre-load {
|
||||
content = <&image>;
|
||||
algo-name = "sha256,rsa2048";
|
||||
padding-name = "pkcs-1.5";
|
||||
key-name = "tools/binman/test/225_dev.key";
|
||||
header-size = <4096>;
|
||||
version = <0x11223344>;
|
||||
};
|
||||
|
||||
image: blob-ext {
|
||||
filename = "refcode.bin";
|
||||
};
|
||||
};
|
||||
};
|
23
tools/binman/test/227_pre_load_pss.dts
Normal file
23
tools/binman/test/227_pre_load_pss.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pre-load {
|
||||
content = <&image>;
|
||||
algo-name = "sha256,rsa2048";
|
||||
padding-name = "pss";
|
||||
key-name = "tools/binman/test/225_dev.key";
|
||||
header-size = <4096>;
|
||||
version = <0x11223344>;
|
||||
};
|
||||
|
||||
image: blob-ext {
|
||||
filename = "refcode.bin";
|
||||
};
|
||||
};
|
||||
};
|
23
tools/binman/test/228_pre_load_invalid_padding.dts
Normal file
23
tools/binman/test/228_pre_load_invalid_padding.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pre-load {
|
||||
content = <&image>;
|
||||
algo-name = "sha256,rsa2048";
|
||||
padding-name = "padding";
|
||||
key-name = "tools/binman/test/225_dev.key";
|
||||
header-size = <4096>;
|
||||
version = <1>;
|
||||
};
|
||||
|
||||
image: blob-ext {
|
||||
filename = "refcode.bin";
|
||||
};
|
||||
};
|
||||
};
|
23
tools/binman/test/229_pre_load_invalid_sha.dts
Normal file
23
tools/binman/test/229_pre_load_invalid_sha.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pre-load {
|
||||
content = <&image>;
|
||||
algo-name = "sha2560,rsa2048";
|
||||
padding-name = "pkcs-1.5";
|
||||
key-name = "tools/binman/test/225_dev.key";
|
||||
header-size = <4096>;
|
||||
version = <1>;
|
||||
};
|
||||
|
||||
image: blob-ext {
|
||||
filename = "refcode.bin";
|
||||
};
|
||||
};
|
||||
};
|
23
tools/binman/test/230_pre_load_invalid_algo.dts
Normal file
23
tools/binman/test/230_pre_load_invalid_algo.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pre-load {
|
||||
content = <&image>;
|
||||
algo-name = "sha256,rsa20480";
|
||||
padding-name = "pkcs-1.5";
|
||||
key-name = "tools/binman/test/225_dev.key";
|
||||
header-size = <4096>;
|
||||
version = <1>;
|
||||
};
|
||||
|
||||
image: blob-ext {
|
||||
filename = "refcode.bin";
|
||||
};
|
||||
};
|
||||
};
|
23
tools/binman/test/231_pre_load_invalid_key.dts
Normal file
23
tools/binman/test/231_pre_load_invalid_key.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pre-load {
|
||||
content = <&image>;
|
||||
algo-name = "sha256,rsa4096";
|
||||
padding-name = "pkcs-1.5";
|
||||
key-name = "tools/binman/test/225_dev.key";
|
||||
header-size = <4096>;
|
||||
version = <1>;
|
||||
};
|
||||
|
||||
image: blob-ext {
|
||||
filename = "refcode.bin";
|
||||
};
|
||||
};
|
||||
};
|
Loading…
Reference in a new issue