1ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart# Use of this source code is governed by a BSD-style license that can be
3ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart# found in the LICENSE file.
4ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
5ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewartimport tempfile
6ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
7ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewartfrom autotest_lib.client.bin import utils
8088c75f64155b89255e9ebd324230f5c34eda74eKris Rambishfrom autotest_lib.client.common_lib import error
9088c75f64155b89255e9ebd324230f5c34eda74eKris Rambishfrom autotest_lib.client.cros import cryptohome
10ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
11ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewartclass TPMStore(object):
12ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    """Context enclosing the use of the TPM."""
13ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
14ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    CHAPS_CLIENT_COMMAND = 'chaps_client'
15ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    CONVERT_TYPE_RSA = 'rsa'
16ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    CONVERT_TYPE_X509 = 'x509'
17ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    CRYPTOHOME_ACTION_TAKE_OWNERSHIP = 'tpm_take_ownership'
18ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    CRYPTOHOME_ACTION_WAIT_OWNERSHIP = 'tpm_wait_ownership'
19ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    CRYPTOHOME_COMMAND = '/usr/sbin/cryptohome'
20ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    OPENSSL_COMMAND = 'openssl'
21ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    OUTPUT_TYPE_CERTIFICATE = 'cert'
22ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    OUTPUT_TYPE_PRIVATE_KEY = 'privkey'
23ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    PIN = '11111'
2413372b17e81e16243b50a4c73384a86f31fed802Peter Qiu    # TPM maintain two slots for certificates, slot 0 for system specific
2513372b17e81e16243b50a4c73384a86f31fed802Peter Qiu    # certificates, slot 1 for user specific certificates. Currently, all
2613372b17e81e16243b50a4c73384a86f31fed802Peter Qiu    # certificates are programmed in slot 1. So hardcode this slot ID for now.
2713372b17e81e16243b50a4c73384a86f31fed802Peter Qiu    SLOT_ID = '1'
2813372b17e81e16243b50a4c73384a86f31fed802Peter Qiu    PKCS11_REPLAY_COMMAND = 'p11_replay --slot=%s' % SLOT_ID
29ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    TPM_GROUP = 'chronos-access'
30ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    TPM_USER = 'chaps'
31ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
32ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
33ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    def __enter__(self):
34ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        self.setup()
35ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        return self
36ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
37ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    def __exit__(self, exception, value, traceback):
38ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        self.reset()
39ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
40ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
41ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    def _cryptohome_action(self, action):
42ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        """Set the TPM up for operation in tests."""
43ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        utils.system('%s --action=%s' % (self.CRYPTOHOME_COMMAND, action),
44ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                     ignore_status=True)
45ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
46ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
47ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    def _install_object(self, pem, identifier, conversion_type, output_type):
48ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        """Convert a PEM object to DER and store it in the TPM.
49ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
50ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        @param pem string PEM encoded object to be stored.
51ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        @param identifier string associated with the new object.
52ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        @param conversion_type the object type to use in PEM to DER conversion.
53ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        @param output_type the object type to use in inserting into the TPM.
54ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
55ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        """
56037f8dfe77e077aca44226ef9c555094e52973cfKris Rambish        if cryptohome.is_tpm_lockout_in_effect():
57037f8dfe77e077aca44226ef9c555094e52973cfKris Rambish            raise error.TestError('The TPM is in dictonary defend mode. '
58037f8dfe77e077aca44226ef9c555094e52973cfKris Rambish                                  'The TPMStore may behave in unexpected '
59037f8dfe77e077aca44226ef9c555094e52973cfKris Rambish                                  'ways, exiting.')
60ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        pem_file = tempfile.NamedTemporaryFile()
61ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        pem_file.file.write(pem)
62ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        pem_file.file.flush()
63ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        der_file = tempfile.NamedTemporaryFile()
64ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        utils.system('%s %s -in %s -out %s -inform PEM -outform DER' %
65ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                     (self.OPENSSL_COMMAND, conversion_type, pem_file.name,
66ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                      der_file.name))
67ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        utils.system('%s --import --type=%s --path=%s --id="%s"' %
68ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                     (self.PKCS11_REPLAY_COMMAND, output_type, der_file.name,
69ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                      identifier))
70ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
71ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
72ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    def setup(self):
73ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        """Set the TPM up for operation in tests."""
74ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        self.reset()
75ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        self._directory = tempfile.mkdtemp()
76ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        utils.system('chown %s:%s %s' %
77ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                     (self.TPM_USER, self.TPM_GROUP, self._directory))
78ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        utils.system('%s --load --path=%s --auth="%s"' %
79ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                     (self.CHAPS_CLIENT_COMMAND, self._directory, self.PIN))
80ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
81ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
82ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    def reset(self):
83ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        """Reset the crypto store and take ownership of the device."""
84ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        utils.system('initctl restart chapsd')
85ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        self._cryptohome_action(self.CRYPTOHOME_ACTION_TAKE_OWNERSHIP)
86ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        self._cryptohome_action(self.CRYPTOHOME_ACTION_WAIT_OWNERSHIP)
87ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
88ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
89ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    def install_certificate(self, certificate, identifier):
90ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        """Install a certificate into the TPM, returning the certificate ID.
91ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
92ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        @param certificate string PEM x509 contents of the certificate.
93ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        @param identifier string associated with this certificate in the TPM.
94ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
95ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        """
96ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        return self._install_object(certificate,
97ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                                    identifier,
98ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                                    self.CONVERT_TYPE_X509,
99ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                                    self.OUTPUT_TYPE_CERTIFICATE)
100ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
101ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
102ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart    def install_private_key(self, key, identifier):
103ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        """Install a private key into the TPM, returning the certificate ID.
104ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
105ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        @param key string PEM RSA private key contents.
106ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        @param identifier string associated with this private key in the TPM.
107ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart
108ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        """
109ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart        return self._install_object(key,
110ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                                    identifier,
111ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                                    self.CONVERT_TYPE_RSA,
112ea00bc8fb56a93ebe34924b94cdea9019db0bf8bPaul Stewart                                    self.OUTPUT_TYPE_PRIVATE_KEY)
113