]> git.sur5r.net Git - u-boot/blob - test/py/tests/test_tpm2.py
pinctrl: renesas: Sync Gen3 PFC tables with Linux v4.17
[u-boot] / test / py / tests / test_tpm2.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2018, Bootlin
3 # Author: Miquel Raynal <miquel.raynal@bootlin.com>
4
5 import os.path
6 import pytest
7 import u_boot_utils
8 import re
9 import time
10
11 """
12 Test the TPMv2.x related commands. You must have a working hardware setup in
13 order to do these tests.
14
15 Notes:
16 * These tests will prove the password mechanism. The TPM chip must be cleared of
17 any password.
18 * Commands like pcr_setauthpolicy and pcr_resetauthpolicy are not implemented
19 here because they would fail the tests in most cases (TPMs do not implement them
20 and return an error).
21 """
22
23 updates = 0
24
25 def force_init(u_boot_console, force=False):
26     """When a test fails, U-Boot is reset. Because TPM stack must be initialized
27     after each reboot, we must ensure these lines are always executed before
28     trying any command or they will fail with no reason. Executing 'tpm init'
29     twice will spawn an error used to detect that the TPM was not reset and no
30     initialization code should be run.
31     """
32     output = u_boot_console.run_command('tpm init')
33     if force or not 'Error' in output:
34         u_boot_console.run_command('echo --- start of init ---')
35         u_boot_console.run_command('tpm startup TPM2_SU_CLEAR')
36         u_boot_console.run_command('tpm self_test full')
37         u_boot_console.run_command('tpm clear TPM2_RH_LOCKOUT')
38         output = u_boot_console.run_command('echo $?')
39         if not output.endswith('0'):
40             u_boot_console.run_command('tpm clear TPM2_RH_PLATFORM')
41         u_boot_console.run_command('echo --- end of init ---')
42
43 @pytest.mark.buildconfigspec('cmd_tpm_v2')
44 def test_tpm2_init(u_boot_console):
45     """Init the software stack to use TPMv2 commands."""
46
47     u_boot_console.run_command('tpm init')
48     output = u_boot_console.run_command('echo $?')
49     assert output.endswith('0')
50
51 @pytest.mark.buildconfigspec('cmd_tpm_v2')
52 def test_tpm2_startup(u_boot_console):
53     """Execute a TPM2_Startup command.
54
55     Initiate the TPM internal state machine.
56     """
57
58     u_boot_console.run_command('tpm startup TPM2_SU_CLEAR')
59     output = u_boot_console.run_command('echo $?')
60     assert output.endswith('0')
61
62 @pytest.mark.buildconfigspec('cmd_tpm_v2')
63 def test_tpm2_self_test_full(u_boot_console):
64     """Execute a TPM2_SelfTest (full) command.
65
66     Ask the TPM to perform all self tests to also enable full capabilities.
67     """
68
69     u_boot_console.run_command('tpm self_test full')
70     output = u_boot_console.run_command('echo $?')
71     assert output.endswith('0')
72
73 @pytest.mark.buildconfigspec('cmd_tpm_v2')
74 def test_tpm2_continue_self_test(u_boot_console):
75     """Execute a TPM2_SelfTest (continued) command.
76
77     Ask the TPM to finish its self tests (alternative to the full test) in order
78     to enter a fully operational state.
79     """
80
81     u_boot_console.run_command('tpm self_test continue')
82     output = u_boot_console.run_command('echo $?')
83     assert output.endswith('0')
84
85 @pytest.mark.buildconfigspec('cmd_tpm_v2')
86 def test_tpm2_clear(u_boot_console):
87     """Execute a TPM2_Clear command.
88
89     Ask the TPM to reset entirely its internal state (including internal
90     configuration, passwords, counters and DAM parameters). This is half of the
91     TAKE_OWNERSHIP command from TPMv1.
92
93     Use the LOCKOUT hierarchy for this. The LOCKOUT/PLATFORM hierarchies must
94     not have a password set, otherwise this test will fail. ENDORSEMENT and
95     PLATFORM hierarchies are also available.
96     """
97
98     u_boot_console.run_command('tpm clear TPM2_RH_LOCKOUT')
99     output = u_boot_console.run_command('echo $?')
100     assert output.endswith('0')
101
102     u_boot_console.run_command('tpm clear TPM2_RH_PLATFORM')
103     output = u_boot_console.run_command('echo $?')
104     assert output.endswith('0')
105
106 @pytest.mark.buildconfigspec('cmd_tpm_v2')
107 def test_tpm2_change_auth(u_boot_console):
108     """Execute a TPM2_HierarchyChangeAuth command.
109
110     Ask the TPM to change the owner, ie. set a new password: 'unicorn'
111
112     Use the LOCKOUT hierarchy for this. ENDORSEMENT and PLATFORM hierarchies are
113     also available.
114     """
115
116     force_init(u_boot_console)
117
118     u_boot_console.run_command('tpm change_auth TPM2_RH_LOCKOUT unicorn')
119     output = u_boot_console.run_command('echo $?')
120     assert output.endswith('0')
121
122     u_boot_console.run_command('tpm clear TPM2_RH_LOCKOUT unicorn')
123     output = u_boot_console.run_command('echo $?')
124     u_boot_console.run_command('tpm clear TPM2_RH_PLATFORM')
125     assert output.endswith('0')
126
127 @pytest.mark.buildconfigspec('cmd_tpm_v2')
128 def test_tpm2_get_capability(u_boot_console):
129     """Execute a TPM_GetCapability command.
130
131     Display one capability. In our test case, let's display the default DAM
132     lockout counter that should be 0 since the CLEAR:
133     - TPM_CAP_TPM_PROPERTIES = 0x6
134     - TPM_PT_LOCKOUT_COUNTER (1st parameter) = PTR_VAR + 14
135
136     There is no expected default values because it would depend on the chip
137     used. We can still save them in order to check they have changed later.
138     """
139
140     force_init(u_boot_console)
141     ram = u_boot_utils.find_ram_base(u_boot_console)
142
143     read_cap = u_boot_console.run_command('tpm get_capability 0x6 0x20e 0x200 1') #0x%x 1' % ram)
144     output = u_boot_console.run_command('echo $?')
145     assert output.endswith('0')
146     assert 'Property 0x0000020e: 0x00000000' in read_cap
147
148 @pytest.mark.buildconfigspec('cmd_tpm_v2')
149 def test_tpm2_dam_parameters(u_boot_console):
150     """Execute a TPM2_DictionaryAttackParameters command.
151
152     Change Dictionary Attack Mitigation (DAM) parameters. Ask the TPM to change:
153     - Max number of failed authentication before lockout: 3
154     - Time before the failure counter is automatically decremented: 10 sec
155     - Time after a lockout failure before it can be attempted again: 0 sec
156
157     For an unknown reason, the DAM parameters must be changed before changing
158     the authentication, otherwise the lockout will be engaged after the first
159     failed authentication attempt.
160     """
161
162     force_init(u_boot_console)
163     ram = u_boot_utils.find_ram_base(u_boot_console)
164
165     # Set the DAM parameters to known values
166     u_boot_console.run_command('tpm dam_parameters 3 10 0')
167     output = u_boot_console.run_command('echo $?')
168     assert output.endswith('0')
169
170     # Check the values have been saved
171     read_cap = u_boot_console.run_command('tpm get_capability 0x6 0x20f 0x%x 3' % ram)
172     output = u_boot_console.run_command('echo $?')
173     assert output.endswith('0')
174     assert 'Property 0x0000020f: 0x00000003' in read_cap
175     assert 'Property 0x00000210: 0x0000000a' in read_cap
176     assert 'Property 0x00000211: 0x00000000' in read_cap
177
178 @pytest.mark.buildconfigspec('cmd_tpm_v2')
179 def test_tpm2_pcr_read(u_boot_console):
180     """Execute a TPM2_PCR_Read command.
181
182     Perform a PCR read of the 0th PCR. Must be zero.
183     """
184
185     force_init(u_boot_console)
186     ram = u_boot_utils.find_ram_base(u_boot_console) + 1024
187
188     read_pcr = u_boot_console.run_command('tpm pcr_read 0 0x%x' % ram)
189     output = u_boot_console.run_command('echo $?')
190     assert output.endswith('0')
191
192     # Save the number of PCR updates
193     str = re.findall(r'\d+ known updates', read_pcr)[0]
194     global updates
195     updates = int(re.findall(r'\d+', str)[0])
196
197     # Check the output value
198     assert 'PCR #0 content' in read_pcr
199     assert '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' in read_pcr
200
201 @pytest.mark.buildconfigspec('cmd_tpm_v2')
202 def test_tpm2_pcr_extend(u_boot_console):
203     """Execute a TPM2_PCR_Extend command.
204
205     Perform a PCR extension with a known hash in memory (zeroed since the board
206     must have been rebooted).
207
208     No authentication mechanism is used here, not protecting against packet
209     replay, yet.
210     """
211
212     force_init(u_boot_console)
213     ram = u_boot_utils.find_ram_base(u_boot_console) + 1024
214
215     u_boot_console.run_command('tpm pcr_extend 0 0x%x' % ram)
216     output = u_boot_console.run_command('echo $?')
217     assert output.endswith('0')
218
219     read_pcr = u_boot_console.run_command('tpm pcr_read 0 0x%x' % ram)
220     output = u_boot_console.run_command('echo $?')
221     assert output.endswith('0')
222     assert 'f5 a5 fd 42 d1 6a 20 30 27 98 ef 6e d3 09 97 9b' in read_pcr
223     assert '43 00 3d 23 20 d9 f0 e8 ea 98 31 a9 27 59 fb 4b' in read_pcr
224
225     str = re.findall(r'\d+ known updates', read_pcr)[0]
226     new_updates = int(re.findall(r'\d+', str)[0])
227     assert (updates + 1) == new_updates
228
229 @pytest.mark.buildconfigspec('cmd_tpm_v2')
230 def test_tpm2_cleanup(u_boot_console):
231     """Ensure the TPM is cleared from password or test related configuration."""
232
233     force_init(u_boot_console, True)