blob: 17658f1d843e0d3ba339f2063aa8091910829404 [file] [log] [blame]
Mate Toth-Pal51b61982022-03-17 14:19:30 +01001# -----------------------------------------------------------------------------
Mate Toth-Pal916a3de2024-05-03 09:34:41 +02002# Copyright (c) 2019-2024, Arm Limited. All rights reserved.
Mate Toth-Pal51b61982022-03-17 14:19:30 +01003#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6# -----------------------------------------------------------------------------
7
Mate Toth-Palb9057ff2022-04-29 16:03:21 +02008"""Unittests for iat-verifier using PSAIoTProfile1TokenVerifier"""
9
Mate Toth-Pal51b61982022-03-17 14:19:30 +010010import os
Mate Toth-Pal51b61982022-03-17 14:19:30 +010011import unittest
12
Thomas Fossatif4e1ca32024-08-16 16:01:31 +000013from pycose.algorithms import Es256, Es384
14
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020015from iatverifier.psa_iot_profile1_token_verifier import PSAIoTProfile1TokenVerifier
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010016from iatverifier.cca_token_verifier import CCATokenVerifier, CCAPlatformTokenVerifier
Mate Toth-Palb2508d52022-04-30 14:10:06 +020017from iatverifier.util import read_keyfile
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010018from iatverifier.attest_token_verifier import AttestationClaim, VerifierConfiguration
19from iatverifier.attest_token_verifier import AttestationTokenVerifier
Mate Toth-Palb2508d52022-04-30 14:10:06 +020020from test_utils import create_and_read_iat, read_iat, create_token_tmp_file
Mate Toth-Pal51b61982022-03-17 14:19:30 +010021
22
23THIS_DIR = os.path.dirname(__file__)
24
25DATA_DIR = os.path.join(THIS_DIR, 'data')
26KEYFILE = os.path.join(DATA_DIR, 'key.pem')
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010027KEYFILE_CCA_PLAT = os.path.join(DATA_DIR, 'cca_platform.pem')
28KEYFILE_CCA_REALM = os.path.join(DATA_DIR, 'cca_realm.pem')
Mate Toth-Palb21ae522022-09-01 12:02:21 +020029KEYFILE_CCA_REALM2= os.path.join(DATA_DIR, 'cca_realm2.pem')
Mate Toth-Pal51b61982022-03-17 14:19:30 +010030KEYFILE_ALT = os.path.join(DATA_DIR, 'key-alt.pem')
31
Mate Toth-Pal51b61982022-03-17 14:19:30 +010032class TestIatVerifier(unittest.TestCase):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020033 """A class used for testing iat-verifier.
34
35 This class uses the claim and token definitions for PSA Attestation Token"""
Mate Toth-Pal51b61982022-03-17 14:19:30 +010036
37 def setUp(self):
38 self.config = VerifierConfiguration()
39
40 def test_validate_signature(self):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020041 """Testing Signature validation"""
42 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1
Thomas Fossatif4e1ca32024-08-16 16:01:31 +000043 cose_alg=Es256
Mate Toth-Pal51b61982022-03-17 14:19:30 +010044
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020045 signing_key = read_keyfile(KEYFILE, method)
46 verifier_good_sig = PSAIoTProfile1TokenVerifier(
47 method=method,
48 cose_alg=cose_alg,
49 signing_key=signing_key,
50 configuration=self.config)
Mate Toth-Palb2508d52022-04-30 14:10:06 +020051 good_sig = create_token_tmp_file(DATA_DIR, 'valid-iat.yaml', verifier_good_sig)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010052
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020053 signing_key = read_keyfile(KEYFILE_ALT, method)
54 verifier_bad_sig = PSAIoTProfile1TokenVerifier(
55 method=method,
56 cose_alg=cose_alg,
57 signing_key=signing_key,
58 configuration=self.config)
Mate Toth-Palb2508d52022-04-30 14:10:06 +020059 bad_sig = create_token_tmp_file(DATA_DIR, 'valid-iat.yaml', verifier_bad_sig)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010060
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020061 #dump_file_binary(good_sig)
62
63 with open(good_sig, 'rb') as wfh:
Mate Toth-Palc7404e92022-07-15 11:11:13 +020064 token_item = verifier_good_sig.parse_token(
65 token=wfh.read(),
Mate Toth-Palc7404e92022-07-15 11:11:13 +020066 lower_case_key=False)
67 token_item.verify()
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020068
69 with self.assertRaises(ValueError) as test_ctx:
70 with open(bad_sig, 'rb') as wfh:
Mate Toth-Palc7404e92022-07-15 11:11:13 +020071 token_item = verifier_good_sig.parse_token(
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020072 token=wfh.read(),
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020073 lower_case_key=False)
Mate Toth-Palc7404e92022-07-15 11:11:13 +020074 token_item.verify()
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020075
76 self.assertIn('Bad signature', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +010077
78 def test_validate_iat_structure(self):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020079 """Testing IAT structure validation"""
Mate Toth-Pal51b61982022-03-17 14:19:30 +010080 keep_going_conf = VerifierConfiguration(keep_going=True)
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020081 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1
Thomas Fossatif4e1ca32024-08-16 16:01:31 +000082 cose_alg=Es256
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020083 signing_key = read_keyfile(KEYFILE, method)
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010084 realm_token_key = read_keyfile(KEYFILE_CCA_REALM, method)
Mate Toth-Palb21ae522022-09-01 12:02:21 +020085 realm_token_key2 = read_keyfile(KEYFILE_CCA_REALM2, method)
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010086 platform_token_key = read_keyfile(KEYFILE_CCA_PLAT, method)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010087
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020088 create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +020089 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020090 'valid-iat.yaml',
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010091 PSAIoTProfile1TokenVerifier(
92 method=method,
93 cose_alg=cose_alg,
94 signing_key=signing_key,
95 configuration=self.config))
Mate Toth-Palb21ae522022-09-01 12:02:21 +020096
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010097 create_and_read_iat(
98 DATA_DIR,
99 'valid-cca-token.yaml',
100 CCATokenVerifier(
101 realm_token_method=method,
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000102 realm_token_cose_alg=Es384,
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100103 realm_token_key=realm_token_key,
104 platform_token_method=method,
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000105 platform_token_cose_alg=Es384,
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100106 platform_token_key=platform_token_key,
107 configuration=self.config))
108
109 create_and_read_iat(
110 DATA_DIR,
111 'cca_platform_token.yaml',
112 CCAPlatformTokenVerifier(
113 method=method,
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000114 cose_alg=Es384,
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100115 signing_key=platform_token_key,
116 configuration=self.config,
117 necessity=AttestationClaim.MANDATORY))
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100118
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200119 with self.assertRaises(ValueError) as test_ctx:
120 create_and_read_iat(
Mate Toth-Palb21ae522022-09-01 12:02:21 +0200121 DATA_DIR,
Mate Toth-Palc5dbad02022-09-01 22:17:26 +0200122 'cca-invalid-plat-challenge.yaml',
123 CCATokenVerifier(
124 realm_token_method=method,
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000125 realm_token_cose_alg=Es384,
Mate Toth-Palc5dbad02022-09-01 22:17:26 +0200126 realm_token_key=realm_token_key,
127 platform_token_method=method,
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000128 platform_token_cose_alg=Es384,
Mate Toth-Palc5dbad02022-09-01 22:17:26 +0200129 platform_token_key=platform_token_key,
130 configuration=self.config))
131 self.assertIn("Invalid CCA_PLATFORM_CHALLENGE byte at 16: 0x00 instead of 0xe4", test_ctx.exception.args[0])
132
133 with self.assertRaises(ValueError) as test_ctx:
134 create_and_read_iat(
135 DATA_DIR,
Mate Toth-Palb21ae522022-09-01 12:02:21 +0200136 'valid-cca-token.yaml',
137 CCATokenVerifier(
138 realm_token_method=method,
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000139 realm_token_cose_alg=Es384,
Mate Toth-Palb21ae522022-09-01 12:02:21 +0200140 realm_token_key=realm_token_key2,
141 platform_token_method=method,
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000142 platform_token_cose_alg=Es384,
Mate Toth-Palb21ae522022-09-01 12:02:21 +0200143 platform_token_key=platform_token_key,
144 configuration=self.config))
145 self.assertIn("Realm signature doesn't match Realm Public Key claim in Realm token", test_ctx.exception.args[0])
146
147 with self.assertRaises(ValueError) as test_ctx:
148 create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200149 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200150 'invalid-profile-id.yaml',
151 PSAIoTProfile1TokenVerifier(method=method,
152 cose_alg=cose_alg,
153 signing_key=signing_key,
154 configuration=self.config))
155 self.assertIn('Invalid PROFILE_ID', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100156
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200157 with self.assertRaises(ValueError) as test_ctx:
158 read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200159 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200160 'malformed.cbor',
161 PSAIoTProfile1TokenVerifier(method=method,
162 cose_alg=cose_alg,
163 signing_key=signing_key,
164 configuration=self.config))
165 self.assertIn('Bad COSE', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100166
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200167 with self.assertRaises(ValueError) as test_ctx:
168 create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200169 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200170 'missing-claim.yaml',
171 PSAIoTProfile1TokenVerifier(method=method,
172 cose_alg=cose_alg,
173 signing_key=signing_key,
174 configuration=self.config))
175 self.assertIn('missing MANDATORY claim', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100176
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200177 with self.assertRaises(ValueError) as test_ctx:
178 create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200179 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200180 'submod-missing-claim.yaml',
181 PSAIoTProfile1TokenVerifier(method=method,
182 cose_alg=cose_alg,
183 signing_key=signing_key,
184 configuration=self.config))
185 self.assertIn('missing MANDATORY claim', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100186
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200187 with self.assertRaises(ValueError) as test_ctx:
188 create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200189 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200190 'missing-sw-comps.yaml',
191 PSAIoTProfile1TokenVerifier(method=method,
192 cose_alg=cose_alg,
193 signing_key=signing_key,
194 configuration=self.config))
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100195 self.assertIn('NO_MEASUREMENTS claim is not present',
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200196 test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100197
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200198 with self.assertLogs() as test_ctx:
199 create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200200 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200201 'missing-signer-id.yaml',
202 PSAIoTProfile1TokenVerifier(method=method,
203 cose_alg=cose_alg,
204 signing_key=signing_key,
205 configuration=self.config))
Mate Toth-Pald10a9142022-04-28 15:34:13 +0200206 self.assertIn('Missing RECOMMENDED claim "SIGNER_ID" from SW_COMPONENTS',
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200207 test_ctx.records[0].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100208
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200209 with self.assertLogs() as test_ctx:
210 create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200211 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200212 'invalid-type-length.yaml',
213 PSAIoTProfile1TokenVerifier(method=method,
214 cose_alg=cose_alg,
215 signing_key=signing_key,
216 configuration=keep_going_conf))
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100217 self.assertIn("Invalid PROFILE_ID: must be a(n) <class 'str'>: found <class 'int'>",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200218 test_ctx.records[0].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100219 self.assertIn("Invalid SIGNER_ID: must be a(n) <class 'bytes'>: found <class 'str'>",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200220 test_ctx.records[1].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100221 self.assertIn("Invalid SIGNER_ID length: must be at least 32 bytes, found 12 bytes",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200222 test_ctx.records[2].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100223 self.assertIn("Invalid MEASUREMENT length: must be at least 32 bytes, found 28 bytes",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200224 test_ctx.records[3].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100225
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200226 with self.assertLogs() as test_ctx:
227 create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200228 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200229 'invalid-hw-version.yaml',
Tamas Ban8ac8d172022-07-04 13:01:08 +0200230 PSAIoTProfile1TokenVerifier(
231 method=method,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200232 cose_alg=cose_alg,
233 signing_key=signing_key,
234 configuration=keep_going_conf))
Tamas Ban8ac8d172022-07-04 13:01:08 +0200235 self.assertIn("Invalid HARDWARE_VERSION length; "
236 "must be 19 characters, found 10 characters",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200237 test_ctx.records[0].getMessage())
Tamas Ban8ac8d172022-07-04 13:01:08 +0200238 self.assertIn("Invalid character at position 1",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200239 test_ctx.records[1].getMessage())
Tamas Ban8ac8d172022-07-04 13:01:08 +0200240 self.assertIn("Invalid character - at position 4",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200241 test_ctx.records[2].getMessage())
Tamas Ban8ac8d172022-07-04 13:01:08 +0200242 self.assertIn("Invalid character a at position 10",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200243 test_ctx.records[3].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100244
245 def test_binary_string_decoding(self):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200246 """Test binary_string decoding"""
247 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000248 cose_alg=Es256
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200249 signing_key = read_keyfile(KEYFILE, method)
250 iat = create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200251 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200252 'valid-iat.yaml',
253 PSAIoTProfile1TokenVerifier(method=method,
254 cose_alg=cose_alg,
255 signing_key=signing_key,
Mate Toth-Palc7404e92022-07-15 11:11:13 +0200256 configuration=self.config)).get_token_map()
Mate Toth-Pal916a3de2024-05-03 09:34:41 +0200257 self.assertEqual(iat['SECURITY_LIFECYCLE'], 'sl_secured_3000')
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100258
259 def test_security_lifecycle_decoding(self):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200260 """Test security lifecycle decoding"""
261 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000262 cose_alg=Es256
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200263 signing_key = read_keyfile(KEYFILE, method)
264 iat = create_and_read_iat(
Mate Toth-Palb2508d52022-04-30 14:10:06 +0200265 DATA_DIR,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200266 'valid-iat.yaml',
267 PSAIoTProfile1TokenVerifier(method=method,
268 cose_alg=cose_alg,
269 signing_key=signing_key,
Mate Toth-Palc7404e92022-07-15 11:11:13 +0200270 configuration=self.config)).get_token_map()
Mate Toth-Pal916a3de2024-05-03 09:34:41 +0200271 self.assertEqual(iat['SECURITY_LIFECYCLE'], 'sl_secured_3000')
Thomas Fossati5ebf4832024-08-26 09:30:05 +0000272
273 def test_profiles(self):
274 """
275 Test that both legacy and new profiles are handled correctly.
276 In particular, ensure that the different RAK encodings are accommodated,
277 and that use of legacy profiles triggers a warning.
278 """
279 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1
280 realm_token_key = read_keyfile(KEYFILE_CCA_REALM, method)
281 platform_token_key = read_keyfile(KEYFILE_CCA_PLAT, method)
282
283 # change directory here to make !inc work
284 os.chdir(DATA_DIR)
285
286 create_and_read_iat(
287 '.',
288 'cca_example_token.yaml',
289 CCATokenVerifier(
290 realm_token_method=method,
291 realm_token_cose_alg=Es384,
292 realm_token_key=realm_token_key,
293 platform_token_method=method,
294 platform_token_cose_alg=Es384,
295 platform_token_key=platform_token_key,
296 configuration=self.config
297 )
298 )
299
300 with self.assertLogs() as test_ctx:
301 create_and_read_iat(
302 '.',
303 'cca_example_token_legacy.yaml',
304 CCATokenVerifier(
305 realm_token_method=method,
306 realm_token_cose_alg=Es384,
307 realm_token_key=realm_token_key,
308 platform_token_method=method,
309 platform_token_cose_alg=Es384,
310 platform_token_key=platform_token_key,
311 configuration=self.config
312 )
313 )
314 self.assertIn('legacy profile http://arm.com/CCA-SSD/1.0.0 is deprecated',
315 test_ctx.records[0].getMessage())