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