Add new verify command
imgtool verify -k <some-key.(pub|sec)> <img-file>
Allow imgtool to validate that an image has a valid sha256sum and that
it was signed by the supplied key.
NOTE: this does not yet support verifying encrypted images
Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py
index ad156a1..20f8e75 100644
--- a/scripts/imgtool/image.py
+++ b/scripts/imgtool/image.py
@@ -19,6 +19,7 @@
"""
from . import version as versmod
+from enum import Enum
from intelhex import IntelHex
import hashlib
import struct
@@ -27,6 +28,7 @@
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
+from cryptography.exceptions import InvalidSignature
IMAGE_MAGIC = 0x96f3b83d
IMAGE_HEADER_SIZE = 32
@@ -55,6 +57,7 @@
'DEPENDENCY': 0x40
}
+TLV_SIZE = 4
TLV_INFO_SIZE = 4
TLV_INFO_MAGIC = 0x6907
@@ -69,6 +72,13 @@
'big': '>'
}
+VerifyResult = Enum('VerifyResult',
+ """
+ OK INVALID_MAGIC INVALID_TLV_INFO_MAGIC INVALID_HASH
+ INVALID_SIGNATURE
+ """)
+
+
class TLV():
def __init__(self, endian):
self.buf = bytearray()
@@ -307,3 +317,47 @@
pbytes += b'\xff' * (tsize - len(boot_magic))
pbytes += boot_magic
self.payload += pbytes
+
+ @staticmethod
+ def verify(imgfile, key):
+ with open(imgfile, "rb") as f:
+ b = f.read()
+
+ magic, _, header_size, _, img_size = struct.unpack('IIHHI', b[:16])
+ if magic != IMAGE_MAGIC:
+ return VerifyResult.INVALID_MAGIC
+
+ tlv_info = b[header_size+img_size:header_size+img_size+TLV_INFO_SIZE]
+ magic, tlv_tot = struct.unpack('HH', tlv_info)
+ if magic != TLV_INFO_MAGIC:
+ return VerifyResult.INVALID_TLV_INFO_MAGIC
+
+ sha = hashlib.sha256()
+ sha.update(b[:header_size+img_size])
+ digest = sha.digest()
+
+ tlv_off = header_size + img_size
+ tlv_end = tlv_off + tlv_tot
+ tlv_off += TLV_INFO_SIZE # skip tlv info
+ while tlv_off < tlv_end:
+ tlv = b[tlv_off:tlv_off+TLV_SIZE]
+ tlv_type, _, tlv_len = struct.unpack('BBH', tlv)
+ if tlv_type == TLV_VALUES["SHA256"]:
+ off = tlv_off + TLV_SIZE
+ if digest == b[off:off+tlv_len]:
+ if key is None:
+ return VerifyResult.OK
+ else:
+ return VerifyResult.INVALID_HASH
+ elif key is not None and tlv_type == TLV_VALUES[key.sig_tlv()]:
+ off = tlv_off + TLV_SIZE
+ tlv_sig = b[off:off+tlv_len]
+ payload = b[:header_size+img_size]
+ try:
+ key.verify(tlv_sig, payload)
+ return VerifyResult.OK
+ except InvalidSignature:
+ # continue to next TLV
+ pass
+ tlv_off += TLV_SIZE + tlv_len
+ return VerifyResult.INVALID_SIGNATURE