1# Use of this source code is governed by a BSD-style license that can be 2# found in the LICENSE file. 3 4import hashlib 5 6from autotest_lib.client.common_lib import error 7from autotest_lib.client.common_lib.cros import g2f_utils 8from autotest_lib.client.common_lib.cros import tpm_utils 9from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 10 11U2F_AUTH_ENFORCE=3 12 13class firmware_Cr50U2fPowerwash(FirmwareTest): 14 """ 15 A test that runs confidence checks for U2F register and authenticate 16 functions, and checks that key handles are invalidated after TPM clear. 17 """ 18 version = 1 19 20 TEST_CHALLENGE_DIGEST = hashlib.sha256(b'test_challenge').hexdigest() 21 TEST_APPLICATION_DIGEST = hashlib.sha256(b'test_application').hexdigest() 22 23 def _safe_power_short_press(self): 24 """Stop powerd before pressing the power button.""" 25 # Validating U2F requires pressing the power button. If those power button 26 # presses power off the AP, stop powerd before the test to ignore them. 27 if self.faft_config.ec_forwards_short_pp_press: 28 self.stop_powerd() 29 self.servo.power_short_press() 30 31 def parse_g2ftool_output(self, stdout): 32 """Parses the key-value pairs returned by g2ftool 33 34 @param stdout: g2ftool output. 35 """ 36 return dict((k, v) 37 for k,v in (line.split('=') 38 for line in stdout.strip().split('\n'))) 39 40 def run_once(self, host=None): 41 """Tests that U2F keys are invalidated by powerwash.""" 42 self.client = host 43 44 # Start by clearing TPM to make sure the device is in a known state. 45 tpm_utils.ClearTPMOwnerRequest(self.client, wait_for_ready=True) 46 47 # u2fd reads files from the user's home dir, so we need to log in. 48 g2f_utils.ChromeOSLogin(self.client); 49 50 # U2fd does will not start normally if the device has not gone 51 # through OOBE. Force it to startup. 52 cr50_dev = g2f_utils.StartU2fd(self.client) 53 54 # Register requires physical presence. 55 self._safe_power_short_press() 56 57 # Register to create a new key handle. 58 g2f_reg = g2f_utils.G2fRegister(self.client, cr50_dev, 59 self.TEST_CHALLENGE_DIGEST, 60 self.TEST_APPLICATION_DIGEST, 61 U2F_AUTH_ENFORCE) 62 63 # Check that we managed to register. 64 if not g2f_reg.exit_status == 0: 65 raise error.TestError('Register failed.') 66 67 # Extract newly created key handle. 68 key_handle = self.parse_g2ftool_output(g2f_reg.stdout)['key_handle'] 69 70 # Auth requires physical presence. 71 self._safe_power_short_press() 72 73 # Check that we can authenticate with the new key handle. 74 g2f_auth = g2f_utils.G2fAuth(self.client, cr50_dev, 75 self.TEST_CHALLENGE_DIGEST, 76 self.TEST_APPLICATION_DIGEST, key_handle, 77 U2F_AUTH_ENFORCE) 78 79 if not g2f_auth.exit_status == 0: 80 raise error.TestError('Authenticate failed.') 81 82 # Clear TPM. We should no longer be able to authenticate with the 83 # key handle after this. 84 tpm_utils.ClearTPMOwnerRequest(self.client, wait_for_ready=True) 85 86 # u2fd reads files from the user's home dir, so we need to log in. 87 g2f_utils.ChromeOSLogin(self.client) 88 89 # U2fd does will not start normally if the device has not gone 90 # through OOBE. Force it to startup. 91 cr50_dev = g2f_utils.StartU2fd(self.client) 92 93 # Check the key handle is no longer valid. 94 self._safe_power_short_press() 95 g2f_auth_clear = g2f_utils.G2fAuth(self.client, cr50_dev, 96 self.TEST_CHALLENGE_DIGEST, 97 self.TEST_APPLICATION_DIGEST, 98 key_handle, U2F_AUTH_ENFORCE) 99 100 if g2f_auth_clear.exit_status == 0: 101 raise error.TestError('Authenticate succeeded; should have failed') 102 103 104 def cleanup(self): 105 """Leave the device in a predictable state""" 106 g2f_utils.ChromeOSLogout(self.client) 107 108 super(firmware_Cr50U2fPowerwash, self).cleanup() 109