2020-02-26 14:44:13 +01:00
|
|
|
#!/usr/bin/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.
|
|
|
|
# ----------------------------------------------------------------------------
|
2020-06-29 15:42:47 +02:00
|
|
|
import cbor2 as cbor
|
|
|
|
import json
|
2020-02-26 14:44:13 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2020-06-29 15:42:47 +02:00
|
|
|
from suit_tool.manifest import COSE_Sign1, COSEList, SUITDigest,\
|
|
|
|
SUITEnvelope, SUITBytes, SUITBWrapField, \
|
|
|
|
COSETaggedAuth
|
2020-02-26 14:44:13 +01:00
|
|
|
import logging
|
|
|
|
import binascii
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
2020-06-29 15:42:47 +02:00
|
|
|
def get_cose_es_bytes(options, private_key, sig_val):
|
2020-02-26 14:44:13 +01:00
|
|
|
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
|
|
|
|
|
2020-06-29 15:42:47 +02:00
|
|
|
def get_cose_ed25519_bytes(options, private_key, sig_val):
|
2020-02-26 14:44:13 +01:00
|
|
|
return private_key.sign(sig_val)
|
|
|
|
|
2020-06-29 15:42:47 +02:00
|
|
|
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
|
|
|
|
|
2020-02-26 14:44:13 +01:00
|
|
|
def main(options):
|
|
|
|
# Read the manifest wrapper
|
|
|
|
wrapper = cbor.loads(options.manifest.read())
|
|
|
|
|
|
|
|
private_key = None
|
|
|
|
digest = None
|
2020-06-29 15:42:47 +02:00
|
|
|
private_key_buffer = options.private_key.read()
|
2020-02-26 14:44:13 +01:00
|
|
|
try:
|
2020-06-29 15:42:47 +02:00
|
|
|
private_key = ks.load_pem_private_key(private_key_buffer, password=None, backend=default_backend())
|
2020-02-26 14:44:13 +01:00
|
|
|
if isinstance(private_key, ec.EllipticCurvePrivateKey):
|
|
|
|
options.key_type = 'ES{}'.format(private_key.key_size)
|
|
|
|
elif isinstance(private_key, ed25519.Ed25519PrivateKey):
|
|
|
|
options.key_type = 'EdDSA'
|
|
|
|
else:
|
|
|
|
LOG.critical('Unrecognized key: {}'.format(type(private_key).__name__))
|
|
|
|
return 1
|
|
|
|
digest = {
|
|
|
|
'ES256' : hashes.Hash(hashes.SHA256(), backend=default_backend()),
|
|
|
|
'ES384' : hashes.Hash(hashes.SHA384(), backend=default_backend()),
|
|
|
|
'ES512' : hashes.Hash(hashes.SHA512(), backend=default_backend()),
|
|
|
|
'EdDSA' : hashes.Hash(hashes.SHA256(), backend=default_backend()),
|
|
|
|
}.get(options.key_type)
|
|
|
|
except:
|
|
|
|
LOG.critical('Non-library key type not implemented')
|
2020-06-29 15:42:47 +02:00
|
|
|
return 1
|
2020-02-26 14:44:13 +01:00
|
|
|
|
2020-06-29 15:42:47 +02:00
|
|
|
digest.update(cbor.dumps(wrapper[SUITEnvelope.fields['manifest'].suit_key]))
|
2020-02-26 14:44:13 +01:00
|
|
|
|
|
|
|
cose_signature = COSE_Sign1().from_json({
|
|
|
|
'protected' : {
|
|
|
|
'alg' : options.key_type
|
|
|
|
},
|
|
|
|
'unprotected' : {},
|
|
|
|
'payload' : {
|
|
|
|
'algorithm-id' : 'sha256',
|
2020-06-29 15:42:47 +02:00
|
|
|
'digest-bytes' : digest.finalize()
|
2020-02-26 14:44:13 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
Sig_structure = cbor.dumps([
|
|
|
|
"Signature1",
|
|
|
|
cose_signature.protected.to_suit(),
|
|
|
|
b'',
|
|
|
|
cose_signature.payload.to_suit(),
|
2020-06-29 15:42:47 +02:00
|
|
|
], canonical = True)
|
|
|
|
LOG.debug('Signing: {}'.format(binascii.b2a_hex(Sig_structure).decode('utf-8')))
|
2020-02-26 14:44:13 +01:00
|
|
|
|
|
|
|
signature_bytes = {
|
|
|
|
'ES256' : get_cose_es_bytes,
|
|
|
|
'ES384' : get_cose_es_bytes,
|
|
|
|
'ES512' : get_cose_es_bytes,
|
|
|
|
'EdDSA' : get_cose_ed25519_bytes,
|
2020-06-29 15:42:47 +02:00
|
|
|
'HSS-LMS' : get_hsslms_bytes,
|
|
|
|
}.get(options.key_type)(options, private_key, Sig_structure)
|
2020-02-26 14:44:13 +01:00
|
|
|
|
|
|
|
cose_signature.signature = SUITBytes().from_suit(signature_bytes)
|
|
|
|
|
2020-06-29 15:42:47 +02:00
|
|
|
auth = SUITBWrapField(COSEList)().from_suit(wrapper[SUITEnvelope.fields['auth'].suit_key])
|
|
|
|
auth.v.append(auth.v.field.obj().from_json({
|
2020-02-26 14:44:13 +01:00
|
|
|
'COSE_Sign1_Tagged' : cose_signature.to_json()
|
2020-06-29 15:42:47 +02:00
|
|
|
}))
|
|
|
|
wrapper[SUITEnvelope.fields['auth'].suit_key] = auth.to_suit()
|
2020-02-26 14:44:13 +01:00
|
|
|
|
2020-06-29 15:42:47 +02:00
|
|
|
options.output_file.write(cbor.dumps(wrapper, canonical=True))
|
2020-02-26 14:44:13 +01:00
|
|
|
return 0
|