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