• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2013 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 tempfile
6
7from autotest_lib.client.bin import utils
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.cros import cryptohome
10
11class TPMStore(object):
12    """Context enclosing the use of the TPM."""
13
14    CHAPS_CLIENT_COMMAND = 'chaps_client'
15    CONVERT_TYPE_RSA = 'rsa'
16    CONVERT_TYPE_X509 = 'x509'
17    OPENSSL_COMMAND = 'openssl'
18    OUTPUT_TYPE_CERTIFICATE = 'cert'
19    OUTPUT_TYPE_PRIVATE_KEY = 'privkey'
20    PIN = '11111'
21    # TPM maintain two slots for certificates, slot 0 for system specific
22    # certificates, slot 1 for user specific certificates. Currently, all
23    # certificates are programmed in slot 1. So hardcode this slot ID for now.
24    SLOT_ID = '1'
25    PKCS11_REPLAY_COMMAND = 'p11_replay --slot=%s' % SLOT_ID
26    TPM_GROUP = 'chronos-access'
27    TPM_USER = 'chaps'
28
29
30    def __enter__(self):
31        self.setup()
32        return self
33
34    def __exit__(self, exception, value, traceback):
35        self.reset()
36
37
38    def _install_object(self, pem, identifier, conversion_type, output_type):
39        """Convert a PEM object to DER and store it in the TPM.
40
41        @param pem string PEM encoded object to be stored.
42        @param identifier string associated with the new object.
43        @param conversion_type the object type to use in PEM to DER conversion.
44        @param output_type the object type to use in inserting into the TPM.
45
46        """
47        if cryptohome.is_tpm_lockout_in_effect():
48            raise error.TestError('The TPM is in dictonary defend mode. '
49                                  'The TPMStore may behave in unexpected '
50                                  'ways, exiting.')
51        pem_file = tempfile.NamedTemporaryFile()
52        pem_file.file.write(pem)
53        pem_file.file.flush()
54        der_file = tempfile.NamedTemporaryFile()
55        utils.system('%s %s -in %s -out %s -inform PEM -outform DER' %
56                     (self.OPENSSL_COMMAND, conversion_type, pem_file.name,
57                      der_file.name))
58        utils.system('%s --import --type=%s --path=%s --id="%s"' %
59                     (self.PKCS11_REPLAY_COMMAND, output_type, der_file.name,
60                      identifier))
61
62
63    def setup(self):
64        """Set the TPM up for operation in tests."""
65        self.reset()
66        self._directory = tempfile.mkdtemp()
67        utils.system('chown %s:%s %s' %
68                     (self.TPM_USER, self.TPM_GROUP, self._directory))
69        utils.system('%s --load --path=%s --auth="%s"' %
70                     (self.CHAPS_CLIENT_COMMAND, self._directory, self.PIN))
71
72
73    def reset(self):
74        """Reset the crypto store and take ownership of the device."""
75        utils.system('initctl restart chapsd')
76        cryptohome.take_tpm_ownership(wait_for_ownership=True)
77
78
79    def install_certificate(self, certificate, identifier):
80        """Install a certificate into the TPM, returning the certificate ID.
81
82        @param certificate string PEM x509 contents of the certificate.
83        @param identifier string associated with this certificate in the TPM.
84
85        """
86        return self._install_object(certificate,
87                                    identifier,
88                                    self.CONVERT_TYPE_X509,
89                                    self.OUTPUT_TYPE_CERTIFICATE)
90
91
92    def install_private_key(self, key, identifier):
93        """Install a private key into the TPM, returning the certificate ID.
94
95        @param key string PEM RSA private key contents.
96        @param identifier string associated with this private key in the TPM.
97
98        """
99        return self._install_object(key,
100                                    identifier,
101                                    self.CONVERT_TYPE_RSA,
102                                    self.OUTPUT_TYPE_PRIVATE_KEY)
103