summaryrefslogtreecommitdiff
path: root/tools/binman/ftest.py
diff options
context:
space:
mode:
authorRasmus Villemoes <ravi@prevas.dk>2025-06-10 14:27:48 +0200
committerTom Rini <trini@konsulko.com>2025-06-26 11:48:39 -0600
commit7d4eacb0e68a7eb471a8dc43a5585b46ec67a333 (patch)
tree564bedb11d8fa91653fe4a476bc63c1833132d89 /tools/binman/ftest.py
parentba60a726d9e64f9ef8af01fcf2d9a6239940e799 (diff)
mkimage: do a rough estimate for the size needed for hashes/signatures
Background: I have several customers that will be using a certain remote signing service for signing their images, in order that the private keys are never exposed outside that company's secure servers. This is done via a pkcs#11 interface that talks to the remote signing server, and all of that works quite well. However, the way this particular signing service works is that one must upfront create a "signing session", where one indicates which keys one will use and, importantly, how many times each key will (may) be used. Then, depending on the keys requested and the customer's configuration, one or more humans must authorize that signing session So for example, if official release keys are to be used, maybe two different people from upper management must authorize, while if development keys are requested, the developer himself can authorize the session. Once authorized, the requester receives a token that must then be used for signing via one of the keys associated to that session. I have that integrated in Yocto in a way that when a CI starts a BSP build, it automatically works out which keys will be needed (e.g. one for signing U-Boot, another for signing a kernel FIT image) based on bitbake metadata, requests an appropriate signing session, and the appropriate people are then notified and can then look at the details of that CI pipeline and confirm that it is legitimate. The problem: The way mkimage does FIT image signing means that the remote server can be asked to perform a signature an unbounded number of times, or at least a number of times that cannot be determined upfront. This means that currently, I need to artificially say that a kernel key will be used, say, 10 times, even when only a single FIT image with just one configuration node is created. Part of the security model is that once the number of signings using a given key has been depleted, the authorization token becomes useless even if somehow leaked from the CI - and _if_ it is leaked/compromised and abused before the CI has gotten around to do its signings, the build will then fail with a clear indication of the compromise. Clearly, having to specify a "high enough" expected use count is counter to that part of the security model, because it will inevitably leave some allowed uses behind. While not perfect, we can give a reasonable estimate of an upper bound on the necessary extra size by simply counting the number of hash and signature nodes in the FIT image. As indicated in the comments, one could probably make it even more precise, and if there would ever be signatures larger than 512 bytes, probably one would have to do that. But this works well enough in practice for now, and is in fact an improvement in the normal case: Currently, starting with size_inc of 0 is guaranteed to fail, so we always enter the loop at least twice, even when not doing any signing but merely filling hash values. Just in case I've missed anything, keep the loop incrementing 1024 bytes at a time, and also, in case the estimate turns out to be over 64K, ensure that we do at least one attempt by changing to a do-while loop. With a little debug printf, creating a FIT image with three configuration nodes previously resulted in Trying size_inc=0 Trying size_inc=1024 Trying size_inc=2048 Trying size_inc=3072 Succeeded at size_inc=3072 and dumping info from the signing session (where I've artifically asked for 10 uses of the kernel key) shows "keyid": "kernel-dev-20250218", "usagecount": 9, "maxusagecount": 10 corresponding to 1+2+3+3 signatures requested (so while the loop count is roughly linear in the number of config nodes, the number of signings is quadratic). With this, I instead get Trying size_inc=3456 Succeeded at size_inc=3456 and the expected "keyid": "kernel-dev-20250218", "usagecount": 3, "maxusagecount": 10 thus allowing me to set maxusagecount correctly. Update a binman test case accordingly: With the previous behaviour, mkimage would try size_inc=0 and then size_inc=1024 and then succeed. With this patch, we first try, and succeed, with 4*128=512 due to the four hash nodes (and no signature nodes) in 161_fit.dts, so the image ends up 512 bytes smaller. Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
Diffstat (limited to 'tools/binman/ftest.py')
-rw-r--r--tools/binman/ftest.py8
1 files changed, 4 insertions, 4 deletions
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 1e570aba287..3d556535e07 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -4019,7 +4019,7 @@ class TestFunctional(unittest.TestCase):
self.assertEqual({
'image-pos': 0,
'offset': 0,
- 'size': 1890,
+ 'size': 1378,
'u-boot:image-pos': 0,
'u-boot:offset': 0,
@@ -4027,7 +4027,7 @@ class TestFunctional(unittest.TestCase):
'fit:image-pos': 4,
'fit:offset': 4,
- 'fit:size': 1840,
+ 'fit:size': 1328,
'fit/images/kernel:image-pos': 304,
'fit/images/kernel:offset': 300,
@@ -4045,8 +4045,8 @@ class TestFunctional(unittest.TestCase):
'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
- 'u-boot-nodtb:image-pos': 1844,
- 'u-boot-nodtb:offset': 1844,
+ 'u-boot-nodtb:image-pos': 1332,
+ 'u-boot-nodtb:offset': 1332,
'u-boot-nodtb:size': 46,
}, props)