Skip to content

Commit 1aaabde

Browse files
tomchyrlubos
authored andcommitted
[nrf fromtree] imgtool: Add support for VID and CID
Allow to specify VID and CID for an image. Signed-off-by: Tomasz Chyrowicz <[email protected]> (cherry picked from commit 59d2f7a)
1 parent a652982 commit 1aaabde

File tree

2 files changed

+65
-6
lines changed

2 files changed

+65
-6
lines changed

scripts/imgtool/image.py

Lines changed: 57 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': 0x74,
102+
'UUID_CID': 0x75,
99103
}
100104

101105
TLV_SIZE = 4
@@ -253,6 +257,27 @@ def tlv_matches_key_type(tlv_type, key):
253257

254258
return False
255259

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

257282
class Image:
258283

@@ -262,7 +287,7 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE,
262287
overwrite_only=False, endian="little", load_addr=0,
263288
rom_fixed=None, erased_val=None, save_enctlv=False,
264289
security_counter=None, max_align=None,
265-
non_bootable=False):
290+
non_bootable=False, vid=None, cid=None):
266291

267292
if load_addr and rom_fixed:
268293
raise click.UsageError("Can not set rom_fixed and load_addr at the same time")
@@ -291,6 +316,8 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE,
291316
self.enctlv_len = 0
292317
self.max_align = max(DEFAULT_MAX_ALIGN, align) if max_align is None else int(max_align)
293318
self.non_bootable = non_bootable
319+
self.vid = vid
320+
self.cid = cid
294321

295322
if self.max_align == DEFAULT_MAX_ALIGN:
296323
self.boot_magic = bytes([
@@ -320,7 +347,7 @@ def __repr__(self):
320347
return "<Image version={}, header_size={}, security_counter={}, \
321348
base_addr={}, load_addr={}, align={}, slot_size={}, \
322349
max_sectors={}, overwrite_only={}, endian={} format={}, \
323-
payloadlen=0x{:x}>".format(
350+
payloadlen=0x{:x}, vid={}, cid={}>".format(
324351
self.version,
325352
self.header_size,
326353
self.security_counter,
@@ -332,7 +359,9 @@ def __repr__(self):
332359
self.overwrite_only,
333360
self.endian,
334361
self.__class__.__name__,
335-
len(self.payload))
362+
len(self.payload),
363+
self.vid,
364+
self.cid)
336365

337366
def load(self, path):
338367
"""Load an image from a given file"""
@@ -508,6 +537,16 @@ def create(self, key, public_key_format, enckey, dependencies=None,
508537
# = 4 + 4 = 8 Bytes
509538
protected_tlv_size += TLV_SIZE + 4
510539

540+
if self.vid is not None:
541+
# Size of the VID TLV: header ('HH') + payload ('16s')
542+
# = 4 + 16 = 20 Bytes
543+
protected_tlv_size += TLV_SIZE + 16
544+
545+
if self.cid is not None:
546+
# Size of the CID TLV: header ('HH') + payload ('16s')
547+
# = 4 + 16 = 20 Bytes
548+
protected_tlv_size += TLV_SIZE + 16
549+
511550
if sw_type is not None:
512551
if len(sw_type) > MAX_SW_TYPE_LENGTH:
513552
msg = "'{}' is too long ({} characters) for sw_type. Its " \
@@ -611,6 +650,21 @@ def create(self, key, public_key_format, enckey, dependencies=None,
611650
if compression_tlvs is not None:
612651
for tag, value in compression_tlvs.items():
613652
prot_tlv.add(tag, value)
653+
654+
if self.vid is not None:
655+
vid = parse_uuid(uuid.NAMESPACE_DNS, self.vid)
656+
payload = struct.pack(e + '16s', vid)
657+
prot_tlv.add('UUID_VID', payload)
658+
659+
if self.cid is not None:
660+
if self.vid is not None:
661+
namespace = uuid.UUID(bytes=vid)
662+
else:
663+
namespace = None
664+
cid = parse_uuid(namespace, self.cid)
665+
payload = struct.pack(e + '16s', cid)
666+
prot_tlv.add('UUID_CID', payload)
667+
614668
if custom_tlvs is not None:
615669
for tag, value in custom_tlvs.items():
616670
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)