|
40 | 40 | from .boot_record import create_sw_component_data
|
41 | 41 | from .keys import rsa, ecdsa, x25519
|
42 | 42 |
|
| 43 | +from collections import namedtuple |
| 44 | + |
43 | 45 | IMAGE_MAGIC = 0x96f3b83d
|
44 | 46 | IMAGE_HEADER_SIZE = 32
|
45 | 47 | BIN_EXT = "bin"
|
|
65 | 67 | 'PUBKEY': 0x02,
|
66 | 68 | 'SHA256': 0x10,
|
67 | 69 | 'SHA384': 0x11,
|
| 70 | + 'SHA512': 0x12, |
68 | 71 | 'RSA2048': 0x20,
|
69 | 72 | 'ECDSASIG': 0x22,
|
70 | 73 | 'RSA3072': 0x23,
|
@@ -135,21 +138,90 @@ def get(self):
|
135 | 138 | return header + bytes(self.buf)
|
136 | 139 |
|
137 | 140 |
|
| 141 | +SHAAndAlgT = namedtuple('SHAAndAlgT', ['sha', 'alg']) |
| 142 | + |
| 143 | +TLV_SHA_TO_SHA_AND_ALG = { |
| 144 | + TLV_VALUES['SHA256'] : SHAAndAlgT('256', hashlib.sha256), |
| 145 | + TLV_VALUES['SHA384'] : SHAAndAlgT('384', hashlib.sha384), |
| 146 | + TLV_VALUES['SHA512'] : SHAAndAlgT('512', hashlib.sha512), |
| 147 | +} |
| 148 | + |
| 149 | + |
| 150 | +USER_SHA_TO_ALG_AND_TLV = { |
| 151 | + 'auto' : (hashlib.sha256, 'SHA256'), |
| 152 | + '256' : (hashlib.sha256, 'SHA256'), |
| 153 | + '384' : (hashlib.sha384, 'SHA384'), |
| 154 | + '512' : (hashlib.sha512, 'SHA512') |
| 155 | +} |
| 156 | + |
| 157 | + |
| 158 | +def is_sha_tlv(tlv): |
| 159 | + return tlv in TLV_SHA_TO_SHA_AND_ALG.keys() |
| 160 | + |
| 161 | + |
| 162 | +def tlv_sha_to_sha(tlv): |
| 163 | + return TLV_SHA_TO_SHA_AND_ALG[tlv].sha |
| 164 | + |
| 165 | + |
| 166 | +# Auto selecting hash algorithm for type(key) |
| 167 | +ALLOWED_KEY_SHA = { |
| 168 | + keys.ECDSA384P1 : ['384'], |
| 169 | + keys.ECDSA384P1Public : ['384'], |
| 170 | + keys.ECDSA256P1 : ['256'], |
| 171 | + keys.RSA : ['256'], |
| 172 | + # This two are set to 256 for compatibility, the right would be 512 |
| 173 | + keys.Ed25519 : ['256', '512'], |
| 174 | + keys.X25519 : ['256', '512'] |
| 175 | +} |
| 176 | + |
| 177 | +def key_and_user_sha_to_alg_and_tlv(key, user_sha): |
| 178 | + """Matches key and user requested sha to sha alogrithm and TLV name. |
| 179 | +
|
| 180 | + The returned tuple will contain hash functions and TVL name. |
| 181 | + The function is designed to succeed or completely fail execution, |
| 182 | + as providing incorrect pair here basically prevents doing |
| 183 | + any more work. |
| 184 | + """ |
| 185 | + if key is None: |
| 186 | + # If key is none, we allow whatever user has selected for sha |
| 187 | + return USER_SHA_TO_ALG_AND_TLV[user_sha] |
| 188 | + |
| 189 | + # If key is not None, then we have to filter hash to only allowed |
| 190 | + allowed = None |
| 191 | + try: |
| 192 | + allowed = ALLOWED_KEY_SHA[type(key)] |
| 193 | + except KeyError: |
| 194 | + raise click.UsageError("Colud not find allowed hash algorithms for {}" |
| 195 | + .format(type(key))) |
| 196 | + if user_sha == 'auto': |
| 197 | + return USER_SHA_TO_ALG_AND_TLV[allowed[0]] |
| 198 | + |
| 199 | + if user_sha in allowed: |
| 200 | + return USER_SHA_TO_ALG_AND_TLV[user_sha] |
| 201 | + |
| 202 | + raise click.UsageError("Key {} can not be used with --sha {}; allowed sha are one of {}" |
| 203 | + .format(key.sig_type(), user_sha, allowed)) |
| 204 | + |
| 205 | + |
138 | 206 | 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() |
| 207 | + sha = TLV_SHA_TO_SHA_AND_ALG[tlv_type].alg() |
143 | 208 |
|
144 | 209 | sha.update(hash_region)
|
145 | 210 | return sha.digest()
|
146 | 211 |
|
147 | 212 |
|
148 | 213 | def tlv_matches_key_type(tlv_type, key):
|
149 | 214 | """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"]) |
| 215 | + try: |
| 216 | + # We do not need the result here, and the key_and_user_sha_to_alg_and_tlv |
| 217 | + # will either succeed finding match or rise exception, so on success we |
| 218 | + # return True, on exception we return False. |
| 219 | + _, _ = key_and_user_sha_to_alg_and_tlv(key, tlv_sha_to_sha(tlv_type)) |
| 220 | + return True |
| 221 | + except: |
| 222 | + pass |
| 223 | + |
| 224 | + return False |
153 | 225 |
|
154 | 226 |
|
155 | 227 | class Image:
|
@@ -336,17 +408,13 @@ def ecies_hkdf(self, enckey, plainkey):
|
336 | 408 |
|
337 | 409 | def create(self, key, public_key_format, enckey, dependencies=None,
|
338 | 410 | sw_type=None, custom_tlvs=None, encrypt_keylen=128, clear=False,
|
339 |
| - fixed_sig=None, pub_key=None, vector_to_sign=None): |
| 411 | + fixed_sig=None, pub_key=None, vector_to_sign=None, user_sha='auto'): |
340 | 412 | self.enckey = enckey
|
341 | 413 |
|
342 |
| - # Check what hashing algorithm should be used |
343 |
| - if (key and isinstance(key, ecdsa.ECDSA384P1) |
344 |
| - or pub_key and isinstance(pub_key, ecdsa.ECDSA384P1Public)): |
345 |
| - hash_algorithm = hashlib.sha384 |
346 |
| - hash_tlv = "SHA384" |
347 |
| - else: |
348 |
| - hash_algorithm = hashlib.sha256 |
349 |
| - hash_tlv = "SHA256" |
| 414 | + # key decides on sha, then pub_key; of both are none default is used |
| 415 | + check_key = key if key is not None else pub_key |
| 416 | + hash_algorithm, hash_tlv = key_and_user_sha_to_alg_and_tlv(check_key, user_sha) |
| 417 | + |
350 | 418 | # Calculate the hash of the public key
|
351 | 419 | if key is not None:
|
352 | 420 | pub = key.get_public_bytes()
|
@@ -466,11 +534,14 @@ def create(self, key, public_key_format, enckey, dependencies=None,
|
466 | 534 |
|
467 | 535 | tlv = TLV(self.endian)
|
468 | 536 |
|
469 |
| - # Note that ecdsa wants to do the hashing itself, which means |
470 |
| - # we get to hash it twice. |
| 537 | + # These signature is done over sha of image. In case of |
| 538 | + # EC signatures so called Pure algorithm, designated to be run |
| 539 | + # over entire message is used with sha of image as message, |
| 540 | + # so, for example, in case of ED25519 we have here SHAxxx-ED25519-SHA512. |
471 | 541 | sha = hash_algorithm()
|
472 | 542 | sha.update(self.payload)
|
473 | 543 | digest = sha.digest()
|
| 544 | + message = digest; |
474 | 545 | tlv.add(hash_tlv, digest)
|
475 | 546 |
|
476 | 547 | if vector_to_sign == 'payload':
|
@@ -499,7 +570,7 @@ def create(self, key, public_key_format, enckey, dependencies=None,
|
499 | 570 | sig = key.sign(bytes(self.payload))
|
500 | 571 | else:
|
501 | 572 | print(os.path.basename(__file__) + ": sign the digest")
|
502 |
| - sig = key.sign_digest(digest) |
| 573 | + sig = key.sign_digest(message) |
503 | 574 | tlv.add(key.sig_tlv(), sig)
|
504 | 575 | self.signature = sig
|
505 | 576 | elif fixed_sig is not None and key is None:
|
@@ -678,7 +749,7 @@ def verify(imgfile, key):
|
678 | 749 | while tlv_off < tlv_end:
|
679 | 750 | tlv = b[tlv_off:tlv_off + TLV_SIZE]
|
680 | 751 | tlv_type, _, tlv_len = struct.unpack('BBH', tlv)
|
681 |
| - if tlv_type == TLV_VALUES["SHA256"] or tlv_type == TLV_VALUES["SHA384"]: |
| 752 | + if is_sha_tlv(tlv_type): |
682 | 753 | if not tlv_matches_key_type(tlv_type, key):
|
683 | 754 | return VerifyResult.KEY_MISMATCH, None, None
|
684 | 755 | off = tlv_off + TLV_SIZE
|
|
0 commit comments