blob: 48604b1f08404076cfb2a677f99cb000cab41044 [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')