• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_FILES = ['/home/chronos/.oobe_completed',
13             '/home/chronos/Local\ State',
14             '/var/cache/shill/default.profile']
15_RM_DIRS = ['/home/.shadow/*',
16            '/var/lib/whitelist/*',
17            '/var/cache/app_pack',
18            '/var/lib/tpm']
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 ClearTPMIfOwned(client):
123    """Clear the TPM only if device is already owned.
124
125    @param client: client object to run commands on."""
126    tpm_status = TPMStatus(client)
127    logging.info('TPM status: %s', tpm_status)
128    if tpm_status['Owned']:
129        logging.info('Clearing TPM because this device is owned.')
130        ClearTPMOwnerRequest(client)
131
132
133def CleanupAndReboot(client):
134    """Cleanup and reboot the device.
135
136    @param client: client object to run commands on.
137    """
138    full_rm = 'sudo rm -rf ' + ' '.join(_RM_FILES + _RM_DIRS)
139    client.run(full_rm, ignore_status=True)
140    client.run('sync', ignore_status=True)
141    client.reboot()
142