blob: 7824ea68061ca7727c57893289ed1b9282328c73 [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
8import os
9import tempfile
10import unittest
11
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020012from iatverifier.psa_iot_profile1_token_verifier import PSAIoTProfile1TokenVerifier
13from iatverifier.util import convert_map_to_token_files, extract_iat_from_cose
Mate Toth-Pal51b61982022-03-17 14:19:30 +010014from iatverifier.verifiers import VerifierConfiguration
15
16
17THIS_DIR = os.path.dirname(__file__)
18
19DATA_DIR = os.path.join(THIS_DIR, 'data')
20KEYFILE = os.path.join(DATA_DIR, 'key.pem')
21KEYFILE_ALT = os.path.join(DATA_DIR, 'key-alt.pem')
22
23
24def create_token(source_name, keyfile, verifier):
25 source_path = os.path.join(DATA_DIR, source_name)
26 fd, dest_path = tempfile.mkstemp()
27 os.close(fd)
Mate Toth-Palbdb475e2022-04-24 12:11:22 +020028 convert_map_to_token_files(source_path, keyfile, verifier, dest_path, True)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010029 return dest_path
30
31
32def read_iat(filename, keyfile, verifier):
33 filepath = os.path.join(DATA_DIR, filename)
Mate Toth-Palbdb475e2022-04-24 12:11:22 +020034 raw_iat = extract_iat_from_cose(keyfile, filepath, verifier, True)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010035 return verifier.decode_and_validate_iat(raw_iat)
36
37
38def create_and_read_iat(source_name, keyfile, verifier):
39 token_file = create_token(source_name, keyfile, verifier)
40 return read_iat(token_file, keyfile, verifier)
41
42
43class TestIatVerifier(unittest.TestCase):
44
45 def setUp(self):
46 self.config = VerifierConfiguration()
47
48 def test_validate_signature(self):
49 verifier = PSAIoTProfile1TokenVerifier.get_verifier(self.config)
50 good_sig = create_token('valid-iat.yaml', KEYFILE, verifier)
51 bad_sig = create_token('valid-iat.yaml', KEYFILE_ALT, verifier)
52
Mate Toth-Palbdb475e2022-04-24 12:11:22 +020053 raw_iat = extract_iat_from_cose(KEYFILE, good_sig, verifier, True)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010054
55 with self.assertRaises(ValueError) as cm:
Mate Toth-Palbdb475e2022-04-24 12:11:22 +020056 raw_iat = extract_iat_from_cose(KEYFILE, bad_sig, verifier, True)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010057
58 self.assertIn('Bad signature', cm.exception.args[0])
59
60 def test_validate_iat_structure(self):
61 keep_going_conf = VerifierConfiguration(keep_going=True)
62
63 iat = create_and_read_iat('valid-iat.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(self.config))
64
65 with self.assertRaises(ValueError) as cm:
66 iat = create_and_read_iat('invalid-profile-id.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(self.config))
67 self.assertIn('Invalid PROFILE_ID', cm.exception.args[0])
68
69 with self.assertRaises(ValueError) as cm:
70 iat = read_iat('malformed.cbor', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(self.config))
71 self.assertIn('Bad COSE', cm.exception.args[0])
72
73 with self.assertRaises(ValueError) as cm:
74 iat = create_and_read_iat('missing-claim.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(self.config))
75 self.assertIn('missing MANDATORY claim', cm.exception.args[0])
76
77 with self.assertRaises(ValueError) as cm:
78 iat = create_and_read_iat('submod-missing-claim.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(self.config))
79 self.assertIn('missing MANDATORY claim', cm.exception.args[0])
80
81 with self.assertRaises(ValueError) as cm:
82 iat = create_and_read_iat('missing-sw-comps.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(self.config))
83 self.assertIn('NO_MEASUREMENTS claim is not present',
84 cm.exception.args[0])
85
86 with self.assertLogs() as cm:
87 iat = create_and_read_iat('missing-signer-id.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(self.config))
88 self.assertIn('Missing RECOMMENDED claim "SIGNER_ID" from sw_component',
89 cm.records[0].getMessage())
90
91 with self.assertLogs() as cm:
92 iat = create_and_read_iat('invalid-type-length.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(keep_going_conf))
93 self.assertIn("Invalid PROFILE_ID: must be a(n) <class 'str'>: found <class 'int'>",
94 cm.records[0].getMessage())
95 self.assertIn("Invalid SIGNER_ID: must be a(n) <class 'bytes'>: found <class 'str'>",
96 cm.records[1].getMessage())
97 self.assertIn("Invalid SIGNER_ID length: must be at least 32 bytes, found 12 bytes",
98 cm.records[2].getMessage())
99 self.assertIn("Invalid MEASUREMENT length: must be at least 32 bytes, found 28 bytes",
100 cm.records[3].getMessage())
101
102 with self.assertLogs() as cm:
103 iat = create_and_read_iat('invalid-hw-version.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(keep_going_conf))
104 self.assertIn("Invalid HARDWARE_VERSION length; must be 13 digits, found 10 characters",
105 cm.records[0].getMessage())
106 self.assertIn("Invalid digit at position 1",
107 cm.records[1].getMessage())
108 self.assertIn("Invalid digit - at position 4",
109 cm.records[2].getMessage())
110 self.assertIn("Invalid digit a at position 10",
111 cm.records[3].getMessage())
112
113 def test_binary_string_decoding(self):
114 iat = create_and_read_iat('valid-iat.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(self.config))
115 self.assertEqual(iat['SECURITY_LIFECYCLE'], 'SL_SECURED')
116
117 def test_security_lifecycle_decoding(self):
118 iat = create_and_read_iat('valid-iat.yaml', KEYFILE, PSAIoTProfile1TokenVerifier.get_verifier(self.config))
119 self.assertEqual(iat['SECURITY_LIFECYCLE'], 'SL_SECURED')