blob: e7c15fa51dd397a5f08250b3f3044deddcf9495e [file] [log] [blame]
# Copyright (c) 2021 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.
"""Utilities to interact with the TPM on a CrOS device."""
import logging
import re
import common
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
CRYPTOHOME_CMD = '/usr/sbin/cryptohome'
UNAVAILABLE_ACTION = 'Unknown action or no action given.'
class ChromiumOSError(error.TestError):
"""Generic error for ChromiumOS-specific exceptions."""
pass
def get_tpm_status():
"""Get the TPM status.
Returns:
A TPM status dictionary, for example:
{ 'Enabled': True,
'Owned': True,
'Being Owned': False,
'Ready': True,
'Password': ''
}
"""
out = __run_cmd(CRYPTOHOME_CMD + ' --action=tpm_status')
status = {}
for field in ['Enabled', 'Owned', 'Being Owned', 'Ready']:
match = re.search('TPM %s: (true|false)' % field, out)
if not match:
raise ChromiumOSError('Invalid TPM status: "%s".' % out)
status[field] = match.group(1) == 'true'
match = re.search('TPM Password: (\w*)', out)
status['Password'] = ''
if match:
status['Password'] = match.group(1)
return status
def get_tpm_more_status():
"""Get more of the TPM status.
Returns:
A TPM more status dictionary, for example:
{ 'dictionary_attack_lockout_in_effect': False,
'attestation_prepared': False,
'boot_lockbox_finalized': False,
'enabled': True,
'owned': True,
'owner_password': ''
'dictionary_attack_counter': 0,
'dictionary_attack_lockout_seconds_remaining': 0,
'dictionary_attack_threshold': 10,
'attestation_enrolled': False,
'initialized': True,
'verified_boot_measured': False,
'install_lockbox_finalized': True
}
An empty dictionary is returned if the command is not supported.
"""
status = {}
out = __run_cmd(CRYPTOHOME_CMD + ' --action=tpm_more_status | grep :')
if out.startswith(UNAVAILABLE_ACTION):
# --action=tpm_more_status only exists >= 41.
logging.info('Method not supported!')
return status
for line in out.splitlines():
items = line.strip().split(':')
if items[1].strip() == 'false':
value = False
elif items[1].strip() == 'true':
value = True
elif items[1].strip().isdigit():
value = int(items[1].strip())
else:
value = items[1].strip(' "')
status[items[0]] = value
return status
def __run_cmd(cmd):
"""Run a command on utils.system_output, and append '2>&1'."""
return utils.system_output(cmd + ' 2>&1', retain_output=True,
ignore_status=True).strip()