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