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