1# Copyright (c) 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 os
6
7from autotest_lib.client.bin import test, utils
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.cros import cryptohome
10
11
12class platform_BootLockbox(test.test):
13    """ Test basic boot-lockbox functionality."""
14    version = 1
15
16    def initialize(self):
17        test.test.initialize(self)
18        self.data_file = '/tmp/__lockbox_test'
19        open(self.data_file, mode='w').write('test_lockbox_data')
20
21    def cleanup(self):
22        self._remove_file(self.data_file)
23        self._remove_file(self.data_file + '.signature')
24        self._remove_file('/var/lib/boot-lockbox/boot_attributes.pb')
25        self._remove_file('/var/lib/boot-lockbox/boot_attributes.sig')
26        test.test.cleanup(self)
27
28    def _remove_file(self, filename):
29        try:
30            os.remove(filename)
31        except OSError:
32            # Ignore errors
33            pass
34
35    def _ensure_tpm_ready(self):
36        status = cryptohome.get_tpm_status()
37        if not status['Enabled']:
38            raise error.TestNAError('Test NA because there is no TPM.')
39        if not status['Owned']:
40            cryptohome.take_tpm_ownership()
41        status = cryptohome.get_tpm_status()
42        if not status['Ready']:
43            raise error.TestError('Failed to initialize TPM.')
44
45    def _sign_lockbox(self):
46        return utils.system(cryptohome.CRYPTOHOME_CMD +
47                            ' --action=sign_lockbox --file=' + self.data_file,
48                            ignore_status=True) == 0
49
50    def _verify_lockbox(self):
51        return utils.system(cryptohome.CRYPTOHOME_CMD +
52                            ' --action=verify_lockbox --file=' + self.data_file,
53                            ignore_status=True) == 0
54
55    def _finalize_lockbox(self):
56        utils.system(cryptohome.CRYPTOHOME_CMD + ' --action=finalize_lockbox')
57
58    def _get_boot_attribute(self):
59        return utils.system(cryptohome.CRYPTOHOME_CMD +
60                            ' --action=get_boot_attribute --name=test',
61                            ignore_status=True) == 0
62
63    def _set_boot_attribute(self):
64        utils.system(cryptohome.CRYPTOHOME_CMD +
65                     ' --action=set_boot_attribute --name=test --value=1234')
66
67    def _flush_and_sign_boot_attributes(self):
68        return utils.system(cryptohome.CRYPTOHOME_CMD +
69                            ' --action=flush_and_sign_boot_attributes',
70                            ignore_status=True) == 0
71
72    def run_once(self):
73        self._ensure_tpm_ready()
74        if not self._sign_lockbox():
75            # This will fire if you forget to reboot before running the test!
76            raise error.TestFail('Boot lockbox could not be signed.')
77
78        if cryptohome.get_login_status()['boot_lockbox_finalized']:
79            raise error.TestFail('Boot lockbox is already finalized.')
80
81        if not self._verify_lockbox():
82            raise error.TestFail('Boot lockbox could not be verified.')
83
84        # Setup a bad signature and make sure it doesn't verify.
85        open(self.data_file, mode='w').write('test_lockbox_data2')
86        if self._verify_lockbox():
87            raise error.TestFail('Boot lockbox verified bad data.')
88        open(self.data_file, mode='w').write('test_lockbox_data')
89
90        self._set_boot_attribute()
91
92        if self._get_boot_attribute():
93            raise error.TestFail('Boot attributes already have data.')
94
95        if not self._flush_and_sign_boot_attributes():
96            raise error.TestFail('Boot attributes could not sign.')
97
98        if not self._get_boot_attribute():
99            raise error.TestFail('Boot attribute was not available.')
100
101        # Check again to make sure nothing has tricked the finalize check.
102        if cryptohome.get_login_status()['boot_lockbox_finalized']:
103            raise error.TestFail('Boot lockbox prematurely finalized.')
104
105        # Finalize and make sure we can verify but not sign.
106        self._finalize_lockbox()
107
108        if not cryptohome.get_login_status()['boot_lockbox_finalized']:
109            raise error.TestFail('Boot lockbox finalize status did not change '
110                                 'after finalization.')
111
112        if self._flush_and_sign_boot_attributes():
113            raise error.TestFail('Boot attributes signed after finalization.')
114
115        if not self._verify_lockbox():
116            raise error.TestFail('Boot lockbox could not be verified after '
117                                 'finalization.')
118
119        if self._sign_lockbox():
120            raise error.TestFail('Boot lockbox signed after finalization.')
121