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