|
19 | 19 | """ |
20 | 20 |
|
21 | 21 | from . import version as versmod |
| 22 | +from enum import Enum |
22 | 23 | from intelhex import IntelHex |
23 | 24 | import hashlib |
24 | 25 | import struct |
|
27 | 28 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes |
28 | 29 | from cryptography.hazmat.backends import default_backend |
29 | 30 | from cryptography.hazmat.primitives import hashes |
| 31 | +from cryptography.exceptions import InvalidSignature |
30 | 32 |
|
31 | 33 | IMAGE_MAGIC = 0x96f3b83d |
32 | 34 | IMAGE_HEADER_SIZE = 32 |
|
55 | 57 | 'DEPENDENCY': 0x40 |
56 | 58 | } |
57 | 59 |
|
| 60 | +TLV_SIZE = 4 |
58 | 61 | TLV_INFO_SIZE = 4 |
59 | 62 | TLV_INFO_MAGIC = 0x6907 |
60 | 63 |
|
|
69 | 72 | 'big': '>' |
70 | 73 | } |
71 | 74 |
|
| 75 | +VerifyResult = Enum('VerifyResult', |
| 76 | + """ |
| 77 | + OK INVALID_MAGIC INVALID_TLV_INFO_MAGIC INVALID_HASH |
| 78 | + INVALID_SIGNATURE |
| 79 | + """) |
| 80 | + |
| 81 | + |
72 | 82 | class TLV(): |
73 | 83 | def __init__(self, endian): |
74 | 84 | self.buf = bytearray() |
@@ -307,3 +317,47 @@ def pad_to(self, size): |
307 | 317 | pbytes += b'\xff' * (tsize - len(boot_magic)) |
308 | 318 | pbytes += boot_magic |
309 | 319 | self.payload += pbytes |
| 320 | + |
| 321 | + @staticmethod |
| 322 | + def verify(imgfile, key): |
| 323 | + with open(imgfile, "rb") as f: |
| 324 | + b = f.read() |
| 325 | + |
| 326 | + magic, _, header_size, _, img_size = struct.unpack('IIHHI', b[:16]) |
| 327 | + if magic != IMAGE_MAGIC: |
| 328 | + return VerifyResult.INVALID_MAGIC |
| 329 | + |
| 330 | + tlv_info = b[header_size+img_size:header_size+img_size+TLV_INFO_SIZE] |
| 331 | + magic, tlv_tot = struct.unpack('HH', tlv_info) |
| 332 | + if magic != TLV_INFO_MAGIC: |
| 333 | + return VerifyResult.INVALID_TLV_INFO_MAGIC |
| 334 | + |
| 335 | + sha = hashlib.sha256() |
| 336 | + sha.update(b[:header_size+img_size]) |
| 337 | + digest = sha.digest() |
| 338 | + |
| 339 | + tlv_off = header_size + img_size |
| 340 | + tlv_end = tlv_off + tlv_tot |
| 341 | + tlv_off += TLV_INFO_SIZE # skip tlv info |
| 342 | + while tlv_off < tlv_end: |
| 343 | + tlv = b[tlv_off:tlv_off+TLV_SIZE] |
| 344 | + tlv_type, _, tlv_len = struct.unpack('BBH', tlv) |
| 345 | + if tlv_type == TLV_VALUES["SHA256"]: |
| 346 | + off = tlv_off + TLV_SIZE |
| 347 | + if digest == b[off:off+tlv_len]: |
| 348 | + if key is None: |
| 349 | + return VerifyResult.OK |
| 350 | + else: |
| 351 | + return VerifyResult.INVALID_HASH |
| 352 | + elif key is not None and tlv_type == TLV_VALUES[key.sig_tlv()]: |
| 353 | + off = tlv_off + TLV_SIZE |
| 354 | + tlv_sig = b[off:off+tlv_len] |
| 355 | + payload = b[:header_size+img_size] |
| 356 | + try: |
| 357 | + key.verify(tlv_sig, payload) |
| 358 | + return VerifyResult.OK |
| 359 | + except InvalidSignature: |
| 360 | + # continue to next TLV |
| 361 | + pass |
| 362 | + tlv_off += TLV_SIZE + tlv_len |
| 363 | + return VerifyResult.INVALID_SIGNATURE |
0 commit comments