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