blob: 63b41a997c6f66a49db7924824a09aeb973155c1 [file] [log] [blame]
Mate Toth-Pal51b61982022-03-17 14:19:30 +01001# -----------------------------------------------------------------------------
2# Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3#
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
11import tempfile
12import unittest
13
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020014from iatverifier.psa_iot_profile1_token_verifier import PSAIoTProfile1TokenVerifier
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020015from iatverifier.util import read_token_map, convert_map_to_token, read_keyfile
16from iatverifier.attest_token_verifier import VerifierConfiguration, AttestationTokenVerifier
Mate Toth-Pal51b61982022-03-17 14:19:30 +010017
18
19THIS_DIR = os.path.dirname(__file__)
20
21DATA_DIR = os.path.join(THIS_DIR, 'data')
22KEYFILE = os.path.join(DATA_DIR, 'key.pem')
23KEYFILE_ALT = os.path.join(DATA_DIR, 'key-alt.pem')
24
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020025def create_token(source_name, verifier):
26 """Create a CBOR encoded token and save it to a temp file
Mate Toth-Pal51b61982022-03-17 14:19:30 +010027
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020028 Return the name of the temp file."""
Mate Toth-Pal51b61982022-03-17 14:19:30 +010029 source_path = os.path.join(DATA_DIR, source_name)
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020030 temp_file, dest_path = tempfile.mkstemp()
31 os.close(temp_file)
32
33 token_map = read_token_map(source_path)
34 with open(dest_path, 'wb') as wfh:
35 convert_map_to_token(
36 token_map,
37 verifier,
38 wfh,
39 add_p_header=False,
40 name_as_key=True,
41 parse_raw_value=True)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010042 return dest_path
43
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020044def read_iat(filename, verifier):
45 """Parse a token file"""
Mate Toth-Pal51b61982022-03-17 14:19:30 +010046 filepath = os.path.join(DATA_DIR, filename)
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020047 with open(filepath, 'rb') as token_file:
48 return verifier.parse_token(
49 token=token_file.read(),
50 verify=True,
51 check_p_header=False,
52 lower_case_key=False)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010053
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020054def create_and_read_iat(source_name, verifier):
55 """Create a cbor encoded token in a temp file and parse it back"""
56 token_file = create_token(source_name, verifier)
57 return read_iat(token_file, verifier)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010058
59class TestIatVerifier(unittest.TestCase):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020060 """A class used for testing iat-verifier.
61
62 This class uses the claim and token definitions for PSA Attestation Token"""
Mate Toth-Pal51b61982022-03-17 14:19:30 +010063
64 def setUp(self):
65 self.config = VerifierConfiguration()
66
67 def test_validate_signature(self):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020068 """Testing Signature validation"""
69 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1
70 cose_alg=AttestationTokenVerifier.COSE_ALG_ES256
Mate Toth-Pal51b61982022-03-17 14:19:30 +010071
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020072 signing_key = read_keyfile(KEYFILE, method)
73 verifier_good_sig = PSAIoTProfile1TokenVerifier(
74 method=method,
75 cose_alg=cose_alg,
76 signing_key=signing_key,
77 configuration=self.config)
78 good_sig = create_token('valid-iat.yaml', verifier_good_sig)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010079
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020080 signing_key = read_keyfile(KEYFILE_ALT, method)
81 verifier_bad_sig = PSAIoTProfile1TokenVerifier(
82 method=method,
83 cose_alg=cose_alg,
84 signing_key=signing_key,
85 configuration=self.config)
86 bad_sig = create_token('valid-iat.yaml', verifier_bad_sig)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010087
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020088 #dump_file_binary(good_sig)
89
90 with open(good_sig, 'rb') as wfh:
91 verifier_good_sig.parse_token(
92 token=wfh.read(),
93 verify=True,
94 check_p_header=False,
95 lower_case_key=False)
96
97
98 with self.assertRaises(ValueError) as test_ctx:
99 with open(bad_sig, 'rb') as wfh:
100 verifier_good_sig.parse_token(
101 token=wfh.read(),
102 verify=True,
103 check_p_header=False,
104 lower_case_key=False)
105
106 self.assertIn('Bad signature', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100107
108 def test_validate_iat_structure(self):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200109 """Testing IAT structure validation"""
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100110 keep_going_conf = VerifierConfiguration(keep_going=True)
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200111 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1
112 cose_alg=AttestationTokenVerifier.COSE_ALG_ES256
113 signing_key = read_keyfile(KEYFILE, method)
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100114
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200115 create_and_read_iat(
116 'valid-iat.yaml',
117 PSAIoTProfile1TokenVerifier(method=method,
118 cose_alg=cose_alg,
119 signing_key=signing_key,
120 configuration=self.config))
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100121
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200122 with self.assertRaises(ValueError) as test_ctx:
123 create_and_read_iat(
124 'invalid-profile-id.yaml',
125 PSAIoTProfile1TokenVerifier(method=method,
126 cose_alg=cose_alg,
127 signing_key=signing_key,
128 configuration=self.config))
129 self.assertIn('Invalid PROFILE_ID', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100130
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200131 with self.assertRaises(ValueError) as test_ctx:
132 read_iat(
133 'malformed.cbor',
134 PSAIoTProfile1TokenVerifier(method=method,
135 cose_alg=cose_alg,
136 signing_key=signing_key,
137 configuration=self.config))
138 self.assertIn('Bad COSE', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100139
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200140 with self.assertRaises(ValueError) as test_ctx:
141 create_and_read_iat(
142 'missing-claim.yaml',
143 PSAIoTProfile1TokenVerifier(method=method,
144 cose_alg=cose_alg,
145 signing_key=signing_key,
146 configuration=self.config))
147 self.assertIn('missing MANDATORY claim', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100148
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200149 with self.assertRaises(ValueError) as test_ctx:
150 create_and_read_iat(
151 'submod-missing-claim.yaml',
152 PSAIoTProfile1TokenVerifier(method=method,
153 cose_alg=cose_alg,
154 signing_key=signing_key,
155 configuration=self.config))
156 self.assertIn('missing MANDATORY claim', test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100157
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200158 with self.assertRaises(ValueError) as test_ctx:
159 create_and_read_iat(
160 'missing-sw-comps.yaml',
161 PSAIoTProfile1TokenVerifier(method=method,
162 cose_alg=cose_alg,
163 signing_key=signing_key,
164 configuration=self.config))
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100165 self.assertIn('NO_MEASUREMENTS claim is not present',
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200166 test_ctx.exception.args[0])
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100167
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200168 with self.assertLogs() as test_ctx:
169 create_and_read_iat(
170 'missing-signer-id.yaml',
171 PSAIoTProfile1TokenVerifier(method=method,
172 cose_alg=cose_alg,
173 signing_key=signing_key,
174 configuration=self.config))
Mate Toth-Pald10a9142022-04-28 15:34:13 +0200175 self.assertIn('Missing RECOMMENDED claim "SIGNER_ID" from SW_COMPONENTS',
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200176 test_ctx.records[0].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100177
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200178 with self.assertLogs() as test_ctx:
179 create_and_read_iat(
180 'invalid-type-length.yaml',
181 PSAIoTProfile1TokenVerifier(method=method,
182 cose_alg=cose_alg,
183 signing_key=signing_key,
184 configuration=keep_going_conf))
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100185 self.assertIn("Invalid PROFILE_ID: must be a(n) <class 'str'>: found <class 'int'>",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200186 test_ctx.records[0].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100187 self.assertIn("Invalid SIGNER_ID: must be a(n) <class 'bytes'>: found <class 'str'>",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200188 test_ctx.records[1].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100189 self.assertIn("Invalid SIGNER_ID length: must be at least 32 bytes, found 12 bytes",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200190 test_ctx.records[2].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100191 self.assertIn("Invalid MEASUREMENT length: must be at least 32 bytes, found 28 bytes",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200192 test_ctx.records[3].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100193
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200194 with self.assertLogs() as test_ctx:
195 create_and_read_iat(
196 'invalid-hw-version.yaml',
197 PSAIoTProfile1TokenVerifier(method=method,
198 cose_alg=cose_alg,
199 signing_key=signing_key,
200 configuration=keep_going_conf))
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100201 self.assertIn("Invalid HARDWARE_VERSION length; must be 13 digits, found 10 characters",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200202 test_ctx.records[0].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100203 self.assertIn("Invalid digit at position 1",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200204 test_ctx.records[1].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100205 self.assertIn("Invalid digit - at position 4",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200206 test_ctx.records[2].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100207 self.assertIn("Invalid digit a at position 10",
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200208 test_ctx.records[3].getMessage())
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100209
210 def test_binary_string_decoding(self):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200211 """Test binary_string decoding"""
212 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1
213 cose_alg=AttestationTokenVerifier.COSE_ALG_ES256
214 signing_key = read_keyfile(KEYFILE, method)
215 iat = create_and_read_iat(
216 'valid-iat.yaml',
217 PSAIoTProfile1TokenVerifier(method=method,
218 cose_alg=cose_alg,
219 signing_key=signing_key,
220 configuration=self.config))
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100221 self.assertEqual(iat['SECURITY_LIFECYCLE'], 'SL_SECURED')
222
223 def test_security_lifecycle_decoding(self):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200224 """Test security lifecycle decoding"""
225 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1
226 cose_alg=AttestationTokenVerifier.COSE_ALG_ES256
227 signing_key = read_keyfile(KEYFILE, method)
228 iat = create_and_read_iat(
229 'valid-iat.yaml',
230 PSAIoTProfile1TokenVerifier(method=method,
231 cose_alg=cose_alg,
232 signing_key=signing_key,
233 configuration=self.config))
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100234 self.assertEqual(iat['SECURITY_LIFECYCLE'], 'SL_SECURED')