Paul Stewart | ea00bc8 | 2013-06-25 10:13:25 -0700 | [diff] [blame] | 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 |
Kris Rambish | 088c75f | 2014-12-11 11:02:38 -0800 | [diff] [blame] | 8 | from autotest_lib.client.common_lib import error |
| 9 | from autotest_lib.client.cros import cryptohome |
Paul Stewart | ea00bc8 | 2013-06-25 10:13:25 -0700 | [diff] [blame] | 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' |
Paul Stewart | ea00bc8 | 2013-06-25 10:13:25 -0700 | [diff] [blame] | 17 | OPENSSL_COMMAND = 'openssl' |
| 18 | OUTPUT_TYPE_CERTIFICATE = 'cert' |
| 19 | OUTPUT_TYPE_PRIVATE_KEY = 'privkey' |
| 20 | PIN = '11111' |
Peter Qiu | 13372b1 | 2014-11-10 19:46:28 -0800 | [diff] [blame] | 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 |
Paul Stewart | ea00bc8 | 2013-06-25 10:13:25 -0700 | [diff] [blame] | 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 | |
Paul Stewart | ea00bc8 | 2013-06-25 10:13:25 -0700 | [diff] [blame] | 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 | """ |
Kris Rambish | 037f8df | 2015-01-26 12:47:35 -0800 | [diff] [blame] | 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.') |
Paul Stewart | ea00bc8 | 2013-06-25 10:13:25 -0700 | [diff] [blame] | 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') |
Brian Norris | 7bf96c9 | 2019-10-30 18:21:18 -0700 | [diff] [blame] | 76 | cryptohome.take_tpm_ownership(wait_for_ownership=True) |
Paul Stewart | ea00bc8 | 2013-06-25 10:13:25 -0700 | [diff] [blame] | 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) |