forked from ARMmbed/suit-manifest-generator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sign.py
146 lines (127 loc) · 3.9 KB
/
sign.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# ----------------------------------------------------------------------------
# Copyright 2018 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 cbor
import sys
import ed25519
import eddsa
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
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(eddsa.parse_privkey(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(eddsa.parse_pubkey(pub_key_bytes))
# Read the input file
doc = None
with open(sys.argv[3], 'rb') as fd:
doc = fd.read()
# Check if the content is already a COSE_Sign_Tagged
isCOSE_Sign_Tagged = False
COSE_Sign = []
try:
decodedDoc = cbor.loads(doc)
if isinstance(decodedDoc, cbor.Tag) and decodedDoc.tag == COSE_Sign_Tag:
isCOSE_Sign_Tagged = True
COSE_Sign = decodedDoc.value
except:
pass
if not isCOSE_Sign_Tagged:
protected = cbor.dumps({
3: APPLICATION_OCTET_STREAM_ID, # Content Type
})
unprotected = {
}
payload = doc
signatures = []
# Create a COSE_Sign_Tagged object
COSE_Sign = [
protected,
unprotected,
payload,
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
4: kid #kid
})
unprotected = {
}
Sig_structure = [
"Signature", # Context
COSE_Sign[0], # Body Protected
protected, # signature protected
b'', # External AAD
COSE_Sign[2]
]
sig_str = cbor.dumps(Sig_structure)
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)
with open(sys.argv[4], 'wb') as fd:
COSE_Sign_Tagged = cbor.Tag(98, COSE_Sign)
fd.write(cbor.dumps(COSE_Sign_Tagged))