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 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