From ee318ee01fb9e22bf5c765971f0162248f83af3c Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Mon, 29 Jun 2020 15:42:47 +0200 Subject: [PATCH] dist/tools/suit: Update suit tooling to IETF-v7 compliance --- dist/tools/{suit_v3 => suit}/gen_key.py | 0 dist/tools/{suit_v3 => suit}/gen_manifest.py | 0 .../suit-manifest-generator/LICENSE | 0 .../suit-manifest-generator/README.md | 29 ++++- .../suit-manifest-generator/bin/suit-tool | 2 +- .../suit-manifest-generator/setup.py | 3 +- .../suit_tool/__init__.py | 1 - .../suit_tool/argparser.py | 26 ++-- .../suit_tool/clidriver.py | 21 +-- .../suit_tool/compile.py | 94 +++++++++----- .../suit_tool/create.py | 6 +- .../suit_tool/get_pubkey.py | 98 ++++++++++++++ .../suit_tool/keygen.py | 64 +++++++++ .../suit_tool/manifest.py | 121 ++++++++++++------ .../suit_tool/parse.py | 1 + .../suit-manifest-generator/suit_tool/sign.py | 38 ++++-- .../suit-manifest-generator/.gitignore | 5 - .../suit_tool/get_uecc_pubkey.py | 53 -------- makefiles/suit.base.inc.mk | 6 +- makefiles/suit.inc.mk | 2 +- tests/suit_manifest/create_test_data.sh | 2 +- 21 files changed, 406 insertions(+), 166 deletions(-) rename dist/tools/{suit_v3 => suit}/gen_key.py (100%) rename dist/tools/{suit_v3 => suit}/gen_manifest.py (100%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/LICENSE (100%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/README.md (90%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/bin/suit-tool (95%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/setup.py (97%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/suit_tool/__init__.py (97%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/suit_tool/argparser.py (73%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/suit_tool/clidriver.py (74%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/suit_tool/compile.py (78%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/suit_tool/create.py (90%) create mode 100644 dist/tools/suit/suit-manifest-generator/suit_tool/get_pubkey.py create mode 100644 dist/tools/suit/suit-manifest-generator/suit_tool/keygen.py rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/suit_tool/manifest.py (88%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/suit_tool/parse.py (97%) rename dist/tools/{suit_v3 => suit}/suit-manifest-generator/suit_tool/sign.py (75%) delete mode 100644 dist/tools/suit_v3/suit-manifest-generator/.gitignore delete mode 100644 dist/tools/suit_v3/suit-manifest-generator/suit_tool/get_uecc_pubkey.py diff --git a/dist/tools/suit_v3/gen_key.py b/dist/tools/suit/gen_key.py similarity index 100% rename from dist/tools/suit_v3/gen_key.py rename to dist/tools/suit/gen_key.py diff --git a/dist/tools/suit_v3/gen_manifest.py b/dist/tools/suit/gen_manifest.py similarity index 100% rename from dist/tools/suit_v3/gen_manifest.py rename to dist/tools/suit/gen_manifest.py diff --git a/dist/tools/suit_v3/suit-manifest-generator/LICENSE b/dist/tools/suit/suit-manifest-generator/LICENSE similarity index 100% rename from dist/tools/suit_v3/suit-manifest-generator/LICENSE rename to dist/tools/suit/suit-manifest-generator/LICENSE diff --git a/dist/tools/suit_v3/suit-manifest-generator/README.md b/dist/tools/suit/suit-manifest-generator/README.md similarity index 90% rename from dist/tools/suit_v3/suit-manifest-generator/README.md rename to dist/tools/suit/suit-manifest-generator/README.md index 221593c16ef6d..6a0fb78cfc0ff 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/README.md +++ b/dist/tools/suit/suit-manifest-generator/README.md @@ -144,6 +144,8 @@ The `suit-tool` supports three sub-commands: * `create` generates a new manifest. * `sign` signs a manifest. * `parse` parses an existing manifest into cbor-debug or a json representation. +* `keygen` Create a signing key. Not for production use. +* `pubkey` Get the public key for a supplied private key in uECC-compatible C definition. The `suit-tool` has a configurable log level, specified with `-l`: @@ -178,7 +180,7 @@ To add a component to the manifest from the command-line, use the following synt The supported fields are: -* `file` the path to a file to use as a payload file. +* `file` the path fo a file to use as a payload file. * `inst` the `install-id`. * `uri` the URI where the file will be found. @@ -207,3 +209,28 @@ suit-tool parse -m MANIFEST ``` If a json-representation is needed, add the '-j' flag. + +## Keygen + +Create an asymmetric keypair for non-production use. Production systems should use closely guarded keys, such as keys stored in an HSM. + +```sh + suit-tool keygen [-t TYPE] -o KEYFILE + ``` + +`suit-tool keygen` defaults to creating SECP256r1 keys. To create another type of key, use `-t`followed by one of: + +* `secp256r1` +* `secp384r1` +* `secp521r1` +* `ed25519` + +## UECC public key + +Derive a public key in the format used by micro ECC. The input is a PEM private key. + +```sh +suit-tool pubkey -k FILE +``` + +The tool will then print the public key in micro ECC format. \ No newline at end of file diff --git a/dist/tools/suit_v3/suit-manifest-generator/bin/suit-tool b/dist/tools/suit/suit-manifest-generator/bin/suit-tool similarity index 95% rename from dist/tools/suit_v3/suit-manifest-generator/bin/suit-tool rename to dist/tools/suit/suit-manifest-generator/bin/suit-tool index 11960296ff15a..e36f2cfa03cdc 100755 --- a/dist/tools/suit_v3/suit-manifest-generator/bin/suit-tool +++ b/dist/tools/suit/suit-manifest-generator/bin/suit-tool @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # ---------------------------------------------------------------------------- -# Copyright 2016-2019 ARM Limited or its affiliates +# Copyright 2016-2020 ARM Limited or its affiliates # # SPDX-License-Identifier: Apache-2.0 # diff --git a/dist/tools/suit_v3/suit-manifest-generator/setup.py b/dist/tools/suit/suit-manifest-generator/setup.py similarity index 97% rename from dist/tools/suit_v3/suit-manifest-generator/setup.py rename to dist/tools/suit/suit-manifest-generator/setup.py index beb15ae7193f3..bdf7d3e7af89d 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/setup.py +++ b/dist/tools/suit/suit-manifest-generator/setup.py @@ -55,7 +55,8 @@ install_requires = [ 'cbor>=1.0.0', 'colorama>=0.4.0', - 'cryptography>=2.8' + 'cryptography>=2.8', + 'pyhsslms>=1.0.0', ], classifiers = [ "Programming Language :: Python :: 3", diff --git a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/__init__.py b/dist/tools/suit/suit-manifest-generator/suit_tool/__init__.py similarity index 97% rename from dist/tools/suit_v3/suit-manifest-generator/suit_tool/__init__.py rename to dist/tools/suit/suit-manifest-generator/suit_tool/__init__.py index 126457d2cebd1..9edb0371607bb 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/__init__.py +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/__init__.py @@ -1,4 +1,3 @@ -#!/usr/bin/python3 # -*- coding: utf-8 -*- # ---------------------------------------------------------------------------- # Copyright 2016-2019 ARM Limited or its affiliates diff --git a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/argparser.py b/dist/tools/suit/suit-manifest-generator/suit_tool/argparser.py similarity index 73% rename from dist/tools/suit_v3/suit-manifest-generator/suit_tool/argparser.py rename to dist/tools/suit/suit-manifest-generator/suit_tool/argparser.py index 84b90cfb55738..bc736a8f72903 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/argparser.py +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/argparser.py @@ -1,4 +1,3 @@ -#!/usr/bin/python3 # -*- coding: utf-8 -*- # ---------------------------------------------------------------------------- # Copyright 2019-2020 ARM Limited or its affiliates @@ -17,22 +16,23 @@ # See the License for the specific language governing permissions and # limitations under the License. # ---------------------------------------------------------------------------- -import sys -import argparse +import sys, argparse, os from suit_tool import __version__ +from suit_tool import keygen +from suit_tool import get_pubkey +import json import re - def str_to_component(s): types = { 'file' : ('file', lambda x : str(x.strip('"'))), + # 'desc' : ('component-description', lambda x : str(x.strip('"'))), 'inst' : ('install-id', lambda x : [ str(y) for y in eval(x) ]), 'uri' : ('uri', lambda x : str(x.strip('"'))) } d = {types[k][0]:types[k][1](v) for k,v in [ re.split(r'=',e, maxsplit=1) for e in re.split(r''',\s*(?=["']?[a-zA-Z0-9_-]+["']?=)''', s)]} return d - class MainArgumentParser(object): def __init__(self): @@ -54,7 +54,7 @@ def _make_parser(self): # create_parser.add_argument('-v', '--manifest-version', choices=['1'], default='1') create_parser.add_argument('-i', '--input-file', metavar='FILE', type=argparse.FileType('r'), - help='An input file describing the update. The file must be formatted as JSON. The overal structure is described in README.') + help='An input file describing the update. The file must be formated as JSON. The overal structure is described in README.') create_parser.add_argument('-o', '--output-file', metavar='FILE', type=argparse.FileType('wb'), required=True) create_parser.add_argument('-f', '--format', metavar='FMT', choices=['suit', 'suit-debug', 'json'], default='suit') create_parser.add_argument('-s', '--severable', action='store_true', help='Convert large elements to severable fields.') @@ -72,9 +72,19 @@ def _make_parser(self): parse_parser.add_argument('-m', '--manifest', metavar='FILE', type=argparse.FileType('rb'), required=True) parse_parser.add_argument('-j', '--json-output', default=False, action='store_true', dest='json') - get_uecc_pubkey_parser = subparsers.add_parser('pubkey', help='Get the public key for a supplied private key in uECC-compatible C definition.') + get_pubkey_parser = subparsers.add_parser('pubkey', help='Get the public key for a supplied private key.') + + get_pubkey_parser.add_argument('-k', '--private-key', metavar='FILE', type=argparse.FileType('rb'), required=True) + get_pubkey_parser.add_argument('-f', '--output-format', choices=get_pubkey.OutputFormaters.keys(), default='pem') + get_pubkey_parser.add_argument('-o', '--output-file', metavar='FILE', type=argparse.FileType('wb'), default=sys.stdout) + + keygen_parser = subparsers.add_parser('keygen', help='Create a signing key. Not for production use') - get_uecc_pubkey_parser.add_argument('-k', '--private-key', metavar='FILE', type=argparse.FileType('rb'), required=True) + keygen_parser.add_argument('-t', '--type', choices=keygen.KeyGenerators.keys(), + default='secp256r1', help='The type of the key to generate') + keygen_parser.add_argument('-o', '--output-file', metavar='FILE', type=argparse.FileType('wb'), default=sys.stdout) + keygen_parser.add_argument('-f', '--output-format', choices=keygen.OutputFormaters.keys(), default='pem') + keygen_parser.add_argument('-l', '--levels', help='The number of hss-lms levels', type=int, default=2) return parser diff --git a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/clidriver.py b/dist/tools/suit/suit-manifest-generator/suit_tool/clidriver.py similarity index 74% rename from dist/tools/suit_v3/suit-manifest-generator/suit_tool/clidriver.py rename to dist/tools/suit/suit-manifest-generator/suit_tool/clidriver.py index 5b388139299d5..eb830603fc16c 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/clidriver.py +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/clidriver.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # ---------------------------------------------------------------------------- # Copyright 2018-2020 ARM Limited or its affiliates @@ -17,21 +17,19 @@ # See the License for the specific language governing permissions and # limitations under the License. # ---------------------------------------------------------------------------- -import logging -import sys +import logging, sys from suit_tool.argparser import MainArgumentParser -from suit_tool import create, sign, parse, get_uecc_pubkey +from suit_tool import create, sign, parse, get_pubkey, keygen #, verify, cert, init -LOG = logging.getLogger(__name__) -LOG_FORMAT = '[%(levelname)s] %(asctime)s - %(name)s - %(message)s' +LOG = logging.getLogger(__name__) +LOG_FORMAT='[%(levelname)s] %(asctime)s - %(name)s - %(message)s' def main(): driver = CLIDriver() return driver.main() - class CLIDriver(object): def __init__(self): @@ -46,6 +44,10 @@ def __init__(self): logging.basicConfig(level=log_level, format=LOG_FORMAT, datefmt='%Y-%m-%d %H:%M:%S') + logging.addLevelName( logging.INFO, "\033[1;32m%s\033[1;0m" % logging.getLevelName(logging.INFO)) + logging.addLevelName( logging.WARNING, "\033[1;93m%s\033[1;0m" % logging.getLevelName(logging.WARNING)) + logging.addLevelName( logging.CRITICAL, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.CRITICAL)) + LOG.debug('CLIDriver created. Arguments parsed and logging setup.') def main(self): @@ -56,8 +58,9 @@ def main(self): # "cert": cert.main, # "init": init.main, # "update" : update.main, - "pubkey": get_uecc_pubkey.main, - "sign": sign.main + "pubkey": get_pubkey.main, + "sign": sign.main, + "keygen": keygen.main, }[self.options.action](self.options) or 0 sys.exit(rc) diff --git a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/compile.py b/dist/tools/suit/suit-manifest-generator/suit_tool/compile.py similarity index 78% rename from dist/tools/suit_v3/suit-manifest-generator/suit_tool/compile.py rename to dist/tools/suit/suit-manifest-generator/suit_tool/compile.py index 15101f027c9b1..e7b752cfa884c 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/compile.py +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/compile.py @@ -1,7 +1,6 @@ -#!/usr/bin/python3 # -*- coding: utf-8 -*- # ---------------------------------------------------------------------------- -# Copyright 2019 ARM Limited or its affiliates +# Copyright 2019-2020 ARM Limited or its affiliates # # SPDX-License-Identifier: Apache-2.0 # @@ -19,16 +18,24 @@ # ---------------------------------------------------------------------------- import binascii import copy +import collections +import json +import cbor +import sys +import textwrap +import itertools import logging +from collections import OrderedDict + from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from suit_tool.manifest import SUITComponentId, SUITCommon, SUITSequence, \ - SUITCommand, \ - SUITWrapper, SUITTryEach + suitCommonInfo, SUITCommand, SUITManifest, \ + SUITWrapper, SUITTryEach, SUITBWrapField LOG = logging.getLogger(__name__) @@ -92,16 +99,30 @@ def make_sequence(cid, choices, seq, params, cmds, pcid_key=None, param_drctv='d seq.append(mkCommand(pcid, param_drctv, params)) TryEachCmd = SUITTryEach() for c in choices: - TECseq = SUITSequence() - for item, cmd in neqcmds.items(): - TECseq.append(cmd(cid, c)) + TECseq = TryEachCmd.field.obj().from_json([]) params = {} for param, pcmd in neqparams.items(): k,v = pcmd(cid, c) params[k] = v + dep_params = {} + TECseq_cmds = [] + for item, cmd in neqcmds.items(): + ncmd = cmd(cid, c) + for dp in ncmd.dep_params: + if dp in params: + dep_params[dp] = params[dp] + del params[dp] + TECseq_cmds.append(ncmd) + + if len(dep_params): + TECseq.v.append(mkCommand(pcid, param_drctv, dep_params)) + + for cmd in TECseq_cmds: + TECseq.v.append(cmd) + if len(params): - TECseq.append(mkCommand(pcid, param_drctv, params)) - if len(TECseq.items): + TECseq.v.append(mkCommand(pcid, param_drctv, params)) + if hasattr(TECseq, "v") and len(TECseq.v.items): TryEachCmd.append(TECseq) if len(TryEachCmd.items): seq.append(mkCommand(cid, 'directive-try-each', TryEachCmd)) @@ -114,14 +135,15 @@ def compile_manifest(options, m): m = copy.deepcopy(m) m['components'] += options.components # Compile list of All Component IDs - ids = set([ + # There is no ordered set, so use ordered dict instead + ids = OrderedDict.fromkeys([ SUITComponentId().from_json(id) for comp_ids in [ [c[f] for f in [ 'install-id', 'download-id', 'load-id' ] if f in c] for c in m['components'] ] for id in comp_ids ]) - cid_data = {} + cid_data = OrderedDict() for c in m['components']: if not 'install-id' in c: LOG.critical('install-id required for all components') @@ -153,20 +175,19 @@ def compile_manifest(options, m): # Construct common sequence CommonCmds = { - 'offset': lambda cid, data: mkCommand(cid, 'condition-component-offset', data['offset']) + 'offset': lambda cid, data: mkCommand(cid, 'condition-component-offset', None), + 'vendor-id': lambda cid, data: mkCommand(cid, 'condition-vendor-identifier', None), + 'class-id': lambda cid, data: mkCommand(cid, 'condition-class-identifier', None), } CommonParams = { 'install-digest': lambda cid, data: ('image-digest', data['install-digest']), 'install-size': lambda cid, data: ('image-size', data['install-size']), + 'vendor-id' : lambda cid, data: ('vendor-id', data['vendor-id']), + 'class-id' : lambda cid, data: ('class-id', data['class-id']), + 'offset' : lambda cid, data: ('offset', data['offset']) } CommonSeq = SUITSequence() for cid, choices in cid_data.items(): - if any(['vendor-id' in c for c in choices]): - CommonSeq.append(mkCommand(cid, 'condition-vendor-identifier', - [c['vendor-id'] for c in choices if 'vendor-id' in c][0])) - if any(['vendor-id' in c for c in choices]): - CommonSeq.append(mkCommand(cid, 'condition-class-identifier', - [c['class-id'] for c in choices if 'class-id' in c][0])) CommonSeq = make_sequence(cid, choices, CommonSeq, CommonParams, CommonCmds, param_drctv='directive-override-parameters') @@ -176,12 +197,13 @@ def compile_manifest(options, m): if any([c.get('install-on-download', True) and 'uri' in c for c in choices]): InstParams = { 'uri' : lambda cid, data: ('uri', data['uri']), + 'offset' : lambda cid, data: ('offset', data['offset']), } if any(['compression-info' in c and not c.get('decompress-on-load', False) for c in choices]): InstParams['compression-info'] = lambda cid, data: data.get('compression-info') InstCmds = { 'offset': lambda cid, data: mkCommand( - cid, 'condition-component-offset', data['offset']) + cid, 'condition-component-offset', None) } InstSeq = make_sequence(cid, choices, InstSeq, InstParams, InstCmds) InstSeq.append(mkCommand(cid, 'directive-fetch', None)) @@ -191,7 +213,8 @@ def compile_manifest(options, m): FetchParams = { 'uri' : lambda cid, data: ('uri', data['uri']), 'download-digest' : lambda cid, data : ( - 'image-digest', data.get('download-digest', data['install-digest'])) + 'image-digest', data.get('download-digest', data['install-digest'])), + 'offset' : lambda cid, data: ('offset', data['offset']), } if any(['compression-info' in c and not c.get('decompress-on-load', False) for c in choices]): FetchParams['compression-info'] = lambda cid, data: data.get('compression-info') @@ -224,19 +247,26 @@ def compile_manifest(options, m): LoadSeq = SUITSequence() # If any component is marked bootable for cid, choices in cid_data.items(): - if any([c.get('bootable', False) for c in choices]): - # TODO: Dependencies - # If there are dependencies - # Verify dependencies - # Process dependencies - ValidateSeq.append(mkCommand(cid, 'condition-image-match', None)) + ValidateCmds = { + # 'install-digest' : lambda cid, data : mkCommand(cid, 'condition-image-match', None) + } + ValidateParams = { + } + ValidateSeq = make_sequence(cid, choices, ValidateSeq, ValidateParams, ValidateCmds) + ValidateSeq.append(mkCommand(cid, 'condition-image-match', None)) + # if any([c.get('bootable', False) for c in choices]): + # TODO: Dependencies + # If there are dependencies + # Verify dependencies + # Process dependencies + if any(['loadable' in c for c in choices]): # Generate image load section LoadParams = { - 'install-id' : lambda cid, data : ('source-component', c['install-id']), - 'load-digest' : ('image-digest', c.get('load-digest', c['install-digest'])), - 'load-size' : ('image-size', c.get('load-size', c['install-size'])) + 'install-id' : lambda cid, data : ('source-component', c['install-id']), + 'load-digest' : lambda cid, data : ('image-digest', c.get('load-digest', c['install-digest'])), + 'load-size' : lambda cid, data : ('image-size', c.get('load-size', c['install-size'])), } if 'compression-info' in c and c.get('decompress-on-load', False): LoadParams['compression-info'] = lambda cid, data: ('compression-info', c['compression-info']) @@ -244,7 +274,7 @@ def compile_manifest(options, m): # Move each loadable component } load_id = SUITComponentId().from_json(choices[0]['load-id']) - LoadSeq = make_sequence(load_id, choices, ValidateSeq, LoadParams, LoadCmds) + LoadSeq = make_sequence(load_id, choices, LoadSeq, LoadParams, LoadCmds) LoadSeq.append(mkCommand(load_id, 'directive-copy', None)) LoadSeq.append(mkCommand(load_id, 'condition-image-match', None)) @@ -258,7 +288,7 @@ def compile_manifest(options, m): 'command-arg' : None })) else: - t = [] + te = [] for c in bootable_components: pass # TODO: conditions @@ -267,7 +297,7 @@ def compile_manifest(options, m): # ) #TODO: Text common = SUITCommon().from_json({ - 'components': [id.to_json() for id in ids], + 'components': [id.to_json() for id in ids.keys()], 'common-sequence': CommonSeq.to_json(), }) diff --git a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/create.py b/dist/tools/suit/suit-manifest-generator/suit_tool/create.py similarity index 90% rename from dist/tools/suit_v3/suit-manifest-generator/suit_tool/create.py rename to dist/tools/suit/suit-manifest-generator/suit_tool/create.py index a930a3c914253..1931f228e1a8e 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/create.py +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/create.py @@ -1,4 +1,3 @@ -#!/usr/bin/python3 # -*- coding: utf-8 -*- # ---------------------------------------------------------------------------- # Copyright 2019 ARM Limited or its affiliates @@ -22,13 +21,14 @@ import cbor import itertools import textwrap +from collections import OrderedDict def main(options): - m = json.loads(options.input_file.read()) + m = json.loads(options.input_file.read(), object_pairs_hook=OrderedDict) nm = compile_manifest(options, m) if hasattr(options, 'severable') and options.severable: - nm = nm.to_severable() + nm = nm.to_severable('sha256') output = { 'suit' : lambda x: cbor.dumps(x.to_suit(), sort_keys=True), 'suit-debug' : lambda x: '\n'.join(itertools.chain.from_iterable( diff --git a/dist/tools/suit/suit-manifest-generator/suit_tool/get_pubkey.py b/dist/tools/suit/suit-manifest-generator/suit_tool/get_pubkey.py new file mode 100644 index 0000000000000..001cb2e96004e --- /dev/null +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/get_pubkey.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +# ---------------------------------------------------------------------------- +# Copyright 2020 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 textwrap +import binascii +import pyhsslms + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import ec, ed25519 +from cryptography.hazmat.primitives.asymmetric import utils as asymmetric_utils +from cryptography.hazmat.primitives import serialization as ks + + +def to_uecc_pubkey(pk): + if not isinstance(pk, ec.EllipticCurvePrivateKey): + raise Exception('Private key of type {} is not supported'.format(type(pk))) + public_numbers = pk.public_key().public_numbers() + x = public_numbers.x + y = public_numbers.y + uecc_bytes = x.to_bytes( + (x.bit_length() + 7) // 8, byteorder='big' + ) + y.to_bytes( + (y.bit_length() + 7) // 8, byteorder='big' + ) + uecc_c_def = ['const uint8_t public_key[] = {'] + textwrap.wrap( + ', '.join(['{:0=#4x}'.format(x) for x in uecc_bytes]), + 76 + ) + return '\n '.join(uecc_c_def) + '\n};\n' + + +def to_header(pk): + if isinstance(pk, ec.EllipticCurvePrivateKey): + return to_uecc_pubkey(pk) + if isinstance(pk, ed25519.Ed25519PrivateKey): + public_bytes = pk.public_key().public_bytes(ks.Encoding.Raw, + ks.PublicFormat.Raw) + public_c_def = ['const uint8_t public_key[] = {'] + textwrap.wrap( + ', '.join(['{:0=#4x}'.format(x) for x in public_bytes]), + 76 + ) + return str.encode('\n '.join(public_c_def) + '\n};\n') + + +OutputFormaters = { + 'uecc' : to_uecc_pubkey, + 'header': to_header, + 'pem' : lambda pk: pk.public_key().public_bytes(ks.Encoding.PEM, ks.PublicFormat.SubjectPublicKeyInfo), + 'der' : lambda pk: pk.public_key().public_bytes(ks.Encoding.DER, ks.PublicFormat.SubjectPublicKeyInfo), + 'hsslms' : lambda pk: pk.publicKey().serialize(), + 'c-hsslms' : lambda pk: ('\n '.join(['const uint8_t hsslms_public_key[] = {'] + textwrap.wrap( + ', '.join(['{:0=#4x}'.format(x) for x in pk.publicKey().serialize()]), + 76 + )) + '\n};\n').encode('utf-8') +} + + +def main(options): + private_key = None + # This test is here because the cryptography module doesn't know about hss-lms keys + if options.output_format in ('pem', 'der', 'uecc', 'header'): + private_key = ks.load_pem_private_key( + options.private_key.read(), + password=None, + backend=default_backend() + ) + elif options.output_format in ('c-hsslms', 'hsslms'): + private_key = pyhsslms.HssPrivateKey.deserialize(options.private_key.read()) + + odata = OutputFormaters.get(options.output_format)(private_key) + + try: + odata = odata.decode('utf-8') + except: + odata = binascii.b2a_hex(odata).decode('utf-8') + + odata = '\n'.join( + [line for lines in [textwrap.wrap(line, 80) + for line in odata.split('\n')] for line in lines] + ) + '\n' + options.output_file.write(odata) + + return 0 diff --git a/dist/tools/suit/suit-manifest-generator/suit_tool/keygen.py b/dist/tools/suit/suit-manifest-generator/suit_tool/keygen.py new file mode 100644 index 0000000000000..55cf84e0fab58 --- /dev/null +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/keygen.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# ---------------------------------------------------------------------------- +# Copyright 2019-2020 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. +# ---------------------------------------------------------------------------- +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import ed25519 +from cryptography.hazmat.primitives.asymmetric import utils as asymmetric_utils +from cryptography.hazmat.primitives import serialization as ks + +import pyhsslms + +import logging +import binascii +import textwrap + +LOG = logging.getLogger(__name__) + +KeyGenerators = { + 'secp256r1' : lambda o: ec.generate_private_key(ec.SECP256R1(), default_backend()), + 'secp384r1' : lambda o: ec.generate_private_key(ec.SECP384R1(), default_backend()), + 'secp521r1' : lambda o: ec.generate_private_key(ec.SECP521R1(), default_backend()), + 'ed25519' : lambda o: ed25519.Ed25519PrivateKey.generate(), + 'hsslms' : lambda o: pyhsslms.HssPrivateKey(levels=o.levels, lms_type=pyhsslms.lms_sha256_m32_h5, + lmots_type=pyhsslms.lmots_sha256_n32_w8), +} +OutputFormaters = { + 'pem' : lambda pk: pk.private_bytes(ks.Encoding.PEM, ks.PrivateFormat.PKCS8, ks.NoEncryption()), + 'der' : lambda pk: pk.private_bytes(ks.Encoding.DER, ks.PrivateFormat.PKCS8, ks.NoEncryption()), + 'c-hss-lms' : lambda pk: pk.serialize(), +} + +def main(options): + if options.type == 'hsslms': + options.output_format = 'c-hss-lms' + # Read the manifest wrapper + private_key = KeyGenerators.get(options.type) (options) + + odata = OutputFormaters.get(options.output_format)(private_key) + + if options.output_file.isatty(): + try: + odata = odata.decode('utf-8') + except: + odata = binascii.b2a_hex(odata).decode('utf-8') + odata = '\n'.join(textwrap.wrap(odata, 64)) + '\n' + options.output_file.write(odata) + + return 0 diff --git a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/manifest.py b/dist/tools/suit/suit-manifest-generator/suit_tool/manifest.py similarity index 88% rename from dist/tools/suit_v3/suit-manifest-generator/suit_tool/manifest.py rename to dist/tools/suit/suit-manifest-generator/suit_tool/manifest.py index 57760f50578c0..2c852abe1a7e4 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/manifest.py +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/manifest.py @@ -1,7 +1,6 @@ -#!/usr/bin/python3 # -*- coding: utf-8 -*- # ---------------------------------------------------------------------------- -# Copyright 2019 ARM Limited or its affiliates +# Copyright 2019-2020 ARM Limited or its affiliates # # SPDX-License-Identifier: Apache-2.0 # @@ -20,11 +19,19 @@ import collections import binascii import cbor +import json import copy import uuid from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes +from collections import OrderedDict + +import logging +LOG = logging.getLogger(__name__) + +TreeBranch = [] + ManifestKey = collections.namedtuple( 'ManifestKey', [ @@ -47,6 +54,12 @@ def to_bytes(s): else: return str(s).encode('utf-8') +class SUITException(Exception): + def __init__(self, m, data, tree_branch): + super().__init__(m) + self.data = data + self.tree_branch = tree_branch + class SUITCommonInformation: def __init__(self): self.component_ids = [] @@ -69,7 +82,9 @@ def from_json(self, v): def to_json(self): return self.v def from_suit(self, v): + TreeBranch.append(type(self)) self.v = int(v) + TreeBranch.pop() return self def to_suit(self): return self.v @@ -78,17 +93,19 @@ def to_debug(self, indent): class SUITPosInt(SUITInt): def from_json(self, v): + TreeBranch.append(type(self)) _v = int(v) if _v < 0: raise Exception('Positive Integers must be >= 0') self.v = _v + TreeBranch.pop() return self def from_suit(self, v): return self.from_json(v) class SUITManifestDict: def mkfields(d): - # rd = {} + # rd = OderedDict() return {k: ManifestKey(*v) for k,v in d.items()} def __init__(self): @@ -100,7 +117,7 @@ def from_json(self, data): return self def to_json(self): - j = {} + j = OrderedDict() for k, f in self.fields.items(): v = getattr(self, k) if v: @@ -108,14 +125,18 @@ def to_json(self): return j def from_suit(self, data): + TreeBranch.append(type(self)) for k, f in self.fields.items(): + TreeBranch.append(k) v = data.get(f.suit_key, None) d = f.obj().from_suit(v) if v is not None else None setattr(self, k, d) + TreeBranch.pop() + TreeBranch.pop() return self def to_suit(self): - sd = {} + sd = OrderedDict() for k, f in self.fields.items(): v = getattr(self, k) if v: @@ -136,8 +157,12 @@ def to_debug(self, indent): class SUITManifestNamedList(SUITManifestDict): def from_suit(self, data): + TreeBranch.append(type(self)) for k, f in self.fields.items(): + TreeBranch.append(k) setattr(self, k, f.obj().from_suit(data[f.suit_key])) + TreeBranch.pop() + TreeBranch.pop() return self def to_suit(self): @@ -172,10 +197,12 @@ def from_json(self, d): def to_suit(self): return self.v def from_suit(self, d): + TreeBranch.append(type(self)) self.v = self.keymap[self.rkeymap[d]] + TreeBranch.pop() return self def to_debug(self, indent): - s = str(self.v) + ' / ' + self.to_json() + ' /' + s = str(self.v) + ' / ' + json.dumps(self.to_json(),sort_keys = True) + ' /' return s def SUITBWrapField(c): @@ -183,7 +210,21 @@ class SUITBWrapper: def to_suit(self): return cbor.dumps(self.v.to_suit(), sort_keys=True) def from_suit(self, d): - self.v = c().from_suit(cbor.loads(d)) + TreeBranch.append(type(self)) + try: + self.v = c().from_suit(cbor.loads(d)) + except SUITException as e: + raise e + except Exception as e: + LOG.debug('At {}: failed to load "{}" as CBOR'.format(type(self),binascii.b2a_hex(d).decode('utf-8'))) + LOG.debug('Path: {}'.format(TreeBranch)) + # LOG.debug('At {}: failed to load "{}" as CBOR'.format(type(self),binascii.b2a_hex(d).decode('utf-8'))) + raise SUITException( + m = 'At {}: failed to load "{}" as CBOR'.format(type(self),binascii.b2a_hex(d).decode('utf-8')), + data = d, + tree_branch = TreeBranch + ) + TreeBranch.pop() return self def to_json(self): return self.v.to_json() @@ -225,8 +266,12 @@ def to_json(self): def from_suit(self, data): self.items = [] + TreeBranch.append(type(self)) for d in data: + TreeBranch.append(len(self.items)) self.items.append(self.field.obj().from_suit(d)) + TreeBranch.pop() + TreeBranch.pop() return self def to_suit(self): @@ -270,7 +315,7 @@ def from_suit(self, d): self.v = uuid.UUID(bytes=d).bytes return self def to_debug(self, indent): - return 'h\'' + self.to_json() + '\' / ' + str(uuid.UUID(bytes=self.v)) + ' /' + return 'h\'' + json.dumps(self.to_json(), sort_keys=True) + '\' / ' + str(uuid.UUID(bytes=self.v)) + ' /' class SUITRaw: @@ -376,11 +421,14 @@ class SUITCompressionInfo(SUITKeyMap): class SUITParameters(SUITManifestDict): fields = SUITManifestDict.mkfields({ - 'digest' : ('image-digest', 11, SUITDigest), - 'size' : ('image-size', 12, SUITPosInt), - 'uri' : ('uri', 6, SUITTStr), - 'src' : ('source-component', 10, SUITComponentIndex), - 'compress' : ('compression-info', 8, SUITCompressionInfo) + 'vendor-id' : ('vendor-id', 1, SUITUUID), + 'class-id' : ('class-id', 2, SUITUUID), + 'digest' : ('image-digest', 3, SUITBWrapField(SUITDigest)), + 'size' : ('image-size', 14, SUITPosInt), + 'uri' : ('uri', 21, SUITTStr), + 'src' : ('source-component', 22, SUITComponentIndex), + 'compress' : ('compression-info', 19, SUITCompressionInfo), + 'offset' : ('offset', 5, SUITPosInt) }) def from_json(self, j): return super(SUITParameters, self).from_json(j) @@ -388,10 +436,11 @@ def from_json(self, j): class SUITTryEach(SUITManifestArray): pass -def SUITCommandContainer(jkey, skey, argtype): +def SUITCommandContainer(jkey, skey, argtype, dp=[]): class SUITCmd(SUITCommand): json_key = jkey suit_key = skey + dep_params = dp def __init__(self): pass def to_suit(self): @@ -435,31 +484,30 @@ def from_suit(self, s): return self.scommands[s[0]]().from_suit(s) SUITCommand.commands = [ - SUITCommandContainer('condition-vendor-identifier', 1, SUITUUID), - SUITCommandContainer('condition-class-identifier', 2, SUITUUID), - SUITCommandContainer('condition-image-match', 3, SUITNil), - SUITCommandContainer('condition-use-before', 4, SUITRaw), - SUITCommandContainer('condition-component-offset', 5, SUITRaw), - SUITCommandContainer('condition-custom', 6, SUITRaw), - SUITCommandContainer('condition-device-identifier', 24, SUITRaw), - SUITCommandContainer('condition-image-not-match', 25, SUITRaw), - SUITCommandContainer('condition-minimum-battery', 26, SUITRaw), - SUITCommandContainer('condition-update-authorised', 27, SUITRaw), - SUITCommandContainer('condition-version', 28, SUITRaw), + SUITCommandContainer('condition-vendor-identifier', 1, SUITNil, ['vendor-id']), + SUITCommandContainer('condition-class-identifier', 2, SUITNil, ['class-id']), + SUITCommandContainer('condition-image-match', 3, SUITNil, ['digest']), + SUITCommandContainer('condition-use-before', 4, SUITNil), + SUITCommandContainer('condition-component-offset', 5, SUITNil, ['offset']), + SUITCommandContainer('condition-device-identifier', 24, SUITNil), + SUITCommandContainer('condition-image-not-match', 25, SUITNil), + SUITCommandContainer('condition-minimum-battery', 26, SUITNil), + SUITCommandContainer('condition-update-authorised', 27, SUITNil), + SUITCommandContainer('condition-version', 28, SUITNil), SUITCommandContainer('directive-set-component-index', 12, SUITPosInt), - SUITCommandContainer('directive-set-dependency-index', 13, SUITRaw), - SUITCommandContainer('directive-abort', 14, SUITRaw), + SUITCommandContainer('directive-set-dependency-index', 13, SUITPosInt), + SUITCommandContainer('directive-abort', 14, SUITNil), SUITCommandContainer('directive-try-each', 15, SUITTryEach), - SUITCommandContainer('directive-process-dependency', 18, SUITRaw), + SUITCommandContainer('directive-process-dependency', 18, SUITNil), SUITCommandContainer('directive-set-parameters', 19, SUITParameters), SUITCommandContainer('directive-override-parameters', 20, SUITParameters), SUITCommandContainer('directive-fetch', 21, SUITNil), - SUITCommandContainer('directive-copy', 22, SUITRaw), - SUITCommandContainer('directive-run', 23, SUITRaw), - SUITCommandContainer('directive-wait', 29, SUITRaw), + SUITCommandContainer('directive-copy', 22, SUITNil), + SUITCommandContainer('directive-run', 23, SUITNil), + SUITCommandContainer('directive-wait', 29, SUITNil), SUITCommandContainer('directive-run-sequence', 30, SUITRaw), SUITCommandContainer('directive-run-with-arguments', 31, SUITRaw), - SUITCommandContainer('directive-swap', 32, SUITRaw), + SUITCommandContainer('directive-swap', 32, SUITNil), ] SUITCommand.jcommands = { c.json_key : c for c in SUITCommand.commands} SUITCommand.scommands = { c.suit_key : c for c in SUITCommand.commands} @@ -471,6 +519,7 @@ def to_suit(self): suit_l = [] suitCommonInfo.current_index = 0 if len(suitCommonInfo.component_ids) == 1 else None for i in self.items: + # print(i.json_key, i.arg) if i.json_key == 'directive-set-component-index': suitCommonInfo.current_index = i.arg.v else: @@ -491,7 +540,7 @@ def from_suit(self, s): self.items = [SUITCommand().from_suit(i) for i in zip(*[iter(s)]*2)] return self -SUITTryEach.field = collections.namedtuple('ArrayElement', 'obj')(obj=SUITSequence) +SUITTryEach.field = collections.namedtuple('ArrayElement', 'obj')(obj=SUITBWrapField(SUITSequence)) class SUITSequenceComponentReset(SUITSequence): def to_suit(self): @@ -618,7 +667,7 @@ class COSETaggedAuth(COSETagChoice): }) class COSEList(SUITManifestArray): - field = collections.namedtuple('ArrayElement', 'obj')(obj=COSETaggedAuth) + field = collections.namedtuple('ArrayElement', 'obj')(obj=SUITBWrapField(COSETaggedAuth)) def from_suit(self, data): return super(COSEList, self).from_suit(data) @@ -651,7 +700,7 @@ def to_severable(self, digest_alg): if v is None: continue cbor_field = cbor.dumps(v.to_suit(), sort_keys=True) - digest = hashes.Hash(digest_algorithms.get(digest_alg)(), backend=default_backend()) + digest = hashes.Hash(self.digest_algorithms.get(digest_alg)(), backend=default_backend()) digest.update(cbor_field) field_digest = SUITDigest().from_json({ 'algorithm-id' : digest_alg, @@ -677,7 +726,7 @@ def from_severable(self): digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) digest.update(cbor_field) actual_digest = digest.finalize() - field_digest = getattr(sev.nsev.v, k) + field_digest = getattr(nsev.v, k) expected_digest = field_digest.to_suit()[1] if digest != expected_digest: raise Exception('Field Digest mismatch: For {}, expected: {}, got {}'.format( diff --git a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/parse.py b/dist/tools/suit/suit-manifest-generator/suit_tool/parse.py similarity index 97% rename from dist/tools/suit_v3/suit-manifest-generator/suit_tool/parse.py rename to dist/tools/suit/suit-manifest-generator/suit_tool/parse.py index 9544778d64ecf..daef85c467a50 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/parse.py +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/parse.py @@ -27,6 +27,7 @@ def main(options): # Read the manifest wrapper decoded_cbor_wrapper = cbor.loads(options.manifest.read()) + # print(decoded_cbor_wrapper) wrapper = SUITWrapper().from_suit(decoded_cbor_wrapper) if options.json: print (json.dumps(wrapper.to_json(),indent=2)) diff --git a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/sign.py b/dist/tools/suit/suit-manifest-generator/suit_tool/sign.py similarity index 75% rename from dist/tools/suit_v3/suit-manifest-generator/suit_tool/sign.py rename to dist/tools/suit/suit-manifest-generator/suit_tool/sign.py index f573331374486..559b4c3f8672b 100644 --- a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/sign.py +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/sign.py @@ -18,6 +18,7 @@ # limitations under the License. # ---------------------------------------------------------------------------- import cbor +import json from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes @@ -26,31 +27,41 @@ from cryptography.hazmat.primitives.asymmetric import utils as asymmetric_utils from cryptography.hazmat.primitives import serialization as ks +import pyhsslms -from suit_tool.manifest import COSE_Sign1, COSEList, \ +from suit_tool.manifest import COSE_Sign1, COSEList, SUITDigest,\ SUITWrapper, SUITBytes, SUITBWrapField import logging import binascii LOG = logging.getLogger(__name__) -def get_cose_es_bytes(private_key, sig_val): +def get_cose_es_bytes(options, private_key, sig_val): ASN1_signature = private_key.sign(sig_val, ec.ECDSA(hashes.SHA256())) r,s = asymmetric_utils.decode_dss_signature(ASN1_signature) ssize = private_key.key_size signature_bytes = r.to_bytes(ssize//8, byteorder='big') + s.to_bytes(ssize//8, byteorder='big') return signature_bytes -def get_cose_ed25519_bytes(private_key, sig_val): +def get_cose_ed25519_bytes(options, private_key, sig_val): return private_key.sign(sig_val) +def get_hsslms_bytes(options, private_key, sig_val): + sig = private_key.sign(sig_val) + key_file_name = options.private_key.name + options.private_key.close() + with open(key_file_name, 'wb') as fd: + fd.write(private_key.serialize()) + return sig + def main(options): # Read the manifest wrapper wrapper = cbor.loads(options.manifest.read()) private_key = None digest = None + private_key_buffer = options.private_key.read() try: - private_key = ks.load_pem_private_key(options.private_key.read(), password=None, backend=default_backend()) + private_key = ks.load_pem_private_key(private_key_buffer, password=None, backend=default_backend()) if isinstance(private_key, ec.EllipticCurvePrivateKey): options.key_type = 'ES{}'.format(private_key.key_size) elif isinstance(private_key, ed25519.Ed25519PrivateKey): @@ -65,11 +76,15 @@ def main(options): 'EdDSA' : hashes.Hash(hashes.SHA256(), backend=default_backend()), }.get(options.key_type) except: - digest= hashes.Hash(hashes.SHA256(), backend=default_backend()) - # private_key = None - # TODO: Implement loading of DSA keys not supported by python cryptography - LOG.critical('Non-library key type not implemented') - # return 1 + try: + digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) + private_key = pyhsslms.HssPrivateKey.deserialize(private_key_buffer) + options.key_type = 'HSS-LMS' + except: + # private_key = None + # TODO: Implement loading of DSA keys not supported by python cryptography + LOG.critical('Non-library key type not implemented') + return 1 digest.update(cbor.dumps(wrapper[SUITWrapper.fields['manifest'].suit_key])) @@ -90,14 +105,15 @@ def main(options): b'', cose_signature.payload.to_suit(), ], sort_keys = True) - sig_val = Sig_structure + LOG.debug('Signing: {}'.format(binascii.b2a_hex(Sig_structure).decode('utf-8'))) signature_bytes = { 'ES256' : get_cose_es_bytes, 'ES384' : get_cose_es_bytes, 'ES512' : get_cose_es_bytes, 'EdDSA' : get_cose_ed25519_bytes, - }.get(options.key_type)(private_key, sig_val) + 'HSS-LMS' : get_hsslms_bytes, + }.get(options.key_type)(options, private_key, Sig_structure) cose_signature.signature = SUITBytes().from_suit(signature_bytes) diff --git a/dist/tools/suit_v3/suit-manifest-generator/.gitignore b/dist/tools/suit_v3/suit-manifest-generator/.gitignore deleted file mode 100644 index 8b2f59d6b8216..0000000000000 --- a/dist/tools/suit_v3/suit-manifest-generator/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*__pycache__ -*.pyc -*.DS_Store -*.hex -examples/*.cbor diff --git a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/get_uecc_pubkey.py b/dist/tools/suit_v3/suit-manifest-generator/suit_tool/get_uecc_pubkey.py deleted file mode 100644 index 6993044a685b9..0000000000000 --- a/dist/tools/suit_v3/suit-manifest-generator/suit_tool/get_uecc_pubkey.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/python3 -# -*- coding: utf-8 -*- -# ---------------------------------------------------------------------------- -# Copyright 2020 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 textwrap - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization as ks - -def main(options): - private_key = ks.load_pem_private_key( - options.private_key.read(), - password=None, - backend=default_backend() - ) - #public_numbers = private_key.public_key().public_numbers() - #x = public_numbers.x - #y = public_numbers.y - #uecc_bytes = x.to_bytes( - # (x.bit_length() + 7) // 8, byteorder='big' - #) + y.to_bytes( - # (y.bit_length() + 7) // 8, byteorder='big' - #) - #uecc_c_def = ['const uint8_t public_key[] = {'] + textwrap.wrap( - # ', '.join(['{:0=#4x}'.format(x) for x in uecc_bytes]), - # 76 - #) - public_bytes = private_key.public_key().public_bytes( - encoding=ks.Encoding.Raw, - format=ks.PublicFormat.Raw - ) - - c_def = ['const uint8_t public_key[] = {'] + textwrap.wrap( - ', '.join(['{:0=#4x}'.format(x) for x in public_bytes]), - 76 - ) - print('\n '.join(c_def) + '\n};') - return 0 diff --git a/makefiles/suit.base.inc.mk b/makefiles/suit.base.inc.mk index ab0d84c1034a7..9e1df547ac4bc 100644 --- a/makefiles/suit.base.inc.mk +++ b/makefiles/suit.base.inc.mk @@ -1,6 +1,6 @@ # # path to suit-tool -SUIT_TOOL ?= $(RIOTBASE)/dist/tools/suit_v3/suit-manifest-generator/bin/suit-tool +SUIT_TOOL ?= $(RIOTBASE)/dist/tools/suit/suit-manifest-generator/bin/suit-tool # # SUIT encryption keys @@ -27,14 +27,14 @@ BUILDDEPS += $(SUIT_PUB_HDR) $(SUIT_SEC): $(CLEAN) @echo suit: generating key in $(SUIT_KEY_DIR) @mkdir -p $(SUIT_KEY_DIR) - @$(RIOTBASE)/dist/tools/suit_v3/gen_key.py $(SUIT_SEC) + @$(RIOTBASE)/dist/tools/suit/gen_key.py $(SUIT_SEC) # set FORCE so switching between keys using "SUIT_KEY=foo make ..." # triggers a rebuild even if the new key would otherwise not (because the other # key's mtime is too far back). $(SUIT_PUB_HDR): $(SUIT_SEC) FORCE | $(CLEAN) @mkdir -p $(SUIT_PUB_HDR_DIR) - @$(SUIT_TOOL) pubkey -k $(SUIT_SEC) \ + @$(SUIT_TOOL) pubkey -f header -k $(SUIT_SEC) \ | '$(LAZYSPONGE)' $(LAZYSPONGE_FLAGS) '$@' suit/genkey: $(SUIT_SEC) diff --git a/makefiles/suit.inc.mk b/makefiles/suit.inc.mk index e343b2bac1950..6f7af2a0c5249 100644 --- a/makefiles/suit.inc.mk +++ b/makefiles/suit.inc.mk @@ -27,7 +27,7 @@ SUIT_CLASS ?= $(BOARD) # $(SUIT_MANIFEST): $(SLOT0_RIOT_BIN) $(SLOT1_RIOT_BIN) - $(RIOTBASE)/dist/tools/suit_v3/gen_manifest.py \ + $(RIOTBASE)/dist/tools/suit/gen_manifest.py \ --urlroot $(SUIT_COAP_ROOT) \ --seqnr $(SUIT_SEQNR) \ --uuid-vendor $(SUIT_VENDOR) \ diff --git a/tests/suit_manifest/create_test_data.sh b/tests/suit_manifest/create_test_data.sh index 79a3af71f5609..4c337047bb478 100644 --- a/tests/suit_manifest/create_test_data.sh +++ b/tests/suit_manifest/create_test_data.sh @@ -9,7 +9,7 @@ gen_manifest() { shift - "${RIOTBASE}/dist/tools/suit_v3/gen_manifest.py" \ + "${RIOTBASE}/dist/tools/suit/gen_manifest.py" \ --urlroot "test://test" \ --seqnr "$seqnr" \ --uuid-vendor "riot-os.org" \