mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
suit: add SUIT draft v4 manifest tools
This commit adds support tools used by the SUIT firmware upgrade module. Co-authored-by: Alexandre Abadie <alexandre.abadie@inria.fr> Co-authored-by: Koen Zandberg <koen@bergzand.net> Co-authored-by: Francisco Molina <femolina@uc.cl>
This commit is contained in:
parent
e867da315a
commit
7f6862c2d3
33
dist/tools/suit_v4/gen_key.py
vendored
Executable file
33
dist/tools/suit_v4/gen_key.py
vendored
Executable file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Copyright (C) 2019 Inria
|
||||
# 2019 FU Berlin
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
#
|
||||
|
||||
import sys
|
||||
import ed25519
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("usage: gen_key.py <secret filename> <public filename>")
|
||||
sys.exit(1)
|
||||
|
||||
_signing_key, _verifying_key = ed25519.create_keypair()
|
||||
with open(sys.argv[1], "wb") as f:
|
||||
f.write(_signing_key.to_bytes())
|
||||
|
||||
with open(sys.argv[2], "wb") as f:
|
||||
f.write(_verifying_key.to_bytes())
|
||||
|
||||
vkey_hex = _verifying_key.to_ascii(encoding="hex")
|
||||
print("Generated public key: '{}'".format(vkey_hex.decode()))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
87
dist/tools/suit_v4/gen_manifest.py
vendored
Executable file
87
dist/tools/suit_v4/gen_manifest.py
vendored
Executable file
@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Copyright (C) 2019 Inria
|
||||
# 2019 FU Berlin
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
#
|
||||
|
||||
import os
|
||||
import hashlib
|
||||
import json
|
||||
import uuid
|
||||
|
||||
import click
|
||||
|
||||
from suit_manifest_encoder_04 import compile_to_suit
|
||||
|
||||
|
||||
def str2int(x):
|
||||
if x.startswith("0x"):
|
||||
return int(x, 16)
|
||||
else:
|
||||
return x
|
||||
|
||||
|
||||
def sha256_from_file(filepath):
|
||||
sha256 = hashlib.sha256()
|
||||
sha256.update(open(filepath, "rb").read())
|
||||
return sha256.digest()
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option("--template", "-t", required=True, type=click.File())
|
||||
@click.option("--urlroot", "-u", required=True, type=click.STRING)
|
||||
@click.option("--offsets", "-O", required=True, type=click.STRING)
|
||||
@click.option("--seqnr", "-s", required=True, type=click.INT)
|
||||
@click.option("--output", "-o", type=click.File(mode="wb"))
|
||||
@click.option("--uuid-vendor", "-V", required=True)
|
||||
@click.option("--uuid-class", "-C", required=True)
|
||||
@click.option("--keyfile", "-K", required=False, type=click.File())
|
||||
@click.argument("slotfiles", nargs=2, type=click.Path())
|
||||
def main(template, urlroot, offsets, slotfiles, output, seqnr, uuid_vendor,
|
||||
uuid_class, keyfile):
|
||||
|
||||
uuid_vendor = uuid.uuid5(uuid.NAMESPACE_DNS, uuid_vendor)
|
||||
uuid_class = uuid.uuid5(uuid_vendor, uuid_class)
|
||||
template = json.load(template)
|
||||
slotfiles = list(slotfiles)
|
||||
|
||||
template["sequence-number"] = seqnr
|
||||
template["conditions"] = [
|
||||
{"condition-vendor-id": uuid_vendor.hex},
|
||||
{"condition-class-id": uuid_class.hex},
|
||||
]
|
||||
|
||||
offsets = offsets.split(",")
|
||||
offsets = [str2int(x) for x in offsets]
|
||||
|
||||
for slot, slotfile in enumerate(slotfiles):
|
||||
filename = slotfile
|
||||
size = os.path.getsize(filename)
|
||||
uri = os.path.join(urlroot, os.path.basename(filename))
|
||||
offset = offsets[slot]
|
||||
|
||||
_image_slot = template["components"][0]["images"][slot]
|
||||
_image_slot.update({
|
||||
"file": filename,
|
||||
"uri": uri,
|
||||
"size": size,
|
||||
"digest": sha256_from_file(slotfile),
|
||||
})
|
||||
|
||||
_image_slot["conditions"][0]["condition-component-offset"] = offset
|
||||
_image_slot["file"] = filename
|
||||
|
||||
result = compile_to_suit(template)
|
||||
if output:
|
||||
output.write(result)
|
||||
else:
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
154
dist/tools/suit_v4/sign-04.py
vendored
Executable file
154
dist/tools/suit_v4/sign-04.py
vendored
Executable file
@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# ----------------------------------------------------------------------------
|
||||
# Copyright 2018-2019 ARM Limited or its affiliates
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
"""
|
||||
This is a demo script that is intended to act as a reference for SUIT manifest
|
||||
signing.
|
||||
|
||||
NOTE: It is expected that C and C++ parser implementations will be written
|
||||
against this script, so it does not adhere to PEP8 in order to maintain
|
||||
similarity between the naming in this script and that of C/C++ implementations.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import copy
|
||||
|
||||
import cbor
|
||||
import ed25519
|
||||
|
||||
from pprint import pprint
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
|
||||
# Private key in arg 1
|
||||
# Public key in arg 2
|
||||
# Input file in arg 3
|
||||
# Output file in arg 4
|
||||
|
||||
COSE_Sign_Tag = 98
|
||||
APPLICATION_OCTET_STREAM_ID = 42
|
||||
ES256 = -7
|
||||
EDDSA = -8
|
||||
|
||||
|
||||
def signWrapper(algo, private_key, public_key, encwrapper):
|
||||
wrapper = cbor.loads(encwrapper)
|
||||
|
||||
pprint(wrapper[1])
|
||||
COSE_Sign = copy.deepcopy(wrapper[1])
|
||||
if not COSE_Sign:
|
||||
protected = cbor.dumps({
|
||||
3: APPLICATION_OCTET_STREAM_ID, # Content Type
|
||||
})
|
||||
unprotected = {
|
||||
}
|
||||
signatures = []
|
||||
|
||||
# Create a COSE_Sign_Tagged object
|
||||
COSE_Sign = [
|
||||
protected,
|
||||
unprotected,
|
||||
b'',
|
||||
signatures
|
||||
]
|
||||
|
||||
if algo == EDDSA:
|
||||
public_bytes = public_key.to_bytes()
|
||||
else:
|
||||
public_bytes = public_key.public_bytes(
|
||||
serialization.Encoding.DER,
|
||||
serialization.PublicFormat.SubjectPublicKeyInfo)
|
||||
|
||||
# NOTE: Using RFC7093, Method 4
|
||||
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
|
||||
digest.update(public_bytes)
|
||||
kid = digest.finalize()
|
||||
# Sign the payload
|
||||
protected = cbor.dumps({
|
||||
1: algo, # alg
|
||||
})
|
||||
# Create the signing object
|
||||
unprotected = {
|
||||
4: kid # kid
|
||||
}
|
||||
|
||||
Sig_structure = [
|
||||
"Signature", # Context
|
||||
COSE_Sign[0], # Body Protected
|
||||
protected, # signature protected
|
||||
b'', # External AAD
|
||||
wrapper[2] # payload
|
||||
]
|
||||
sig_str = cbor.dumps(Sig_structure, sort_keys=True)
|
||||
|
||||
if algo == EDDSA:
|
||||
signature = private_key.sign(sig_str)
|
||||
else:
|
||||
signature = private_key.sign(
|
||||
sig_str,
|
||||
ec.ECDSA(hashes.SHA256())
|
||||
)
|
||||
|
||||
COSE_Signature = [
|
||||
protected,
|
||||
unprotected,
|
||||
signature
|
||||
]
|
||||
COSE_Sign[3].append(COSE_Signature)
|
||||
wrapper[1] = cbor.dumps(cbor.Tag(COSE_Sign_Tag, COSE_Sign), sort_keys=True)
|
||||
return wrapper
|
||||
|
||||
|
||||
def main():
|
||||
private_key = None
|
||||
algo = ES256
|
||||
with open(sys.argv[1], 'rb') as fd:
|
||||
priv_key_bytes = fd.read()
|
||||
try:
|
||||
private_key = serialization.load_pem_private_key(
|
||||
priv_key_bytes, password=None, backend=default_backend())
|
||||
except ValueError:
|
||||
algo = EDDSA
|
||||
private_key = ed25519.SigningKey(priv_key_bytes)
|
||||
|
||||
public_key = None
|
||||
with open(sys.argv[2], 'rb') as fd:
|
||||
pub_key_bytes = fd.read()
|
||||
try:
|
||||
public_key = serialization.load_pem_public_key(
|
||||
pub_key_bytes, backend=default_backend())
|
||||
except ValueError:
|
||||
public_key = ed25519.VerifyingKey(pub_key_bytes)
|
||||
|
||||
# Read the input file
|
||||
doc = None
|
||||
with open(sys.argv[3], 'rb') as fd:
|
||||
doc = fd.read()
|
||||
|
||||
outDoc = signWrapper(algo, private_key, public_key, doc)
|
||||
|
||||
with open(sys.argv[4], 'wb') as fd:
|
||||
fd.write(cbor.dumps(outDoc, sort_keys=True))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
411
dist/tools/suit_v4/suit_manifest_encoder_04.py
vendored
Normal file
411
dist/tools/suit_v4/suit_manifest_encoder_04.py
vendored
Normal file
@ -0,0 +1,411 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# ----------------------------------------------------------------------------
|
||||
# Copyright 2019 ARM Limited or its affiliates
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
import json
|
||||
import cbor
|
||||
import binascii
|
||||
import uuid
|
||||
import os
|
||||
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
|
||||
COSE_ALG = 1
|
||||
COSE_Sign_Tag = 98
|
||||
APPLICATION_OCTET_STREAM_ID = 42
|
||||
ES256 = -7
|
||||
EDDSA = -8
|
||||
|
||||
SUIT_Authentication_Wrapper = 1
|
||||
SUIT_Manifest = 2
|
||||
SUIT_Dependency_Resolution = 7
|
||||
SUIT_Payload_Fetch = 8
|
||||
SUIT_Install = 9
|
||||
SUIT_Text = 13
|
||||
SUIT_Coswid = 14
|
||||
|
||||
SUIT_Manifest_Version = 1
|
||||
SUIT_Manifest_Sequence_Number = 2
|
||||
SUIT_Dependencies = 3
|
||||
SUIT_Components = 4
|
||||
SUIT_Dependency_Components = 5
|
||||
SUIT_Common = 6
|
||||
SUIT_Dependency_Resolution = 7
|
||||
SUIT_Payload_Fetch = 8
|
||||
SUIT_Install = 9
|
||||
SUIT_Validate = 10
|
||||
SUIT_Load = 11
|
||||
SUIT_Run = 12
|
||||
SUIT_Text = 13
|
||||
SUIT_Coswid = 14
|
||||
|
||||
SUIT_Dependency_Digest = 1
|
||||
SUIT_Dependency_Prefix = 2
|
||||
|
||||
SUIT_Component_Identifier = 1
|
||||
SUIT_Component_Size = 2
|
||||
SUIT_Component_Digest = 3
|
||||
|
||||
SUIT_Component_Dependency_Index = 2
|
||||
|
||||
SUIT_Condition_Vendor_Identifier = 1
|
||||
SUIT_Condition_Class_Identifier = 2
|
||||
SUIT_Condition_Device_Identifier = 3
|
||||
SUIT_Condition_Image_Match = 4
|
||||
SUIT_Condition_Image_Not_Match = 5
|
||||
SUIT_Condition_Use_Before = 6
|
||||
SUIT_Condition_Minimum_Battery = 7
|
||||
SUIT_Condition_Update_Authorised = 8
|
||||
SUIT_Condition_Version = 9
|
||||
SUIT_Condition_Component_Offset = 10
|
||||
|
||||
SUIT_Directive_Set_Component_Index = 11
|
||||
SUIT_Directive_Set_Manifest_Index = 12
|
||||
SUIT_Directive_Run_Sequence = 13
|
||||
SUIT_Directive_Run_Sequence_Conditional = 14
|
||||
SUIT_Directive_Process_Dependency = 15
|
||||
SUIT_Directive_Set_Parameters = 16
|
||||
SUIT_Directive_Override_Parameters = 19
|
||||
SUIT_Directive_Fetch = 20
|
||||
SUIT_Directive_Copy = 21
|
||||
SUIT_Directive_Run = 22
|
||||
SUIT_Directive_Wait = 23
|
||||
|
||||
SUIT_Parameter_Strict_Order = 1
|
||||
SUIT_Parameter_Coerce_Condition_Failure = 2
|
||||
SUIT_Parameter_Vendor_ID = 3
|
||||
SUIT_Parameter_Class_ID = 4
|
||||
SUIT_Parameter_Device_ID = 5
|
||||
SUIT_Parameter_URI_List = 6
|
||||
SUIT_Parameter_Encryption_Info = 7
|
||||
SUIT_Parameter_Compression_Info = 8
|
||||
SUIT_Parameter_Unpack_Info = 9
|
||||
SUIT_Parameter_Source_Component = 10
|
||||
SUIT_Parameter_Image_Digest = 11
|
||||
SUIT_Parameter_Image_Size = 12
|
||||
|
||||
SUIT_Compression_Algorithm = 1
|
||||
|
||||
def obj2bytes(o):
|
||||
if isinstance(o, int):
|
||||
l = []
|
||||
while o:
|
||||
l.append(o&0xff)
|
||||
o = o >> 8
|
||||
return bytes(l)
|
||||
if isinstance(o, str):
|
||||
return o.encode('utf-8')
|
||||
if isinstance(o, bytes):
|
||||
return o
|
||||
return b''
|
||||
|
||||
def make_SUIT_Components(unused, components):
|
||||
comps = []
|
||||
for component in components:
|
||||
c = {
|
||||
SUIT_Component_Identifier : [obj2bytes(x) for x in component["id"]]
|
||||
}
|
||||
if "digest" in component:
|
||||
c[SUIT_Component_Digest] = [1, binascii.a2b_hex(component["digest"])]
|
||||
if "size" in component:
|
||||
c[SUIT_Component_Size] = component["size"]
|
||||
comps.append(c)
|
||||
return (SUIT_Components, comps)
|
||||
|
||||
def make_SUIT_Compression_Info(info):
|
||||
algorithms = {
|
||||
'gzip' : 1,
|
||||
'bzip2' : 2,
|
||||
'deflate' : 3,
|
||||
'lz4' : 4,
|
||||
'lzma' : 7,
|
||||
}
|
||||
cinfo = {
|
||||
SUIT_Compression_Algorithm :algorithms[info['algorithm']]
|
||||
}
|
||||
|
||||
def make_SUIT_Set_Parameters(parameters):
|
||||
set_parameters = {}
|
||||
SUIT_Parameters_Keys = {
|
||||
# SUIT_Parameter_Strict_Order = 1
|
||||
# SUIT_Parameter_Coerce_Condition_Failure = 2
|
||||
# SUIT_Parameter_Vendor_ID = 3
|
||||
# SUIT_Parameter_Class_ID = 4
|
||||
# SUIT_Parameter_Device_ID = 5
|
||||
# SUIT_Parameter_URI_List = 6
|
||||
'uris' : lambda x: (SUIT_Parameter_URI_List, cbor.dumps(x)),
|
||||
# SUIT_Parameter_Encryption_Info = 7
|
||||
# SUIT_Parameter_Compression_Info = 8
|
||||
'compression-info': lambda x : (
|
||||
SUIT_Parameter_Compression_Info,
|
||||
cbor.dumps(make_SUIT_Compression_Info(x))
|
||||
),
|
||||
# SUIT_Parameter_Unpack_Info = 9
|
||||
'source-index' : lambda x :(SUIT_Parameter_Source_Component, int(x)),
|
||||
'image-digest' : lambda x :(SUIT_Parameter_Image_Digest, cbor.dumps(x, sort_keys=True)),
|
||||
'image-size' : lambda x :(SUIT_Parameter_Image_Size, int(x)),
|
||||
}
|
||||
for p in parameters:
|
||||
if p in SUIT_Parameters_Keys:
|
||||
k, v = SUIT_Parameters_Keys[p](parameters[p])
|
||||
set_parameters[k] = v
|
||||
else:
|
||||
raise Exception('ERROR: {} not found!'.format(p))
|
||||
|
||||
return (SUIT_Directive_Set_Parameters, set_parameters)
|
||||
|
||||
def make_SUIT_Sequence(seq_name, sequence):
|
||||
seq = []
|
||||
SUIT_Sequence_Keys = {
|
||||
"condition-vendor-id" : lambda x : (SUIT_Condition_Vendor_Identifier, uuid.UUID(x).bytes),
|
||||
"condition-class-id" : lambda x : (SUIT_Condition_Class_Identifier, uuid.UUID(x).bytes),
|
||||
"condition-device-id" : lambda x : (SUIT_Condition_Device_Identifier, uuid.UUID(x).bytes),
|
||||
"condition-image" : lambda x : (SUIT_Condition_Image_Match, None),
|
||||
"condition-not-image" : lambda x : (SUIT_Condition_Image_Not_Match, None),
|
||||
# SUIT_Condition_Use_Before = 6
|
||||
# SUIT_Condition_Minimum_Battery = 7
|
||||
# SUIT_Condition_Update_Authorised = 8
|
||||
# SUIT_Condition_Version = 9
|
||||
"condition-component-offset" : lambda x: (SUIT_Condition_Component_Offset, int(x)),
|
||||
#
|
||||
"directive-set-component" : lambda x : (SUIT_Directive_Set_Component_Index, x),
|
||||
# SUIT_Directive_Set_Manifest_Index = 12
|
||||
# SUIT_Directive_Run_Sequence = 13
|
||||
# SUIT_Directive_Run_Sequence_Conditional = 14
|
||||
"directive-run-conditional" : lambda x : (
|
||||
SUIT_Directive_Run_Sequence_Conditional,
|
||||
cbor.dumps(make_SUIT_Sequence("conditional-sequence", x), sort_keys = True)
|
||||
),
|
||||
# SUIT_Directive_Process_Dependency = 15
|
||||
# SUIT_Directive_Set_Parameters = 16
|
||||
"directive-set-var" : make_SUIT_Set_Parameters,
|
||||
# SUIT_Directive_Override_Parameters = 19
|
||||
"directive-fetch" : lambda x : (SUIT_Directive_Fetch, None),
|
||||
"directive-copy" : lambda x : (SUIT_Directive_Copy, None),
|
||||
"directive-run" : lambda x : (SUIT_Directive_Run, None),
|
||||
# SUIT_Directive_Wait = 23
|
||||
}
|
||||
for command in sequence:
|
||||
com_dict = {}
|
||||
for c in command:
|
||||
if c in SUIT_Sequence_Keys:
|
||||
k, v = SUIT_Sequence_Keys[c](command[c])
|
||||
com_dict[k] = v
|
||||
else:
|
||||
raise Exception('ERROR: {} not found!'.format(c))
|
||||
seq.append(com_dict)
|
||||
return seq
|
||||
|
||||
def make_SUIT_Manifest(info):
|
||||
# print(info)
|
||||
SUIT_Manifest_Keys = {
|
||||
"structure-version" : lambda y, x: (SUIT_Manifest_Version, x),
|
||||
"sequence-number" : lambda y, x: (SUIT_Manifest_Sequence_Number, x),
|
||||
# SUIT_Dependencies = 3
|
||||
"components" : make_SUIT_Components,
|
||||
# SUIT_Dependency_Components = 5
|
||||
"common" : lambda y, x: (SUIT_Common, cbor.dumps(make_SUIT_Sequence(y, x), sort_keys=True)),
|
||||
# SUIT_Dependency_Resolution = 7
|
||||
# SUIT_Payload_Fetch = 8
|
||||
"apply-image" : lambda y, x: (SUIT_Install, cbor.dumps(make_SUIT_Sequence(y, x), sort_keys=True)),
|
||||
"system-verification": lambda y, x: (SUIT_Validate, cbor.dumps(make_SUIT_Sequence(y, x), sort_keys=True)),
|
||||
"load-image" : lambda y, x: (SUIT_Load, cbor.dumps(make_SUIT_Sequence(y, x), sort_keys=True)),
|
||||
"run-image" : lambda y, x: (SUIT_Run, cbor.dumps(make_SUIT_Sequence(y, x), sort_keys=True)),
|
||||
# SUIT_Text = 13
|
||||
# SUIT_Coswid = 14
|
||||
}
|
||||
manifest = {}
|
||||
for field in info:
|
||||
if field in SUIT_Manifest_Keys:
|
||||
k, v = SUIT_Manifest_Keys[field](field, info[field])
|
||||
manifest[k] = v
|
||||
else:
|
||||
raise Exception('ERROR: {} not found!'.format(field))
|
||||
|
||||
# print ('suit-manifest: {}'.format(manifest))
|
||||
return manifest
|
||||
|
||||
def make_SUIT_Outer_Wrapper(info):
|
||||
Outer_Wrapper = {
|
||||
SUIT_Authentication_Wrapper : None,
|
||||
SUIT_Manifest : cbor.dumps(make_SUIT_Manifest(info), sort_keys = True)
|
||||
}
|
||||
# print('Outer_Wrapper: {}'.format(Outer_Wrapper))
|
||||
return Outer_Wrapper
|
||||
|
||||
|
||||
def make_SUIT_Components(unused, components):
|
||||
comps = []
|
||||
for component in components:
|
||||
c = {
|
||||
SUIT_Component_Identifier : [obj2bytes(x) for x in component["id"]]
|
||||
}
|
||||
if "digest" in component:
|
||||
c[SUIT_Component_Digest] = [1, binascii.a2b_hex(component["digest"])]
|
||||
if "size" in component:
|
||||
c[SUIT_Component_Size] = component["size"]
|
||||
comps.append(c)
|
||||
return (SUIT_Components, comps)
|
||||
|
||||
# Expected input format:
|
||||
# {
|
||||
# "digest-type" : "str",
|
||||
# "structure-version" : 1,
|
||||
# "sequence-number" : 2,
|
||||
# "components": [
|
||||
# {
|
||||
# "component-id":[bytes()],
|
||||
# "bootable" : bool(),
|
||||
# "images" : [
|
||||
# {
|
||||
# "conditions" : [
|
||||
# {"current-digest": bytes()},
|
||||
# {"target-offset" : int()},
|
||||
# {"target-id": [bytes()]},
|
||||
# ],
|
||||
# "digest": bytes(),
|
||||
# "size" : int(),
|
||||
# "uri" : str(),
|
||||
# }
|
||||
# ]
|
||||
# "conditions" : [
|
||||
# {"current-digest": bytes()},
|
||||
# {"vendor-id" : bytes()},
|
||||
# {"class-id" : bytes()},
|
||||
# {"device-id" : bytes()},
|
||||
# ]
|
||||
# }
|
||||
# ],
|
||||
# "conditions" : [
|
||||
# {"vendor-id" : bytes()},
|
||||
# {"class-id" : bytes()},
|
||||
# {"device-id" : bytes()},
|
||||
# ]
|
||||
# }
|
||||
def digest_str_to_id(s):
|
||||
return {
|
||||
'sha-256' : 1,
|
||||
'sha-256-128' : 2,
|
||||
'sha-256-120' : 3,
|
||||
'sha-256-96' : 4,
|
||||
'sha-256-64' : 5,
|
||||
'sha-256-32' : 6,
|
||||
'sha-384' : 7,
|
||||
'sha-512' : 8,
|
||||
'sha3-224' : 9,
|
||||
'sha3-256' : 10,
|
||||
'sha3-384' : 11,
|
||||
'sha3-512' : 12,
|
||||
}.get(s, 1)
|
||||
|
||||
def compile_to_suit(suit_info):
|
||||
digest_id = digest_str_to_id(suit_info.get('digest-type', 'sha-256'))
|
||||
suit_manifest_desc = {
|
||||
'structure-version':int(suit_info.get('structure-version', 1)),
|
||||
'sequence-number':int(suit_info['sequence-number']),
|
||||
}
|
||||
#TODO: Dependencies
|
||||
# Components
|
||||
components = []
|
||||
#TODO: dependency components
|
||||
common = []
|
||||
dependency_fetch = None
|
||||
#TODO: Image Fetch when not in streaming mode
|
||||
fetch_image = None
|
||||
apply_image = []
|
||||
# System Verification
|
||||
#TODO: Dependencies
|
||||
system_verification = [
|
||||
{"directive-set-component": True},
|
||||
{"condition-image": None},
|
||||
]
|
||||
#TODO: Load Image
|
||||
load_image = None
|
||||
run_image = []
|
||||
|
||||
for con in suit_info.get('conditions', []):
|
||||
common.append(con)
|
||||
# for each component
|
||||
for i, comp in enumerate(suit_info['components']):
|
||||
comp_info = {
|
||||
'id' : comp['id']
|
||||
}
|
||||
components.append(comp_info)
|
||||
if len(comp['images']) == 1:
|
||||
set_comp = {"directive-set-component": i}
|
||||
set_params = {
|
||||
"directive-set-var" : {
|
||||
"image-size" : int(comp['images'][0]['size']),
|
||||
"image-digest" : [digest_id, bytes(comp['images'][0]['digest'])]
|
||||
}
|
||||
}
|
||||
common.append(set_comp)
|
||||
common.append(set_params)
|
||||
set_params = {
|
||||
"directive-set-var" : {
|
||||
"uris" : [[0, str(comp['images'][0]['uri'])]]
|
||||
}
|
||||
}
|
||||
apply_image.append(set_comp)
|
||||
apply_image.append(set_params)
|
||||
else:
|
||||
for image in comp['images']:
|
||||
set_comp = {"directive-set-component": i}
|
||||
set_params = {
|
||||
"directive-set-var" : {
|
||||
"image-size" : int(image['size']),
|
||||
"image-digest" : [digest_id, bytes(image['digest'])]
|
||||
}
|
||||
}
|
||||
conditional_seq = [set_comp] + image.get('conditions',[])[:] + [set_params]
|
||||
conditional_set_params = {
|
||||
'directive-run-conditional': conditional_seq
|
||||
}
|
||||
common.append(conditional_set_params)
|
||||
set_params = {
|
||||
"directive-set-var" : {
|
||||
"uris" : [[0, str(image['uri'])]]
|
||||
}
|
||||
}
|
||||
conditional_seq = [set_comp] + image.get('conditions',[])[:] + [set_params]
|
||||
conditional_set_params = {
|
||||
'directive-run-conditional': conditional_seq
|
||||
}
|
||||
|
||||
apply_image.append(conditional_set_params)
|
||||
if comp.get('bootable', False):
|
||||
run_image.append({'directive-set-component' : i})
|
||||
run_image.append({'directive-run':None})
|
||||
|
||||
apply_image.append({"directive-set-component": True})
|
||||
apply_image.append({"directive-fetch": None})
|
||||
|
||||
suit_manifest_desc.update({
|
||||
"components" : components,
|
||||
"common" : common,
|
||||
"apply-image" : apply_image,
|
||||
"system-verification": system_verification,
|
||||
"run-image" : run_image,
|
||||
})
|
||||
|
||||
print(suit_manifest_desc)
|
||||
|
||||
return cbor.dumps(make_SUIT_Outer_Wrapper(suit_manifest_desc), sort_keys=True)
|
33
dist/tools/suit_v4/test-2img.json
vendored
Normal file
33
dist/tools/suit_v4/test-2img.json
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"digest-type" : "sha-256",
|
||||
"structure-version" : 1,
|
||||
"sequence-number" : 2,
|
||||
"components": [
|
||||
{
|
||||
"id":["00"],
|
||||
"bootable" : true,
|
||||
"images" : [
|
||||
{
|
||||
"file" : "encode-04.py",
|
||||
"uri" : "http://example.com/file.bin",
|
||||
"conditions" : [
|
||||
{"condition-component-offset":4096}
|
||||
]
|
||||
|
||||
},
|
||||
{
|
||||
"file" : "suit_manifest_encoder_04.py",
|
||||
"uri" : "http://example.com/file1.bin",
|
||||
"conditions" : [
|
||||
{"condition-component-offset":8192}
|
||||
]
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"conditions" : [
|
||||
{"condition-vendor-id" : "fa6b4a53-d5ad-5fdf-be9d-e663e4d41ffe"},
|
||||
{"condition-class-id" : "1492af14-2569-5e48-bf42-9b2d51f2ab45"}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user