Skip to content

Commit ee21ade

Browse files
committed
imgtool: Add support for VID and CID
Allow to specify VID and CID for an image. Signed-off-by: Tomasz Chyrowicz <[email protected]>
1 parent a3812ad commit ee21ade

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

scripts/imgtool/image.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
import hashlib
3131
import array
3232
import os.path
33+
import re
3334
import struct
35+
import uuid
3436
from enum import Enum
3537

3638
import click
@@ -96,6 +98,8 @@
9698
'DECOMP_SHA': 0x71,
9799
'DECOMP_SIGNATURE': 0x72,
98100
'COMP_DEC_SIZE' : 0x73,
101+
'UUID_VID': 0x80,
102+
'UUID_CID': 0x81,
99103
}
100104

101105
TLV_SIZE = 4
@@ -254,6 +258,23 @@ def tlv_matches_key_type(tlv_type, key):
254258

255259
return False
256260

261+
def parse_uuid(namespace, value):
262+
# Check if UUID is in the RAW format (12345678-1234-5678-1234-567812345678)
263+
uuid_re = r'[0-9A-f]{8}-[0-9A-f]{4}-[0-9A-f]{4}-[0-9A-f]{4}-[0-9A-f]{12}'
264+
if re.match(uuid_re, value):
265+
uuid_bytes = bytes.fromhex(value.replace('-', ''))
266+
267+
# Check if UUID is in the string format
268+
elif value.isprintable():
269+
if namespace is not None:
270+
uuid_bytes = uuid.uuid5(namespace, value).bytes
271+
else:
272+
raise ValueError(f"Unknown namespace for UUID: {value}")
273+
else:
274+
raise ValueError(f"Unknown UUID format: {value}")
275+
276+
return uuid_bytes
277+
257278

258279
class Image:
259280

@@ -263,7 +284,7 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE,
263284
overwrite_only=False, endian="little", load_addr=0,
264285
rom_fixed=None, erased_val=None, save_enctlv=False,
265286
security_counter=None, max_align=None,
266-
non_bootable=False):
287+
non_bootable=False, vid=None, cid=None):
267288

268289
if load_addr and rom_fixed:
269290
raise click.UsageError("Can not set rom_fixed and load_addr at the same time")
@@ -292,6 +313,8 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE,
292313
self.enctlv_len = 0
293314
self.max_align = max(DEFAULT_MAX_ALIGN, align) if max_align is None else int(max_align)
294315
self.non_bootable = non_bootable
316+
self.vid = vid
317+
self.cid = cid
295318

296319
if self.max_align == DEFAULT_MAX_ALIGN:
297320
self.boot_magic = bytes([
@@ -321,7 +344,7 @@ def __repr__(self):
321344
return "<Image version={}, header_size={}, security_counter={}, \
322345
base_addr={}, load_addr={}, align={}, slot_size={}, \
323346
max_sectors={}, overwrite_only={}, endian={} format={}, \
324-
payloadlen=0x{:x}>".format(
347+
payloadlen=0x{:x}, vid={}, cid={}>".format(
325348
self.version,
326349
self.header_size,
327350
self.security_counter,
@@ -333,7 +356,9 @@ def __repr__(self):
333356
self.overwrite_only,
334357
self.endian,
335358
self.__class__.__name__,
336-
len(self.payload))
359+
len(self.payload),
360+
self.vid,
361+
self.cid)
337362

338363
def load(self, path):
339364
"""Load an image from a given file"""
@@ -500,6 +525,16 @@ def create(self, key, public_key_format, enckey, dependencies=None,
500525
# = 4 + 4 = 8 Bytes
501526
protected_tlv_size += TLV_SIZE + 4
502527

528+
if self.vid is not None:
529+
# Size of the VID TLV: header ('HH') + payload ('16s')
530+
# = 4 + 16 = 20 Bytes
531+
protected_tlv_size += TLV_SIZE + 16
532+
533+
if self.cid is not None:
534+
# Size of the CID TLV: header ('HH') + payload ('16s')
535+
# = 4 + 16 = 20 Bytes
536+
protected_tlv_size += TLV_SIZE + 16
537+
503538
if sw_type is not None:
504539
if len(sw_type) > MAX_SW_TYPE_LENGTH:
505540
msg = "'{}' is too long ({} characters) for sw_type. Its " \
@@ -603,6 +638,21 @@ def create(self, key, public_key_format, enckey, dependencies=None,
603638
if compression_tlvs is not None:
604639
for tag, value in compression_tlvs.items():
605640
prot_tlv.add(tag, value)
641+
642+
if self.vid is not None:
643+
vid = parse_uuid(uuid.NAMESPACE_DNS, self.vid)
644+
payload = struct.pack(e + '16s', vid)
645+
prot_tlv.add('UUID_VID', payload)
646+
647+
if self.cid is not None:
648+
if self.vid is not None:
649+
namespace = uuid.UUID(bytes=vid)
650+
else:
651+
namespace = None
652+
cid = parse_uuid(namespace, self.cid)
653+
payload = struct.pack(e + '16s', cid)
654+
prot_tlv.add('UUID_CID', payload)
655+
606656
if custom_tlvs is not None:
607657
for tag, value in custom_tlvs.items():
608658
prot_tlv.add(tag, value)

scripts/imgtool/main.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,13 +473,17 @@ def convert(self, value, param, ctx):
473473
@click.command(help='''Create a signed or unsigned image\n
474474
INFILE and OUTFILE are parsed as Intel HEX if the params have
475475
.hex extension, otherwise binary format is used''')
476+
@click.option('--vid', default=None, required=False,
477+
help='Unique vendor identifier, format: (<raw_uuid>|<domain_name)>')
478+
@click.option('--cid', default=None, required=False,
479+
help='Unique image class identifier, format: (<raw_uuid>|<image_class_name>)')
476480
def sign(key, public_key_format, align, version, pad_sig, header_size,
477481
pad_header, slot_size, pad, confirm, max_sectors, overwrite_only,
478482
endian, encrypt_keylen, encrypt, compression, infile, outfile,
479483
dependencies, load_addr, hex_addr, erased_val, save_enctlv,
480484
security_counter, boot_record, custom_tlv, rom_fixed, max_align,
481485
clear, fix_sig, fix_sig_pubkey, sig_out, user_sha, hmac_sha, is_pure,
482-
vector_to_sign, non_bootable):
486+
vector_to_sign, non_bootable, vid, cid):
483487

484488
if confirm:
485489
# Confirmed but non-padded images don't make much sense, because
@@ -492,7 +496,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size,
492496
endian=endian, load_addr=load_addr, rom_fixed=rom_fixed,
493497
erased_val=erased_val, save_enctlv=save_enctlv,
494498
security_counter=security_counter, max_align=max_align,
495-
non_bootable=non_bootable)
499+
non_bootable=non_bootable, vid=vid, cid=cid)
496500
compression_tlvs = {}
497501
img.load(infile)
498502
key = load_key(key) if key else None
@@ -563,7 +567,8 @@ def sign(key, public_key_format, align, version, pad_sig, header_size,
563567
overwrite_only=overwrite_only, endian=endian,
564568
load_addr=load_addr, rom_fixed=rom_fixed,
565569
erased_val=erased_val, save_enctlv=save_enctlv,
566-
security_counter=security_counter, max_align=max_align)
570+
security_counter=security_counter, max_align=max_align,
571+
vid=vid, cid=cid)
567572
compression_filters = [
568573
{"id": lzma.FILTER_LZMA2, "preset": comp_default_preset,
569574
"dict_size": comp_default_dictsize, "lp": comp_default_lp,

0 commit comments

Comments
 (0)