|
1 | 1 | # Copyright 2018 Nordic Semiconductor ASA
|
2 | 2 | # Copyright 2017-2020 Linaro Limited
|
3 |
| -# Copyright 2019-2023 Arm Limited |
| 3 | +# Copyright 2019-2024 Arm Limited |
4 | 4 | #
|
5 | 5 | # SPDX-License-Identifier: Apache-2.0
|
6 | 6 | #
|
|
20 | 20 | Image signing and management.
|
21 | 21 | """
|
22 | 22 |
|
23 |
| -from . import version as versmod |
24 |
| -from .boot_record import create_sw_component_data |
25 |
| -import click |
26 |
| -from enum import Enum |
27 |
| -from intelhex import IntelHex |
28 | 23 | import hashlib
|
29 |
| -import struct |
30 | 24 | import os.path
|
31 |
| -from .keys import rsa, ecdsa, x25519 |
| 25 | +import struct |
| 26 | +from enum import Enum |
| 27 | + |
| 28 | +import click |
| 29 | +from cryptography.exceptions import InvalidSignature |
| 30 | +from cryptography.hazmat.backends import default_backend |
| 31 | +from cryptography.hazmat.primitives import hashes, hmac |
32 | 32 | from cryptography.hazmat.primitives.asymmetric import ec, padding
|
33 | 33 | from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
|
34 | 34 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
35 | 35 | from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
36 | 36 | from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
|
37 |
| -from cryptography.hazmat.backends import default_backend |
38 |
| -from cryptography.hazmat.primitives import hashes, hmac |
39 |
| -from cryptography.exceptions import InvalidSignature |
| 37 | +from intelhex import IntelHex |
| 38 | + |
| 39 | +from . import version as versmod, keys |
| 40 | +from .boot_record import create_sw_component_data |
| 41 | +from .keys import rsa, ecdsa, x25519 |
40 | 42 |
|
41 | 43 | IMAGE_MAGIC = 0x96f3b83d
|
42 | 44 | IMAGE_HEADER_SIZE = 32
|
|
90 | 92 | }
|
91 | 93 |
|
92 | 94 | VerifyResult = Enum('VerifyResult',
|
93 |
| - """ |
94 |
| - OK INVALID_MAGIC INVALID_TLV_INFO_MAGIC INVALID_HASH |
95 |
| - INVALID_SIGNATURE |
96 |
| - """) |
| 95 | + ['OK', 'INVALID_MAGIC', 'INVALID_TLV_INFO_MAGIC', 'INVALID_HASH', 'INVALID_SIGNATURE', |
| 96 | + 'KEY_MISMATCH']) |
97 | 97 |
|
98 | 98 |
|
99 | 99 | def align_up(num, align):
|
@@ -135,7 +135,24 @@ def get(self):
|
135 | 135 | return header + bytes(self.buf)
|
136 | 136 |
|
137 | 137 |
|
138 |
| -class Image(): |
| 138 | +def get_digest(tlv_type, hash_region): |
| 139 | + if tlv_type == TLV_VALUES["SHA384"]: |
| 140 | + sha = hashlib.sha384() |
| 141 | + elif tlv_type == TLV_VALUES["SHA256"]: |
| 142 | + sha = hashlib.sha256() |
| 143 | + |
| 144 | + sha.update(hash_region) |
| 145 | + return sha.digest() |
| 146 | + |
| 147 | + |
| 148 | +def tlv_matches_key_type(tlv_type, key): |
| 149 | + """Check if provided key matches to TLV record in the image""" |
| 150 | + return (key is None or |
| 151 | + type(key) == keys.ECDSA384P1 and tlv_type == TLV_VALUES["SHA384"] or |
| 152 | + type(key) != keys.ECDSA384P1 and tlv_type == TLV_VALUES["SHA256"]) |
| 153 | + |
| 154 | + |
| 155 | +class Image: |
139 | 156 |
|
140 | 157 | def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE,
|
141 | 158 | pad_header=False, pad=False, confirm=False, align=1,
|
@@ -178,9 +195,9 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE,
|
178 | 195 | msb = (self.max_align & 0xff00) >> 8
|
179 | 196 | align = bytes([msb, lsb]) if self.endian == "big" else bytes([lsb, msb])
|
180 | 197 | self.boot_magic = align + bytes([0x2d, 0xe1,
|
181 |
| - 0x5d, 0x29, 0x41, 0x0b, |
182 |
| - 0x8d, 0x77, 0x67, 0x9c, |
183 |
| - 0x11, 0x0f, 0x1f, 0x8a, ]) |
| 198 | + 0x5d, 0x29, 0x41, 0x0b, |
| 199 | + 0x8d, 0x77, 0x67, 0x9c, |
| 200 | + 0x11, 0x0f, 0x1f, 0x8a, ]) |
184 | 201 |
|
185 | 202 | if security_counter == 'auto':
|
186 | 203 | # Security counter has not been explicitly provided,
|
@@ -321,9 +338,8 @@ def create(self, key, public_key_format, enckey, dependencies=None,
|
321 | 338 | self.enckey = enckey
|
322 | 339 |
|
323 | 340 | # Check what hashing algorithm should be used
|
324 |
| - if (key is not None and isinstance(key, ecdsa.ECDSA384P1) or |
325 |
| - pub_key is not None and isinstance(pub_key, |
326 |
| - ecdsa.ECDSA384P1Public)): |
| 341 | + if (key and isinstance(key, ecdsa.ECDSA384P1) |
| 342 | + or pub_key and isinstance(pub_key, ecdsa.ECDSA384P1Public)): |
327 | 343 | hash_algorithm = hashlib.sha384
|
328 | 344 | hash_tlv = "SHA384"
|
329 | 345 | else:
|
@@ -430,13 +446,13 @@ def create(self, key, public_key_format, enckey, dependencies=None,
|
430 | 446 | if dependencies is not None:
|
431 | 447 | for i in range(dependencies_num):
|
432 | 448 | payload = struct.pack(
|
433 |
| - e + 'B3x'+'BBHI', |
434 |
| - int(dependencies[DEP_IMAGES_KEY][i]), |
435 |
| - dependencies[DEP_VERSIONS_KEY][i].major, |
436 |
| - dependencies[DEP_VERSIONS_KEY][i].minor, |
437 |
| - dependencies[DEP_VERSIONS_KEY][i].revision, |
438 |
| - dependencies[DEP_VERSIONS_KEY][i].build |
439 |
| - ) |
| 449 | + e + 'B3x' + 'BBHI', |
| 450 | + int(dependencies[DEP_IMAGES_KEY][i]), |
| 451 | + dependencies[DEP_VERSIONS_KEY][i].major, |
| 452 | + dependencies[DEP_VERSIONS_KEY][i].minor, |
| 453 | + dependencies[DEP_VERSIONS_KEY][i].revision, |
| 454 | + dependencies[DEP_VERSIONS_KEY][i].build |
| 455 | + ) |
440 | 456 | prot_tlv.add('DEPENDENCY', payload)
|
441 | 457 |
|
442 | 458 | if custom_tlvs is not None:
|
@@ -640,42 +656,37 @@ def verify(imgfile, key):
|
640 | 656 | return VerifyResult.INVALID_MAGIC, None, None
|
641 | 657 |
|
642 | 658 | tlv_off = header_size + img_size
|
643 |
| - tlv_info = b[tlv_off:tlv_off+TLV_INFO_SIZE] |
| 659 | + tlv_info = b[tlv_off:tlv_off + TLV_INFO_SIZE] |
644 | 660 | magic, tlv_tot = struct.unpack('HH', tlv_info)
|
645 | 661 | if magic == TLV_PROT_INFO_MAGIC:
|
646 | 662 | tlv_off += tlv_tot
|
647 |
| - tlv_info = b[tlv_off:tlv_off+TLV_INFO_SIZE] |
| 663 | + tlv_info = b[tlv_off:tlv_off + TLV_INFO_SIZE] |
648 | 664 | magic, tlv_tot = struct.unpack('HH', tlv_info)
|
649 | 665 |
|
650 | 666 | if magic != TLV_INFO_MAGIC:
|
651 | 667 | return VerifyResult.INVALID_TLV_INFO_MAGIC, None, None
|
652 | 668 |
|
653 |
| - if isinstance(key, ecdsa.ECDSA384P1Public): |
654 |
| - sha = hashlib.sha384() |
655 |
| - hash_tlv = "SHA384" |
656 |
| - else: |
657 |
| - sha = hashlib.sha256() |
658 |
| - hash_tlv = "SHA256" |
659 |
| - |
660 | 669 | prot_tlv_size = tlv_off
|
661 |
| - sha.update(b[:prot_tlv_size]) |
662 |
| - digest = sha.digest() |
663 |
| - |
| 670 | + hash_region = b[:prot_tlv_size] |
| 671 | + digest = None |
664 | 672 | tlv_end = tlv_off + tlv_tot
|
665 | 673 | tlv_off += TLV_INFO_SIZE # skip tlv info
|
666 | 674 | while tlv_off < tlv_end:
|
667 |
| - tlv = b[tlv_off:tlv_off+TLV_SIZE] |
| 675 | + tlv = b[tlv_off:tlv_off + TLV_SIZE] |
668 | 676 | tlv_type, _, tlv_len = struct.unpack('BBH', tlv)
|
669 |
| - if tlv_type == TLV_VALUES[hash_tlv]: |
| 677 | + if tlv_type == TLV_VALUES["SHA256"] or tlv_type == TLV_VALUES["SHA384"]: |
| 678 | + if not tlv_matches_key_type(tlv_type, key): |
| 679 | + return VerifyResult.KEY_MISMATCH, None, None |
670 | 680 | off = tlv_off + TLV_SIZE
|
671 |
| - if digest == b[off:off+tlv_len]: |
| 681 | + digest = get_digest(tlv_type, hash_region) |
| 682 | + if digest == b[off:off + tlv_len]: |
672 | 683 | if key is None:
|
673 | 684 | return VerifyResult.OK, version, digest
|
674 | 685 | else:
|
675 | 686 | return VerifyResult.INVALID_HASH, None, None
|
676 | 687 | elif key is not None and tlv_type == TLV_VALUES[key.sig_tlv()]:
|
677 | 688 | off = tlv_off + TLV_SIZE
|
678 |
| - tlv_sig = b[off:off+tlv_len] |
| 689 | + tlv_sig = b[off:off + tlv_len] |
679 | 690 | payload = b[:prot_tlv_size]
|
680 | 691 | try:
|
681 | 692 | if hasattr(key, 'verify'):
|
|
0 commit comments