114 lines
4.0 KiB
Python
114 lines
4.0 KiB
Python
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import hashlib
|
|
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.client.common_lib.cros import g2f_utils
|
|
from autotest_lib.client.common_lib.cros import tpm_utils
|
|
from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
|
|
|
|
U2F_AUTH_ENFORCE=3
|
|
|
|
class firmware_Cr50U2fPowerwash(FirmwareTest):
|
|
"""
|
|
A test that runs sanity checks for U2F register and authenticate functions,
|
|
and checks that key handles are invalidated after TPM clear.
|
|
"""
|
|
version = 1
|
|
|
|
def _safe_power_short_press(self):
|
|
"""Stop powerd before pressing the power button."""
|
|
# Validating U2F requires pressing the power button. If those power button
|
|
# presses power off the AP, stop powerd before the test to ignore them.
|
|
if self.faft_config.ec_forwards_short_pp_press:
|
|
self.stop_powerd()
|
|
self.servo.power_short_press()
|
|
|
|
def parse_g2ftool_output(self, stdout):
|
|
"""Parses the key-value pairs returned by g2ftool
|
|
|
|
@param stdout: g2ftool output.
|
|
"""
|
|
return dict((k, v)
|
|
for k,v in (line.split('=')
|
|
for line in stdout.strip().split('\n')))
|
|
|
|
def run_once(self, host=None):
|
|
"""Tests that U2F keys are invalidated by powerwash."""
|
|
self.client = host
|
|
|
|
# Start by clearing TPM to make sure the device is in a known state.
|
|
tpm_utils.ClearTPMOwnerRequest(self.client, wait_for_ready=True)
|
|
|
|
# u2fd reads files from the user's home dir, so we need to log in.
|
|
g2f_utils.ChromeOSLogin(self.client);
|
|
|
|
# U2fd does will not start normally if the device has not gone
|
|
# through OOBE. Force it to startup.
|
|
cr50_dev = g2f_utils.StartU2fd(self.client)
|
|
|
|
# Register requires physical presence.
|
|
self._safe_power_short_press()
|
|
|
|
# Register to create a new key handle.
|
|
g2f_reg = g2f_utils.G2fRegister(
|
|
self.client,
|
|
cr50_dev,
|
|
hashlib.sha256('test_challenge').hexdigest(),
|
|
hashlib.sha256('test_application').hexdigest(),
|
|
U2F_AUTH_ENFORCE)
|
|
|
|
# Sanity check that we managed to register.
|
|
if not g2f_reg.exit_status == 0:
|
|
raise error.TestError('Register failed.')
|
|
|
|
# Extract newly created key handle.
|
|
key_handle = self.parse_g2ftool_output(g2f_reg.stdout)['key_handle']
|
|
|
|
# Auth requires physical presence.
|
|
self._safe_power_short_press()
|
|
|
|
# Sanity check that we can authenticate with the new key handle.
|
|
g2f_auth = g2f_utils.G2fAuth(
|
|
self.client,
|
|
cr50_dev,
|
|
hashlib.sha256('test_challenge').hexdigest(),
|
|
hashlib.sha256('test_application').hexdigest(),
|
|
key_handle,
|
|
U2F_AUTH_ENFORCE)
|
|
|
|
if not g2f_auth.exit_status == 0:
|
|
raise error.TestError('Authenticate failed.')
|
|
|
|
# Clear TPM. We should no longer be able to authenticate with the
|
|
# key handle after this.
|
|
tpm_utils.ClearTPMOwnerRequest(self.client, wait_for_ready=True)
|
|
|
|
# u2fd reads files from the user's home dir, so we need to log in.
|
|
g2f_utils.ChromeOSLogin(self.client)
|
|
|
|
# U2fd does will not start normally if the device has not gone
|
|
# through OOBE. Force it to startup.
|
|
cr50_dev = g2f_utils.StartU2fd(self.client)
|
|
|
|
# Check the key handle is no longer valid.
|
|
self._safe_power_short_press()
|
|
g2f_auth_clear = g2f_utils.G2fAuth(
|
|
self.client,
|
|
cr50_dev,
|
|
hashlib.sha256('test_challenge').hexdigest(),
|
|
hashlib.sha256('test_application').hexdigest(),
|
|
key_handle,
|
|
U2F_AUTH_ENFORCE)
|
|
|
|
if g2f_auth_clear.exit_status == 0:
|
|
raise error.TestError('Authenticate succeeded; should have failed')
|
|
|
|
|
|
def cleanup(self):
|
|
"""Leave the device in a predictable state"""
|
|
g2f_utils.ChromeOSLogout(self.client)
|
|
|
|
super(firmware_Cr50U2fPowerwash, self).cleanup()
|