Skip to content

Commit 5c1103a

Browse files
michalek-nonordicjm
authored andcommitted
cmake: sysbuild: NSIB sign with custom key.
adds keyhash check to make sure custom key will not yield hash containing 0xFFFF. Signed-off-by: Mateusz Michalek <[email protected]>
1 parent 56895ae commit 5c1103a

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

cmake/sysbuild/sign.cmake

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ function(b0_gen_keys)
3434

3535
if(NOT EXISTS ${SIGNATURE_PUBLIC_KEY_FILE} OR IS_DIRECTORY ${SIGNATURE_PUBLIC_KEY_FILE})
3636
message(WARNING "Invalid public key file: ${SIGNATURE_PUBLIC_KEY_FILE}")
37+
else()
38+
execute_process(COMMAND ${PYTHON_EXECUTABLE}
39+
${ZEPHYR_NRF_MODULE_DIR}/scripts/bootloader/keyhash_validate.py ${keygen_algorithm}
40+
-in ${SIGNATURE_PUBLIC_KEY_FILE} RESULT_VARIABLE keyhash)
41+
if(NOT "${keyhash}" STREQUAL "0")
42+
message(WARNING "Key file ${SIGNATURE_PUBLIC_KEY_FILE} yields HASH that contains 0xffff "
43+
"which isn't allowed due to limitations of the internal clockworks. "
44+
"To solve the issue use another key."
45+
)
46+
endif()
3747
endif()
3848
else()
3949
message(WARNING "Unable to parse signing config.")
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (c) 2025 Nordic Semiconductor ASA
4+
#
5+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
6+
7+
from __future__ import annotations
8+
9+
import argparse
10+
import sys
11+
from hashlib import sha256, sha512
12+
13+
from cryptography.hazmat.primitives import serialization
14+
from cryptography.hazmat.primitives.serialization import load_pem_public_key
15+
16+
17+
def check_elliptic_curve(infile):
18+
"""
19+
Ensure that we don't have 0xFFFF in the hash of the public key.
20+
"""
21+
key = load_pem_public_key(infile.read())
22+
public_bytes = key.public_bytes(
23+
encoding=serialization.Encoding.X962,
24+
format=serialization.PublicFormat.UncompressedPoint,
25+
)
26+
digest = sha256(public_bytes[1:]).digest()[:16]
27+
if not (any([digest[n:n + 2] == b'\xff\xff'
28+
for n in range(0, len(digest), 2)])):
29+
print("EC key hash ok ", digest.hex())
30+
return 0
31+
return 1
32+
33+
34+
def check_ed25519(infile):
35+
"""
36+
Ensure that we don't have 0xFFFF in the hash of the public key.
37+
"""
38+
key = load_pem_public_key(infile.read())
39+
public_bytes = key.public_bytes(
40+
encoding=serialization.Encoding.PEM,
41+
format=serialization.PublicFormat.SubjectPublicKeyInfo,
42+
)
43+
digest = sha512(public_bytes[1:]).digest()[:16]
44+
if not any([digest[n:n + 2] == b'\xff\xff' for n in range(0, len(digest), 2)]):
45+
print("ED25519 key hash ok ", digest.hex())
46+
return 0
47+
return 1
48+
49+
def main(argv=None) -> int:
50+
parser = argparse.ArgumentParser(
51+
description='Check PEM file.',
52+
formatter_class=argparse.RawDescriptionHelpFormatter,
53+
allow_abbrev=False
54+
)
55+
56+
parser.add_argument('--in', '-in', '-i', required=True, dest='infile',
57+
type=argparse.FileType('rb'),
58+
help='Read public key from specified PEM file.')
59+
parser.add_argument(
60+
'--algorithm', '-a', help='Signing algorithm (default: %(default)s)',
61+
required=False, action='store', choices=('ec', 'ed25519'), default='ec'
62+
)
63+
64+
args = parser.parse_args(argv)
65+
if args.algorithm == "ec":
66+
return check_elliptic_curve(args.infile)
67+
else:
68+
return check_ed25519(args.infile)
69+
70+
71+
if __name__ == '__main__':
72+
sys.exit(main())

0 commit comments

Comments
 (0)