xref: /openbmc/u-boot/test/py/tests/test_tpm2.py (revision d87434a2baf1db6d2a2582e3204c27fa5785935e)
12dffe1c6SMiquel Raynal# SPDX-License-Identifier: GPL-2.0+
22dffe1c6SMiquel Raynal# Copyright (c) 2018, Bootlin
32dffe1c6SMiquel Raynal# Author: Miquel Raynal <miquel.raynal@bootlin.com>
42dffe1c6SMiquel Raynal
52dffe1c6SMiquel Raynalimport os.path
62dffe1c6SMiquel Raynalimport pytest
72dffe1c6SMiquel Raynalimport u_boot_utils
82dffe1c6SMiquel Raynalimport re
92dffe1c6SMiquel Raynalimport time
102dffe1c6SMiquel Raynal
112dffe1c6SMiquel Raynal"""
122dffe1c6SMiquel RaynalTest the TPMv2.x related commands. You must have a working hardware setup in
132dffe1c6SMiquel Raynalorder to do these tests.
142dffe1c6SMiquel Raynal
152dffe1c6SMiquel RaynalNotes:
162dffe1c6SMiquel Raynal* These tests will prove the password mechanism. The TPM chip must be cleared of
172dffe1c6SMiquel Raynalany password.
182dffe1c6SMiquel Raynal* Commands like pcr_setauthpolicy and pcr_resetauthpolicy are not implemented
192dffe1c6SMiquel Raynalhere because they would fail the tests in most cases (TPMs do not implement them
202dffe1c6SMiquel Raynaland return an error).
212dffe1c6SMiquel Raynal"""
222dffe1c6SMiquel Raynal
232dffe1c6SMiquel Raynalupdates = 0
242dffe1c6SMiquel Raynal
252dffe1c6SMiquel Raynaldef force_init(u_boot_console, force=False):
262dffe1c6SMiquel Raynal    """When a test fails, U-Boot is reset. Because TPM stack must be initialized
272dffe1c6SMiquel Raynal    after each reboot, we must ensure these lines are always executed before
282dffe1c6SMiquel Raynal    trying any command or they will fail with no reason. Executing 'tpm init'
292dffe1c6SMiquel Raynal    twice will spawn an error used to detect that the TPM was not reset and no
302dffe1c6SMiquel Raynal    initialization code should be run.
312dffe1c6SMiquel Raynal    """
32*d87434a2SMiquel Raynal    output = u_boot_console.run_command('tpm2 init')
332dffe1c6SMiquel Raynal    if force or not 'Error' in output:
342dffe1c6SMiquel Raynal        u_boot_console.run_command('echo --- start of init ---')
35*d87434a2SMiquel Raynal        u_boot_console.run_command('tpm2 startup TPM2_SU_CLEAR')
36*d87434a2SMiquel Raynal        u_boot_console.run_command('tpm2 self_test full')
37*d87434a2SMiquel Raynal        u_boot_console.run_command('tpm2 clear TPM2_RH_LOCKOUT')
382dffe1c6SMiquel Raynal        output = u_boot_console.run_command('echo $?')
392dffe1c6SMiquel Raynal        if not output.endswith('0'):
40*d87434a2SMiquel Raynal            u_boot_console.run_command('tpm2 clear TPM2_RH_PLATFORM')
412dffe1c6SMiquel Raynal        u_boot_console.run_command('echo --- end of init ---')
422dffe1c6SMiquel Raynal
432dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
442dffe1c6SMiquel Raynaldef test_tpm2_init(u_boot_console):
452dffe1c6SMiquel Raynal    """Init the software stack to use TPMv2 commands."""
462dffe1c6SMiquel Raynal
47*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 init')
482dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
492dffe1c6SMiquel Raynal    assert output.endswith('0')
502dffe1c6SMiquel Raynal
512dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
522dffe1c6SMiquel Raynaldef test_tpm2_startup(u_boot_console):
532dffe1c6SMiquel Raynal    """Execute a TPM2_Startup command.
542dffe1c6SMiquel Raynal
552dffe1c6SMiquel Raynal    Initiate the TPM internal state machine.
562dffe1c6SMiquel Raynal    """
572dffe1c6SMiquel Raynal
58*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 startup TPM2_SU_CLEAR')
592dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
602dffe1c6SMiquel Raynal    assert output.endswith('0')
612dffe1c6SMiquel Raynal
622dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
632dffe1c6SMiquel Raynaldef test_tpm2_self_test_full(u_boot_console):
642dffe1c6SMiquel Raynal    """Execute a TPM2_SelfTest (full) command.
652dffe1c6SMiquel Raynal
662dffe1c6SMiquel Raynal    Ask the TPM to perform all self tests to also enable full capabilities.
672dffe1c6SMiquel Raynal    """
682dffe1c6SMiquel Raynal
69*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 self_test full')
702dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
712dffe1c6SMiquel Raynal    assert output.endswith('0')
722dffe1c6SMiquel Raynal
732dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
742dffe1c6SMiquel Raynaldef test_tpm2_continue_self_test(u_boot_console):
752dffe1c6SMiquel Raynal    """Execute a TPM2_SelfTest (continued) command.
762dffe1c6SMiquel Raynal
772dffe1c6SMiquel Raynal    Ask the TPM to finish its self tests (alternative to the full test) in order
782dffe1c6SMiquel Raynal    to enter a fully operational state.
792dffe1c6SMiquel Raynal    """
802dffe1c6SMiquel Raynal
81*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 self_test continue')
822dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
832dffe1c6SMiquel Raynal    assert output.endswith('0')
842dffe1c6SMiquel Raynal
852dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
862dffe1c6SMiquel Raynaldef test_tpm2_clear(u_boot_console):
872dffe1c6SMiquel Raynal    """Execute a TPM2_Clear command.
882dffe1c6SMiquel Raynal
892dffe1c6SMiquel Raynal    Ask the TPM to reset entirely its internal state (including internal
902dffe1c6SMiquel Raynal    configuration, passwords, counters and DAM parameters). This is half of the
912dffe1c6SMiquel Raynal    TAKE_OWNERSHIP command from TPMv1.
922dffe1c6SMiquel Raynal
932dffe1c6SMiquel Raynal    Use the LOCKOUT hierarchy for this. The LOCKOUT/PLATFORM hierarchies must
942dffe1c6SMiquel Raynal    not have a password set, otherwise this test will fail. ENDORSEMENT and
952dffe1c6SMiquel Raynal    PLATFORM hierarchies are also available.
962dffe1c6SMiquel Raynal    """
972dffe1c6SMiquel Raynal
98*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 clear TPM2_RH_LOCKOUT')
992dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
1002dffe1c6SMiquel Raynal    assert output.endswith('0')
1012dffe1c6SMiquel Raynal
102*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 clear TPM2_RH_PLATFORM')
1032dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
1042dffe1c6SMiquel Raynal    assert output.endswith('0')
1052dffe1c6SMiquel Raynal
1062dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
1072dffe1c6SMiquel Raynaldef test_tpm2_change_auth(u_boot_console):
1082dffe1c6SMiquel Raynal    """Execute a TPM2_HierarchyChangeAuth command.
1092dffe1c6SMiquel Raynal
1102dffe1c6SMiquel Raynal    Ask the TPM to change the owner, ie. set a new password: 'unicorn'
1112dffe1c6SMiquel Raynal
1122dffe1c6SMiquel Raynal    Use the LOCKOUT hierarchy for this. ENDORSEMENT and PLATFORM hierarchies are
1132dffe1c6SMiquel Raynal    also available.
1142dffe1c6SMiquel Raynal    """
1152dffe1c6SMiquel Raynal
1162dffe1c6SMiquel Raynal    force_init(u_boot_console)
1172dffe1c6SMiquel Raynal
118*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 change_auth TPM2_RH_LOCKOUT unicorn')
1192dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
1202dffe1c6SMiquel Raynal    assert output.endswith('0')
1212dffe1c6SMiquel Raynal
122*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 clear TPM2_RH_LOCKOUT unicorn')
1232dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
124*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 clear TPM2_RH_PLATFORM')
1252dffe1c6SMiquel Raynal    assert output.endswith('0')
1262dffe1c6SMiquel Raynal
1272dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
1282dffe1c6SMiquel Raynaldef test_tpm2_get_capability(u_boot_console):
1292dffe1c6SMiquel Raynal    """Execute a TPM_GetCapability command.
1302dffe1c6SMiquel Raynal
1312dffe1c6SMiquel Raynal    Display one capability. In our test case, let's display the default DAM
1322dffe1c6SMiquel Raynal    lockout counter that should be 0 since the CLEAR:
1332dffe1c6SMiquel Raynal    - TPM_CAP_TPM_PROPERTIES = 0x6
1342dffe1c6SMiquel Raynal    - TPM_PT_LOCKOUT_COUNTER (1st parameter) = PTR_VAR + 14
1352dffe1c6SMiquel Raynal
1362dffe1c6SMiquel Raynal    There is no expected default values because it would depend on the chip
1372dffe1c6SMiquel Raynal    used. We can still save them in order to check they have changed later.
1382dffe1c6SMiquel Raynal    """
1392dffe1c6SMiquel Raynal
1402dffe1c6SMiquel Raynal    force_init(u_boot_console)
1412dffe1c6SMiquel Raynal    ram = u_boot_utils.find_ram_base(u_boot_console)
1422dffe1c6SMiquel Raynal
143*d87434a2SMiquel Raynal    read_cap = u_boot_console.run_command('tpm2 get_capability 0x6 0x20e 0x200 1') #0x%x 1' % ram)
1442dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
1452dffe1c6SMiquel Raynal    assert output.endswith('0')
1462dffe1c6SMiquel Raynal    assert 'Property 0x0000020e: 0x00000000' in read_cap
1472dffe1c6SMiquel Raynal
1482dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
1492dffe1c6SMiquel Raynaldef test_tpm2_dam_parameters(u_boot_console):
1502dffe1c6SMiquel Raynal    """Execute a TPM2_DictionaryAttackParameters command.
1512dffe1c6SMiquel Raynal
1522dffe1c6SMiquel Raynal    Change Dictionary Attack Mitigation (DAM) parameters. Ask the TPM to change:
1532dffe1c6SMiquel Raynal    - Max number of failed authentication before lockout: 3
1542dffe1c6SMiquel Raynal    - Time before the failure counter is automatically decremented: 10 sec
1552dffe1c6SMiquel Raynal    - Time after a lockout failure before it can be attempted again: 0 sec
1562dffe1c6SMiquel Raynal
1572dffe1c6SMiquel Raynal    For an unknown reason, the DAM parameters must be changed before changing
1582dffe1c6SMiquel Raynal    the authentication, otherwise the lockout will be engaged after the first
1592dffe1c6SMiquel Raynal    failed authentication attempt.
1602dffe1c6SMiquel Raynal    """
1612dffe1c6SMiquel Raynal
1622dffe1c6SMiquel Raynal    force_init(u_boot_console)
1632dffe1c6SMiquel Raynal    ram = u_boot_utils.find_ram_base(u_boot_console)
1642dffe1c6SMiquel Raynal
1652dffe1c6SMiquel Raynal    # Set the DAM parameters to known values
166*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 dam_parameters 3 10 0')
1672dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
1682dffe1c6SMiquel Raynal    assert output.endswith('0')
1692dffe1c6SMiquel Raynal
1702dffe1c6SMiquel Raynal    # Check the values have been saved
171*d87434a2SMiquel Raynal    read_cap = u_boot_console.run_command('tpm2 get_capability 0x6 0x20f 0x%x 3' % ram)
1722dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
1732dffe1c6SMiquel Raynal    assert output.endswith('0')
1742dffe1c6SMiquel Raynal    assert 'Property 0x0000020f: 0x00000003' in read_cap
1752dffe1c6SMiquel Raynal    assert 'Property 0x00000210: 0x0000000a' in read_cap
1762dffe1c6SMiquel Raynal    assert 'Property 0x00000211: 0x00000000' in read_cap
1772dffe1c6SMiquel Raynal
1782dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
1792dffe1c6SMiquel Raynaldef test_tpm2_pcr_read(u_boot_console):
1802dffe1c6SMiquel Raynal    """Execute a TPM2_PCR_Read command.
1812dffe1c6SMiquel Raynal
1822dffe1c6SMiquel Raynal    Perform a PCR read of the 0th PCR. Must be zero.
1832dffe1c6SMiquel Raynal    """
1842dffe1c6SMiquel Raynal
1852dffe1c6SMiquel Raynal    force_init(u_boot_console)
186f4eef40bSQuentin Schulz    ram = u_boot_utils.find_ram_base(u_boot_console)
1872dffe1c6SMiquel Raynal
188*d87434a2SMiquel Raynal    read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % ram)
1892dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
1902dffe1c6SMiquel Raynal    assert output.endswith('0')
1912dffe1c6SMiquel Raynal
1922dffe1c6SMiquel Raynal    # Save the number of PCR updates
1932dffe1c6SMiquel Raynal    str = re.findall(r'\d+ known updates', read_pcr)[0]
1942dffe1c6SMiquel Raynal    global updates
1952dffe1c6SMiquel Raynal    updates = int(re.findall(r'\d+', str)[0])
1962dffe1c6SMiquel Raynal
1972dffe1c6SMiquel Raynal    # Check the output value
1982dffe1c6SMiquel Raynal    assert 'PCR #0 content' in read_pcr
1992dffe1c6SMiquel Raynal    assert '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' in read_pcr
2002dffe1c6SMiquel Raynal
2012dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
2022dffe1c6SMiquel Raynaldef test_tpm2_pcr_extend(u_boot_console):
2032dffe1c6SMiquel Raynal    """Execute a TPM2_PCR_Extend command.
2042dffe1c6SMiquel Raynal
2052dffe1c6SMiquel Raynal    Perform a PCR extension with a known hash in memory (zeroed since the board
2062dffe1c6SMiquel Raynal    must have been rebooted).
2072dffe1c6SMiquel Raynal
2082dffe1c6SMiquel Raynal    No authentication mechanism is used here, not protecting against packet
2092dffe1c6SMiquel Raynal    replay, yet.
2102dffe1c6SMiquel Raynal    """
2112dffe1c6SMiquel Raynal
2122dffe1c6SMiquel Raynal    force_init(u_boot_console)
213f4eef40bSQuentin Schulz    ram = u_boot_utils.find_ram_base(u_boot_console)
2142dffe1c6SMiquel Raynal
215*d87434a2SMiquel Raynal    u_boot_console.run_command('tpm2 pcr_extend 0 0x%x' % ram)
2162dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
2172dffe1c6SMiquel Raynal    assert output.endswith('0')
2182dffe1c6SMiquel Raynal
219*d87434a2SMiquel Raynal    read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % ram)
2202dffe1c6SMiquel Raynal    output = u_boot_console.run_command('echo $?')
2212dffe1c6SMiquel Raynal    assert output.endswith('0')
2222dffe1c6SMiquel Raynal    assert 'f5 a5 fd 42 d1 6a 20 30 27 98 ef 6e d3 09 97 9b' in read_pcr
2232dffe1c6SMiquel Raynal    assert '43 00 3d 23 20 d9 f0 e8 ea 98 31 a9 27 59 fb 4b' in read_pcr
2242dffe1c6SMiquel Raynal
2252dffe1c6SMiquel Raynal    str = re.findall(r'\d+ known updates', read_pcr)[0]
2262dffe1c6SMiquel Raynal    new_updates = int(re.findall(r'\d+', str)[0])
2272dffe1c6SMiquel Raynal    assert (updates + 1) == new_updates
2282dffe1c6SMiquel Raynal
2292dffe1c6SMiquel Raynal@pytest.mark.buildconfigspec('cmd_tpm_v2')
2302dffe1c6SMiquel Raynaldef test_tpm2_cleanup(u_boot_console):
2312dffe1c6SMiquel Raynal    """Ensure the TPM is cleared from password or test related configuration."""
2322dffe1c6SMiquel Raynal
2332dffe1c6SMiquel Raynal    force_init(u_boot_console, True)
234