Coverage for tests/admin/test_certificate_v1_element.py: 100%
77 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-07-10 13:43 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-07-10 13:43 +0000
1# The MIT License (MIT)
2#
3# Copyright (c) 2021 RSK Labs Ltd
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy of
6# this software and associated documentation files (the "Software"), to deal in
7# the Software without restriction, including without limitation the rights to
8# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9# of the Software, and to permit persons to whom the Software is furnished to do
10# so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
23import hashlib
24import hmac
25import os
26from parameterized import parameterized
27import secp256k1 as ec
29from unittest import TestCase
30from unittest.mock import Mock
31from admin.certificate import HSMCertificateRoot, HSMCertificateElement
34class TestHSMCertificateRoot(TestCase):
35 def test_ok(self):
36 pubkey = ec.PrivateKey().pubkey
37 root = HSMCertificateRoot(pubkey.serialize(compressed=False).hex())
38 self.assertEqual(
39 pubkey.serialize(compressed=True),
40 root.get_pubkey().serialize(compressed=True))
42 def test_invalid_pubkey(self):
43 with self.assertRaises(ValueError):
44 HSMCertificateRoot("invalid-pubkey")
47class TestHSMCertificateElement(TestCase):
48 def test_create_certificate_element_ok(self):
49 element = HSMCertificateElement({
50 "name": "device",
51 "message": 'cc',
52 "signature": 'dd',
53 "signed_by": "root",
54 "tweak": 'ee'
55 })
56 self.assertEqual({
57 "name": "device",
58 "message": 'cc',
59 "signature": 'dd',
60 "signed_by": "root",
61 "tweak": 'ee'
62 }, element.to_dict())
64 def test_create_certificate_element_invalid_name(self):
65 with self.assertRaises(ValueError):
66 HSMCertificateElement({
67 "name": "invalid-name",
68 "message": 'cc',
69 "signature": 'dd',
70 "signed_by": "root",
71 "tweak": 'ee'
72 })
74 def test_create_certificate_element_missing_certifier(self):
75 with self.assertRaises(ValueError):
76 HSMCertificateElement({
77 "name": "device",
78 "message": 'cc',
79 "signature": 'dd',
80 "tweak": 'ee'
81 })
83 def test_create_certificate_element_invalid_tweak(self):
84 with self.assertRaises(ValueError):
85 HSMCertificateElement({
86 "name": "device",
87 "message": 'cc',
88 "signature": 'dd',
89 "signed_by": "root",
90 "tweak": 'invalid-tweak'
91 })
93 def test_create_certificate_element_invalid_message(self):
94 with self.assertRaises(ValueError):
95 HSMCertificateElement({
96 "name": "device",
97 "message": 'invalid-message',
98 "signature": 'dd',
99 "signed_by": "root",
100 "tweak": 'ee'
101 })
103 def test_create_certificate_element_invalid_signature(self):
104 with self.assertRaises(ValueError):
105 HSMCertificateElement({
106 "name": "device",
107 "message": 'cc',
108 "signature": 'invalid-signature',
109 "signed_by": "root",
110 "tweak": 'ee'
111 })
113 def test_certificate_element_is_valid_ok(self):
114 privkey = ec.PrivateKey()
115 msg = 'aa' * 65
116 signature = privkey.ecdsa_serialize(privkey.ecdsa_sign(bytes.fromhex(msg))).hex()
117 mock_certifier = Mock(get_pubkey=lambda: privkey.pubkey)
119 element = HSMCertificateElement({
120 "name": "device",
121 "message": msg,
122 "signature": signature,
123 "signed_by": "root"
124 })
125 self.assertEqual({
126 "name": "device",
127 "message": msg,
128 "signature": signature,
129 "signed_by": "root"
130 }, element.to_dict())
131 self.assertTrue(element.is_valid(mock_certifier))
133 def test_certificate_element_is_valid_with_tweak_ok(self):
134 privkey = ec.PrivateKey()
135 pubkey = privkey.pubkey
136 raw_tweak = os.urandom(32).hex()
137 tweak = hmac.new(
138 bytes.fromhex(raw_tweak),
139 pubkey.serialize(compressed=False),
140 hashlib.sha256,
141 ).digest()
142 mock_certifier = Mock(get_pubkey=lambda: pubkey)
144 tweak_privkey = ec.PrivateKey(privkey.tweak_add(tweak), raw=True)
145 msg = os.urandom(66).hex()
146 signature = tweak_privkey.ecdsa_serialize(
147 tweak_privkey.ecdsa_sign(bytes.fromhex(msg))).hex()
149 element = HSMCertificateElement({
150 "name": "device",
151 "message": msg,
152 "signature": signature,
153 "signed_by": "root",
154 "tweak": raw_tweak
155 })
156 self.assertEqual({
157 "name": "device",
158 "message": msg,
159 "signature": signature,
160 "signed_by": "root",
161 "tweak": raw_tweak
162 }, element.to_dict())
163 self.assertTrue(element.is_valid(mock_certifier))
165 def test_certificate_element_is_valid_wrong_signature(self):
166 privkey = ec.PrivateKey()
167 msg = 'aa' * 65
169 element = HSMCertificateElement({
170 "name": "device",
171 "message": msg,
172 "signature": 'bb' * 65,
173 "signed_by": "root"
174 })
175 self.assertEqual({
176 "name": "device",
177 "message": msg,
178 "signature": 'bb' * 65,
179 "signed_by": "root"
180 }, element.to_dict())
181 self.assertFalse(element.is_valid(privkey.pubkey))
183 def test_certificate_element_is_valid_wrong_tweak(self):
184 privkey = ec.PrivateKey()
185 pubkey = privkey.pubkey
186 raw_tweak = os.urandom(32).hex()
187 tweak = hmac.new(
188 bytes.fromhex(raw_tweak),
189 pubkey.serialize(compressed=False),
190 hashlib.sha256,
191 ).digest()
193 tweak_privkey = ec.PrivateKey(privkey.tweak_add(tweak), raw=True)
194 msg = os.urandom(66).hex()
195 signature = tweak_privkey.ecdsa_serialize(
196 tweak_privkey.ecdsa_sign(bytes.fromhex(msg))).hex()
198 element = HSMCertificateElement({
199 "name": "device",
200 "message": msg,
201 "signature": signature,
202 "signed_by": "root",
203 "tweak": 'bb' * 32
204 })
205 self.assertEqual({
206 "name": "device",
207 "message": msg,
208 "signature": signature,
209 "signed_by": "root",
210 "tweak": 'bb' * 32
211 }, element.to_dict())
212 self.assertFalse(element.is_valid(pubkey))
214 @parameterized.expand([
215 ("device", lambda b: b[-65:]),
216 ("attestation", lambda b: b[1:]),
217 ("ui", lambda b: b[:]),
218 ("signer", lambda b: b[:])
219 ])
220 def test_certificate_element_get_value(self, name, extractor):
221 msg = os.urandom(66).hex()
222 element = HSMCertificateElement({
223 "name": name,
224 "message": msg,
225 "signature": 'aa' * 70,
226 "signed_by": "root",
227 "tweak": 'bb' * 32
228 })
229 self.assertEqual(extractor(bytes.fromhex(msg)).hex(), element.get_value())