• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6import time
7
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.common_lib.cros import tpm_utils
10from autotest_lib.server import test, autotest
11from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
12
13
14class firmware_FWMPDisableCCD(FirmwareTest):
15    """A test that uses cryptohome to set the FWMP flags and verifies that
16    cr50 disables/enables console unlock."""
17    version = 1
18
19    FWMP_DEV_DISABLE_CCD_UNLOCK = (1 << 6)
20
21
22    def initialize(self, host, cmdline_args):
23        """Initialize servo check if cr50 exists"""
24        super(firmware_FWMPDisableCCD, self).initialize(host, cmdline_args)
25
26        self.host = host
27        self.test_cr50_unlock = hasattr(self, "cr50")
28
29        if self.test_cr50_unlock:
30            rv = self.cr50.send_command_get_output('lock dummy', ['.+>'])
31            if 'Access Denied' in rv[0]:
32                self.test_cr50_unlock = False
33                logging.warning('Cr50 image is permanently locked.')
34
35
36    def cr50_try_unlock(self, fwmp_disabled_unlock):
37        """Run lock disable
38
39        The FWMP flags may disable ccd. If they do then we expect lock disable
40        to fail.
41
42        @param fwmp_disabled_unlock: True if the unlock process should fail
43        """
44        if fwmp_disabled_unlock:
45            if 'DBG' in self.servo.get('cr50_version'):
46                response = self.cr50.FWMP_LOCKED_DBG
47            else:
48                response = self.cr50.FWMP_LOCKED_PROD
49            self.cr50.send_command_get_output('lock disable', response)
50        else:
51            self.cr50.lock_disable()
52
53
54    def cr50_check_fwmp_flag(self, fwmp_disabled_unlock):
55        """Verify cr50 thinks the flag is set or cleared"""
56        response = 'Console unlock%s allowed' % (' not' if fwmp_disabled_unlock
57                                                 else '')
58        self.cr50.send_command_get_output('sysrst pulse', [response])
59
60
61    def cr50_check_lock_control(self, flags):
62        """Verify cr50 lock enable/disable works as intended based on flags.
63
64        If flags & self.FWMP_DEV_DISABLE_CCD_UNLOCK is true, lock disable should
65        fail.
66
67        This will only run during a test with access to the cr50  console
68
69        @param flags: A string with the FWMP settings.
70        """
71        if not self.test_cr50_unlock:
72            return
73
74        fwmp_disabled_unlock = (self.FWMP_DEV_DISABLE_CCD_UNLOCK &
75                               int(flags, 16))
76
77        logging.info('Flags are set to %s ccd unlock is %s', flags,
78                     'disabled' if fwmp_disabled_unlock else 'enabled')
79
80        # Verify that the ccd disable flag is still set
81        self.cr50_check_fwmp_flag(fwmp_disabled_unlock)
82
83        # Enable the lock
84        self.cr50.lock_enable()
85
86        # Try to disable it
87        self.cr50_try_unlock(fwmp_disabled_unlock)
88
89        # Verify that the ccd disable flag is still set
90        self.cr50_check_fwmp_flag(fwmp_disabled_unlock)
91
92
93    def check_fwmp(self, flags, clear_tpm_owner):
94        """Set the flags and verify ccd lock/unlock
95
96        Args:
97            flags: A string to used set the FWMP flags
98            clear_tpm_owner: True if the TPM owner needs to be cleared before
99                             setting the flags and verifying ccd lock/unlock
100        """
101        if clear_tpm_owner:
102            logging.info('Clearing TPM owner')
103            tpm_utils.ClearTPMOwnerRequest(self.host)
104
105        logging.info('setting flags to %s', flags)
106        autotest.Autotest(self.host).run_test('firmware_SetFWMP', flags=flags,
107                fwmp_cleared=clear_tpm_owner, check_client_result=True)
108
109        # Verify ccd lock/unlock with the current flags works as intended.
110        self.cr50_check_lock_control(flags)
111
112
113    def run_once(self):
114        self.check_fwmp('0xaa00', True)
115        # Verify that the flags can be changed on the same boot
116        self.check_fwmp('0xbb00', False)
117
118        # Verify setting FWMP_DEV_DISABLE_CCD_UNLOCK disables ccd
119        self.check_fwmp(hex(self.FWMP_DEV_DISABLE_CCD_UNLOCK), True)
120
121        # 0x41 is the flag setting when dev boot is disabled. Make sure that
122        # nothing unexpected happens.
123        self.check_fwmp('0x41', True)
124
125        # Clear the TPM owner and verify lock can still be enabled/disabled when
126        # the FWMP has not been created
127        tpm_utils.ClearTPMOwnerRequest(self.host)
128        self.cr50_check_lock_control('0')
129