1# Copyright 2014 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging, os 6import time 7 8from autotest_lib.client.common_lib import error 9 10 11_PASSWD_FILE = '/var/tmp/tpm_password' 12_RM_DIRS = ('/home/.shadow/* ' + 13 '/home/chronos/.oobe_completed ' + 14 '/home/chronos/Local\ State ' + 15 '/var/cache/app_pack ' + 16 '/var/cache/shill/default.profile ' + 17 '/var/lib/tpm ' + 18 '/var/lib/whitelist/* ') 19 20 21class NoTPMPasswordException(Exception): 22 """No TPM Password could be found.""" 23 pass 24 25 26def TPMStatus(client): 27 """Returns a dictionary with TPM status. 28 29 @param client: client object to run commands on. 30 """ 31 out = client.run('cryptohome --action=tpm_status').stdout.strip() 32 out = out.replace('TPM ', '') 33 lines = out.split('\n') 34 status = {} 35 for item in lines: 36 item = item.split(':') 37 if not item[0]: 38 continue 39 if len(item) == 1: 40 item.append('') 41 item = map(lambda x : x.strip(), item) 42 item[1] = True if item[1] == 'true' else item[1] 43 item[1] = False if item[1] == 'false' else item[1] 44 status[item[0]] = item[1] 45 return status 46 47 48def IsTPMAvailable(client): 49 """Returns True if the TPM is unowned and enabled. 50 51 @param client: client object to run commands on. 52 """ 53 status = TPMStatus(client) 54 return status['Enabled'] and not status['Owned'] 55 56 57def ClearTPMServer(client, out_dir): 58 """Clears the TPM and reboots from a server-side autotest. 59 60 @param client: client object to run commands on. 61 @param out_dir: temporary directory to store the retrieved password file. 62 """ 63 if IsTPMAvailable(client): 64 logging.debug('TPM is not owned') 65 return 66 67 client.run('stop ui') 68 try: 69 password = TPMStatus(client)['Password'] 70 if not password: 71 try: 72 client.get_file(_PASSWD_FILE, out_dir) 73 except error.AutoservRunError: 74 raise NoTPMPasswordException( 75 'TPM Password file %s doesn\'t exist, falling back on ' 76 'clear_tpm_owner_request to clear the TPM. You may ' 77 'need to have the firmware clear the TPM, for instance ' 78 'by toggling the dev switch.' % _PASSWD_FILE) 79 with open(os.path.join(out_dir, 80 os.path.basename(_PASSWD_FILE))) as f: 81 password = f.read().rstrip() 82 if not password: 83 raise NoTPMPasswordException( 84 'TPM Password file %s empty, falling back on ' 85 'clear_tpm_owner_request to clear the TPM. You may need to ' 86 'have the firmware clear the TPM, for instance by toggling ' 87 'the dev switch.' % _PASSWD_FILE) 88 89 res = client.run('tpm_clear --pass ' + password).stdout.strip() 90 logging.warn(repr(res)) 91 except NoTPMPasswordException as e: 92 logging.warn(e.args[0]) 93 client.run('crossystem clear_tpm_owner_request=1') 94 95 CleanupAndReboot(client) 96 97 98def ClearTPMOwnerRequest(client, wait_for_ready=False, timeout=60): 99 """Clears the TPM using crossystem command. 100 101 @param client: client object to run commands on. 102 @param wait_for_ready: wait until the TPM status is ready 103 @param timeout: number of seconds to wait for the TPM to become ready. 104 """ 105 if not client.run('crossystem clear_tpm_owner_request=1', 106 ignore_status=True).exit_status == 0: 107 raise error.TestFail('Unable to clear TPM.') 108 109 CleanupAndReboot(client) 110 111 if wait_for_ready: 112 status = '' 113 end_time = time.time() + timeout 114 # Wait for cryptohome to send a successful reply. 115 while 'GetTpmStatus success' not in status and time.time() < end_time: 116 status = client.run('cryptohome --action=tpm_more_status', 117 ignore_status=True).stdout.strip() 118 logging.debug(status) 119 time.sleep(1) 120 121 122def CleanupAndReboot(client): 123 """Cleanup and reboot the device. 124 125 @param client: client object to run commands on. 126 """ 127 client.run('sudo rm -rf ' + _RM_DIRS, ignore_status=True) 128 client.run('sync', ignore_status=True) 129 client.reboot() 130