blob: 63990e99f1897c56651ae950cc74f43abfadf0ad [file] [log] [blame]
# Copyright 2018 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from hashlib import sha256
import logging
from pprint import pformat
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib.cros import pinweaver_client
from autotest_lib.server import test
def compute_empty_tree_auxilary_hashes(bits_per_level=2, height=6):
"""Returns a binary string representation of the auxilary digests of an
empty path in a Merkle tree with the specified parameters.
"""
num_siblings = 2 ^ bits_per_level - 1
child = '\0' * 32
result = ''
for _ in range(height):
part = child * num_siblings
child = sha256(part + child).digest()
result += part
return result
class firmware_Cr50PinWeaverServer(test.test):
"""Tests the PinWeaver functionality on Cr50 using pinweaver_client through
trunksd.
"""
version = 1
RESULT_CODE_SUCCESS = 'EC_SUCCESS'
RESULT_CODE_AUTH_FAILED = 'PW_ERR_LOWENT_AUTH_FAILED'
RESULT_CODE_RATE_LIMITED = 'PW_ERR_RATE_LIMIT_REACHED'
def run_once(self, host):
"""Runs the firmware_Cr50PinWeaverServer test.
This test is made up of the pinweaver_client self test, and a test that
checks that PinWeaver works as expected across device reboots.
"""
# Run "pinweaver_client selftest".
try:
if not pinweaver_client.SelfTest(host):
raise error.TestFail('Failed SelfTest: %s' %
self.__class__.__name__)
except pinweaver_client.PinWeaverNotAvailableError:
logging.info('PinWeaver not supported!')
raise error.TestNAError('PinWeaver is not available')
# Check PinWeaver logic across reboots including the reboot counter.
# Insert an entry.
#
# Label 0 is guaranteed to be empty because the self test above resets
# the tree and removes the leaf it adds.
label = 0
h_aux = compute_empty_tree_auxilary_hashes().encode('hex')
le_secret = sha256('1234').hexdigest()
he_secret = sha256('ag3#l4Z9').hexdigest()
reset_secret = sha256('W8oE@Ja2mq.R1').hexdigest()
delay_schedule = '5 %d' % 0x00ffffffff
result = pinweaver_client.InsertLeaf(host, label, h_aux, le_secret,
he_secret, reset_secret,
delay_schedule)
logging.info('Insert: %s', pformat(result))
if (result['result_code']['name'] !=
firmware_Cr50PinWeaverServer.RESULT_CODE_SUCCESS):
raise error.TestFail('Failed InsertLeaf: %s' %
self.__class__.__name__)
cred_metadata = result['cred_metadata']
# Exhaust the allowed number of attempts.
for i in range(6):
result = pinweaver_client.TryAuth(host, h_aux, '0' * 64,
cred_metadata)
if result['cred_metadata']:
cred_metadata = result['cred_metadata']
logging.info('TryAuth: %s', pformat(result))
if ((i <= 4 and result['result_code']['name'] !=
firmware_Cr50PinWeaverServer.RESULT_CODE_AUTH_FAILED) or
(i > 4 and result['result_code']['name'] !=
firmware_Cr50PinWeaverServer.RESULT_CODE_RATE_LIMITED)):
raise error.TestFail('Failed TryAuth: %s' %
self.__class__.__name__)
if result['seconds_to_wait'] == 0:
raise error.TestFail('Failed TryAuth: %s' %
self.__class__.__name__)
# Reboot the device. This calls TPM_startup() which reloads the Merkle
# tree from NVRAM. Note that this doesn't reset the timer on Cr50, so
# restart_count doesn't increment.
host.reboot()
# Verify that the lockout is still enforced.
result = pinweaver_client.TryAuth(host, h_aux, le_secret, cred_metadata)
logging.info('TryAuth: %s', pformat(result))
if (result['result_code']['name'] !=
firmware_Cr50PinWeaverServer.RESULT_CODE_RATE_LIMITED):
raise error.TestFail('Failed TryAuth: %s' %
self.__class__.__name__)
if result['seconds_to_wait'] == 0:
raise error.TestFail('Failed TryAuth: %s' %
self.__class__.__name__)
# Perform a reset.
result = pinweaver_client.ResetAuth(host, h_aux, reset_secret,
cred_metadata)
if (result['result_code']['name'] !=
firmware_Cr50PinWeaverServer.RESULT_CODE_SUCCESS):
raise error.TestFail('Failed ResetAuth: %s' %
self.__class__.__name__)
cred_metadata = result['cred_metadata']
logging.info('ResetAuth: %s', pformat(result))
# Verify that using a PIN would work.
result = pinweaver_client.TryAuth(host, h_aux, le_secret, cred_metadata)
mac = result['mac']
logging.info('TryAuth: %s', pformat(result))
if (result['result_code']['name'] !=
firmware_Cr50PinWeaverServer.RESULT_CODE_SUCCESS):
raise error.TestFail('Failed TryAuth: %s' %
self.__class__.__name__)
# Remove the leaf.
result = pinweaver_client.RemoveLeaf(host, label, h_aux, mac)
logging.info('RemoveLeaf: %s', pformat(result))
if (result['result_code']['name'] !=
firmware_Cr50PinWeaverServer.RESULT_CODE_SUCCESS):
raise error.TestFail('Failed RemoveLeaf: %s' %
self.__class__.__name__)