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