Make `cryptohome::Tpm` independent of Cryptohome.
1. Decouple `Tpm` from `TpmInit`.
2. Build TPM into libcrostpm.
3. Move initialization of the TPM from `Tpm` to `TpmInit`.
House keeping functions such as `LoadTpmStatus`, `StoreTpmStatus`, are
moved to `TpmInit`.
Functions related to owner passwords are also moved to `TpmInit`.
4. Move all key loading/saving out of `Tpm` into `TpmInit`.
`Tpm::Init` is removed. `Tpm` no longer depends on `Platform`.
`Tpm` instances now MUST be handed handles to context and key in order for
it to perform any cryptographic operations.
`TpmInit` can load the key blobs on disk. See
`TpmInit::LoadCryptohomeKey`.
5. `CreateCryptohomeKey` is replaced with `CreateWrappedRsaKey`. The later
function uses OpenSSL to generate an RSA key and wraps it with SRK.
6. Add `MockTpmInit`.
7. Make dependency injection clearer in `Init` function. The idiom is:
construct an object with default constructor then call `Init` and
pass in necessary dependencies.
BUG=chromium:355634
TEST=unittest
TEST=create an account on the device before applying this CL. download
some files to its home dir.
TEST=then apply this CL. do it in a way that does not wipe out stateful
partition.
TEST=do the combo (login, let it idle for a minute or two, reboot) a few
times. make sure that the existing accounts can still be used and
downloaded files are still there.
TEST=also make sure that new accounts and guests can login.
TEST=`stop cryptohomed`, then run `cryptohomed --noclose`, make sure
that there is no apparent problems or warnings related to TPM in the log.
Change-Id: I9a582c9aca8b0cad81520c0a42c68cedf43d5251
Reviewed-on: https://chromium-review.googlesource.com/196911
Reviewed-by: Darren Krahn <dkrahn@chromium.org>
Tested-by: Nam Nguyen <namnguyen@chromium.org>
Commit-Queue: Nam Nguyen <namnguyen@chromium.org>
diff --git a/Makefile b/Makefile
index b40009e..080d680 100644
--- a/Makefile
+++ b/Makefile
@@ -47,8 +47,8 @@
TEST_OBJS := $(filter %_unittest.o cryptohome_testrunner.o %_tests.o mock_%.o, \
$(CXX_OBJECTS))
SHARED_OBJS := $(filter-out cryptohomed.o cryptohome.o cryptohome-path.o \
- lockbox-cache-main.o $(ME_OBJS) $(TEST_OBJS), \
- $(CXX_OBJECTS))
+ lockbox-cache-main.o $(ME_OBJS) $(TEST_OBJS) \
+ tpm.o cryptolib.o, $(CXX_OBJECTS))
# Used to cause an object to depend on all the generated headers. Since the
# headers are generated, there's no way for common.mk's dependency detection to
@@ -74,6 +74,7 @@
$(GEN_OBJS), \
$(call add_gen_hdrs,$(obj))))
+all: libcrostpm.a
all: CXX_BINARY(cryptohomed) CXX_BINARY(cryptohome) CXX_BINARY(cryptohome-path)
all: CXX_BINARY(lockbox-cache) CC_BINARY(mount-encrypted)
tests: TEST(CXX_BINARY(cryptohome_testrunner))
@@ -107,17 +108,20 @@
mkdir -p $(dir $@)
$(DBUS_BINDING_TOOL) --mode=glib-server --prefix=cryptohome $^ > $@
-CXX_BINARY(cryptohomed): $(SHARED_OBJS) cryptohomed.o
-CXX_BINARY(cryptohome): $(SHARED_OBJS) cryptohome.o
-CXX_BINARY(cryptohome-path): $(SHARED_OBJS) cryptohome-path.o
+CXX_STATIC_LIBRARY(libcrostpm.pie.a): tpm.o cryptolib.o
+libcrostpm.a: CXX_STATIC_LIBRARY(libcrostpm.pie.a)
+ cp $(OUT)libcrostpm.pie.a $(OUT)libcrostpm.a
+CXX_BINARY(cryptohomed): $(SHARED_OBJS) cryptohomed.o libcrostpm.a
+CXX_BINARY(cryptohome): $(SHARED_OBJS) cryptohome.o libcrostpm.a
+CXX_BINARY(cryptohome-path): $(SHARED_OBJS) cryptohome-path.o libcrostpm.a
CXX_BINARY(cryptohome_testrunner): LDLIBS += -lgtest -lgmock
-CXX_BINARY(cryptohome_testrunner): $(SHARED_OBJS) $(TEST_OBJS)
+CXX_BINARY(cryptohome_testrunner): $(SHARED_OBJS) $(TEST_OBJS) libcrostpm.a
CC_BINARY(mount-encrypted): $(ME_OBJS)
-
-CXX_BINARY(lockbox-cache): tpm_status.pb.o cryptolib.o platform.o tpm.o \
- lockbox.o lockbox-cache.o lockbox-cache-tpm.o \
- lockbox-cache-main.o
+CXX_BINARY(lockbox-cache): tpm_status.pb.o lockbox.o lockbox-cache-tpm.o \
+ lockbox-cache.o lockbox-cache-main.o platform.o \
+ libcrostpm.a
clean: CLEAN(*.pb.cc) CLEAN(*.pb.h) CLEAN(cryptohomed) CLEAN(lockbox-cache)
clean: CLEAN(cryptohome) CLEAN(cryptohome-path) CLEAN(cryptohome_testrunner)
clean: CLEAN(mount-encrypted) CLEAN($(SHARED_PROTO_FILES))
+clean: CLEAN(libcrostpm.pie.a) libcrostpm.a
diff --git a/attestation.cc b/attestation.cc
index 08b8405..45ab140 100644
--- a/attestation.cc
+++ b/attestation.cc
@@ -26,6 +26,7 @@
#include "pkcs11_keystore.h"
#include "platform.h"
#include "tpm.h"
+#include "tpm_init.h"
using chromeos::SecureBlob;
using std::string;
@@ -224,12 +225,14 @@
}
void Attestation::Initialize(Tpm* tpm,
+ TpmInit* tpm_init,
Platform* platform,
Crypto* crypto,
InstallAttributes* install_attributes) {
base::AutoLock lock(lock_);
// Inject dependencies.
tpm_ = tpm;
+ tpm_init_ = tpm_init;
platform_ = platform;
crypto_ = crypto;
if (install_attributes_ != install_attributes) {
@@ -251,7 +254,7 @@
FinalizeEndorsementData();
LOG(INFO) << "Attestation: Valid attestation data exists.";
// Make sure the owner password is not being held on our account.
- tpm_->RemoveOwnerDependency(Tpm::kAttestation);
+ tpm_init_->RemoveTpmOwnerDependency(TpmInit::kAttestation);
}
}
@@ -475,7 +478,7 @@
LOG(ERROR) << "Attestation: Failed to store db.";
return;
}
- tpm_->RemoveOwnerDependency(Tpm::kAttestation);
+ tpm_init_->RemoveTpmOwnerDependency(TpmInit::kAttestation);
base::TimeDelta delta = (base::TimeTicks::Now() - start);
LOG(INFO) << "Attestation: Prepared successfully (" << delta.InMilliseconds()
<< "ms).";
diff --git a/attestation.h b/attestation.h
index 1bb0aca..cd70406 100644
--- a/attestation.h
+++ b/attestation.h
@@ -26,6 +26,7 @@
class Pkcs11KeyStore;
class Platform;
class Tpm;
+class TpmInit;
// This class performs tasks which enable attestation enrollment. These tasks
// include creating an AIK and recording all information about the AIK and EK
@@ -46,6 +47,7 @@
// Must be called before any other method.
virtual void Initialize(Tpm* tpm,
+ TpmInit* tpm_init,
Platform* platform,
Crypto* crypto,
InstallAttributes* install_attributes);
@@ -379,6 +381,7 @@
static const char kAlternatePCAKeyIDAttributeName[];
Tpm* tpm_;
+ TpmInit* tpm_init_;
Platform* platform_;
Crypto* crypto_;
// A lock to protect |database_pb_| because PrepareForEnrollment may happen on
@@ -558,6 +561,9 @@
// Returns true if the TPM is ready.
bool IsTPMReady();
+ // Injects a TpmInit object to be used for RemoveTpmOwnerDependency
+ void set_tpm_init(TpmInit* value) { tpm_init_ = value; }
+
friend class AttestationTest;
DISALLOW_COPY_AND_ASSIGN(Attestation);
diff --git a/attestation_unittest.cc b/attestation_unittest.cc
index c97ff60..52a7d85 100644
--- a/attestation_unittest.cc
+++ b/attestation_unittest.cc
@@ -21,6 +21,7 @@
#include "mock_keystore.h"
#include "mock_platform.h"
#include "mock_tpm.h"
+#include "mock_tpm_init.h"
using chromeos::SecureBlob;
using std::string;
@@ -62,7 +63,8 @@
ON_CALL(tpm_, IsEnabled()).WillByDefault(Return(true));
ON_CALL(tpm_, IsOwned()).WillByDefault(Return(true));
ON_CALL(tpm_, IsBeingOwned()).WillByDefault(Return(false));
- attestation_.Initialize(&tpm_, &platform_, &crypto_, &install_attributes_);
+ attestation_.Initialize(&tpm_, &tpm_init_, &platform_, &crypto_,
+ &install_attributes_);
}
virtual bool WriteDB(const string& path, const string& db) {
@@ -77,6 +79,7 @@
protected:
string serialized_db_;
NiceMock<MockTpm> tpm_;
+ NiceMock<MockTpmInit> tpm_init_;
NiceMock<MockPlatform> platform_;
Crypto crypto_;
NiceMock<MockKeyStore> key_store_;
@@ -291,8 +294,8 @@
TEST(AttestationTest_, NullTpm) {
Attestation without_tpm;
- without_tpm.Initialize(NULL, NULL, new Crypto(NULL),
- new InstallAttributes(NULL));
+ without_tpm.Initialize(NULL, NULL, NULL, new Crypto(NULL),
+ new InstallAttributes(NULL));
without_tpm.PrepareForEnrollment();
EXPECT_FALSE(without_tpm.IsPreparedForEnrollment());
EXPECT_FALSE(without_tpm.Verify());
@@ -606,7 +609,8 @@
db.credentials().has_endorsement_credential());
// Simulate second login.
- attestation_.Initialize(&tpm_, &platform_, &crypto_, &install_attributes_);
+ attestation_.Initialize(&tpm_, &tpm_init_, &platform_, &crypto_,
+ &install_attributes_);
// Expect endorsement data to be no longer available.
db = GetPersistentDatabase();
EXPECT_TRUE(db.has_credentials() &&
diff --git a/crypto.cc b/crypto.cc
index 6ece8e9..65b856d 100644
--- a/crypto.cc
+++ b/crypto.cc
@@ -27,6 +27,7 @@
#include "cryptohome_common.h"
#include "cryptolib.h"
#include "platform.h"
+#include "tpm_init.h"
#include "username_passkey.h"
// Included last because they both have conflicting defines :(
@@ -83,33 +84,30 @@
Crypto::Crypto(Platform* platform)
: use_tpm_(false),
tpm_(NULL),
- platform_(platform) {
+ platform_(platform),
+ tpm_init_(NULL) {
}
Crypto::~Crypto() {
}
-bool Crypto::Init() {
- if (use_tpm_ && tpm_ == NULL) {
- tpm_ = Tpm::GetSingleton();
- }
- if (tpm_) {
- tpm_->Init(platform_, true);
+bool Crypto::Init(TpmInit* tpm_init) {
+ if (use_tpm_) {
+ CHECK(tpm_init) << "Crypto wanted to use TPM but was not provided a TPM";
+ if (tpm_ == NULL) {
+ tpm_ = tpm_init->get_tpm();
+ }
+ tpm_init_ = tpm_init;
+ tpm_init_->SetupTpm(true);
}
return true;
}
-Crypto::CryptoError Crypto::EnsureTpm(bool disconnect_first) const {
+Crypto::CryptoError Crypto::EnsureTpm(bool reload_key) const {
Crypto::CryptoError result = Crypto::CE_NONE;
- if (tpm_) {
- if (disconnect_first) {
- tpm_->Disconnect();
- }
- if (!tpm_->IsConnected()) {
- Tpm::TpmRetryAction retry_action;
- if (!tpm_->Connect(&retry_action)) {
- result = TpmErrorToCrypto(retry_action);
- }
+ if (tpm_ && tpm_init_) {
+ if (reload_key || !tpm_init_->HasCryptohomeKey()) {
+ tpm_init_->SetupTpm(true);
}
}
return result;
@@ -272,7 +270,9 @@
CryptoError* error) const {
SecureBlob pub_key_hash;
Tpm::TpmRetryAction retry_action;
- retry_action = tpm_->GetPublicKeyHash(&pub_key_hash);
+ retry_action = tpm_->GetPublicKeyHash(tpm_init_->GetCryptohomeContext(),
+ tpm_init_->GetCryptohomeKey(),
+ &pub_key_hash);
if (retry_action != Tpm::RetryNone) {
LOG(ERROR) << "Unable to get the cryptohome public key from the TPM.";
if (error)
@@ -328,7 +328,7 @@
}
Crypto::CryptoError local_error = EnsureTpm(false);
- if (!tpm_->IsConnected()) {
+ if (!is_cryptohome_key_loaded()) {
LOG(ERROR) << "Vault keyset is wrapped by the TPM, but the TPM is "
<< "unavailable";
if (error)
@@ -350,13 +350,19 @@
}
}
- Tpm::TpmRetryAction retry_action;
+ TSS_RESULT result;
SecureBlob tpm_key(serialized.tpm_key().length());
serialized.tpm_key().copy(static_cast<char*>(tpm_key.data()),
serialized.tpm_key().length(), 0);
SecureBlob key;
CryptoLib::PasskeyToAesKey(vault_key, salt, rounds, &key, NULL);
- if (!tpm_->Decrypt(tpm_key, key, &local_vault_key, &retry_action)) {
+ if (!tpm_->DecryptBlob(tpm_init_->GetCryptohomeContext(),
+ tpm_init_->GetCryptohomeKey(),
+ tpm_key,
+ key,
+ &local_vault_key,
+ &result)) {
+ Tpm::TpmRetryAction retry_action = tpm_->HandleError(result);
LOG(ERROR) << "The TPM failed to unwrap the intermediate key with the "
<< "supplied credentials";
if (error)
@@ -497,19 +503,24 @@
if (!use_tpm_)
return false;
EnsureTpm(false);
- if (tpm_ == NULL || !tpm_->IsConnected())
+ if (!is_cryptohome_key_loaded())
return false;
SecureBlob local_blob(kDefaultAesKeySize);
CryptoLib::GetSecureRandom(static_cast<unsigned char*>(local_blob.data()),
local_blob.size());
- Tpm::TpmRetryAction retry_action;
+ TSS_RESULT result;
SecureBlob tpm_key;
SecureBlob derived_key;
CryptoLib::PasskeyToAesKey(key, salt, rounds, &derived_key, NULL);
// Encrypt the VKK using the TPM and the user's passkey. The output is an
// encrypted blob in tpm_key, which is stored in the serialized vault
// keyset.
- if (!tpm_->Encrypt(local_blob, derived_key, &tpm_key, &retry_action)) {
+ if (!tpm_->EncryptBlob(tpm_init_->GetCryptohomeContext(),
+ tpm_init_->GetCryptohomeKey(),
+ local_blob,
+ derived_key,
+ &tpm_key,
+ &result)) {
LOG(ERROR) << "Failed to wrap vkk with creds.";
return false;
}
@@ -531,7 +542,9 @@
// detect a TPM clear. If this fails due to a transient issue, then on next
// successful login, the vault keyset will be re-saved anyway.
SecureBlob pub_key_hash;
- if (tpm_->GetPublicKeyHash(&pub_key_hash) == Tpm::RetryNone)
+ if (tpm_->GetPublicKeyHash(tpm_init_->GetCryptohomeContext(),
+ tpm_init_->GetCryptohomeKey(),
+ &pub_key_hash) == Tpm::RetryNone)
serialized->set_tpm_public_key_hash(pub_key_hash.const_data(),
pub_key_hash.size());
@@ -749,4 +762,11 @@
return true;
}
+bool Crypto::is_cryptohome_key_loaded() const {
+ if (tpm_ == NULL || tpm_init_ == NULL) {
+ return false;
+ }
+ return tpm_init_->HasCryptohomeKey();
+}
+
} // namespace cryptohome
diff --git a/crypto.h b/crypto.h
index 6ec0fe9..e758355 100644
--- a/crypto.h
+++ b/crypto.h
@@ -15,6 +15,7 @@
#include <chromeos/secure_blob.h>
#include "tpm.h"
+#include "tpm_init.h"
#include "vault_keyset.h"
#include "vault_keyset.pb.h"
@@ -41,7 +42,7 @@
virtual ~Crypto();
// Initializes Crypto
- bool Init();
+ bool Init(TpmInit* tpm_init);
// Decrypts an encrypted vault keyset. The vault keyset should be the output
// of EncryptVaultKeyset().
@@ -118,7 +119,7 @@
chromeos::SecureBlob* passkey);
// Ensures that the TPM is connected
- CryptoError EnsureTpm(bool disconnect_first) const;
+ CryptoError EnsureTpm(bool reload_key) const;
// Seals arbitrary-length data to the TPM's PCR0.
// Parameters
@@ -185,13 +186,8 @@
return tpm_;
}
- // Checks if the TPM is connected
- bool is_tpm_connected() {
- if (tpm_ == NULL) {
- return false;
- }
- return tpm_->IsConnected();
- }
+ // Checks if the cryptohome key is loaded in TPM
+ bool is_cryptohome_key_loaded() const;
// Sets the Platform implementation
// Does NOT take ownership of the pointer.
@@ -249,6 +245,9 @@
// Platform abstraction
Platform* platform_;
+ // The TpmInit object used to reload Cryptohome key
+ TpmInit* tpm_init_;
+
DISALLOW_COPY_AND_ASSIGN(Crypto);
};
diff --git a/crypto_unittest.cc b/crypto_unittest.cc
index 29f4459..253093a 100644
--- a/crypto_unittest.cc
+++ b/crypto_unittest.cc
@@ -22,12 +22,14 @@
#include "cryptolib.h"
#include "mock_platform.h"
#include "mock_tpm.h"
+#include "mock_tpm_init.h"
using base::FilePath;
using chromeos::Blob;
using chromeos::SecureBlob;
using std::string;
using ::testing::_;
+using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SaveArg;
@@ -310,18 +312,20 @@
MockPlatform platform;
Crypto crypto(&platform);
NiceMock<MockTpm> tpm;
+ NiceMock<MockTpmInit> tpm_init;
crypto.set_tpm(&tpm);
crypto.set_use_tpm(true);
- EXPECT_CALL(tpm, Init(_, _))
- .WillOnce(Return(true));
- EXPECT_CALL(tpm, Encrypt(_, _, _, _));
- EXPECT_CALL(tpm, Decrypt(_, _, _, _));
- EXPECT_CALL(tpm, IsConnected())
+ EXPECT_CALL(tpm, EncryptBlob(_, _, _, _, _, _));
+ EXPECT_CALL(tpm, DecryptBlob(_, _, _, _, _, _));
+ EXPECT_CALL(tpm_init, HasCryptohomeKey())
+ .WillOnce(Return(false))
.WillRepeatedly(Return(true));
+ EXPECT_CALL(tpm_init, SetupTpm(true))
+ .Times(AtLeast(2)); // One by crypto.Init(), one by crypto.EnsureTpm()
- crypto.Init();
+ crypto.Init(&tpm_init);
VaultKeyset vault_keyset;
vault_keyset.Initialize(&platform_, &crypto);
@@ -364,7 +368,7 @@
MockPlatform platform;
Crypto crypto(&platform);
- crypto.Init();
+ crypto.Init(NULL);
VaultKeyset vault_keyset;
vault_keyset.Initialize(&platform, &crypto);
@@ -408,15 +412,15 @@
MockPlatform platform;
Crypto crypto(&platform);
NiceMock<MockTpm> tpm;
+ NiceMock<MockTpmInit> tpm_init;
crypto.set_tpm(&tpm);
crypto.set_use_tpm(true);
- EXPECT_CALL(tpm, Init(_, _)).WillOnce(Return(true));
- EXPECT_CALL(tpm, Encrypt(_, _, _, _));
- EXPECT_CALL(tpm, Decrypt(_, _, _, _));
+ EXPECT_CALL(tpm, EncryptBlob(_, _, _, _, _, _));
+ EXPECT_CALL(tpm, DecryptBlob(_, _, _, _, _, _));
- crypto.Init();
+ crypto.Init(&tpm_init);
VaultKeyset vault_keyset;
vault_keyset.Initialize(&platform_, &crypto);
@@ -517,11 +521,10 @@
Crypto crypto(&platform);
NiceMock<MockTpm> tpm;
+ NiceMock<MockTpmInit> tpm_init;
crypto.set_tpm(&tpm);
crypto.set_use_tpm(true);
- EXPECT_CALL(tpm, Init(_, _))
- .WillOnce(Return(true));
- crypto.Init();
+ crypto.Init(&tpm_init);
string data = "iamsomestufftoencrypt";
SecureBlob data_blob(data.data(), data.size());
@@ -561,11 +564,10 @@
Crypto crypto(&platform);
NiceMock<MockTpm> tpm;
+ NiceMock<MockTpmInit> tpm_init;
crypto.set_tpm(&tpm);
crypto.set_use_tpm(true);
- EXPECT_CALL(tpm, Init(_, _))
- .WillOnce(Return(true));
- crypto.Init();
+ crypto.Init(&tpm_init);
string data = "iamsomestufftoencrypt";
SecureBlob data_blob(data.data(), data.size());
diff --git a/homedirs.cc b/homedirs.cc
index dda7539..c59f7e4 100644
--- a/homedirs.cc
+++ b/homedirs.cc
@@ -39,8 +39,7 @@
enterprise_owned_(false),
default_policy_provider_(new policy::PolicyProvider()),
policy_provider_(default_policy_provider_.get()),
- default_crypto_(new Crypto(platform_)),
- crypto_(default_crypto_.get()),
+ crypto_(NULL),
default_mount_factory_(new MountFactory()),
mount_factory_(default_mount_factory_.get()),
default_vault_keyset_factory_(new VaultKeysetFactory()),
@@ -48,7 +47,10 @@
HomeDirs::~HomeDirs() { }
-bool HomeDirs::Init() {
+bool HomeDirs::Init(Platform* platform, Crypto* crypto) {
+ platform_ = platform;
+ crypto_ = crypto;
+
LoadDevicePolicy();
if (!platform_->DirectoryExists(shadow_root_))
platform_->CreateDirectory(shadow_root_);
@@ -812,9 +814,7 @@
newcreds.GetPasskey(&newkey);
UsernamePasskey oldcreds(newcreds.username().c_str(), oldkey);
scoped_refptr<Mount> mount = mount_factory_->New();
- mount->set_platform(platform_);
- mount->set_crypto(crypto_);
- mount->Init();
+ mount->Init(platform_, crypto_);
std::string obfuscated = newcreds.GetObfuscatedUsername(system_salt_);
if (!mount->MountCryptohome(oldcreds, Mount::MountArgs(), NULL)) {
LOG(ERROR) << "Migrate: Mount failed";
diff --git a/homedirs.h b/homedirs.h
index 0be9e93..1fae11a 100644
--- a/homedirs.h
+++ b/homedirs.h
@@ -40,7 +40,7 @@
virtual ~HomeDirs();
// Initializes this HomeDirs object. Returns true for success.
- virtual bool Init();
+ virtual bool Init(Platform* platform, Crypto* crypto);
// Frees disk space for unused cryptohomes. If less than kMinFreeSpace is
// available, frees space until kEnoughFreeSpace is available. Returns true if
@@ -229,7 +229,6 @@
bool enterprise_owned_;
scoped_ptr<policy::PolicyProvider> default_policy_provider_;
policy::PolicyProvider* policy_provider_;
- scoped_ptr<Crypto> default_crypto_;
Crypto* crypto_;
scoped_ptr<MountFactory> default_mount_factory_;
MountFactory* mount_factory_;
diff --git a/homedirs_unittest.cc b/homedirs_unittest.cc
index d4b7dfe..7f5dff1 100644
--- a/homedirs_unittest.cc
+++ b/homedirs_unittest.cc
@@ -15,6 +15,7 @@
#include "cryptolib.h"
#include "make_tests.h"
+#include "mock_crypto.h"
#include "mock_platform.h"
#include "mock_tpm.h"
#include "mock_user_oldest_activity_timestamp_cache.h"
@@ -104,8 +105,7 @@
test_helper_.SetUpSystemSalt();
// TODO(wad) Only generate the user data we need. This is time consuming.
test_helper_.InitTestData(kTestRoot, kDefaultUsers, kDefaultUserCount);
- homedirs_.set_platform(&platform_);
- homedirs_.crypto()->set_platform(&platform_);
+ crypto_.set_platform(&platform_);
homedirs_.set_shadow_root(kTestRoot);
test_helper_.InjectSystemSalt(&platform_,
StringPrintf("%s/salt", kTestRoot));
@@ -114,7 +114,7 @@
// Mount() normally sets this.
homedirs_.set_timestamp_cache(×tamp_cache_);
- homedirs_.Init();
+ homedirs_.Init(&platform_, &crypto_);
FilePath fp = FilePath(kTestRoot);
for (unsigned int i = 0; i < arraysize(kHomedirs); i++) {
const struct homedir *hd = &kHomedirs[i];
@@ -150,6 +150,7 @@
protected:
HomeDirs homedirs_;
+ NiceMock<MockCrypto> crypto_;
NiceMock<MockPlatform> platform_;
std::vector<std::string> homedir_paths_;
MakeTests test_helper_;
diff --git a/install_attributes.cc b/install_attributes.cc
index 10e5d3b..041bcd6 100644
--- a/install_attributes.cc
+++ b/install_attributes.cc
@@ -11,6 +11,7 @@
#include "lockbox.h"
#include "install_attributes.pb.h"
+#include "tpm_init.h"
namespace cryptohome {
@@ -78,7 +79,7 @@
lockbox_->set_tpm(tpm);
}
-bool InstallAttributes::Init() {
+bool InstallAttributes::Init(TpmInit* tpm_init) {
Lockbox::ErrorId error_id;
// Insure that if Init() was called and it failed, we can retry cleanly.
@@ -100,7 +101,7 @@
}
set_is_initialized(true);
- lockbox_->tpm()->RemoveOwnerDependency(Tpm::kInstallAttributes);
+ tpm_init->RemoveTpmOwnerDependency(TpmInit::kInstallAttributes);
return true;
}
diff --git a/install_attributes.h b/install_attributes.h
index e24e102..85ac3a9 100644
--- a/install_attributes.h
+++ b/install_attributes.h
@@ -18,6 +18,7 @@
#include "lockbox.h"
#include "platform.h"
#include "tpm.h"
+#include "tpm_init.h"
namespace cryptohome {
@@ -38,7 +39,7 @@
// Creates an instance of install attributes that will use the |tpm|. If |tpm|
// is NULL, InstallAttributes will proceed insecurely (unless it is set with
- // set_tpm at a later time).
+ // SetTpm at a later time).
explicit InstallAttributes(Tpm* tpm);
virtual ~InstallAttributes();
@@ -52,8 +53,9 @@
virtual void SetTpm(Tpm* tpm);
// Prepares the class for use including instantiating a new environment
- // if needed.
- virtual bool Init();
+ // if needed. If initialization completes, |tpm_init| will be used to remove
+ // this instance's dependency on the TPM ownership.
+ virtual bool Init(TpmInit* tpm_init);
// Determines if the instance can provide consistent responses to Get*(),
// Set(), Finalize(), and Count(). Repeated calls to Init() may change this.
diff --git a/install_attributes_unittest.cc b/install_attributes_unittest.cc
index 8043c34..be48ec8 100644
--- a/install_attributes_unittest.cc
+++ b/install_attributes_unittest.cc
@@ -17,6 +17,7 @@
#include "mock_lockbox.h"
#include "mock_platform.h"
#include "mock_tpm.h"
+#include "mock_tpm_init.h"
namespace cryptohome {
using std::string;
@@ -78,10 +79,12 @@
if (install_attrs->is_secure()) {
EXPECT_CALL(lockbox_, Create(_))
.WillOnce(Return(true));
- EXPECT_CALL(tpm_, RemoveOwnerDependency(Tpm::kInstallAttributes))
+ EXPECT_CALL(tpm_init_,
+ RemoveTpmOwnerDependency(
+ TpmInit::kInstallAttributes))
.Times(1);
}
- EXPECT_TRUE(install_attrs->Init());
+ EXPECT_TRUE(install_attrs->Init(&tpm_init_));
chromeos::Blob data;
data.assign(kTestData, kTestData + strlen(kTestData));
@@ -127,6 +130,7 @@
InstallAttributes install_attrs_;
NiceMock<MockPlatform> platform_;
NiceMock<MockTpm> tpm_;
+ NiceMock<MockTpmInit> tpm_init_;
private:
DISALLOW_COPY_AND_ASSIGN(InstallAttributesTest);
@@ -152,8 +156,7 @@
EXPECT_CALL(platform_, ReadFile(_, _))
.Times(1)
.WillOnce(Return(false));
-
- EXPECT_TRUE(install_attrs_.Init());
+ EXPECT_TRUE(install_attrs_.Init(&tpm_init_));
EXPECT_TRUE(install_attrs_.is_first_install());
}
@@ -167,7 +170,7 @@
.WillRepeatedly(Return(&tpm_));
EXPECT_CALL(lockbox_, Create(_))
.WillOnce(Return(true));
- EXPECT_TRUE(install_attrs_.Init());
+ EXPECT_TRUE(install_attrs_.Init(&tpm_init_));
chromeos::Blob data;
data.assign(kTestData, kTestData + strlen(kTestData));
@@ -204,7 +207,7 @@
EXPECT_CALL(lockbox_, Verify(_, _))
.Times(1)
.WillOnce(Return(true));
- EXPECT_TRUE(install_attrs_.Init());
+ EXPECT_TRUE(install_attrs_.Init(&tpm_init_));
EXPECT_FALSE(install_attrs_.is_first_install());
EXPECT_FALSE(install_attrs_.is_invalid());
EXPECT_TRUE(install_attrs_.is_initialized());
@@ -231,7 +234,7 @@
.Times(1)
.WillOnce(DoAll(SetArgumentPointee<1>(serialized_data), Return(true)));
- EXPECT_TRUE(install_attrs_.Init());
+ EXPECT_TRUE(install_attrs_.Init(&tpm_init_));
EXPECT_FALSE(install_attrs_.is_first_install());
EXPECT_FALSE(install_attrs_.is_invalid());
EXPECT_TRUE(install_attrs_.is_initialized());
@@ -263,7 +266,7 @@
EXPECT_CALL(lockbox_, Load(_))
.Times(1)
.WillOnce(DoAll(SetArgumentPointee<0>(error_id), Return(false)));
- EXPECT_TRUE(install_attrs_.Init());
+ EXPECT_TRUE(install_attrs_.Init(&tpm_init_));
EXPECT_TRUE(install_attrs_.is_first_install());
EXPECT_FALSE(install_attrs_.is_invalid());
EXPECT_TRUE(install_attrs_.is_initialized());
@@ -294,7 +297,7 @@
EXPECT_CALL(lockbox_, Create(_))
.Times(1)
.WillOnce(Return(true));
- EXPECT_TRUE(install_attrs_.Init());
+ EXPECT_TRUE(install_attrs_.Init(&tpm_init_));
EXPECT_TRUE(install_attrs_.is_first_install());
EXPECT_FALSE(install_attrs_.is_invalid());
EXPECT_TRUE(install_attrs_.is_initialized());
@@ -313,7 +316,7 @@
EXPECT_CALL(lockbox_, Load(_))
.Times(1)
.WillOnce(DoAll(SetArgumentPointee<0>(error_id), Return(false)));
- EXPECT_FALSE(install_attrs_.Init());
+ EXPECT_FALSE(install_attrs_.Init(&tpm_init_));
EXPECT_FALSE(install_attrs_.is_first_install());
EXPECT_TRUE(install_attrs_.is_invalid());
EXPECT_FALSE(install_attrs_.is_initialized());
@@ -334,7 +337,7 @@
EXPECT_CALL(platform_, ReadFile(_, _))
.Times(1)
.WillOnce(Return(false));
- EXPECT_FALSE(install_attrs_.Init());
+ EXPECT_FALSE(install_attrs_.Init(&tpm_init_));
EXPECT_FALSE(install_attrs_.is_first_install());
EXPECT_TRUE(install_attrs_.is_invalid());
EXPECT_FALSE(install_attrs_.is_initialized());
@@ -362,7 +365,7 @@
.Times(1)
.WillOnce(DoAll(SetArgumentPointee<1>(error_id), Return(false)));
- EXPECT_FALSE(install_attrs_.Init());
+ EXPECT_FALSE(install_attrs_.Init(&tpm_init_));
EXPECT_FALSE(install_attrs_.is_first_install());
EXPECT_TRUE(install_attrs_.is_invalid());
EXPECT_FALSE(install_attrs_.is_initialized());
@@ -385,7 +388,7 @@
EXPECT_CALL(lockbox_, Create(_))
.Times(1)
.WillOnce(DoAll(SetArgumentPointee<0>(create_error_id), Return(false)));
- EXPECT_TRUE(install_attrs_.Init());
+ EXPECT_TRUE(install_attrs_.Init(&tpm_init_));
EXPECT_FALSE(install_attrs_.is_first_install());
EXPECT_FALSE(install_attrs_.is_invalid());
EXPECT_TRUE(install_attrs_.is_initialized());
@@ -410,7 +413,7 @@
EXPECT_CALL(lockbox_, Create(_))
.Times(1)
.WillOnce(DoAll(SetArgumentPointee<0>(create_error_id), Return(false)));
- EXPECT_TRUE(install_attrs_.Init());
+ EXPECT_TRUE(install_attrs_.Init(&tpm_init_));
EXPECT_FALSE(install_attrs_.is_first_install());
EXPECT_FALSE(install_attrs_.is_invalid());
EXPECT_TRUE(install_attrs_.is_initialized());
diff --git a/make_tests.cc b/make_tests.cc
index 2df4ad0..895455e 100644
--- a/make_tests.cc
+++ b/make_tests.cc
@@ -24,6 +24,7 @@
#include <gtest/gtest.h>
#include "crypto.h"
+#include "mock_crypto.h"
#include "mock_platform.h"
#include "mock_tpm.h"
#include "mount.h"
@@ -178,13 +179,10 @@
memcpy(&salt.at(0), system_salt->c_str(), system_salt->size());
NiceMock<MockTpm> tpm;
NiceMock<MockPlatform> platform;
- //MockPlatform platform;
+ NiceMock<MockCrypto> crypto;
+ crypto.set_platform(&platform);
+
scoped_refptr<Mount> mount = new cryptohome::Mount();
- mount->set_platform(&platform);
- mount->crypto()->set_tpm(&tpm);
- mount->crypto()->set_platform(&platform);
- mount->homedirs()->set_platform(&platform);
- mount->homedirs()->crypto()->set_platform(&platform);
mount->set_shadow_root(shadow_root);
mount->set_skel_source(skel_dir);
mount->set_use_tpm(false);
@@ -203,7 +201,7 @@
.WillRepeatedly(DoAll(SetArgumentPointee<1>(salt), Return(true)));
EXPECT_CALL(platform, DirectoryExists(shadow_root))
.WillRepeatedly(Return(true));
- mount->Init();
+ mount->Init(&platform, &crypto);
cryptohome::Crypto::PasswordToPasskey(password,
salt,
diff --git a/mock_attestation.h b/mock_attestation.h
index d4a9105..1387d30 100644
--- a/mock_attestation.h
+++ b/mock_attestation.h
@@ -21,7 +21,11 @@
MockAttestation(): Attestation() { }
virtual ~MockAttestation() {}
- MOCK_METHOD4(Initialize, void(Tpm*, Platform*, Crypto*, InstallAttributes*));
+ MOCK_METHOD5(Initialize, void(Tpm*,
+ TpmInit*,
+ Platform*,
+ Crypto*,
+ InstallAttributes*));
MOCK_METHOD0(IsPreparedForEnrollment, bool());
MOCK_METHOD0(IsEnrolled, bool());
MOCK_METHOD0(PrepareForEnrollment, void());
diff --git a/mock_homedirs.cc b/mock_homedirs.cc
index 1038cd0..b84f3e6 100644
--- a/mock_homedirs.cc
+++ b/mock_homedirs.cc
@@ -4,12 +4,13 @@
#include "mock_homedirs.h"
+using testing::_;
using testing::Return;
namespace cryptohome {
MockHomeDirs::MockHomeDirs() {
- ON_CALL(*this, Init()).WillByDefault(Return(true));
+ ON_CALL(*this, Init(_, _)).WillByDefault(Return(true));
}
MockHomeDirs::~MockHomeDirs() {}
diff --git a/mock_homedirs.h b/mock_homedirs.h
index 58af032..36f6501 100644
--- a/mock_homedirs.h
+++ b/mock_homedirs.h
@@ -20,7 +20,7 @@
MockHomeDirs();
virtual ~MockHomeDirs();
- MOCK_METHOD0(Init, bool());
+ MOCK_METHOD2(Init, bool(Platform*, Crypto*));
MOCK_METHOD0(FreeDiskSpace, bool());
MOCK_METHOD1(AreCredentialsValid, bool(const Credentials&));
MOCK_METHOD2(GetValidKeyset, bool(const Credentials&, VaultKeyset*));
diff --git a/mock_install_attributes.h b/mock_install_attributes.h
index cde6803..d1ae6de 100644
--- a/mock_install_attributes.h
+++ b/mock_install_attributes.h
@@ -14,6 +14,7 @@
#include "lockbox.h"
#include "tpm.h"
+#include "tpm_init.h"
namespace cryptohome {
@@ -26,7 +27,7 @@
MOCK_METHOD1(SetTpm, void(Tpm*));
- MOCK_METHOD0(Init, bool());
+ MOCK_METHOD1(Init, bool(TpmInit*));
MOCK_CONST_METHOD0(IsReady, bool());
diff --git a/mock_mount.h b/mock_mount.h
index 295f625..b8be438 100644
--- a/mock_mount.h
+++ b/mock_mount.h
@@ -16,7 +16,7 @@
public:
MockMount();
~MockMount();
- MOCK_METHOD0(Init, bool());
+ MOCK_METHOD2(Init, bool(Platform*, Crypto*));
MOCK_METHOD1(AreSameUser, bool(const Credentials&));
MOCK_METHOD1(AreValid, bool(const Credentials&));
MOCK_METHOD3(MountCryptohome, bool(const Credentials&,
diff --git a/mock_tpm.cc b/mock_tpm.cc
index 8d9ea2d..10857fa 100644
--- a/mock_tpm.cc
+++ b/mock_tpm.cc
@@ -12,20 +12,16 @@
namespace cryptohome {
MockTpm::MockTpm() {
- ON_CALL(*this, Encrypt(_, _, _, _))
+ ON_CALL(*this, EncryptBlob(_, _, _, _, _, _))
.WillByDefault(Invoke(this, &MockTpm::Xor));
- ON_CALL(*this, Decrypt(_, _, _, _))
+ ON_CALL(*this, DecryptBlob(_, _, _, _, _, _))
.WillByDefault(Invoke(this, &MockTpm::Xor));
- ON_CALL(*this, IsConnected())
- .WillByDefault(Return(true));
ON_CALL(*this, Connect(_))
.WillByDefault(Return(true));
ON_CALL(*this, GetPublicKey(_, _))
.WillByDefault(Invoke(this, &MockTpm::GetBlankPublicKey));
- ON_CALL(*this, GetPublicKeyHash(_))
+ ON_CALL(*this, GetPublicKeyHash(_, _, _))
.WillByDefault(Return(Tpm::Fatal));
- ON_CALL(*this, Init(_, _))
- .WillByDefault(Return(true));
ON_CALL(*this, GetEndorsementPublicKey(_))
.WillByDefault(Return(true));
ON_CALL(*this, GetEndorsementCredential(_))
diff --git a/mock_tpm.h b/mock_tpm.h
index 25d14dc..f0e0f6a 100644
--- a/mock_tpm.h
+++ b/mock_tpm.h
@@ -24,22 +24,22 @@
public:
MockTpm();
~MockTpm();
- MOCK_METHOD2(Init, bool(Platform*, bool));
- MOCK_METHOD0(IsConnected, bool());
MOCK_CONST_METHOD0(IsOwned, bool());
MOCK_CONST_METHOD0(IsBeingOwned, bool());
MOCK_METHOD1(Connect, bool(TpmRetryAction*)); // NOLINT
- MOCK_METHOD0(Disconnect, void());
- MOCK_METHOD4(Encrypt, bool(const chromeos::SecureBlob&,
- const chromeos::SecureBlob&,
- chromeos::SecureBlob*, TpmRetryAction*));
- MOCK_METHOD4(Decrypt, bool(const chromeos::SecureBlob&,
- const chromeos::SecureBlob&,
- chromeos::SecureBlob*, TpmRetryAction*));
+ MOCK_METHOD6(EncryptBlob, bool(TSS_HCONTEXT, TSS_HKEY,
+ const chromeos::SecureBlob&,
+ const chromeos::SecureBlob&,
+ chromeos::SecureBlob*, TSS_RESULT*));
+ MOCK_METHOD6(DecryptBlob, bool(TSS_HCONTEXT, TSS_HKEY,
+ const chromeos::SecureBlob&,
+ const chromeos::SecureBlob&,
+ chromeos::SecureBlob*, TSS_RESULT*));
MOCK_METHOD2(GetPublicKey, bool(chromeos::SecureBlob*, TpmRetryAction*));
- MOCK_METHOD1(GetPublicKeyHash, Tpm::TpmRetryAction(chromeos::SecureBlob*));
+ MOCK_METHOD3(GetPublicKeyHash, Tpm::TpmRetryAction(TSS_HCONTEXT,
+ TSS_HKEY,
+ chromeos::SecureBlob*));
MOCK_METHOD1(GetOwnerPassword, bool(chromeos::Blob*));
- MOCK_METHOD1(RemoveOwnerDependency, void(Tpm::TpmOwnerDependency));
MOCK_CONST_METHOD0(IsEnabled, bool());
MOCK_METHOD2(GetRandomData, bool(size_t, chromeos::Blob*));
MOCK_METHOD2(DefineLockOnceNvram, bool(uint32_t, size_t));
@@ -96,10 +96,12 @@
MOCK_METHOD2(ExtendPCR, bool(int, const chromeos::SecureBlob&));
private:
- bool Xor(const chromeos::SecureBlob& plaintext,
+ bool Xor(TSS_HCONTEXT _context,
+ TSS_HKEY _key,
+ const chromeos::SecureBlob& plaintext,
const chromeos::SecureBlob& key,
chromeos::SecureBlob* ciphertext,
- TpmRetryAction* retry_action) {
+ TSS_RESULT* result) {
chromeos::SecureBlob local_data_out(plaintext.size());
for (unsigned int i = 0; i < local_data_out.size(); i++) {
local_data_out[i] = plaintext[i] ^ 0x1e;
diff --git a/mock_tpm_init.cc b/mock_tpm_init.cc
new file mode 100644
index 0000000..aed9c31
--- /dev/null
+++ b/mock_tpm_init.cc
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mock_tpm_init.h"
+
+using testing::_;
+using testing::Return;
+
+namespace cryptohome {
+
+MockTpmInit::MockTpmInit() : TpmInit(NULL, NULL) {
+ ON_CALL(*this, SetupTpm(_))
+ .WillByDefault(Return(true));
+ ON_CALL(*this, HasCryptohomeKey())
+ .WillByDefault(Return(true));
+}
+
+MockTpmInit::~MockTpmInit() {}
+
+} // namespace cryptohome
diff --git a/mock_tpm_init.h b/mock_tpm_init.h
new file mode 100644
index 0000000..c6535a9
--- /dev/null
+++ b/mock_tpm_init.h
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTOHOME_MOCK_TPM_INIT_H_
+#define CRYPTOHOME_MOCK_TPM_INIT_H_
+
+#include "tpm_init.h"
+
+#include <gmock/gmock.h>
+
+namespace cryptohome {
+
+class MockTpmInit : public TpmInit {
+ public:
+ MockTpmInit();
+ ~MockTpmInit();
+
+ MOCK_METHOD1(SetupTpm, bool(bool));
+ MOCK_METHOD1(RemoveTpmOwnerDependency, void(TpmOwnerDependency));
+ MOCK_METHOD0(HasCryptohomeKey, bool());
+};
+
+} // namespace cryptohome
+
+#endif // CRYPTOHOME_MOCK_TPM_INIT_H_
diff --git a/mount.cc b/mount.cc
index de3f0ed..0dfe63f 100644
--- a/mount.cc
+++ b/mount.cc
@@ -108,8 +108,7 @@
system_salt_(),
default_platform_(new Platform()),
platform_(default_platform_.get()),
- default_crypto_(new Crypto(platform_)),
- crypto_(default_crypto_.get()),
+ crypto_(NULL),
default_homedirs_(new HomeDirs()),
homedirs_(default_homedirs_.get()),
use_tpm_(true),
@@ -131,7 +130,10 @@
UnmountCryptohome();
}
-bool Mount::Init() {
+bool Mount::Init(Platform* platform, Crypto* crypto) {
+ platform_ = platform;
+ crypto_ = crypto;
+
bool result = true;
homedirs_->set_platform(platform_);
@@ -142,8 +144,7 @@
// Make sure both we and |homedirs_| have a proper device policy object.
EnsureDevicePolicyLoaded(false);
homedirs_->set_policy_provider(policy_provider_.get());
- homedirs_->set_crypto(crypto_);
- if (!homedirs_->Init())
+ if (!homedirs_->Init(platform, crypto))
result = false;
// Get the user id and group id of the default user
@@ -164,19 +165,12 @@
result = false;
}
- crypto_->set_use_tpm(use_tpm_);
-
int original_mask = platform_->SetMask(kDefaultUmask);
// Create the shadow root if it doesn't exist
if (!platform_->DirectoryExists(shadow_root_)) {
platform_->CreateDirectory(shadow_root_);
}
- if (!crypto_->Init()) {
- LOG(ERROR) << "Failed to initialize a Crypto instance";
- result = false;
- }
-
// One-time load of the global system salt (used in generating username
// hashes)
FilePath system_salt_file(StringPrintf("%s/salt", shadow_root_.c_str()));
@@ -1111,7 +1105,7 @@
bool scrypt_wrapped =
(crypt_flags & SerializedVaultKeyset::SCRYPT_WRAPPED) != 0;
bool should_tpm = (crypto_->has_tpm() && use_tpm_ &&
- crypto_->is_tpm_connected());
+ crypto_->is_cryptohome_key_loaded());
bool should_scrypt = true;
do {
// If the keyset was TPM-wrapped, but there was no public key hash,
diff --git a/mount.h b/mount.h
index ee7ae0a..38cea81 100644
--- a/mount.h
+++ b/mount.h
@@ -86,7 +86,7 @@
virtual ~Mount();
// Gets the uid/gid of the default user and loads the system salt
- virtual bool Init();
+ virtual bool Init(Platform* platform, Crypto* crypto);
// Attempts to mount the cryptohome for the given credentials
//
@@ -723,7 +723,6 @@
Platform *platform_;
// The crypto implementation
- scoped_ptr<Crypto> default_crypto_;
Crypto *crypto_;
// TODO(wad,ellyjones) Require HomeDirs at Init().
diff --git a/mount_unittest.cc b/mount_unittest.cc
index 65fc6f4..0d8b3ac 100644
--- a/mount_unittest.cc
+++ b/mount_unittest.cc
@@ -31,9 +31,11 @@
#include "homedirs.h"
#include "make_tests.h"
#include "mock_chaps_client_factory.h"
+#include "mock_crypto.h"
#include "mock_homedirs.h"
#include "mock_platform.h"
#include "mock_tpm.h"
+#include "mock_tpm_init.h"
#include "mock_user_session.h"
#include "username_passkey.h"
#include "vault_keyset.h"
@@ -78,14 +80,16 @@
}
// Straight pass through.
-bool TpmPassthroughEncrypt(const chromeos::SecureBlob &plaintext, Unused,
+bool TpmPassthroughEncrypt(TSS_HCONTEXT _context, TSS_HKEY _key,
+ const chromeos::SecureBlob &plaintext, Unused,
chromeos::SecureBlob *ciphertext, Unused) {
ciphertext->resize(plaintext.size());
memcpy(ciphertext->data(), plaintext.const_data(), plaintext.size());
return true;
}
-bool TpmPassthroughDecrypt(const chromeos::SecureBlob &ciphertext, Unused,
+bool TpmPassthroughDecrypt(TSS_HCONTEXT _context, TSS_HKEY _key,
+ const chromeos::SecureBlob &ciphertext, Unused,
chromeos::SecureBlob *plaintext, Unused) {
plaintext->resize(ciphertext.size());
memcpy(plaintext->data(), ciphertext.const_data(), ciphertext.size());
@@ -108,16 +112,17 @@
shared_gid_ = 1001;
chaps_uid_ = 223;
+ crypto_.set_tpm(&tpm_);
+ crypto_.set_platform(&platform_);
+ crypto_.set_use_tpm(false);
+
mount_ = new Mount();
- mount_->set_platform(&platform_);
mount_->set_homedirs(&homedirs_);
mount_->set_use_tpm(false);
mount_->set_shadow_root(kImageDir);
mount_->set_skel_source(kSkelDir);
- mount_->crypto()->set_platform(&platform_);
- mount_->crypto()->set_tpm(&tpm_);
mount_->set_chaps_client_factory(&chaps_client_factory_);
- homedirs_.set_crypto(mount_->crypto());
+ homedirs_.set_crypto(&crypto_);
homedirs_.set_platform(&platform_);
homedirs_.set_shadow_root(kImageDir);
set_policy(false, "", false);
@@ -145,7 +150,7 @@
EXPECT_CALL(platform_, GetGroupId("chronos-access", _))
.WillOnce(DoAll(SetArgumentPointee<1>(shared_gid_),
Return(true)));
- return mount_->Init();
+ return mount_->Init(&platform_, &crypto_);
}
bool LoadSerializedKeyset(const chromeos::Blob& contents,
@@ -187,7 +192,9 @@
gid_t shared_gid_;
NiceMock<MockPlatform> platform_;
NiceMock<MockTpm> tpm_;
+ NiceMock<MockTpmInit> tpm_init_;
NiceMock<MockHomeDirs> homedirs_;
+ NiceMock<MockCrypto> crypto_;
MockChapsClientFactory chaps_client_factory_;
scoped_refptr<Mount> mount_;
@@ -222,7 +229,7 @@
Return(true)));
EXPECT_CALL(platform_, GetGroupId("chronos-access", _))
.WillOnce(DoAll(SetArgumentPointee<1>(1002), Return(true)));
- EXPECT_FALSE(mount_->Init());
+ EXPECT_FALSE(mount_->Init(&platform_, &crypto_));
ASSERT_FALSE(mount_->AreValid(up));
}
@@ -384,8 +391,8 @@
kLegacyDir("/legacy"),
kRootUID(0), kRootGID(0), kChapsUID(1), kSharedGID(2),
mount_(new Mount()) {
- mount_->crypto()->set_platform(&platform_);
- mount_->set_platform(&platform_);
+ crypto_.set_platform(&platform_);
+ mount_->Init(&platform_, &crypto_);
mount_->chaps_user_ = kChapsUID;
mount_->default_access_group_ = kSharedGID;
// By default, set stats to the expected values.
@@ -438,6 +445,7 @@
scoped_refptr<Mount> mount_;
NiceMock<MockPlatform> platform_;
+ NiceMock<MockCrypto> crypto_;
private:
void InitStat(struct stat* s, mode_t mode, uid_t uid, gid_t gid) {
@@ -542,6 +550,9 @@
}
TEST_F(MountTest, CheckChapsDirectoryMigration) {
+ EXPECT_CALL(platform_, DirectoryExists(kImageDir))
+ .WillRepeatedly(Return(true));
+
// Configure stub methods.
EXPECT_CALL(platform_, Copy(_, _))
.WillRepeatedly(Return(true));
@@ -586,6 +597,7 @@
EXPECT_CALL(platform_, SetOwnership("/fake", 1, 2)).Times(1);
EXPECT_CALL(platform_, SetPermissions("/fake", 0123)).Times(1);
+ DoMountInit();
EXPECT_TRUE(mount_->CheckChapsDirectory("/fake", "/fake_legacy"));
}
@@ -594,14 +606,12 @@
// Creates a cryptohome and tests credentials.
HomeDirs homedirs;
homedirs.set_shadow_root(kImageDir);
- homedirs.set_platform(&platform_);
- homedirs.set_crypto(mount_->crypto());
TestUser *user = &helper_.users[0];
UsernamePasskey up(user->username, user->passkey);
EXPECT_TRUE(DoMountInit());
- EXPECT_TRUE(homedirs.Init());
+ EXPECT_TRUE(homedirs.Init(&platform_, mount_->crypto()));
// TODO(wad) Make this into a UserDoesntExist() helper.
EXPECT_CALL(platform_, FileExists(user->image_path))
@@ -659,31 +669,34 @@
// Create a Mount instance that points to a good shadow root, test that it
// properly re-authenticates against the first key.
mount_->set_use_tpm(true);
- mount_->crypto()->set_use_tpm(true);
+ crypto_.set_use_tpm(true);
HomeDirs homedirs;
homedirs.set_shadow_root(kImageDir);
- homedirs.set_platform(&platform_);
- homedirs.set_crypto(mount_->crypto());
TestUser *user = &helper_.users[0];
UsernamePasskey up(user->username, user->passkey);
- EXPECT_CALL(tpm_, Init(_, _))
+ EXPECT_CALL(tpm_init_, HasCryptohomeKey())
+ .WillOnce(Return(false))
.WillRepeatedly(Return(true));
+ EXPECT_CALL(tpm_init_, SetupTpm(true))
+ .WillOnce(Return(true)) // This is by crypto.Init() and
+ .WillOnce(Return(true)); // because we forced HasCryptohomeKey to false once
+ crypto_.Init(&tpm_init_);
+
EXPECT_CALL(tpm_, IsEnabled())
.WillRepeatedly(Return(true));
EXPECT_CALL(tpm_, IsOwned())
.WillRepeatedly(Return(true));
- EXPECT_CALL(tpm_, IsConnected())
- .WillRepeatedly(Return(true));
EXPECT_TRUE(DoMountInit());
- EXPECT_TRUE(homedirs.Init());
+ EXPECT_TRUE(homedirs.Init(&platform_, mount_->crypto()));
// Load the pre-generated keyset
std::string key_path = mount_->GetUserLegacyKeyFileForUser(
up.GetObfuscatedUsername(helper_.system_salt), 0);
+ EXPECT_TRUE(key_path.size() > 0);
cryptohome::SerializedVaultKeyset serialized;
EXPECT_TRUE(serialized.ParseFromArray(
static_cast<const unsigned char*>(&user->credentials[0]),
@@ -728,11 +741,11 @@
.WillOnce(Return(true));
// Create the "TPM-wrapped" value by letting it save the plaintext.
- EXPECT_CALL(tpm_, Encrypt(_, _, _, _))
+ EXPECT_CALL(tpm_, EncryptBlob(_, _, _, _, _, _))
.WillRepeatedly(Invoke(TpmPassthroughEncrypt));
chromeos::SecureBlob fake_pub_key("A", 1);
- EXPECT_CALL(tpm_, GetPublicKeyHash(_))
- .WillRepeatedly(DoAll(SetArgumentPointee<0>(fake_pub_key),
+ EXPECT_CALL(tpm_, GetPublicKeyHash(_, _, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<2>(fake_pub_key),
Return(Tpm::RetryNone)));
chromeos::Blob migrated_keyset;
@@ -771,7 +784,7 @@
EXPECT_CALL(platform_, ReadFile(user->salt_path, _))
.WillRepeatedly(DoAll(SetArgumentPointee<1>(user->user_salt),
Return(true)));
- EXPECT_CALL(tpm_, Decrypt(_, _, _, _))
+ EXPECT_CALL(tpm_, DecryptBlob(_, _, _, _, _, _))
.WillRepeatedly(Invoke(TpmPassthroughDecrypt));
MockFileEnumerator* files = new MockFileEnumerator();
diff --git a/platform.cc b/platform.cc
index 6586c8f..a86897b 100644
--- a/platform.cc
+++ b/platform.cc
@@ -261,7 +261,7 @@
FilePath fd_dirpath = pid_path.Append("fd");
base::FileEnumerator fd_dir_enum(fd_dirpath, false,
- base::FileEnumerator::FILES);
+ base::FileEnumerator::FILES);
std::set<std::string> open_files;
// List open file descriptors
@@ -316,7 +316,7 @@
FilePath fd_dirpath = pid_path.Append("fd");
base::FileEnumerator fd_dir_enum(fd_dirpath, false,
- base::FileEnumerator::FILES);
+ base::FileEnumerator::FILES);
// List open file descriptors
for (FilePath fd_path = fd_dir_enum.Next();
diff --git a/service.cc b/service.cc
index efafa88..375baba 100644
--- a/service.cc
+++ b/service.cc
@@ -245,7 +245,7 @@
platform_(default_platform_.get()),
crypto_(new Crypto(platform_)),
tpm_(Tpm::GetSingleton()),
- default_tpm_init_(new TpmInit(platform_)),
+ default_tpm_init_(new TpmInit(tpm_, platform_)),
tpm_init_(default_tpm_init_.get()),
default_pkcs11_init_(new Pkcs11Init()),
pkcs11_init_(default_pkcs11_init_.get()),
@@ -446,11 +446,10 @@
chromeos_metrics::TimerReporter::set_metrics_lib(&metrics_lib_);
crypto_->set_use_tpm(use_tpm_);
- if (!crypto_->Init())
+ if (!crypto_->Init(tpm_init_))
return false;
- homedirs_->set_crypto(crypto_);
- if (!homedirs_->Init())
+ if (!homedirs_->Init(platform_, crypto_))
return false;
// If the TPM is unowned or doesn't exist, it's safe for
@@ -464,12 +463,11 @@
// Pass in all the shared dependencies here rather than
// needing to always get the Attestation object to set them
// during testing.
- attestation_->Initialize(tpm_, platform_, crypto_, install_attrs_);
+ attestation_->Initialize(tpm_, tpm_init_, platform_, crypto_, install_attrs_);
// TODO(wad) Determine if this should only be called if
// tpm->IsEnabled() is true.
if (tpm_ && initialize_tpm_) {
- tpm_init_->set_tpm(tpm_);
tpm_init_->Init(this);
if (!SeedUrandom()) {
LOG(ERROR) << "FAILED TO SEED /dev/urandom AT START";
@@ -568,7 +566,7 @@
}
// Init can fail without making the interface inconsistent so we're okay here.
- install_attrs_->Init();
+ install_attrs_->Init(tpm_init_);
// Check if the machine is enterprise owned and report to mount_ then.
DetectEnterpriseOwnership();
@@ -612,7 +610,7 @@
bool Service::SeedUrandom() {
SecureBlob random;
- if (!tpm_init_->GetRandomData(kDefaultRandomSeedLength, &random)) {
+ if (!tpm_->GetRandomData(kDefaultRandomSeedLength, &random)) {
LOG(ERROR) << "Could not get random data from the TPM";
return false;
}
@@ -2059,7 +2057,7 @@
if (!tpm_init_->HasInitializeBeenCalled()) {
timer_collection_->UpdateTimer(TimerCollection::kTpmTakeOwnershipTimer,
true);
- tpm_init_->StartInitializeTpm();
+ tpm_init_->AsyncInitializeTpm();
}
return TRUE;
}
@@ -2666,7 +2664,26 @@
for (MountMap::iterator it = mounts_.begin(); it != mounts_.end(); it++)
mounts->Append(it->second->GetStatus());
base::Value* attrs = install_attrs_->GetStatus();
- base::Value* tpm = tpm_->GetStatusValue(tpm_init_);
+
+ Tpm::TpmStatusInfo tpm_status_info;
+ tpm_->GetStatus(tpm_init_->GetCryptohomeContext(),
+ tpm_init_->GetCryptohomeKey(),
+ &tpm_status_info);
+ base::DictionaryValue* tpm = new base::DictionaryValue();
+ tpm->SetBoolean("can_connect", tpm_status_info.CanConnect);
+ tpm->SetBoolean("can_load_srk", tpm_status_info.CanLoadSrk);
+ tpm->SetBoolean("can_load_srk_pubkey", tpm_status_info.CanLoadSrkPublicKey);
+ tpm->SetBoolean("has_cryptohome_key", tpm_status_info.HasCryptohomeKey);
+ tpm->SetBoolean("can_encrypt", tpm_status_info.CanEncrypt);
+ tpm->SetBoolean("can_decrypt", tpm_status_info.CanDecrypt);
+ tpm->SetBoolean("has_context", tpm_status_info.ThisInstanceHasContext);
+ tpm->SetBoolean("has_key_handle", tpm_status_info.ThisInstanceHasKeyHandle);
+ tpm->SetInteger("last_error", tpm_status_info.LastTpmError);
+
+ tpm->SetBoolean("enabled", tpm_->IsEnabled());
+ tpm->SetBoolean("owned", tpm_->IsOwned());
+ tpm->SetBoolean("being_owned", tpm_->IsBeingOwned());
+
dv.Set("mounts", mounts);
dv.Set("installattrs", attrs);
dv.Set("tpm", tpm);
@@ -2720,7 +2737,7 @@
mounts_lock_.Acquire();
if (mounts_.count(username) == 0U) {
m = mount_factory_->New();
- m->Init();
+ m->Init(platform_, crypto_);
m->set_enterprise_owned(enterprise_owned_);
m->set_legacy_mount(legacy_mount_);
mounts_[username] = m;
diff --git a/service.h b/service.h
index 99c1d19..509379a 100644
--- a/service.h
+++ b/service.h
@@ -19,6 +19,7 @@
#include <metrics/metrics_library.h>
#include <metrics/timer.h>
+#include "attestation.h"
#include "cryptohome_event_source.h"
#include "dbus_transition.h"
#include "install_attributes.h"
diff --git a/service_unittest.cc b/service_unittest.cc
index c15d963..6f3cc70 100644
--- a/service_unittest.cc
+++ b/service_unittest.cc
@@ -93,8 +93,6 @@
TEST_F(ServiceInterfaceTest, CheckKeySuccessTest) {
MockHomeDirs homedirs;
scoped_refptr<MockMount> mount = new MockMount();
- EXPECT_CALL(homedirs, Init())
- .WillOnce(Return(true));
EXPECT_CALL(homedirs, FreeDiskSpace())
.WillOnce(Return(true));
EXPECT_CALL(*mount, AreSameUser(_))
@@ -114,6 +112,9 @@
service.set_platform(&platform);
service.set_chaps_client(&chaps);
service.set_initialize_tpm(false);
+ EXPECT_CALL(homedirs, Init(&platform, service.crypto()))
+ .WillOnce(Return(true));
+
service.Initialize();
gboolean out = FALSE;
GError *error = NULL;
@@ -131,8 +132,6 @@
void SetUp() {
mount_ = new MockMount();
- EXPECT_CALL(homedirs_, Init())
- .WillOnce(Return(true));
EXPECT_CALL(homedirs_, FreeDiskSpace())
.WillOnce(Return(true));
@@ -144,6 +143,8 @@
service_.set_platform(&platform_);
service_.set_chaps_client(&chaps_);
service_.set_initialize_tpm(false);
+ EXPECT_CALL(homedirs_, Init(&platform_, service_.crypto()))
+ .WillOnce(Return(true));
service_.Initialize();
}
void TearDown() {
@@ -285,9 +286,6 @@
user->InjectKeyset(&platform);
HomeDirs homedirs;
- homedirs.crypto()->set_tpm(&tpm);
- homedirs.crypto()->set_use_tpm(false);
- homedirs.crypto()->set_platform(&platform);
homedirs.set_shadow_root(kImageDir);
homedirs.set_platform(&platform);
homedirs.set_policy_provider(new policy::PolicyProvider(
@@ -405,13 +403,15 @@
MockHomeDirs homedirs;
Service service;
service.set_homedirs(&homedirs);
+ NiceMock<MockPlatform> platform;
+ service.set_platform(&platform);
NiceMock<MockInstallAttributes> attrs;
service.set_install_attrs(&attrs);
service.set_initialize_tpm(false);
// Service will schedule periodic clean-ups. Wait a bit and make
// sure that we had at least 3 executed.
- EXPECT_CALL(homedirs, Init())
+ EXPECT_CALL(homedirs, Init(&platform, service.crypto()))
.WillOnce(Return(true));
EXPECT_CALL(homedirs, FreeDiskSpace())
.Times(::testing::AtLeast(3));
@@ -441,9 +441,11 @@
service.set_initialize_tpm(false);
NiceMock<MockAttestation> attest;
service.set_attestation(&attest);
+ NiceMock<MockPlatform> platform;
+ service.set_platform(&platform);
// Service will schedule first cleanup right after its init.
- EXPECT_CALL(homedirs, Init())
+ EXPECT_CALL(homedirs, Init(&platform, service.crypto()))
.WillOnce(Return(true));
EXPECT_CALL(homedirs, FreeDiskSpace())
.Times(1);
@@ -563,7 +565,7 @@
service_.set_mount_factory(&f);
- EXPECT_CALL(homedirs_, Init())
+ EXPECT_CALL(homedirs_, Init(&platform_, service_.crypto()))
.WillOnce(Return(true));
EXPECT_CALL(platform_, GetMountsBySourcePrefix(_, _))
@@ -572,7 +574,7 @@
ASSERT_TRUE(service_.Initialize());
- EXPECT_CALL(*m, Init())
+ EXPECT_CALL(*m, Init(&platform_, service_.crypto()))
.WillOnce(Return(true));
EXPECT_CALL(*m, MountCryptohome(_, _, _))
.WillOnce(Return(true));
@@ -741,7 +743,7 @@
g_error_ = NULL;
// Fast path through Initialize()
- EXPECT_CALL(homedirs_, Init())
+ EXPECT_CALL(homedirs_, Init(&platform_, service_.crypto()))
.WillOnce(Return(true));
// Skip the CleanUpStaleMounts bit.
EXPECT_CALL(platform_, GetMountsBySourcePrefix(_, _))
diff --git a/stub_tpm.h b/stub_tpm.h
index b651efb..617ad95 100644
--- a/stub_tpm.h
+++ b/stub_tpm.h
@@ -4,7 +4,6 @@
#include <stdio.h>
#include <unistd.h>
-#include "platform.h"
#include "tpm.h"
namespace cryptohome {
@@ -15,7 +14,6 @@
virtual ~StubTpm() { }
// See tpm.h for comments
- virtual bool Init(Platform* platform, bool open_key) { return false; }
virtual bool Connect(TpmRetryAction* retry_action) { return false; }
virtual bool IsConnected() { return false; }
virtual bool IsEnabled() const { return false; }
@@ -28,7 +26,6 @@
virtual void Disconnect() { }
virtual bool GetOwnerPassword(
chromeos::Blob* owner_password) { return false; }
- virtual void RemoveOwnerDependency(TpmOwnerDependency dependency) { }
virtual bool Encrypt(const chromeos::SecureBlob& plaintext,
const chromeos::SecureBlob& key,
chromeos::SecureBlob* ciphertext,
diff --git a/tpm.cc b/tpm.cc
index 0dfd04e..ba026b2 100644
--- a/tpm.cc
+++ b/tpm.cc
@@ -21,8 +21,6 @@
#include <trousers/trousers.h>
#include "cryptolib.h"
-#include "platform.h"
-#include "tpm_init.h"
using base::PlatformThread;
using chromeos::SecureBlob;
@@ -59,27 +57,16 @@
const unsigned int kDefaultTpmRsaKeyBits = 2048;
const unsigned int kDefaultTpmRsaKeyFlag = TSS_KEY_SIZE_2048;
const unsigned int kDefaultDiscardableWrapPasswordLength = 32;
-const char kDefaultCryptohomeKeyFile[] = "/home/.shadow/cryptohome.key";
-const TSS_UUID kCryptohomeWellKnownUuid = {0x0203040b, 0, 0, 0, 0,
- {0, 9, 8, 1, 0, 3}};
+
const char* kWellKnownSrkTmp = "1234567890";
-const int kOwnerPasswordLength = 12;
-const int kMaxTimeoutRetries = 5;
-const char* kTpmCheckEnabledFile = "/sys/class/misc/tpm0/device/enabled";
-const char* kTpmCheckOwnedFile = "/sys/class/misc/tpm0/device/owned";
-const char* kTpmOwnedFileOld = "/var/lib/.tpm_owned";
-const char* kTpmStatusFileOld = "/var/lib/.tpm_status";
-const char* kTpmOwnedFile = "/mnt/stateful_partition/.tpm_owned";
-const char* kTpmStatusFile = "/mnt/stateful_partition/.tpm_status";
-const char* kOpenCryptokiPath = "/var/lib/opencryptoki";
const unsigned int kTpmConnectRetries = 10;
const unsigned int kTpmConnectIntervalMs = 100;
-const char kTpmWellKnownPassword[] = TSS_WELL_KNOWN_SECRET;
const unsigned int kTpmBootPCR = 0;
const unsigned int kTpmPCRLocality = 1;
const int kDelegateSecretSize = 20;
const int kDelegateFamilyLabel = 1;
const int kDelegateEntryLabel = 2;
+
// This error is returned when an attempt is made to use the SRK but it does not
// yet exist because the TPM has not been owned.
const TSS_RESULT kKeyNotFoundError = (TSS_E_PS_KEY_NOTFOUND | TSS_LAYER_TCS);
@@ -99,149 +86,16 @@
Tpm::Tpm()
: initialized_(false),
srk_auth_(kDefaultSrkAuth, sizeof(kDefaultSrkAuth)),
- context_handle_(0),
- key_handle_(0),
owner_password_(),
password_sync_lock_(),
is_disabled_(true),
is_owned_(false),
- is_being_owned_(false),
- platform_(NULL) {
-}
-
-Tpm::~Tpm() {
- Disconnect();
-}
-
-bool Tpm::Init(Platform* platform, bool open_key) {
- if (initialized_) {
- return false;
- }
- initialized_ = true;
- DCHECK(platform);
- platform_ = platform;
-
+ is_being_owned_(false) {
metrics_.reset(new MetricsLibrary());
metrics_->Init();
-
- // Migrate any old status files from old location to new location.
- if (!platform_->FileExists(kTpmOwnedFile) &&
- platform_->FileExists(kTpmOwnedFileOld)) {
- platform_->Move(kTpmOwnedFileOld, kTpmOwnedFile);
- }
- if (!platform_->FileExists(kTpmStatusFile) &&
- platform_->FileExists(kTpmStatusFileOld)) {
- platform_->Move(kTpmStatusFileOld, kTpmStatusFile);
- }
-
- // Checking disabled and owned either via sysfs or via TSS calls will block if
- // ownership is being taken by another thread or process. So for this to work
- // well, Tpm::Init() needs to be called before InitializeTpm() is called. At
- // that point, the public API for Tpm only checks these booleans, so other
- // threads can check without being blocked. InitializeTpm() will reset the
- // is_owned_ bit on success.
- bool successful_check = false;
- if (platform_->FileExists(kTpmCheckEnabledFile)) {
- is_disabled_ = IsDisabledCheckViaSysfs();
- is_owned_ = IsOwnedCheckViaSysfs();
- successful_check = true;
- } else {
- TSS_HCONTEXT context_handle;
- TSS_RESULT result;
- if (OpenAndConnectTpm(&context_handle, &result)) {
- bool enabled = false;
- bool owned = false;
- IsEnabledOwnedCheckViaContext(context_handle, &enabled, &owned);
- DisconnectContext(context_handle);
- is_disabled_ = !enabled;
- is_owned_ = owned;
- successful_check = true;
- }
- }
- if (successful_check && !is_owned_) {
- platform_->DeleteFile(kOpenCryptokiPath, true);
- platform_->DeleteFile(kTpmOwnedFile, false);
- platform_->DeleteFile(kTpmStatusFile, false);
- }
- if (successful_check && is_owned_) {
- if (!platform_->FileExists(kTpmOwnedFile)) {
- chromeos::Blob empty_blob(0);
- platform_->WriteFile(kTpmOwnedFile, empty_blob);
- }
- }
- TpmStatus tpm_status;
- if (LoadTpmStatus(&tpm_status)) {
- if (tpm_status.has_owner_password()) {
- SecureBlob local_owner_password;
- if (LoadOwnerPassword(tpm_status, &local_owner_password)) {
- password_sync_lock_.Acquire();
- owner_password_.assign(local_owner_password.begin(),
- local_owner_password.end());
- password_sync_lock_.Release();
- }
- }
- }
-
- if (open_key && key_handle_ == 0) {
- Tpm::TpmRetryAction retry_action;
- return Connect(&retry_action);
- }
-
- return true;
}
-bool Tpm::Connect(TpmRetryAction* retry_action) {
- // TODO(fes): Check the status of enabled, owned, being_owned first.
- *retry_action = Tpm::RetryNone;
- if (key_handle_ == 0) {
- TSS_RESULT result;
- TSS_HCONTEXT context_handle;
- if (!OpenAndConnectTpm(&context_handle, &result)) {
- context_handle_ = 0;
- key_handle_ = 0;
- *retry_action = HandleError(result);
- TPM_LOG(ERROR, result) << "Error connecting to the TPM";
- return false;
- }
-
- TSS_HKEY key_handle;
- if (!LoadOrCreateCryptohomeKey(context_handle, false, &key_handle,
- &result)) {
- context_handle_ = 0;
- key_handle_ = 0;
- *retry_action = HandleError(result);
- Tspi_Context_Close(context_handle);
- if (result == kKeyNotFoundError) {
- TPM_LOG(WARNING, result)
- << "Cannot load / create the cryptohome TPM key. "
- << "This is normal when the TPM is not owned.";
- } else {
- TPM_LOG(ERROR, result) << "Error loading the cryptohome TPM key";
- }
- return false;
- }
-
- key_handle_ = key_handle;
- context_handle_ = context_handle;
- }
-
- return true;
-}
-
-bool Tpm::IsConnected() {
- return (key_handle_ != 0);
-}
-
-void Tpm::Disconnect() {
- if (key_handle_) {
- Tspi_Context_CloseObject(context_handle_, key_handle_);
- key_handle_ = 0;
- }
- if (context_handle_) {
- Tspi_Context_Close(context_handle_);
- context_handle_ = 0;
- }
-}
+Tpm::~Tpm() { }
TSS_HCONTEXT Tpm::ConnectContext() {
TSS_RESULT result;
@@ -253,12 +107,6 @@
return context_handle;
}
-void Tpm::DisconnectContext(TSS_HCONTEXT context_handle) {
- if (context_handle) {
- Tspi_Context_Close(context_handle);
- }
-}
-
bool Tpm::ConnectContextAsOwner(TSS_HCONTEXT* context, TSS_HTPM* tpm) {
*context = 0;
*tpm = 0;
@@ -332,10 +180,12 @@
}
-void Tpm::GetStatus(bool check_crypto, Tpm::TpmStatusInfo* status) {
+void Tpm::GetStatus(TSS_HCONTEXT context,
+ TSS_HKEY key_handle,
+ Tpm::TpmStatusInfo* status) {
memset(status, 0, sizeof(Tpm::TpmStatusInfo));
- status->ThisInstanceHasContext = (context_handle_ != 0);
- status->ThisInstanceHasKeyHandle = (key_handle_ != 0);
+ status->ThisInstanceHasContext = (context != 0);
+ status->ThisInstanceHasKeyHandle = (key_handle != 0);
ScopedTssContext context_handle;
// Check if we can connect
TSS_RESULT result;
@@ -363,15 +213,10 @@
}
status->CanLoadSrkPublicKey = true;
- // Check the Cryptohome key
- ScopedTssKey key_handle(context_handle);
- if (!LoadCryptohomeKey(context_handle, key_handle.ptr(), &result)) {
- status->LastTpmError = result;
- return;
- }
- status->HasCryptohomeKey = true;
+ // Check the Cryptohome key by using what we have been told.
+ status->HasCryptohomeKey = (context != 0) && (key_handle != 0);
- if (check_crypto) {
+ if (status->HasCryptohomeKey) {
// Check encryption (we don't care about the contents, just whether or not
// there was an error)
SecureBlob data(16);
@@ -384,269 +229,21 @@
memset(data_out.data(), 'D', data_out.size());
SecureBlob key;
CryptoLib::PasskeyToAesKey(password, salt, 13, &key, NULL);
- if (!EncryptBlob(context_handle, key_handle, data, key, &data_out,
- &result)) {
- status->LastTpmError = result;
+ TSS_RESULT result;
+ if (!EncryptBlob(context, key_handle, data, key, &data_out, &result)) {
return;
}
status->CanEncrypt = true;
// Check decryption (we don't care about the contents, just whether or not
// there was an error)
- if (!DecryptBlob(context_handle, key_handle, data_out, key, &data,
- &result)) {
- status->LastTpmError = result;
+ if (!DecryptBlob(context, key_handle, data_out, key, &data, &result)) {
return;
}
status->CanDecrypt = true;
}
}
-bool Tpm::CreateCryptohomeKey(TSS_HCONTEXT context_handle, bool create_in_tpm,
- TSS_RESULT* result) {
- *result = TSS_SUCCESS;
-
- // Load the Storage Root Key
- ScopedTssKey srk_handle(context_handle);
- if (!LoadSrk(context_handle, srk_handle.ptr(), result)) {
- if (*result != kKeyNotFoundError) {
- TPM_LOG(INFO, *result) << "CreateCryptohomeKey: Cannot load SRK";
- }
- return false;
- }
-
- // Make sure we can get the public key for the SRK. If not, then the TPM
- // is not available.
- unsigned int size_n;
- ScopedTssMemory public_srk(context_handle);
- if (TPM_ERROR(*result = Tspi_Key_GetPubKey(srk_handle, &size_n,
- public_srk.ptr()))) {
- TPM_LOG(INFO, *result) << "CreateCryptohomeKey: Cannot load SRK pub key";
- return false;
- }
-
- // Create the key object
- TSS_FLAG init_flags = TSS_KEY_TYPE_LEGACY | TSS_KEY_VOLATILE;
- if (!create_in_tpm) {
- init_flags |= TSS_KEY_MIGRATABLE;
- init_flags |= kDefaultTpmRsaKeyFlag;
- }
- ScopedTssKey local_key_handle(context_handle);
- if (TPM_ERROR(*result = Tspi_Context_CreateObject(context_handle,
- TSS_OBJECT_TYPE_RSAKEY,
- init_flags,
- local_key_handle.ptr()))) {
- TPM_LOG(ERROR, *result) << "Error calling Tspi_Context_CreateObject";
- return false;
- }
-
- // Set the attributes
- UINT32 sig_scheme = TSS_SS_RSASSAPKCS1V15_DER;
- if (TPM_ERROR(*result = Tspi_SetAttribUint32(local_key_handle,
- TSS_TSPATTRIB_KEY_INFO,
- TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
- sig_scheme))) {
- TPM_LOG(ERROR, *result) << "Error calling Tspi_SetAttribUint32";
- return false;
- }
-
- UINT32 enc_scheme = TSS_ES_RSAESPKCSV15;
- if (TPM_ERROR(*result = Tspi_SetAttribUint32(local_key_handle,
- TSS_TSPATTRIB_KEY_INFO,
- TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
- enc_scheme))) {
- TPM_LOG(ERROR, *result) << "Error calling Tspi_SetAttribUint32";
- return false;
- }
-
- // Create a new system-wide key for cryptohome
- if (create_in_tpm) {
- if (TPM_ERROR(*result = Tspi_Key_CreateKey(local_key_handle,
- srk_handle,
- 0))) {
- TPM_LOG(ERROR, *result) << "Error calling Tspi_Key_CreateKey";
- return false;
- }
- } else {
- ScopedTssPolicy policy_handle(context_handle);
- if (TPM_ERROR(*result = Tspi_Context_CreateObject(context_handle,
- TSS_OBJECT_TYPE_POLICY,
- TSS_POLICY_MIGRATION,
- policy_handle.ptr()))) {
- TPM_LOG(ERROR, *result) << "Error creating policy object";
- return false;
- }
-
- // Set a random migration policy password, and discard it. The key will not
- // be migrated, but to create the key outside of the TPM, we have to do it
- // this way.
- SecureBlob migration_password(kDefaultDiscardableWrapPasswordLength);
- CryptoLib::GetSecureRandom(
- static_cast<unsigned char*>(migration_password.data()),
- migration_password.size());
- if (TPM_ERROR(*result = Tspi_Policy_SetSecret(policy_handle,
- TSS_SECRET_MODE_PLAIN,
- migration_password.size(),
- static_cast<BYTE*>(migration_password.data())))) {
- TPM_LOG(ERROR, *result) << "Error setting migration policy password";
- return false;
- }
-
- if (TPM_ERROR(*result = Tspi_Policy_AssignToObject(policy_handle,
- local_key_handle))) {
- TPM_LOG(ERROR, *result) << "Error assigning migration policy";
- return false;
- }
-
- SecureBlob n;
- SecureBlob p;
- if (!CryptoLib::CreateRsaKey(kDefaultTpmRsaKeyBits, &n, &p)) {
- LOG(ERROR) << "Error creating RSA key";
- return false;
- }
-
- if (TPM_ERROR(*result = Tspi_SetAttribData(local_key_handle,
- TSS_TSPATTRIB_RSAKEY_INFO,
- TSS_TSPATTRIB_KEYINFO_RSA_MODULUS,
- n.size(),
- static_cast<BYTE *>(n.data())))) {
- TPM_LOG(ERROR, *result) << "Error setting RSA modulus";
- return false;
- }
-
- if (TPM_ERROR(*result = Tspi_SetAttribData(local_key_handle,
- TSS_TSPATTRIB_KEY_BLOB,
- TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY,
- p.size(),
- static_cast<BYTE *>(p.data())))) {
- TPM_LOG(ERROR, *result) << "Error setting private key";
- return false;
- }
-
- if (TPM_ERROR(*result = Tspi_Key_WrapKey(local_key_handle,
- srk_handle,
- 0))) {
- TPM_LOG(ERROR, *result) << "Error wrapping RSA key";
- return false;
- }
- }
-
- if (!SaveCryptohomeKey(context_handle, local_key_handle, result)) {
- LOG(ERROR) << "Couldn't save cryptohome key";
- return false;
- }
-
- LOG(INFO) << "Created new cryptohome key.";
- return true;
-}
-
-bool Tpm::LoadCryptohomeKey(TSS_HCONTEXT context_handle,
- TSS_HKEY* key_handle, TSS_RESULT* result) {
- // Load the Storage Root Key
- ScopedTssKey srk_handle(context_handle);
- if (!LoadSrk(context_handle, srk_handle.ptr(), result)) {
- if (*result != kKeyNotFoundError) {
- TPM_LOG(INFO, *result) << "LoadCryptohomeKey: Cannot load SRK";
- }
- return false;
- }
-
- // Make sure we can get the public key for the SRK. If not, then the TPM
- // is not available.
- unsigned int size_n;
- ScopedTssMemory public_srk(context_handle);
- if (TPM_ERROR(*result = Tspi_Key_GetPubKey(srk_handle, &size_n,
- public_srk.ptr()))) {
- TPM_LOG(INFO, *result) << "LoadCryptohomeKey: Cannot load SRK public key";
- return false;
- }
-
- // First, try loading the key from the key file
- SecureBlob raw_key;
- if (platform_->ReadFile(kDefaultCryptohomeKeyFile, &raw_key)) {
- if (TPM_ERROR(*result = Tspi_Context_LoadKeyByBlob(
- context_handle,
- srk_handle,
- raw_key.size(),
- vector_as_array(&raw_key),
- key_handle))) {
- // If the error is expected to be transient, return now.
- if (IsTransient(*result)) {
- TPM_LOG(INFO, *result) << "LoadCryptohomeKey: Cannot load key " \
- << "from blob";
- return false;
- }
- } else {
- SecureBlob pub_key;
- // Make sure that we can get the public key
- if (GetPublicKeyBlob(context_handle, *key_handle, &pub_key, result)) {
- return true;
- }
- // Otherwise, close the key and fall through
- Tspi_Context_CloseObject(context_handle, *key_handle);
- if (IsTransient(*result)) {
- TPM_LOG(INFO, *result) << "LoadCryptohomeKey: closed object";
- return false;
- }
- }
- }
-
- // Then try loading the key by the UUID (this is a legacy upgrade path)
- if (TPM_ERROR(*result = Tspi_Context_LoadKeyByUUID(context_handle,
- TSS_PS_TYPE_SYSTEM,
- kCryptohomeWellKnownUuid,
- key_handle))) {
- // If the error is expected to be transient, return now.
- if (IsTransient(*result)) {
- TPM_LOG(INFO, *result) << "LoadCryptohomeKey: failed LoadKeyByUUID";
- return false;
- }
- } else {
- SecureBlob pub_key;
- // Make sure that we can get the public key
- if (GetPublicKeyBlob(context_handle, *key_handle, &pub_key, result)) {
- // Save the cryptohome key to the well-known location
- if (!SaveCryptohomeKey(context_handle, *key_handle, result)) {
- LOG(ERROR) << "Couldn't save cryptohome key";
- Tspi_Context_CloseObject(context_handle, *key_handle);
- return false;
- }
- return true;
- }
- Tspi_Context_CloseObject(context_handle, *key_handle);
- }
-
- TPM_LOG(INFO, *result) << "LoadCryptohomeKey: could not load key";
- return false;
-}
-
-bool Tpm::LoadOrCreateCryptohomeKey(TSS_HCONTEXT context_handle,
- bool create_in_tpm,
- TSS_HKEY* key_handle,
- TSS_RESULT* result) {
- *result = TSS_SUCCESS;
-
- // Try to load the cryptohome key.
- if (LoadCryptohomeKey(context_handle, key_handle, result)) {
- return true;
- }
-
- // If the error is expected to be transient, return now.
- if (IsTransient(*result)) {
- TPM_LOG(INFO, *result) << "Transient failure loading cryptohome key";
- return false;
- }
-
- // Otherwise, the key couldn't be loaded, and it wasn't due to a transient
- // error, so we must create the key.
- if (CreateCryptohomeKey(context_handle, create_in_tpm, result)) {
- if (LoadCryptohomeKey(context_handle, key_handle, result)) {
- return true;
- }
- }
- return false;
-}
-
bool Tpm::IsTransient(TSS_RESULT result) {
bool transient = false;
switch (ERROR_CODE(result)) {
@@ -669,18 +266,15 @@
switch (ERROR_CODE(result)) {
case ERROR_CODE(TSS_E_COMM_FAILURE):
LOG(ERROR) << "Communications failure with the TPM.";
- Disconnect();
status = Tpm::RetryCommFailure;
break;
case ERROR_CODE(TSS_E_INVALID_HANDLE):
LOG(ERROR) << "Invalid handle to the TPM.";
- Disconnect();
status = Tpm::RetryCommFailure;
break;
// TODO(fes): We're considering this a communication failure for now.
case ERROR_CODE(TCS_E_KM_LOADFAILED):
LOG(ERROR) << "Key load failed; problem with parent key authorization.";
- Disconnect();
status = Tpm::RetryCommFailure;
break;
case ERROR_CODE(TPM_E_DEFEND_LOCK_RUNNING):
@@ -704,23 +298,6 @@
return status;
}
-bool Tpm::SaveCryptohomeKey(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
- TSS_RESULT* result) {
- *result = TSS_SUCCESS;
-
- SecureBlob raw_key;
- if (!GetKeyBlob(context_handle, key_handle, &raw_key, result)) {
- LOG(ERROR) << "Error getting key blob";
- return false;
- }
- int previous_mask = platform_->SetMask(cryptohome::kDefaultUmask);
- bool ok = platform_->WriteFile(kDefaultCryptohomeKeyFile, raw_key);
- platform_->SetMask(previous_mask);
- if (!ok)
- LOG(ERROR) << "Error writing key file of desired size: " << raw_key.size();
- return ok;
-}
-
bool Tpm::OpenAndConnectTpm(TSS_HCONTEXT* context_handle, TSS_RESULT* result) {
TSS_RESULT local_result;
ScopedTssContext local_context_handle;
@@ -764,54 +341,12 @@
return (*context_handle != 0);
}
-bool Tpm::Encrypt(const SecureBlob& plaintext,
- const SecureBlob& key,
- SecureBlob* ciphertext,
- Tpm::TpmRetryAction* retry_action) {
- *retry_action = Tpm::RetryNone;
- if (!IsConnected()) {
- if (!Connect(retry_action)) {
- return false;
- }
- }
-
- TSS_RESULT result = TSS_SUCCESS;
- if (!EncryptBlob(context_handle_, key_handle_, plaintext, key, ciphertext,
- &result)) {
- *retry_action = HandleError(result);
- return false;
- }
- return true;
-}
-
-bool Tpm::Decrypt(const SecureBlob& ciphertext,
- const SecureBlob& key,
- SecureBlob* plaintext,
- Tpm::TpmRetryAction* retry_action) {
- *retry_action = Tpm::RetryNone;
- if (!IsConnected()) {
- if (!Connect(retry_action)) {
- return false;
- }
- }
-
- TSS_RESULT result = TSS_SUCCESS;
- if (!DecryptBlob(context_handle_, key_handle_, ciphertext, key, plaintext,
- &result)) {
- *retry_action = HandleError(result);
- return false;
- }
- return true;
-}
-
-Tpm::TpmRetryAction Tpm::GetPublicKeyHash(SecureBlob* hash) {
- TpmRetryAction ret = Tpm::RetryNone;
- if (!IsConnected() && !Connect(&ret))
- return ret;
-
+Tpm::TpmRetryAction Tpm::GetPublicKeyHash(TSS_HCONTEXT context_handle,
+ TSS_HKEY key_handle,
+ SecureBlob* hash) {
TSS_RESULT result = TSS_SUCCESS;
SecureBlob pubkey;
- if (!GetPublicKeyBlob(context_handle_, key_handle_, &pubkey, &result)) {
+ if (!GetPublicKeyBlob(context_handle, key_handle, &pubkey, &result)) {
return HandleError(result);
}
@@ -980,28 +515,8 @@
return true;
}
-bool Tpm::GetKeyBlob(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
- SecureBlob* data_out, TSS_RESULT* result) {
- *result = TSS_SUCCESS;
-
- ScopedTssMemory blob(context_handle);
- UINT32 blob_size;
- if (TPM_ERROR(*result = Tspi_GetAttribData(key_handle, TSS_TSPATTRIB_KEY_BLOB,
- TSS_TSPATTRIB_KEYBLOB_BLOB,
- &blob_size, blob.ptr()))) {
- TPM_LOG(ERROR, *result) << "Couldn't get key blob";
- return false;
- }
-
- SecureBlob local_data(blob_size);
- memcpy(local_data.data(), blob.value(), blob_size);
- chromeos::SecureMemset(blob.value(), 0, blob_size);
- data_out->swap(local_data);
- return true;
-}
-
bool Tpm::GetPublicKeyBlob(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
- SecureBlob* data_out, TSS_RESULT* result) {
+ SecureBlob* data_out, TSS_RESULT* result) const {
*result = TSS_SUCCESS;
ScopedTssMemory blob(context_handle);
@@ -1020,7 +535,7 @@
}
bool Tpm::LoadSrk(TSS_HCONTEXT context_handle, TSS_HKEY* srk_handle,
- TSS_RESULT* result) {
+ TSS_RESULT* result) const {
*result = TSS_SUCCESS;
// Load the Storage Root Key
@@ -1051,10 +566,8 @@
return false;
}
- *result = Tspi_Policy_SetSecret(srk_usage_policy,
- TSS_SECRET_MODE_PLAIN,
- srk_auth_.size(),
- vector_as_array(&srk_auth_));
+ *result = Tspi_Policy_SetSecret(srk_usage_policy, TSS_SECRET_MODE_PLAIN,
+ srk_auth_.size(), const_cast<BYTE*>(vector_as_array(&srk_auth_)));
if (TPM_ERROR(*result)) {
return false;
}
@@ -1064,55 +577,6 @@
return true;
}
-bool Tpm::IsDisabledCheckViaSysfs() {
- std::string contents;
- if (!platform_->ReadFileToString(kTpmCheckEnabledFile, &contents)) {
- return false;
- }
- if (contents.size() < 1) {
- return false;
- }
- return (contents[0] == '0');
-}
-
-bool Tpm::IsOwnedCheckViaSysfs() {
- std::string contents;
- if (!platform_->ReadFileToString(kTpmCheckOwnedFile, &contents)) {
- return false;
- }
- if (contents.size() < 1) {
- return false;
- }
- return (contents[0] != '0');
-}
-
-void Tpm::IsEnabledOwnedCheckViaContext(TSS_HCONTEXT context_handle,
- bool* enabled, bool* owned) {
- *enabled = false;
- *owned = false;
-
- TSS_RESULT result;
- TSS_HTPM tpm_handle;
- if (!GetTpm(context_handle, &tpm_handle)) {
- return;
- }
-
- UINT32 sub_cap = TSS_TPMCAP_PROP_OWNER;
- UINT32 cap_length = 0;
- ScopedTssMemory cap(context_handle);
- if (TPM_ERROR(result = Tspi_TPM_GetCapability(tpm_handle, TSS_TPMCAP_PROPERTY,
- sizeof(sub_cap),
- reinterpret_cast<BYTE*>(&sub_cap),
- &cap_length, cap.ptr())) == 0) {
- if (cap_length >= (sizeof(TSS_BOOL))) {
- *enabled = true;
- *owned = ((*(reinterpret_cast<TSS_BOOL*>(cap.value()))) != 0);
- }
- } else if (ERROR_CODE(result) == TPM_E_DISABLED) {
- *enabled = false;
- }
-}
-
bool Tpm::CreateEndorsementKey(TSS_HCONTEXT context_handle) {
TSS_RESULT result;
TSS_HTPM tpm_handle;
@@ -1157,19 +621,6 @@
return true;
}
-void Tpm::CreateOwnerPassword(SecureBlob* password) {
- // Generate a random owner password. The default is a 12-character,
- // hex-encoded password created from 6 bytes of random data.
- SecureBlob random(kOwnerPasswordLength / 2);
- CryptoLib::GetSecureRandom(static_cast<unsigned char*>(random.data()),
- random.size());
- SecureBlob tpm_password(kOwnerPasswordLength);
- CryptoLib::AsciiEncodeToBuffer(random,
- static_cast<char*>(tpm_password.data()),
- tpm_password.size());
- password->swap(tpm_password);
-}
-
bool Tpm::TakeOwnership(TSS_HCONTEXT context_handle, int max_timeout_tries,
const SecureBlob& owner_password) {
TSS_RESULT result;
@@ -1330,49 +781,6 @@
return true;
}
-bool Tpm::LoadOwnerPassword(const TpmStatus& tpm_status,
- chromeos::Blob* owner_password) {
- if (!(tpm_status.flags() & TpmStatus::OWNED_BY_THIS_INSTALL)) {
- return false;
- }
- if ((tpm_status.flags() & TpmStatus::USES_WELL_KNOWN_OWNER)) {
- SecureBlob default_owner_password(sizeof(kTpmWellKnownPassword));
- memcpy(default_owner_password.data(), kTpmWellKnownPassword,
- sizeof(kTpmWellKnownPassword));
- owner_password->swap(default_owner_password);
- return true;
- }
- if (!(tpm_status.flags() & TpmStatus::USES_RANDOM_OWNER) ||
- !tpm_status.has_owner_password()) {
- return false;
- }
-
- SecureBlob local_owner_password(tpm_status.owner_password().length());
- tpm_status.owner_password().copy(
- static_cast<char*>(local_owner_password.data()),
- tpm_status.owner_password().length(), 0);
- if (!Unseal(local_owner_password, owner_password)) {
- LOG(ERROR) << "Failed to unseal the owner password.";
- return false;
- }
- return true;
-}
-
-bool Tpm::StoreOwnerPassword(const chromeos::Blob& owner_password,
- TpmStatus* tpm_status) {
- // Use PCR0 when sealing the data so that the owner password is only
- // available in the current boot mode. This helps protect the password from
- // offline attacks until it has been presented and cleared.
- SecureBlob sealed_password;
- if (!SealToPCR0(owner_password, &sealed_password)) {
- LOG(ERROR) << "StoreOwnerPassword: Failed to seal owner password.";
- return false;
- }
- tpm_status->set_owner_password(sealed_password.data(),
- sealed_password.size());
- return true;
-}
-
bool Tpm::GetTpm(TSS_HCONTEXT context_handle, TSS_HTPM* tpm_handle) {
TSS_RESULT result;
TSS_HTPM local_tpm_handle;
@@ -1481,140 +889,6 @@
return result;
}
-bool Tpm::InitializeTpm(bool* OUT_took_ownership) {
- TpmStatus tpm_status;
-
- if (!LoadTpmStatus(&tpm_status)) {
- tpm_status.Clear();
- tpm_status.set_flags(TpmStatus::NONE);
- }
-
- if (OUT_took_ownership) {
- *OUT_took_ownership = false;
- }
-
- if (is_disabled_) {
- return false;
- }
-
- ScopedTssContext context_handle;
- if (!(*(context_handle.ptr()) = ConnectContext())) {
- LOG(ERROR) << "Failed to connect to TPM";
- return false;
- }
-
- SecureBlob default_owner_password(sizeof(kTpmWellKnownPassword));
- memcpy(default_owner_password.data(), kTpmWellKnownPassword,
- sizeof(kTpmWellKnownPassword));
-
- bool took_ownership = false;
- if (!is_owned_) {
- is_being_owned_ = true;
- platform_->DeleteFile(kOpenCryptokiPath, true);
- platform_->DeleteFile(kTpmOwnedFile, false);
- platform_->DeleteFile(kTpmStatusFile, false);
-
- if (!IsEndorsementKeyAvailable(context_handle)) {
- if (!CreateEndorsementKey(context_handle)) {
- LOG(ERROR) << "Failed to create endorsement key";
- is_being_owned_ = false;
- return false;
- }
- }
-
- if (!IsEndorsementKeyAvailable(context_handle)) {
- LOG(ERROR) << "Endorsement key is not available";
- is_being_owned_ = false;
- return false;
- }
-
- if (!TakeOwnership(context_handle, kMaxTimeoutRetries,
- default_owner_password)) {
- LOG(ERROR) << "Take Ownership failed";
- is_being_owned_ = false;
- return false;
- }
-
- is_owned_ = true;
- took_ownership = true;
-
- tpm_status.set_flags(TpmStatus::OWNED_BY_THIS_INSTALL |
- TpmStatus::USES_WELL_KNOWN_OWNER |
- TpmStatus::INSTALL_ATTRIBUTES_NEEDS_OWNER |
- TpmStatus::ATTESTATION_NEEDS_OWNER);
- tpm_status.clear_owner_password();
- StoreTpmStatus(tpm_status);
- }
-
- if (OUT_took_ownership) {
- *OUT_took_ownership = took_ownership;
- }
-
- // Ensure the SRK is available
- TSS_RESULT result;
- TSS_HKEY srk_handle;
- TSS_UUID SRK_UUID = TSS_UUID_SRK;
- if (TPM_ERROR(result = Tspi_Context_LoadKeyByUUID(context_handle,
- TSS_PS_TYPE_SYSTEM,
- SRK_UUID,
- &srk_handle))) {
- } else {
- Tspi_Context_CloseObject(context_handle, srk_handle);
- }
-
- // If we can open the TPM with the default password, then we still need to
- // zero the SRK password and unrestrict it, then change the owner password.
- TSS_HTPM tpm_handle;
- if (!platform_->FileExists(kTpmOwnedFile) &&
- GetTpmWithAuth(context_handle, default_owner_password, &tpm_handle) &&
- TestTpmAuth(tpm_handle)) {
- if (!ZeroSrkPassword(context_handle, default_owner_password)) {
- LOG(ERROR) << "Couldn't zero SRK password";
- is_being_owned_ = false;
- return false;
- }
-
- if (!UnrestrictSrk(context_handle, default_owner_password)) {
- LOG(ERROR) << "Couldn't unrestrict the SRK";
- is_being_owned_ = false;
- return false;
- }
-
- SecureBlob owner_password;
- CreateOwnerPassword(&owner_password);
-
- tpm_status.set_flags(TpmStatus::OWNED_BY_THIS_INSTALL |
- TpmStatus::USES_RANDOM_OWNER |
- TpmStatus::INSTALL_ATTRIBUTES_NEEDS_OWNER |
- TpmStatus::ATTESTATION_NEEDS_OWNER);
- if (!StoreOwnerPassword(owner_password, &tpm_status)) {
- tpm_status.clear_owner_password();
- }
- StoreTpmStatus(tpm_status);
-
- if ((result = ChangeOwnerPassword(context_handle, default_owner_password,
- owner_password))) {
- password_sync_lock_.Acquire();
- owner_password_.assign(owner_password.begin(), owner_password.end());
- password_sync_lock_.Release();
- }
- chromeos::Blob empty_blob(0);
- platform_->WriteFile(kTpmOwnedFile, empty_blob);
- } else {
- // If we fall through here, then the TPM owned file doesn't exist, but we
- // couldn't auth with the well-known password. In this case, we must assume
- // that the TPM has already been owned and set to a random password, so
- // touch the TPM owned file.
- if (!platform_->FileExists(kTpmOwnedFile)) {
- chromeos::Blob empty_blob(0);
- platform_->WriteFile(kTpmOwnedFile, empty_blob);
- }
- }
-
- is_being_owned_ = false;
- return true;
-}
-
bool Tpm::GetRandomData(size_t length, chromeos::Blob* data) {
ScopedTssContext context_handle;
if ((*(context_handle.ptr()) = ConnectContext()) == 0) {
@@ -2008,116 +1282,43 @@
return true;
}
-void Tpm::ClearStoredOwnerPassword() {
- TpmStatus tpm_status;
- if (LoadTpmStatus(&tpm_status)) {
- int32 dependency_flags = TpmStatus::INSTALL_ATTRIBUTES_NEEDS_OWNER |
- TpmStatus::ATTESTATION_NEEDS_OWNER;
- if (tpm_status.flags() & dependency_flags) {
- // The password is still needed, do not clear.
- return;
- }
- if (tpm_status.has_owner_password()) {
- tpm_status.clear_owner_password();
- StoreTpmStatus(tpm_status);
- }
- }
- password_sync_lock_.Acquire();
- owner_password_.resize(0);
- password_sync_lock_.Release();
-}
+bool Tpm::PerformEnabledOwnedCheck(bool* enabled, bool* owned) {
+ *enabled = false;
+ *owned = false;
-void Tpm::RemoveOwnerDependency(TpmOwnerDependency dependency) {
- int32 flag_to_clear = TpmStatus::NONE;
- switch (dependency) {
- case kInstallAttributes:
- flag_to_clear = TpmStatus::INSTALL_ATTRIBUTES_NEEDS_OWNER;
- break;
- case kAttestation:
- flag_to_clear = TpmStatus::ATTESTATION_NEEDS_OWNER;
- break;
- default:
- CHECK(false);
+ trousers::ScopedTssContext context(ConnectContext());
+ if (!context) {
+ return false;
}
- TpmStatus tpm_status;
- if (!LoadTpmStatus(&tpm_status))
- return;
- tpm_status.set_flags(tpm_status.flags() & ~flag_to_clear);
- StoreTpmStatus(tpm_status);
-}
-bool Tpm::LoadTpmStatus(TpmStatus* serialized) {
- if (!platform_->FileExists(kTpmStatusFile)) {
+ TSS_HCONTEXT context_handle = context.context();
+ TSS_RESULT result;
+ TSS_HTPM tpm_handle;
+
+ if (TPM_ERROR(result = Tspi_Context_GetTpmObject(context_handle,
+ &tpm_handle))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_GetTpmObject";
return false;
}
- SecureBlob file_data;
- if (!platform_->ReadFile(kTpmStatusFile, &file_data)) {
- return false;
+
+ UINT32 sub_cap = TSS_TPMCAP_PROP_OWNER;
+ UINT32 cap_length = 0;
+ trousers::ScopedTssMemory cap(context_handle);
+ if (TPM_ERROR(result = Tspi_TPM_GetCapability(tpm_handle, TSS_TPMCAP_PROPERTY,
+ sizeof(sub_cap),
+ reinterpret_cast<BYTE*>(&sub_cap),
+ &cap_length, cap.ptr())) == 0) {
+ if (cap_length >= (sizeof(TSS_BOOL))) {
+ *enabled = true;
+ *owned = ((*(reinterpret_cast<TSS_BOOL*>(cap.value()))) != 0);
+ }
+ } else if (ERROR_CODE(result) == TPM_E_DISABLED) {
+ *enabled = false;
}
- if (!serialized->ParseFromArray(
- static_cast<const unsigned char*>(file_data.data()),
- file_data.size())) {
- return false;
- }
+
return true;
}
-bool Tpm::StoreTpmStatus(const TpmStatus& serialized) {
- int old_mask = platform_->SetMask(kDefaultUmask);
- if (platform_->FileExists(kTpmStatusFile)) {
- do {
- int64 file_size;
- if (!platform_->GetFileSize(kTpmStatusFile, &file_size)) {
- break;
- }
- SecureBlob random;
- if (!GetRandomData(file_size, &random)) {
- break;
- }
- FILE* file = platform_->OpenFile(kTpmStatusFile, "wb+");
- if (!file) {
- break;
- }
- if (!platform_->WriteOpenFile(file, random)) {
- platform_->CloseFile(file);
- break;
- }
- platform_->CloseFile(file);
- } while (false);
- platform_->DeleteFile(kTpmStatusFile, false);
- }
- SecureBlob final_blob(serialized.ByteSize());
- serialized.SerializeWithCachedSizesToArray(
- static_cast<google::protobuf::uint8*>(final_blob.data()));
- bool ok = platform_->WriteFile(kTpmStatusFile, final_blob);
- platform_->SetMask(old_mask);
- return ok;
-}
-
-base::Value* Tpm::GetStatusValue(TpmInit* init) {
- base::DictionaryValue* dv = new base::DictionaryValue();
- TpmStatusInfo status;
- GetStatus(true, &status);
-
- dv->SetBoolean("can_connect", status.CanConnect);
- dv->SetBoolean("can_load_srk", status.CanLoadSrk);
- dv->SetBoolean("can_load_srk_pubkey", status.CanLoadSrkPublicKey);
- dv->SetBoolean("has_cryptohome_key", status.HasCryptohomeKey);
- dv->SetBoolean("can_encrypt", status.CanEncrypt);
- dv->SetBoolean("can_decrypt", status.CanDecrypt);
- dv->SetBoolean("has_context", status.ThisInstanceHasContext);
- dv->SetBoolean("has_key_handle", status.ThisInstanceHasKeyHandle);
- dv->SetInteger("last_error", status.LastTpmError);
-
- if (init) {
- dv->SetBoolean("enabled", init->IsTpmEnabled());
- dv->SetBoolean("owned", init->IsTpmOwned());
- dv->SetBoolean("being_owned", init->IsTpmBeingOwned());
- }
-
- return dv;
-}
-
bool Tpm::GetEndorsementPublicKey(SecureBlob* ek_public_key) {
// Connect to the TPM as the owner.
ScopedTssContext context_handle;
@@ -3363,7 +2564,7 @@
TSS_HOBJECT object,
TSS_FLAG flag,
TSS_FLAG sub_flag,
- SecureBlob* data) {
+ SecureBlob* data) const {
UINT32 length = 0;
ScopedTssMemory buf(context);
TSS_RESULT result = Tspi_GetAttribData(object, flag, sub_flag, &length,
@@ -3378,4 +2579,215 @@
return true;
}
+void Tpm::SetOwnerPassword(const chromeos::SecureBlob& owner_password) {
+ base::AutoLock lock(password_sync_lock_);
+ owner_password_.assign(owner_password.begin(), owner_password.end());
+}
+
+bool Tpm::CreateWrappedRsaKey(TSS_HCONTEXT context_handle,
+ SecureBlob* wrapped_key) {
+ TSS_RESULT result;
+
+ // Load the Storage Root Key
+ trousers::ScopedTssKey srk_handle(context_handle);
+ if (!LoadSrk(context_handle, srk_handle.ptr(), &result)) {
+ if (result != kKeyNotFoundError) {
+ TPM_LOG(INFO, result) << "CreateWrappedRsaKey: Cannot load SRK";
+ }
+ return false;
+ }
+
+ // Make sure we can get the public key for the SRK. If not, then the TPM
+ // is not available.
+ unsigned int size_n;
+ trousers::ScopedTssMemory public_srk(context_handle);
+ if (TPM_ERROR(result = Tspi_Key_GetPubKey(srk_handle, &size_n,
+ public_srk.ptr()))) {
+ TPM_LOG(INFO, result) << "CreateWrappedRsaKey: Cannot load SRK pub key";
+ return false;
+ }
+
+ // Create the key object
+ TSS_FLAG init_flags = TSS_KEY_TYPE_LEGACY | TSS_KEY_VOLATILE | \
+ TSS_KEY_MIGRATABLE | kDefaultTpmRsaKeyFlag;
+ trousers::ScopedTssKey local_key_handle(context_handle);
+ if (TPM_ERROR(result = Tspi_Context_CreateObject(context_handle,
+ TSS_OBJECT_TYPE_RSAKEY,
+ init_flags,
+ local_key_handle.ptr()))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
+ return false;
+ }
+
+ // Set the attributes
+ UINT32 sig_scheme = TSS_SS_RSASSAPKCS1V15_DER;
+ if (TPM_ERROR(result = Tspi_SetAttribUint32(local_key_handle,
+ TSS_TSPATTRIB_KEY_INFO,
+ TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
+ sig_scheme))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_SetAttribUint32";
+ return false;
+ }
+
+ UINT32 enc_scheme = TSS_ES_RSAESPKCSV15;
+ if (TPM_ERROR(result = Tspi_SetAttribUint32(local_key_handle,
+ TSS_TSPATTRIB_KEY_INFO,
+ TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
+ enc_scheme))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_SetAttribUint32";
+ return false;
+ }
+
+ trousers::ScopedTssPolicy policy_handle(context_handle);
+ if (TPM_ERROR(result = Tspi_Context_CreateObject(context_handle,
+ TSS_OBJECT_TYPE_POLICY,
+ TSS_POLICY_MIGRATION,
+ policy_handle.ptr()))) {
+ TPM_LOG(ERROR, result) << "Error creating policy object";
+ return false;
+ }
+
+ // Set a random migration policy password, and discard it. The key will not
+ // be migrated, but to create the key outside of the TPM, we have to do it
+ // this way.
+ SecureBlob migration_password(kDefaultDiscardableWrapPasswordLength);
+ CryptoLib::GetSecureRandom(
+ static_cast<unsigned char*>(migration_password.data()),
+ migration_password.size());
+ if (TPM_ERROR(result = Tspi_Policy_SetSecret(policy_handle,
+ TSS_SECRET_MODE_PLAIN,
+ migration_password.size(),
+ static_cast<BYTE*>(migration_password.data())))) {
+ TPM_LOG(ERROR, result) << "Error setting migration policy password";
+ return false;
+ }
+
+ if (TPM_ERROR(result = Tspi_Policy_AssignToObject(policy_handle,
+ local_key_handle))) {
+ TPM_LOG(ERROR, result) << "Error assigning migration policy";
+ return false;
+ }
+
+ SecureBlob n;
+ SecureBlob p;
+ if (!CryptoLib::CreateRsaKey(kDefaultTpmRsaKeyBits, &n, &p)) {
+ LOG(ERROR) << "Error creating RSA key";
+ return false;
+ }
+
+ if (TPM_ERROR(result = Tspi_SetAttribData(local_key_handle,
+ TSS_TSPATTRIB_RSAKEY_INFO,
+ TSS_TSPATTRIB_KEYINFO_RSA_MODULUS,
+ n.size(),
+ static_cast<BYTE *>(n.data())))) {
+ TPM_LOG(ERROR, result) << "Error setting RSA modulus";
+ return false;
+ }
+
+ if (TPM_ERROR(result = Tspi_SetAttribData(local_key_handle,
+ TSS_TSPATTRIB_KEY_BLOB,
+ TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY,
+ p.size(),
+ static_cast<BYTE *>(p.data())))) {
+ TPM_LOG(ERROR, result) << "Error setting private key";
+ return false;
+ }
+
+ if (TPM_ERROR(result = Tspi_Key_WrapKey(local_key_handle,
+ srk_handle,
+ 0))) {
+ TPM_LOG(ERROR, result) << "Error wrapping RSA key";
+ return false;
+ }
+
+ if (!GetKeyBlob(context_handle, local_key_handle, wrapped_key, &result)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool Tpm::GetKeyBlob(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
+ SecureBlob* data_out, TSS_RESULT* result) const {
+ *result = TSS_SUCCESS;
+
+ if (!GetDataAttribute(context_handle, key_handle, TSS_TSPATTRIB_KEY_BLOB,
+ TSS_TSPATTRIB_KEYBLOB_BLOB, data_out)) {
+ LOG(ERROR) << __func__ << ": Failed to get key blob.";
+ return false;
+ }
+
+ return true;
+}
+
+bool Tpm::LoadWrappedKey(TSS_HCONTEXT context_handle,
+ const chromeos::SecureBlob& wrapped_key,
+ TSS_HKEY* key_handle,
+ TSS_RESULT* result) const {
+ // Load the Storage Root Key
+ trousers::ScopedTssKey srk_handle(context_handle);
+ if (!LoadSrk(context_handle, srk_handle.ptr(), result)) {
+ if (*result != kKeyNotFoundError) {
+ TPM_LOG(INFO, *result) << "LoadWrappedKey: Cannot load SRK";
+ }
+ return false;
+ }
+
+ // Make sure we can get the public key for the SRK. If not, then the TPM
+ // is not available.
+ {
+ SecureBlob pubkey;
+ if (!GetPublicKeyBlob(context_handle, srk_handle, &pubkey, result)) {
+ TPM_LOG(INFO, *result) << "LoadWrappedKey: Cannot load SRK public key";
+ return false;
+ }
+ }
+
+ if (TPM_ERROR(*result = Tspi_Context_LoadKeyByBlob(
+ context_handle,
+ srk_handle,
+ wrapped_key.size(),
+ const_cast<BYTE*>(static_cast<const BYTE*>(
+ wrapped_key.const_data())),
+ key_handle))) {
+ TPM_LOG(INFO, *result) << "LoadWrappedKey: Cannot load key " \
+ << "from blob";
+ return false;
+ }
+
+ SecureBlob pub_key;
+ // Make sure that we can get the public key
+ if (!GetPublicKeyBlob(context_handle, *key_handle, &pub_key, result)) {
+ Tspi_Context_CloseObject(context_handle, *key_handle);
+ return false;
+ }
+
+ return true;
+}
+
+bool Tpm::LoadKeyByUuid(TSS_HCONTEXT context_handle,
+ TSS_UUID key_uuid,
+ TSS_HKEY* key_handle,
+ chromeos::SecureBlob* key_blob,
+ TSS_RESULT* result) const {
+ if (TPM_ERROR(*result = Tspi_Context_LoadKeyByUUID(context_handle,
+ TSS_PS_TYPE_SYSTEM,
+ key_uuid,
+ key_handle))) {
+ TPM_LOG(INFO, *result) << "LoadKeyByUuid: failed LoadKeyByUUID";
+ return false;
+ }
+
+ if (key_blob && !GetKeyBlob(context_handle, *key_handle, key_blob, result)) {
+ Tspi_Context_CloseObject(context_handle, *key_handle);
+ return false;
+ }
+
+ return true;
+}
+
+void Tpm::CloseContext(TSS_HCONTEXT context) const {
+ Tspi_Context_Close(context);
+}
+
} // namespace cryptohome
diff --git a/tpm.h b/tpm.h
index e0ab80a..981db4d 100644
--- a/tpm.h
+++ b/tpm.h
@@ -12,7 +12,6 @@
#include <base/logging.h>
#include <base/memory/scoped_ptr.h>
#include <base/synchronization/lock.h>
-#include <base/values.h>
#include <chromeos/secure_blob.h>
#include <chromeos/utility.h>
#include <metrics/metrics_library.h>
@@ -20,7 +19,6 @@
#include <trousers/tss.h>
#include <trousers/trousers.h>
-#include "platform.h"
#include "tpm_status.pb.h"
#ifndef CRYPTOHOME_TPM_H_
@@ -28,10 +26,6 @@
namespace cryptohome {
-class TpmInit;
-
-extern const TSS_UUID kCryptohomeWellKnownUuid;
-
class Tpm {
public:
enum TpmRetryAction {
@@ -42,11 +36,6 @@
RetryReboot
};
- enum TpmOwnerDependency {
- kInstallAttributes,
- kAttestation
- };
-
struct TpmStatusInfo {
TSS_RESULT LastTpmError;
bool CanConnect;
@@ -63,53 +52,42 @@
virtual ~Tpm();
- // Initializes the Tpm instance
+ // Encrypts a data blob using the provided RSA key
//
// Parameters
- // crypto - The Crypto instance to use (for generating an RSA key, entropy,
- // etc.)
- // open_key - Whether or not to open (load) the cryptohome TPM key
- virtual bool Init(Platform* platform, bool open_key);
-
- // Tries to connect to the TPM
- virtual bool Connect(TpmRetryAction* retry_action);
-
- // Returns true if this instance is connected to the TPM
- virtual bool IsConnected();
-
- // Disconnects from the TPM
- virtual void Disconnect();
-
- // Encrypts a data blob using the TPM cryptohome RSA key
- //
- // Parameters
+ // context_handle - The TPM context
+ // key_handle - The loaded TPM key handle
// plaintext - One RSA message to encrypt
// key - AES key to encrypt with
- // ciphertext
- virtual bool Encrypt(const chromeos::SecureBlob& plaintext,
- const chromeos::SecureBlob& key,
- chromeos::SecureBlob* ciphertext,
- TpmRetryAction* retry_action);
+ // ciphertext (OUT) - Encrypted blob
+ // result (OUT) - TPM error code
+ virtual bool EncryptBlob(TSS_HCONTEXT context_handle,
+ TSS_HKEY key_handle,
+ const chromeos::SecureBlob& plaintext,
+ const chromeos::SecureBlob& key,
+ chromeos::SecureBlob* ciphertext,
+ TSS_RESULT* result);
- // Decrypts a data blob using the TPM cryptohome RSA key
+ // Decrypts a data blob using the provided RSA key
//
// Parameters
- // ciphertext - One RSA message to decrypt
- // key - AES key to decrypt with
- // plaintext
- virtual bool Decrypt(const chromeos::SecureBlob& ciphertext,
- const chromeos::SecureBlob& key,
- chromeos::SecureBlob* plaintext,
- TpmRetryAction* retry_action);
+ // context_handle - The TPM context
+ // key_handle - The loaded TPM key handle
+ // ciphertext - One RSA message to encrypt
+ // key - AES key to encrypt with
+ // plaintext (OUT) - Decrypted blob
+ // result (OUT) - TPM error code
+ virtual bool DecryptBlob(TSS_HCONTEXT context_handle,
+ TSS_HKEY key_handle,
+ const chromeos::SecureBlob& ciphertext,
+ const chromeos::SecureBlob& key,
+ chromeos::SecureBlob* plaintext,
+ TSS_RESULT* result);
- // Retrieves the sha1sum of the public key component of the cryptohome RSA key
- virtual TpmRetryAction GetPublicKeyHash(chromeos::SecureBlob* hash);
-
- // Gets the TPM status information as a Value.
- //
- // Parameters
- // init - If non-NULL, overrides some of the status values
- base::Value* GetStatusValue(TpmInit* init);
+ // Retrieves the sha1sum of the public key component of the RSA key
+ virtual TpmRetryAction GetPublicKeyHash(TSS_HCONTEXT context_handle,
+ TSS_HKEY key_handle,
+ chromeos::SecureBlob* hash);
// Returns the owner password if this instance was used to take ownership.
// This will only occur when the TPM is unowned, which will be on OOBE
@@ -118,25 +96,40 @@
// owner_password (OUT) - The random owner password used
virtual bool GetOwnerPassword(chromeos::Blob* owner_password);
- // Clears the owner password from storage if no dependencies exist.
- void ClearStoredOwnerPassword();
-
- // Removes the given owner dependency. When all dependencies have been removed
- // the owner password can be cleared.
- virtual void RemoveOwnerDependency(TpmOwnerDependency dependency);
// Returns whether or not the TPM is enabled. This method call returns a
// cached result because querying the TPM directly will block if ownership is
// currently being taken (such as on a separate thread).
virtual bool IsEnabled() const { return !is_disabled_; }
+ virtual void SetIsEnabled(bool enabled) { is_disabled_ = !enabled; }
// Returns whether or not the TPM is owned. This method call returns a cached
// result because querying the TPM directly will block if ownership is
// currently being taken (such as on a separate thread).
virtual bool IsOwned() const { return is_owned_; }
+ virtual void SetIsOwned(bool owned) { is_owned_ = owned; }
+
+ // Returns whether or not the TPM is enabled and owned using a call to
+ // Tspi_TPM_GetCapability.
+ //
+ // Unlike former functions, this function performs the check (which could take
+ // some time) every time it is invoked. It does not use cached value.
+ //
+ // Parameters
+ // enabled (OUT) - Whether the TPM is enabled
+ // owned (OUT) - Whether the TPM is owned
+ //
+ // Returns true if the check was successfully carried out.
+ bool PerformEnabledOwnedCheck(bool* enabled, bool* owned);
+
+ // Returns whether or not this instance has been setup'd by an external
+ // entity (such as cryptohome::TpmInit).
+ virtual bool IsInitialized() const { return initialized_; }
+ virtual void SetIsInitialized(bool done) { initialized_ = done; }
// Returns whether or not the TPM is being owned
virtual bool IsBeingOwned() const { return is_being_owned_; }
+ virtual void SetIsBeingOwned(bool value) { is_being_owned_ = value; }
// Runs the TPM initialization sequence. This may take a long time due to the
// call to Tspi_TPM_TakeOwnership.
@@ -397,148 +390,14 @@
// Extends the PCR given by |pcr_index| using a SHA-1 hash of |extension|.
virtual bool ExtendPCR(int pcr_index, const chromeos::SecureBlob& extension);
- protected:
- // Default constructor
- Tpm();
-
- private:
- // Gets the TPM status information
- //
- // Parameters
- // check_crypto - Whether to check if encrypt/decrypt works (may take
- // longer)
- // status (OUT) - The TpmStatusInfo structure containing the results
- void GetStatus(bool check_crypto, Tpm::TpmStatusInfo* status);
-
- bool IsTransient(TSS_RESULT result);
-
- TpmRetryAction HandleError(TSS_RESULT result);
-
- bool SaveCryptohomeKey(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
- TSS_RESULT* result);
-
bool OpenAndConnectTpm(TSS_HCONTEXT* context_handle, TSS_RESULT* result);
- // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
- // its matching TPM object iff the owner password is available and
- // authorization is successfully acquired.
- bool ConnectContextAsOwner(TSS_HCONTEXT* context_handle,
- TSS_HTPM* tpm_handle);
-
- // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
- // its matching TPM object authorized by the given delegation.
- bool ConnectContextAsDelegate(const chromeos::SecureBlob& delegate_blob,
- const chromeos::SecureBlob& delegate_secret,
- TSS_HCONTEXT* context, TSS_HTPM* tpm);
-
- // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
- // its matching TPM object iff the context can be created and a TPM object
- // exists in the TSS.
- bool ConnectContextAsUser(TSS_HCONTEXT* context_handle,
- TSS_HTPM* tpm_handle);
-
- bool CreateCryptohomeKey(TSS_HCONTEXT context_handle,
- bool create_in_tpm, TSS_RESULT* result);
-
- bool LoadCryptohomeKey(TSS_HCONTEXT context_handle, TSS_HKEY* key_handle,
- TSS_RESULT* result);
-
- bool LoadOrCreateCryptohomeKey(TSS_HCONTEXT context_handle,
- bool create_in_tpm,
- TSS_HKEY* key_handle,
- TSS_RESULT* result);
-
- bool EncryptBlob(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
- const chromeos::SecureBlob& plaintext,
- const chromeos::SecureBlob& key,
- chromeos::SecureBlob* ciphertext, TSS_RESULT* result);
-
- bool DecryptBlob(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
- const chromeos::SecureBlob& ciphertext,
- const chromeos::SecureBlob& key,
- chromeos::SecureBlob* plaintext, TSS_RESULT* result);
-
- bool GetKeyBlob(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
- chromeos::SecureBlob* data_out, TSS_RESULT* result);
-
- bool GetPublicKeyBlob(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
- chromeos::SecureBlob* data_out, TSS_RESULT* result);
-
// Tries to connect to the TPM
virtual TSS_HCONTEXT ConnectContext();
- // Disconnects from the TPM
- virtual void DisconnectContext(TSS_HCONTEXT context_handle);
-
- // Gets a handle to the SRK
- bool LoadSrk(TSS_HCONTEXT context_handle, TSS_HKEY* srk_handle,
- TSS_RESULT* result);
-
- // Stores the TPM owner password to the TpmStatus object
- bool StoreOwnerPassword(const chromeos::Blob& owner_password,
- TpmStatus* tpm_status);
-
- // Retrieves the TPM owner password
- bool LoadOwnerPassword(const TpmStatus& tpm_status,
- chromeos::Blob* owner_password);
-
- // Loads the TpmStatus object
- bool LoadTpmStatus(TpmStatus* serialized);
-
- // Saves the TpmStatus object
- bool StoreTpmStatus(const TpmStatus& serialized);
-
- // Returns the size of the specified NVRAM space.
- //
- // Parameters
- // context_handle - The context handle for the TPM session
- // index - NVRAM Space index
- // Returns -1 if the index, handle, or space is invalid.
- unsigned int GetNvramSizeForContext(TSS_HCONTEXT context_handle,
- TSS_HTPM tpm_handle,
- uint32_t index);
-
- // Returns if an Nvram space exists using the given context.
- bool IsNvramDefinedForContext(TSS_HCONTEXT context_handle,
- TSS_HTPM tpm_handle,
- uint32_t index);
-
- // Returns if bWriteDefine is true for a given NVRAM space using the given
- // context.
- bool IsNvramLockedForContext(TSS_HCONTEXT context_handle,
- TSS_HTPM tpm_handle,
- uint32_t index);
-
- // Reads an NVRAM space using the given context.
- bool ReadNvramForContext(TSS_HCONTEXT context_handle,
- TSS_HTPM tpm_handle,
- TSS_HPOLICY policy_handle,
- uint32_t index,
- chromeos::SecureBlob* blob);
-
- // Returns whether or not the TPM is disabled by checking a flag in the TPM's
- // entry in /sys/class/misc
- bool IsDisabledCheckViaSysfs();
-
- // Returns whether or not the TPM is owned by checking a flag in the TPM's
- // entry in /sys/class/misc
- bool IsOwnedCheckViaSysfs();
-
- // Returns whether or not the TPM is enabled and owned using a call to
- // Tspi_TPM_GetCapability
- //
- // Parameters
- // context_handle - The context handle for the TPM session
- // enabled (OUT) - Whether the TPM is enabled
- // owned (OUT) - Whether the TPM is owned
- void IsEnabledOwnedCheckViaContext(TSS_HCONTEXT context_handle,
- bool* enabled, bool* owned);
-
- // Attempts to create the endorsement key in the TPM
- //
- // Parameters
- // context_handle - The context handle for the TPM session
- bool CreateEndorsementKey(TSS_HCONTEXT context_handle);
+ // Frees up the context. This is different from Disconnect() method. This
+ // version does not touch on resources owned by this TPM instance.
+ virtual void CloseContext(TSS_HCONTEXT context_handle) const;
// Checks to see if the endorsement key is available by attempting to get its
// public key
@@ -547,11 +406,11 @@
// context_handle - The context handle for the TPM session
bool IsEndorsementKeyAvailable(TSS_HCONTEXT context_handle);
- // Creates a random owner password
+ // Attempts to create the endorsement key in the TPM
//
// Parameters
- // password (OUT) - the generated password
- void CreateOwnerPassword(chromeos::SecureBlob* password);
+ // context_handle - The context handle for the TPM session
+ bool CreateEndorsementKey(TSS_HCONTEXT context_handle);
// Attempts to take ownership of the TPM
//
@@ -588,13 +447,6 @@
const chromeos::SecureBlob& previous_owner_password,
const chromeos::SecureBlob& owner_password);
- // Gets a handle to the TPM from the specified context
- //
- // Parameters
- // context_handle - The context handle for the TPM session
- // tpm_handle (OUT) - The handle for the TPM on success
- bool GetTpm(TSS_HCONTEXT context_handle, TSS_HTPM* tpm_handle);
-
// Gets a handle to the TPM from the specified context with the given owner
// password
//
@@ -606,6 +458,137 @@
const chromeos::SecureBlob& owner_password,
TSS_HTPM* tpm_handle);
+ // Test the TPM auth by calling Tspi_TPM_GetStatus
+ //
+ // Parameters
+ // tpm_handle = The TPM handle
+ bool TestTpmAuth(TSS_HTPM tpm_handle);
+
+ // Sets the TPM owner password to be used in subsequent commands
+ //
+ // Parameters
+ // owner_password - The owner password for the TPM
+ void SetOwnerPassword(const chromeos::SecureBlob& owner_password);
+
+ // Gets a handle to the SRK
+ bool LoadSrk(TSS_HCONTEXT context_handle, TSS_HKEY* srk_handle,
+ TSS_RESULT* result) const;
+
+ bool IsTransient(TSS_RESULT result);
+
+ bool GetPublicKeyBlob(TSS_HCONTEXT context_handle,
+ TSS_HKEY key_handle,
+ chromeos::SecureBlob* data_out,
+ TSS_RESULT* result) const;
+
+ bool GetKeyBlob(TSS_HCONTEXT context_handle, TSS_HKEY key_handle,
+ chromeos::SecureBlob* data_out, TSS_RESULT* result) const;
+
+ // Creates an RSA key wrapped by the TPM's Storage Root Key. The key is
+ // created by OpenSSL, and not by the TPM.
+ //
+ // Parameters
+ // context_handle - The context handle for the TPM session
+ // wrapped_key (OUT) - A blob representing the wrapped key
+ bool CreateWrappedRsaKey(TSS_HCONTEXT context_handle,
+ chromeos::SecureBlob* wrapped_key);
+
+ // Loads an SRK-wrapped key into the TPM.
+ //
+ // Parameters
+ // context_handle - The context handle for the TPM session.
+ // wrapped_key - The blob (as produced by CreateWrappedRsaKey).
+ // key_handle (OUT) - A handle to the key loaded into the TPM.
+ bool LoadWrappedKey(TSS_HCONTEXT context_handle,
+ const chromeos::SecureBlob& wrapped_key,
+ TSS_HKEY* key_handle,
+ TSS_RESULT* result) const;
+
+ // Loads a key by well-known UUID.
+ //
+ // Parameters
+ // context_handle - The context handle for the TPM session.
+ // key_uuid - The well-known UUID identifying the TPM key.
+ // key_handle (OUT) - A handle to the key loaded into the TPM.
+ // key_blob (OUT) - If non-null, the blob representing this loaded key.
+ bool LoadKeyByUuid(TSS_HCONTEXT context_handle,
+ TSS_UUID key_uuid,
+ TSS_HKEY* key_handle,
+ chromeos::SecureBlob* key_blob,
+ TSS_RESULT* result) const;
+
+ TpmRetryAction HandleError(TSS_RESULT result);
+
+ // Gets the TPM status information. If there |context| and |key| are supplied,
+ // they will be used in encryption/decryption test. They can be 0 to bypass
+ // the test.
+ //
+ // Parameters
+ // context - The TPM context to check for encryption/decryption
+ // key - The key to check for encryption/decryption
+ // status (OUT) - The TpmStatusInfo structure containing the results
+ void GetStatus(TSS_HCONTEXT context,
+ TSS_HKEY key,
+ Tpm::TpmStatusInfo* status);
+
+ protected:
+ // Default constructor
+ Tpm();
+
+ private:
+ // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
+ // its matching TPM object iff the owner password is available and
+ // authorization is successfully acquired.
+ bool ConnectContextAsOwner(TSS_HCONTEXT* context_handle,
+ TSS_HTPM* tpm_handle);
+
+ // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
+ // its matching TPM object authorized by the given delegation.
+ bool ConnectContextAsDelegate(const chromeos::SecureBlob& delegate_blob,
+ const chromeos::SecureBlob& delegate_secret,
+ TSS_HCONTEXT* context, TSS_HTPM* tpm);
+
+ // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
+ // its matching TPM object iff the context can be created and a TPM object
+ // exists in the TSS.
+ bool ConnectContextAsUser(TSS_HCONTEXT* context_handle,
+ TSS_HTPM* tpm_handle);
+
+ // Returns the size of the specified NVRAM space.
+ //
+ // Parameters
+ // context_handle - The context handle for the TPM session
+ // index - NVRAM Space index
+ // Returns -1 if the index, handle, or space is invalid.
+ unsigned int GetNvramSizeForContext(TSS_HCONTEXT context_handle,
+ TSS_HTPM tpm_handle,
+ uint32_t index);
+
+ // Returns if an Nvram space exists using the given context.
+ bool IsNvramDefinedForContext(TSS_HCONTEXT context_handle,
+ TSS_HTPM tpm_handle,
+ uint32_t index);
+
+ // Returns if bWriteDefine is true for a given NVRAM space using the given
+ // context.
+ bool IsNvramLockedForContext(TSS_HCONTEXT context_handle,
+ TSS_HTPM tpm_handle,
+ uint32_t index);
+
+ // Reads an NVRAM space using the given context.
+ bool ReadNvramForContext(TSS_HCONTEXT context_handle,
+ TSS_HTPM tpm_handle,
+ TSS_HPOLICY policy_handle,
+ uint32_t index,
+ chromeos::SecureBlob* blob);
+
+ // Gets a handle to the TPM from the specified context
+ //
+ // Parameters
+ // context_handle - The context handle for the TPM session
+ // tpm_handle (OUT) - The handle for the TPM on success
+ bool GetTpm(TSS_HCONTEXT context_handle, TSS_HTPM* tpm_handle);
+
// Gets a handle to the TPM from the specified context with the given
// delegation.
//
@@ -619,12 +602,6 @@
const chromeos::SecureBlob& delegate_secret,
TSS_HTPM* tpm_handle);
- // Test the TPM auth by calling Tspi_TPM_GetStatus
- //
- // Parameters
- // tpm_handle = The TPM handle
- bool TestTpmAuth(TSS_HTPM tpm_handle);
-
// Decrypts and parses an identity request.
//
// Parameters
@@ -675,13 +652,11 @@
TSS_HOBJECT object,
TSS_FLAG flag,
TSS_FLAG sub_flag,
- chromeos::SecureBlob* data);
+ chromeos::SecureBlob* data) const;
// Member variables
bool initialized_;
chromeos::SecureBlob srk_auth_;
- TSS_HCONTEXT context_handle_;
- TSS_HKEY key_handle_;
// If TPM ownership is taken, owner_password_ contains the password used
chromeos::SecureBlob owner_password_;
@@ -702,7 +677,6 @@
static Tpm* singleton_;
static base::Lock singleton_lock_;
- Platform* platform_;
scoped_ptr<MetricsLibraryInterface> metrics_;
DISALLOW_COPY_AND_ASSIGN(Tpm);
diff --git a/tpm_init.cc b/tpm_init.cc
index 7cd03f4..ff830f3 100644
--- a/tpm_init.cc
+++ b/tpm_init.cc
@@ -9,22 +9,41 @@
#include <base/logging.h>
#include <base/threading/platform_thread.h>
#include <base/time/time.h>
+#include <trousers/scoped_tss_type.h>
#include "attestation.h"
+#include "cryptolib.h"
+#include "interface.h"
using base::PlatformThread;
using base::PlatformThreadHandle;
+using chromeos::SecureBlob;
namespace cryptohome {
+const int kMaxTimeoutRetries = 5;
+
+const char* kTpmCheckEnabledFile = "/sys/class/misc/tpm0/device/enabled";
+const char* kTpmCheckOwnedFile = "/sys/class/misc/tpm0/device/owned";
+const char* kTpmOwnedFileOld = "/var/lib/.tpm_owned";
+const char* kTpmStatusFileOld = "/var/lib/.tpm_status";
+const char* kTpmOwnedFile = "/mnt/stateful_partition/.tpm_owned";
+const char* kTpmStatusFile = "/mnt/stateful_partition/.tpm_status";
+const char* kOpenCryptokiPath = "/var/lib/opencryptoki";
+const char kDefaultCryptohomeKeyFile[] = "/home/.shadow/cryptohome.key";
+
+const int kOwnerPasswordLength = 12;
+const char kTpmWellKnownPassword[] = TSS_WELL_KNOWN_SECRET;
+const TSS_UUID kCryptohomeWellKnownUuid = {0x0203040b, 0, 0, 0, 0,
+ {0, 9, 8, 1, 0, 3}};
+
// TpmInitTask is a private class used to handle asynchronous initialization of
// the TPM.
class TpmInitTask : public PlatformThread::Delegate {
public:
- explicit TpmInitTask(Platform* platform)
+ explicit TpmInitTask()
: tpm_(NULL),
- init_(NULL),
- platform_(platform) {
+ init_(NULL) {
}
virtual ~TpmInitTask() {
@@ -32,8 +51,9 @@
void Init(TpmInit* init) {
init_ = init;
- if (tpm_)
- tpm_->Init(platform_, false);
+ if (tpm_) {
+ init->SetupTpm(false);
+ }
}
virtual void ThreadMain() {
@@ -53,16 +73,18 @@
private:
Tpm* tpm_;
TpmInit* init_;
- Platform* platform_;
};
-TpmInit::TpmInit(Platform* platform)
- : tpm_init_task_(new TpmInitTask(platform)),
+TpmInit::TpmInit(Tpm* tpm, Platform* platform)
+ : tpm_init_task_(new TpmInitTask()),
notify_callback_(NULL),
initialize_called_(false),
initialize_took_ownership_(false),
initialization_time_(0),
- platform_(platform) {
+ platform_(platform),
+ cryptohome_context_(0),
+ cryptohome_key_(0, 0) {
+ set_tpm(tpm);
}
TpmInit::~TpmInit() {
@@ -90,11 +112,7 @@
tpm_init_task_->Init(this);
}
-bool TpmInit::GetRandomData(int length, chromeos::Blob* data) {
- return tpm_init_task_->get_tpm()->GetRandomData(length, data);
-}
-
-bool TpmInit::StartInitializeTpm() {
+bool TpmInit::AsyncInitializeTpm() {
initialize_called_ = true;
if (!PlatformThread::Create(0, tpm_init_task_.get(), &init_thread_)) {
LOG(ERROR) << "Unable to create TPM initialization background thread.";
@@ -118,10 +136,18 @@
return tpm_init_task_->get_tpm()->IsOwned();
}
+void TpmInit::SetTpmOwned(bool owned) {
+ tpm_init_task_->get_tpm()->SetIsOwned(owned);
+}
+
bool TpmInit::IsTpmBeingOwned() {
return tpm_init_task_->get_tpm()->IsBeingOwned();
}
+void TpmInit::SetTpmBeingOwned(bool being_owned) {
+ tpm_init_task_->get_tpm()->SetIsBeingOwned(being_owned);
+}
+
bool TpmInit::HasInitializeBeenCalled() {
return initialize_called_;
}
@@ -131,12 +157,26 @@
}
void TpmInit::ClearStoredTpmPassword() {
- tpm_init_task_->get_tpm()->ClearStoredOwnerPassword();
+ TpmStatus tpm_status;
+ if (LoadTpmStatus(&tpm_status)) {
+ int32 dependency_flags = TpmStatus::INSTALL_ATTRIBUTES_NEEDS_OWNER |
+ TpmStatus::ATTESTATION_NEEDS_OWNER;
+ if (tpm_status.flags() & dependency_flags) {
+ // The password is still needed, do not clear.
+ return;
+ }
+ if (tpm_status.has_owner_password()) {
+ tpm_status.clear_owner_password();
+ StoreTpmStatus(tpm_status);
+ }
+ }
+ SecureBlob empty;
+ get_tpm()->SetOwnerPassword(empty);
}
void TpmInit::ThreadMain() {
base::TimeTicks start = base::TimeTicks::Now();
- bool initialize_result = tpm_init_task_->get_tpm()->InitializeTpm(
+ bool initialize_result = InitializeTpm(
&initialize_took_ownership_);
base::TimeDelta delta = (base::TimeTicks::Now() - start);
initialization_time_ = delta.InMilliseconds();
@@ -149,4 +189,455 @@
}
}
+void TpmInit::MigrateStatusFiles() {
+ if (!platform_->FileExists(kTpmOwnedFile) &&
+ platform_->FileExists(kTpmOwnedFileOld)) {
+ platform_->Move(kTpmOwnedFileOld, kTpmOwnedFile);
+ }
+ if (!platform_->FileExists(kTpmStatusFile) &&
+ platform_->FileExists(kTpmStatusFileOld)) {
+ platform_->Move(kTpmStatusFileOld, kTpmStatusFile);
+ }
+}
+
+bool TpmInit::SetupTpm(bool load_key) {
+ if (get_tpm()->IsInitialized()) {
+ return false;
+ }
+ get_tpm()->SetIsInitialized(true);
+
+ MigrateStatusFiles();
+
+ // Checking disabled and owned either via sysfs or via TSS calls will block if
+ // ownership is being taken by another thread or process. So for this to work
+ // well, SetupTpm() needs to be called before InitializeTpm() is called. At
+ // that point, the public API for Tpm only checks these booleans, so other
+ // threads can check without being blocked. InitializeTpm() will reset the
+ // TPM's is_owned_ bit on success.
+ bool is_enabled = false;
+ bool is_owned = false;
+ bool successful_check = false;
+ if (platform_->FileExists(kTpmCheckEnabledFile)) {
+ is_enabled = IsEnabledCheckViaSysfs();
+ is_owned = IsOwnedCheckViaSysfs();
+ successful_check = true;
+ } else {
+ if (get_tpm()->PerformEnabledOwnedCheck(&is_enabled, &is_owned)) {
+ successful_check = true;
+ }
+ }
+
+ get_tpm()->SetIsOwned(is_owned);
+ get_tpm()->SetIsEnabled(is_enabled);
+
+ if (successful_check && !is_owned) {
+ platform_->DeleteFile(kOpenCryptokiPath, true);
+ platform_->DeleteFile(kTpmOwnedFile, false);
+ platform_->DeleteFile(kTpmStatusFile, false);
+ }
+ if (successful_check && is_owned) {
+ if (!platform_->FileExists(kTpmOwnedFile)) {
+ chromeos::Blob empty_blob(0);
+ platform_->WriteFile(kTpmOwnedFile, empty_blob);
+ }
+ }
+
+ TpmStatus tpm_status;
+ if (LoadTpmStatus(&tpm_status)) {
+ if (tpm_status.has_owner_password()) {
+ SecureBlob local_owner_password;
+ if (LoadOwnerPassword(tpm_status, &local_owner_password)) {
+ get_tpm()->SetOwnerPassword(local_owner_password);
+ }
+ }
+ }
+
+ if (load_key) {
+ // load cryptohome key
+ TSS_HCONTEXT context_handle = get_tpm()->ConnectContext();
+ if (context_handle) {
+ TSS_HKEY key_handle;
+ TSS_RESULT result;
+ if (LoadOrCreateCryptohomeKey(
+ context_handle, &key_handle, &result)) {
+ cryptohome_context_.reset(0, context_handle);
+ cryptohome_key_.reset(context_handle, key_handle);
+ } else {
+ get_tpm()->CloseContext(context_handle);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool TpmInit::InitializeTpm(bool* OUT_took_ownership) {
+ TpmStatus tpm_status;
+
+ if (!LoadTpmStatus(&tpm_status)) {
+ tpm_status.Clear();
+ tpm_status.set_flags(TpmStatus::NONE);
+ }
+
+ if (OUT_took_ownership) {
+ *OUT_took_ownership = false;
+ }
+
+ if (!IsTpmEnabled()) {
+ return false;
+ }
+
+ trousers::ScopedTssContext context_handle;
+ if (!(*(context_handle.ptr()) = get_tpm()->ConnectContext())) {
+ LOG(ERROR) << "Failed to connect to TPM";
+ return false;
+ }
+
+ SecureBlob default_owner_password(sizeof(kTpmWellKnownPassword));
+ memcpy(default_owner_password.data(), kTpmWellKnownPassword,
+ sizeof(kTpmWellKnownPassword));
+
+ bool took_ownership = false;
+ if (!IsTpmOwned()) {
+ SetTpmBeingOwned(true);
+ platform_->DeleteFile(kOpenCryptokiPath, true);
+ platform_->DeleteFile(kTpmOwnedFile, false);
+ platform_->DeleteFile(kTpmStatusFile, false);
+
+ if (!get_tpm()->IsEndorsementKeyAvailable(context_handle)) {
+ if (!get_tpm()->CreateEndorsementKey(context_handle)) {
+ LOG(ERROR) << "Failed to create endorsement key";
+ SetTpmBeingOwned(false);
+ return false;
+ }
+ }
+
+ if (!get_tpm()->IsEndorsementKeyAvailable(context_handle)) {
+ LOG(ERROR) << "Endorsement key is not available";
+ SetTpmBeingOwned(false);
+ return false;
+ }
+
+ if (!get_tpm()->TakeOwnership(context_handle, kMaxTimeoutRetries,
+ default_owner_password)) {
+ LOG(ERROR) << "Take Ownership failed";
+ SetTpmBeingOwned(false);
+ return false;
+ }
+
+ SetTpmOwned(true);
+ took_ownership = true;
+
+ tpm_status.set_flags(TpmStatus::OWNED_BY_THIS_INSTALL |
+ TpmStatus::USES_WELL_KNOWN_OWNER |
+ TpmStatus::INSTALL_ATTRIBUTES_NEEDS_OWNER |
+ TpmStatus::ATTESTATION_NEEDS_OWNER);
+ tpm_status.clear_owner_password();
+ StoreTpmStatus(tpm_status);
+ }
+
+ if (OUT_took_ownership) {
+ *OUT_took_ownership = took_ownership;
+ }
+
+ // If we can open the TPM with the default password, then we still need to
+ // zero the SRK password and unrestrict it, then change the owner password.
+ TSS_HTPM tpm_handle;
+ if (!platform_->FileExists(kTpmOwnedFile) &&
+ get_tpm()->GetTpmWithAuth(context_handle,
+ default_owner_password,
+ &tpm_handle) &&
+ get_tpm()->TestTpmAuth(tpm_handle)) {
+ if (!get_tpm()->ZeroSrkPassword(context_handle, default_owner_password)) {
+ LOG(ERROR) << "Couldn't zero SRK password";
+ SetTpmBeingOwned(false);
+ return false;
+ }
+
+ if (!get_tpm()->UnrestrictSrk(context_handle, default_owner_password)) {
+ LOG(ERROR) << "Couldn't unrestrict the SRK";
+ SetTpmBeingOwned(false);
+ return false;
+ }
+
+ SecureBlob owner_password;
+ CreateOwnerPassword(&owner_password);
+
+ tpm_status.set_flags(TpmStatus::OWNED_BY_THIS_INSTALL |
+ TpmStatus::USES_RANDOM_OWNER |
+ TpmStatus::INSTALL_ATTRIBUTES_NEEDS_OWNER |
+ TpmStatus::ATTESTATION_NEEDS_OWNER);
+ if (!StoreOwnerPassword(owner_password, &tpm_status)) {
+ tpm_status.clear_owner_password();
+ }
+ StoreTpmStatus(tpm_status);
+
+ if ((get_tpm()->ChangeOwnerPassword(context_handle,
+ default_owner_password,
+ owner_password))) {
+ get_tpm()->SetOwnerPassword(owner_password);
+ }
+ chromeos::Blob empty_blob(0);
+ platform_->WriteFile(kTpmOwnedFile, empty_blob);
+ } else {
+ // If we fall through here, then the TPM owned file doesn't exist, but we
+ // couldn't auth with the well-known password. In this case, we must assume
+ // that the TPM has already been owned and set to a random password, so
+ // touch the TPM owned file.
+ if (!platform_->FileExists(kTpmOwnedFile)) {
+ chromeos::Blob empty_blob(0);
+ platform_->WriteFile(kTpmOwnedFile, empty_blob);
+ }
+ }
+
+ SetTpmBeingOwned(false);
+ return true;
+}
+
+bool TpmInit::LoadTpmStatus(TpmStatus* serialized) {
+ if (!platform_->FileExists(kTpmStatusFile)) {
+ return false;
+ }
+ SecureBlob file_data;
+ if (!platform_->ReadFile(kTpmStatusFile, &file_data)) {
+ return false;
+ }
+ if (!serialized->ParseFromArray(
+ static_cast<const unsigned char*>(file_data.data()),
+ file_data.size())) {
+ return false;
+ }
+ return true;
+}
+
+bool TpmInit::StoreTpmStatus(const TpmStatus& serialized) {
+ int old_mask = platform_->SetMask(kDefaultUmask);
+ if (platform_->FileExists(kTpmStatusFile)) {
+ do {
+ int64 file_size;
+ if (!platform_->GetFileSize(kTpmStatusFile, &file_size)) {
+ break;
+ }
+ SecureBlob random;
+ if (!get_tpm()->GetRandomData(file_size, &random)) {
+ break;
+ }
+ FILE* file = platform_->OpenFile(kTpmStatusFile, "wb+");
+ if (!file) {
+ break;
+ }
+ if (!platform_->WriteOpenFile(file, random)) {
+ platform_->CloseFile(file);
+ break;
+ }
+ platform_->CloseFile(file);
+ } while (false);
+ platform_->DeleteFile(kTpmStatusFile, false);
+ }
+ SecureBlob final_blob(serialized.ByteSize());
+ serialized.SerializeWithCachedSizesToArray(
+ static_cast<google::protobuf::uint8*>(final_blob.data()));
+ bool ok = platform_->WriteFile(kTpmStatusFile, final_blob);
+ platform_->SetMask(old_mask);
+ return ok;
+}
+
+void TpmInit::CreateOwnerPassword(SecureBlob* password) {
+ // Generate a random owner password. The default is a 12-character,
+ // hex-encoded password created from 6 bytes of random data.
+ SecureBlob random(kOwnerPasswordLength / 2);
+ CryptoLib::GetSecureRandom(static_cast<unsigned char*>(random.data()),
+ random.size());
+ SecureBlob tpm_password(kOwnerPasswordLength);
+ CryptoLib::AsciiEncodeToBuffer(random,
+ static_cast<char*>(tpm_password.data()),
+ tpm_password.size());
+ password->swap(tpm_password);
+}
+
+bool TpmInit::LoadOwnerPassword(const TpmStatus& tpm_status,
+ chromeos::Blob* owner_password) {
+ if (!(tpm_status.flags() & TpmStatus::OWNED_BY_THIS_INSTALL)) {
+ return false;
+ }
+ if ((tpm_status.flags() & TpmStatus::USES_WELL_KNOWN_OWNER)) {
+ SecureBlob default_owner_password(sizeof(kTpmWellKnownPassword));
+ memcpy(default_owner_password.data(), kTpmWellKnownPassword,
+ sizeof(kTpmWellKnownPassword));
+ owner_password->swap(default_owner_password);
+ return true;
+ }
+ if (!(tpm_status.flags() & TpmStatus::USES_RANDOM_OWNER) ||
+ !tpm_status.has_owner_password()) {
+ return false;
+ }
+
+ SecureBlob local_owner_password(tpm_status.owner_password().length());
+ tpm_status.owner_password().copy(
+ static_cast<char*>(local_owner_password.data()),
+ tpm_status.owner_password().length(), 0);
+ if (!get_tpm()->Unseal(local_owner_password, owner_password)) {
+ LOG(ERROR) << "Failed to unseal the owner password.";
+ return false;
+ }
+ return true;
+}
+
+bool TpmInit::StoreOwnerPassword(const chromeos::Blob& owner_password,
+ TpmStatus* tpm_status) {
+ // Use PCR0 when sealing the data so that the owner password is only
+ // available in the current boot mode. This helps protect the password from
+ // offline attacks until it has been presented and cleared.
+ SecureBlob sealed_password;
+ if (!get_tpm()->SealToPCR0(owner_password, &sealed_password)) {
+ LOG(ERROR) << "StoreOwnerPassword: Failed to seal owner password.";
+ return false;
+ }
+ tpm_status->set_owner_password(sealed_password.data(),
+ sealed_password.size());
+ return true;
+}
+
+void TpmInit::RemoveTpmOwnerDependency(TpmOwnerDependency dependency) {
+ int32 flag_to_clear = TpmStatus::NONE;
+ switch (dependency) {
+ case kInstallAttributes:
+ flag_to_clear = TpmStatus::INSTALL_ATTRIBUTES_NEEDS_OWNER;
+ break;
+ case kAttestation:
+ flag_to_clear = TpmStatus::ATTESTATION_NEEDS_OWNER;
+ break;
+ default:
+ CHECK(false);
+ }
+ TpmStatus tpm_status;
+ if (!LoadTpmStatus(&tpm_status))
+ return;
+ tpm_status.set_flags(tpm_status.flags() & ~flag_to_clear);
+ StoreTpmStatus(tpm_status);
+}
+
+bool TpmInit::CheckSysfsForOne(const char* file_name) const {
+ std::string contents;
+ if (!platform_->ReadFileToString(file_name, &contents)) {
+ return false;
+ }
+ if (contents.size() < 1) {
+ return false;
+ }
+ return (contents[0] == '1');
+}
+
+bool TpmInit::IsEnabledCheckViaSysfs() {
+ return CheckSysfsForOne(kTpmCheckEnabledFile);
+}
+
+bool TpmInit::IsOwnedCheckViaSysfs() {
+ return CheckSysfsForOne(kTpmCheckOwnedFile);
+}
+
+bool TpmInit::CreateCryptohomeKey(TSS_HCONTEXT context_handle) {
+ chromeos::SecureBlob wrapped_key;
+ if (!get_tpm()->CreateWrappedRsaKey(context_handle, &wrapped_key)) {
+ LOG(ERROR) << "Couldn't create cryptohome key";
+ return false;
+ }
+
+ if (!SaveCryptohomeKey(wrapped_key)) {
+ LOG(ERROR) << "Couldn't save cryptohome key";
+ return false;
+ }
+
+ LOG(INFO) << "Created new cryptohome key.";
+ return true;
+}
+
+bool TpmInit::SaveCryptohomeKey(const chromeos::SecureBlob& raw_key) {
+ int previous_mask = platform_->SetMask(cryptohome::kDefaultUmask);
+ bool ok = platform_->WriteFile(kDefaultCryptohomeKeyFile, raw_key);
+ platform_->SetMask(previous_mask);
+ if (!ok)
+ LOG(ERROR) << "Error writing key file of desired size: " << raw_key.size();
+ return ok;
+}
+
+bool TpmInit::LoadCryptohomeKey(TSS_HCONTEXT context_handle,
+ TSS_HKEY* key_handle,
+ TSS_RESULT* result) {
+ // First, try loading the key from the key file
+ {
+ SecureBlob raw_key;
+ if (platform_->ReadFile(kDefaultCryptohomeKeyFile, &raw_key)) {
+ if (get_tpm()->LoadWrappedKey(context_handle,
+ raw_key,
+ key_handle,
+ result)) {
+ return true;
+ }
+ if (get_tpm()->IsTransient(*result)) {
+ return false;
+ }
+ }
+ }
+
+ // Then try loading the key by the UUID (this is a legacy upgrade path)
+ SecureBlob raw_key;
+ trousers::ScopedTssKey local_key_handle(context_handle);
+ if (!get_tpm()->LoadKeyByUuid(context_handle,
+ kCryptohomeWellKnownUuid,
+ local_key_handle.ptr(),
+ &raw_key,
+ result)) {
+ return false;
+ }
+
+ // Save the cryptohome key to the well-known location
+ if (!SaveCryptohomeKey(raw_key)) {
+ LOG(ERROR) << "Couldn't save cryptohome key";
+ return false;
+ }
+
+ *key_handle = local_key_handle.release();
+
+ return true;
+}
+
+bool TpmInit::LoadOrCreateCryptohomeKey(TSS_HCONTEXT context_handle,
+ TSS_HKEY* key_handle,
+ TSS_RESULT* result) {
+ *result = TSS_SUCCESS;
+
+ // Try to load the cryptohome key.
+ if (LoadCryptohomeKey(context_handle, key_handle, result)) {
+ return true;
+ }
+
+ // If the error is expected to be transient, return now.
+ if (get_tpm()->IsTransient(*result)) {
+ LOG(INFO) << "Transient failure loading cryptohome key";
+ return false;
+ }
+
+ // Otherwise, the key couldn't be loaded, and it wasn't due to a transient
+ // error, so we must create the key.
+ if (CreateCryptohomeKey(context_handle)) {
+ if (LoadCryptohomeKey(context_handle, key_handle, result)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TpmInit::HasCryptohomeKey() {
+ return cryptohome_context_.value() && cryptohome_key_.value();
+}
+
+TSS_HCONTEXT TpmInit::GetCryptohomeContext() {
+ return cryptohome_context_.value();
+}
+
+TSS_HKEY TpmInit::GetCryptohomeKey() {
+ return cryptohome_key_.value();
+}
+
} // namespace cryptohome
diff --git a/tpm_init.h b/tpm_init.h
index 091dd2c..5634a7d 100644
--- a/tpm_init.h
+++ b/tpm_init.h
@@ -7,10 +7,10 @@
#include <base/basictypes.h>
#include <base/memory/scoped_ptr.h>
#include <chromeos/utility.h>
+#include <trousers/scoped_tss_type.h>
-#include "attestation.h"
-#include "crypto.h"
#include "tpm.h"
+#include "tpm_status.pb.h"
#ifndef CRYPTOHOME_TPM_INIT_H_
#define CRYPTOHOME_TPM_INIT_H_
@@ -26,27 +26,56 @@
// PlatformThread::Delegate
friend class TpmInitTask;
public:
+ enum TpmOwnerDependency {
+ kInstallAttributes,
+ kAttestation
+ };
+
class TpmInitCallback {
public:
virtual void InitializeTpmComplete(bool status, bool took_ownership) = 0;
};
// Default constructor
- explicit TpmInit(Platform* platform);
+ TpmInit(Tpm* tpm, Platform* platform);
virtual ~TpmInit();
virtual void Init(TpmInitCallback* notify_callback);
- // Gets random data from the TPM
+ // Sets the TPM to the state where we last left it in. This must be called
+ // before the *InitializeTpm functions below, if we need to.
//
- // Parameters
- // length - The number of bytes to get
- // data (OUT) - Receives the random bytes
- virtual bool GetRandomData(int length, chromeos::Blob* data);
+ // Parameters:
+ // load_key - TRUE to load load Cryptohome key.
+ //
+ // Returns false if the instance has already been setup.
+ virtual bool SetupTpm(bool load_key);
- // Starts asynchronous initialization of the TPM
- virtual bool StartInitializeTpm();
+ // Asynchronously initializes the TPM. The TPM is initialized following these
+ // steps:
+ //
+ // 1. The TPM is owned with default owner password.
+ // 2. The SRK password is cleared. The SRK is then unrestricted.
+ // 3. New owner password is established.
+ // 4. (This new password WILL be wiped later when all owner dependencies
+ // have been removed.)
+ //
+ // At each step in the process, a status file is updated so that we can
+ // resume the initialization later (see SetupTpm above).
+ //
+ // The initialization is usually done asynchronously. Attestation and
+ // InstallAttributes must remove themselves from owner dependency list so that
+ // the owner password can be cleared.
+ //
+ // Returns true if a thread was spawn to do the actual initialization.
+ virtual bool AsyncInitializeTpm();
+
+ // Synchronously initializes the TPM.
+ //
+ // Returns true if the TPM initialization process (as outlined above) is
+ // completed at step 3.
+ virtual bool InitializeTpm(bool* OUT_took_ownership);
// Returns true if the TPM is initialized and ready for use
virtual bool IsTpmReady();
@@ -57,9 +86,15 @@
// Returns true if the TPM is owned
virtual bool IsTpmOwned();
+ // Marks the TPM as being owned
+ virtual void SetTpmOwned(bool owned);
+
// Returns true if the TPM is being owned
virtual bool IsTpmBeingOwned();
+ // Marks the TPM as being or not being been owned
+ virtual void SetTpmBeingOwned(bool being_owned);
+
// Returns true if initialization has been called
virtual bool HasInitializeBeenCalled();
@@ -72,13 +107,71 @@
// Clears the TPM password from memory and disk
virtual void ClearStoredTpmPassword();
+ // Removes the given owner dependency. When all dependencies have been removed
+ // the owner password can be cleared.
+ //
+ // Parameters
+ // dependency - The dependency (on TPM ownership) to be removed
+ virtual void RemoveTpmOwnerDependency(TpmOwnerDependency dependency);
+
virtual void set_tpm(Tpm* value);
virtual Tpm* get_tpm();
+ virtual bool HasCryptohomeKey();
+
+ virtual TSS_HCONTEXT GetCryptohomeContext();
+
+ virtual TSS_HKEY GetCryptohomeKey();
+
private:
virtual void ThreadMain();
+ // Loads the TpmStatus object
+ bool LoadTpmStatus(TpmStatus* serialized);
+
+ // Saves the TpmStatus object
+ bool StoreTpmStatus(const TpmStatus& serialized);
+
+ // Creates a random owner password
+ //
+ // Parameters
+ // password (OUT) - the generated password
+ void CreateOwnerPassword(chromeos::SecureBlob* password);
+
+ // Stores the TPM owner password to the TpmStatus object
+ bool StoreOwnerPassword(const chromeos::Blob& owner_password,
+ TpmStatus* tpm_status);
+
+ // Retrieves the TPM owner password
+ bool LoadOwnerPassword(const TpmStatus& tpm_status,
+ chromeos::Blob* owner_password);
+
+ // Migrate any TPM status files from old location to new location.
+ void MigrateStatusFiles();
+
+ // Returns whether or not the TPM is enabled by checking a flag in the TPM's
+ // entry in /sys/class/misc
+ bool IsEnabledCheckViaSysfs();
+
+ // Returns whether or not the TPM is owned by checking a flag in the TPM's
+ // entry in /sys/class/misc
+ bool IsOwnedCheckViaSysfs();
+
+ bool SaveCryptohomeKey(const chromeos::SecureBlob& wrapped_key);
+
+ bool LoadCryptohomeKey(TSS_HCONTEXT context_handle, TSS_HKEY* key_handle,
+ TSS_RESULT* result);
+
+ bool CreateCryptohomeKey(TSS_HCONTEXT context_handle);
+
+ bool LoadOrCreateCryptohomeKey(TSS_HCONTEXT context_handle,
+ TSS_HKEY* key_handle,
+ TSS_RESULT* result);
+
+ // Returns true if the first byte of the file |file_name| is "1"
+ bool CheckSysfsForOne(const char* file_name) const;
+
// The background task for initializing the TPM, implemented as a
// PlatformThread::Delegate
scoped_ptr<TpmInitTask> tpm_init_task_;
@@ -90,6 +183,8 @@
bool initialize_took_ownership_;
int64_t initialization_time_;
Platform* platform_;
+ trousers::ScopedTssContext cryptohome_context_;
+ trousers::ScopedTssKey cryptohome_key_;
DISALLOW_COPY_AND_ASSIGN(TpmInit);
};