Adds the necessary changes to tpm_init to allow triggered initialization.

Change-Id: I757a112ef011ee9688f695cdd89ad2786c47778b

BUG=3065
TEST=

Review URL: http://codereview.chromium.org/3475009
diff --git a/SConstruct b/SConstruct
index 603beef..da56dd2 100644
--- a/SConstruct
+++ b/SConstruct
@@ -5,13 +5,51 @@
 import os
 import sys
 
+# Borrowed from updater
+# Protobuffer compilation
+def ProtocolBufferEmitter(target, source, env):
+  """ Inputs:
+          target: list of targets to compile to
+          source: list of sources to compile
+          env: the scons environment in which we are compiling
+      Outputs:
+          target: the list of targets we'll emit
+          source: the list of sources we'll compile"""
+  output = str(source[0])
+  output = output[0:output.rfind('.proto')]
+  target = [
+    output + '.pb.cc',
+    output + '.pb.h',
+  ]
+  return target, source
+
+def ProtocolBufferGenerator(source, target, env, for_signature):
+  """ Inputs:
+          source: list of sources to process
+          target: list of targets to generate
+          env: scons environment in which we are working
+          for_signature: unused
+      Outputs: a list of commands to execute to generate the targets from
+               the sources."""
+  commands = [
+    '/usr/bin/protoc '
+    ' --proto_path . ${SOURCES} --cpp_out .']
+  return commands
+
+proto_builder = Builder(generator = ProtocolBufferGenerator,
+                        emitter = ProtocolBufferEmitter,
+                        single_source = 1,
+                        suffix = '.pb.cc')
+
 env = Environment()
 
 # setup sources
 lib_sources = env.Split("""crypto.cc
+                           platform.cc
                            secure_blob.cc
                            tpm.cc
                            tpm_init.cc
+                           tpm_status.pb.cc
                            """)
 client_sources = env.Split("""main.cc
                            """) + lib_sources
@@ -20,7 +58,7 @@
     CPPPATH=['.', '..'],
     CPPFLAGS=['-pie', '-fstack-protector-all', '-fPIC',
               '-fno-exceptions', '-O2', '-Wall', '-Werror'],
-    LIBS = ['base', 'chromeos', 'crypto', 'rt', 'pthread', 'tspi'],
+    LIBS = ['base', 'chromeos', 'crypto', 'rt', 'protobuf', 'pthread', 'tspi'],
 )
 for key in Split('CC CXX AR RANLIB LD NM CFLAGS CCFLAGS'):
   value = os.environ.get(key)
@@ -32,8 +70,11 @@
   if os.environ.has_key(key):
     env['ENV'][key] = os.environ[key]
 
+env['BUILDERS']['ProtocolBuffer'] = proto_builder
+
 env.Append(LIBPATH = ['.'])
 
 env_lib = env.Clone()
+env_lib.ProtocolBuffer('tpm_status.pb.cc', 'tpm_status.proto')
 env_lib.Library('tpm_init', lib_sources)
 
diff --git a/platform.cc b/platform.cc
new file mode 100644
index 0000000..b07590f
--- /dev/null
+++ b/platform.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2009-2010 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.
+
+// Contains the implementation of class Platform
+
+#include "platform.h"
+
+#include <errno.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+namespace tpm_init {
+
+const int kDefaultUmask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH
+                               | S_IXOTH;
+
+Platform::Platform()
+    : umask_(kDefaultUmask) {
+}
+
+Platform::~Platform() {
+}
+
+int Platform::SetMask(int new_mask) {
+  return umask(new_mask);
+}
+
+} // namespace tpm_init
diff --git a/platform.h b/platform.h
new file mode 100644
index 0000000..e94412a
--- /dev/null
+++ b/platform.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2009-2010 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 TPM_INIT_PLATFORM_H_
+#define TPM_INIT_PLATFORM_H_
+
+#include <base/basictypes.h>
+#include <string>
+#include <vector>
+
+namespace tpm_init {
+
+// Default umask
+extern const int kDefaultUmask;
+
+// Class Platform exists to be able to mock platform calls (in this case, just
+// umask).
+// TODO(fes): Remove this class altogether if tpm_init is merged with
+// cryptohome, or put it in a separate, common library.
+class Platform {
+ public:
+
+  Platform();
+
+  virtual ~Platform();
+
+  // Sets the current umask, returning the old mask
+  //
+  // Parameters
+  //   new_mask - The mask to set
+  virtual int SetMask(int new_mask);
+
+ private:
+  int umask_;
+
+  DISALLOW_COPY_AND_ASSIGN(Platform);
+};
+
+}  // namespace tpm_init
+
+#endif  // TPM_INIT_PLATFORM_H_
diff --git a/tpm.cc b/tpm.cc
index 1efa15c..1f7d75c 100644
--- a/tpm.cc
+++ b/tpm.cc
@@ -14,6 +14,10 @@
 #include <trousers/trousers.h>
 
 namespace tpm_init {
+#define TPM_LOG(severity, result) \
+  LOG(severity) << "TPM error 0x" << std::hex << result \
+                << " (" << Trspi_Error_String(result) << "): "
+
 
 const char* kWellKnownSrkTmp = "1234567890";
 const int kOwnerPasswordLength = 12;
@@ -21,15 +25,19 @@
 const char* kTpmCheckEnabledFile = "/sys/class/misc/tpm0/device/enabled";
 const char* kTpmCheckOwnedFile = "/sys/class/misc/tpm0/device/owned";
 const char* kTpmOwnedFile = "/var/lib/.tpm_owned";
+const char* kTpmStatusFile = "/var/lib/.tpm_status";
 const char* kOpenCryptokiPath = "/var/lib/opencryptoki";
 const int kTpmConnectRetries = 10;
 const int kTpmConnectIntervalMs = 100;
 const char kTpmWellKnownPassword[] = TSS_WELL_KNOWN_SECRET;
+const char kTpmOwnedWithWellKnown = 'W';
+const char kTpmOwnedWithRandom = 'R';
 
 Tpm::Tpm()
-    : context_handle_(0),
-      default_crypto_(new Crypto()),
+    : default_crypto_(new Crypto()),
       crypto_(default_crypto_.get()),
+      default_platform_(new Platform()),
+      platform_(default_platform_.get()),
       owner_password_(),
       password_sync_lock_(),
       is_disabled_(true),
@@ -39,7 +47,6 @@
 }
 
 Tpm::~Tpm() {
-  Disconnect();
 }
 
 bool Tpm::Init() {
@@ -49,9 +56,11 @@
   // 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 (file_util::PathExists(FilePath(kTpmCheckEnabledFile))) {
     is_disabled_ = IsDisabledCheckViaSysfs();
     is_owned_ = IsOwnedCheckViaSysfs();
+    successful_check = true;
   } else {
     TSS_HCONTEXT context_handle;
     if (OpenAndConnectTpm(&context_handle)) {
@@ -61,101 +70,55 @@
       is_disabled_ = !enabled;
       is_owned_ = owned;
       Tspi_Context_Close(context_handle);
-    } else {
+      successful_check = true;
     }
   }
-  return true;
-}
-
-bool Tpm::Connect() {
-  if (context_handle_ == 0) {
-    TSS_HCONTEXT context_handle;
-    if (!OpenAndConnectTpm(&context_handle)) {
-      return false;
+  if (successful_check && !is_owned_) {
+    file_util::Delete(FilePath(kOpenCryptokiPath), true);
+    file_util::Delete(FilePath(kTpmOwnedFile), false);
+    file_util::Delete(FilePath(kTpmStatusFile), false);
+  }
+  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();
+      }
     }
-
-    context_handle_ = context_handle;
   }
 
   return true;
 }
 
-bool Tpm::IsConnected() {
-  return (context_handle_ != 0);
+TSS_HCONTEXT Tpm::Connect() {
+  TSS_HCONTEXT context_handle;
+  if (!OpenAndConnectTpm(&context_handle)) {
+    return NULL;
+  }
+
+  return context_handle;
 }
 
-void Tpm::Disconnect() {
-  if (context_handle_) {
-    Tspi_Context_Close(context_handle_);
-    context_handle_ = 0;
+void Tpm::Disconnect(TSS_HCONTEXT context_handle) {
+  if (context_handle) {
+    Tspi_Context_Close(context_handle);
   }
 }
 
 int Tpm::GetMaxRsaKeyCount() {
-  if (context_handle_ == 0) {
+  TSS_HCONTEXT context_handle = Connect();
+  if (!context_handle) {
     return -1;
   }
-
-  return GetMaxRsaKeyCountForContext(context_handle_);
-}
-
-int Tpm::GetMaxRsaKeyCountForContext(TSS_HCONTEXT context_handle) {
-  int count = -1;
-  TSS_RESULT result;
-  TSS_HTPM tpm_handle;
-  if (!GetTpm(context_handle, &tpm_handle)) {
-    return count;
-  }
-
-  UINT32 cap_length = 0;
-  BYTE* cap = NULL;
-  UINT32 subcap = TSS_TPMCAP_PROP_MAXKEYS;
-  if ((result = Tspi_TPM_GetCapability(tpm_handle, TSS_TPMCAP_PROPERTY,
-                                       sizeof(subcap),
-                                       reinterpret_cast<BYTE*>(&subcap),
-                                       &cap_length, &cap))) {
-    LOG(ERROR) << "Error calling Tspi_TPM_GetCapability: " << result;
-    return count;
-  }
-  if (cap_length == sizeof(int)) {
-    count = *(reinterpret_cast<int*>(cap));
-  }
-  Tspi_Context_FreeMemory(context_handle, cap);
+  int count = GetMaxRsaKeyCountForContext(context_handle);
+  Disconnect(context_handle);
   return count;
 }
 
-bool Tpm::OpenAndConnectTpm(TSS_HCONTEXT* context_handle) {
-  TSS_RESULT result;
-  TSS_HCONTEXT local_context_handle;
-  if ((result = Tspi_Context_Create(&local_context_handle))) {
-    LOG(ERROR) << "Error calling Tspi_Context_Create";
-    return false;
-  }
-
-  for (int i = 0; i < kTpmConnectRetries; i++) {
-    if ((result = Tspi_Context_Connect(local_context_handle, NULL))) {
-      if (result == TSS_E_COMM_FAILURE) {
-        PlatformThread::Sleep(kTpmConnectIntervalMs);
-      } else {
-        LOG(ERROR) << "Error calling Tspi_Context_Connect: " << result;
-        Tspi_Context_Close(local_context_handle);
-        return false;
-      }
-    } else {
-      break;
-    }
-  }
-
-  if (result) {
-    LOG(ERROR) << "Error calling Tspi_Context_Connect: " << result;
-    Tspi_Context_Close(local_context_handle);
-    return false;
-  }
-
-  *context_handle = local_context_handle;
-  return true;
-}
-
 bool Tpm::IsDisabledCheckViaSysfs() {
   std::string contents;
   if (!file_util::ReadFileToString(FilePath(kTpmCheckEnabledFile), &contents)) {
@@ -178,6 +141,63 @@
   return (contents[0] != '0');
 }
 
+int Tpm::GetMaxRsaKeyCountForContext(TSS_HCONTEXT context_handle) {
+  int count = -1;
+  TSS_RESULT result;
+  TSS_HTPM tpm_handle;
+  if (!GetTpm(context_handle, &tpm_handle)) {
+    return count;
+  }
+
+  UINT32 cap_length = 0;
+  BYTE* cap = NULL;
+  UINT32 subcap = TSS_TPMCAP_PROP_MAXKEYS;
+  if ((result = Tspi_TPM_GetCapability(tpm_handle, TSS_TPMCAP_PROPERTY,
+                                       sizeof(subcap),
+                                       reinterpret_cast<BYTE*>(&subcap),
+                                       &cap_length, &cap))) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability";
+    return count;
+  }
+  if (cap_length == sizeof(int)) {
+    count = *(reinterpret_cast<int*>(cap));
+  }
+  Tspi_Context_FreeMemory(context_handle, cap);
+  return count;
+}
+
+bool Tpm::OpenAndConnectTpm(TSS_HCONTEXT* context_handle) {
+  TSS_RESULT result;
+  TSS_HCONTEXT local_context_handle;
+  if ((result = Tspi_Context_Create(&local_context_handle))) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_Create";
+    return false;
+  }
+
+  for (int i = 0; i < kTpmConnectRetries; i++) {
+    if ((result = Tspi_Context_Connect(local_context_handle, NULL))) {
+      if (result == TSS_E_COMM_FAILURE) {
+        PlatformThread::Sleep(kTpmConnectIntervalMs);
+      } else {
+        TPM_LOG(ERROR, result) << "Error calling Tspi_Context_Connect";
+        Tspi_Context_Close(local_context_handle);
+        return false;
+      }
+    } else {
+      break;
+    }
+  }
+
+  if (result) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_Connect";
+    Tspi_Context_Close(local_context_handle);
+    return false;
+  }
+
+  *context_handle = local_context_handle;
+  return true;
+}
+
 void Tpm::IsEnabledOwnedCheckViaContext(TSS_HCONTEXT context_handle,
                                         bool* enabled, bool* owned) {
   *enabled = false;
@@ -218,13 +238,13 @@
   if ((result = Tspi_Context_CreateObject(context_handle,
                                           TSS_OBJECT_TYPE_RSAKEY,
                                           init_flags, &local_key_handle))) {
-    LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
     return false;
   }
 
   if ((result = Tspi_TPM_CreateEndorsementKey(tpm_handle, local_key_handle,
                                               NULL))) {
-    LOG(ERROR) << "Error calling Tspi_TPM_CreateEndorsementKey: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_CreateEndorsementKey";
     Tspi_Context_CloseObject(context_handle, local_key_handle);
     return false;
   }
@@ -242,7 +262,7 @@
   TSS_HKEY local_key_handle;
   if ((result = Tspi_TPM_GetPubEndorsementKey(tpm_handle, false, NULL,
                                               &local_key_handle))) {
-    LOG(ERROR) << "Error calling Tspi_TPM_GetPubEndorsementKey: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetPubEndorsementKey";
     return false;
   }
 
@@ -252,7 +272,9 @@
 }
 
 void Tpm::CreateOwnerPassword(SecureBlob* password) {
-  SecureBlob random(kOwnerPasswordLength);
+  // 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);
   crypto_->GetSecureRandom(static_cast<unsigned char*>(random.data()),
                            random.size());
   SecureBlob tpm_password(kOwnerPasswordLength);
@@ -274,14 +296,14 @@
   if ((result = Tspi_Context_CreateObject(context_handle,
                                           TSS_OBJECT_TYPE_RSAKEY,
                                           init_flags, &srk_handle))) {
-    LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
     return false;
   }
 
   TSS_HPOLICY srk_usage_policy;
   if ((result = Tspi_GetPolicyObject(srk_handle, TSS_POLICY_USAGE,
                                      &srk_usage_policy))) {
-    LOG(ERROR) << "Error calling Tspi_GetPolicyObject: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject";
     Tspi_Context_CloseObject(context_handle, srk_handle);
     return false;
   }
@@ -290,7 +312,7 @@
       TSS_SECRET_MODE_PLAIN,
       strlen(kWellKnownSrkTmp),
       const_cast<BYTE *>(reinterpret_cast<const BYTE *>(kWellKnownSrkTmp))))) {
-    LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
     Tspi_Context_CloseObject(context_handle, srk_handle);
     return false;
   }
@@ -305,8 +327,8 @@
           (retry_count < max_timeout_tries));
 
   if (result) {
-    LOG(ERROR) << "Error calling Tspi_TPM_TakeOwnership: " << result
-               << ", attempts: " << retry_count;
+    TPM_LOG(ERROR, result)
+        << "Error calling Tspi_TPM_TakeOwnership, attempts: " << retry_count;
     Tspi_Context_CloseObject(context_handle, srk_handle);
     return false;
   }
@@ -328,7 +350,7 @@
   TSS_UUID SRK_UUID = TSS_UUID_SRK;
   if ((result = Tspi_Context_LoadKeyByUUID(context_handle, TSS_PS_TYPE_SYSTEM,
                                            SRK_UUID, &srk_handle))) {
-    LOG(ERROR) << "Error calling Tspi_Context_LoadKeyByUUID: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_LoadKeyByUUID";
     return false;
   }
 
@@ -337,7 +359,7 @@
                                           TSS_OBJECT_TYPE_POLICY,
                                           TSS_POLICY_USAGE,
                                           &policy_handle))) {
-    LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
     Tspi_Context_CloseObject(context_handle, srk_handle);
     return false;
   }
@@ -345,7 +367,7 @@
   BYTE new_password[0];
   if ((result = Tspi_Policy_SetSecret(policy_handle, TSS_SECRET_MODE_PLAIN,
                                       0, new_password))) {
-    LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
     Tspi_Context_CloseObject(context_handle, policy_handle);
     Tspi_Context_CloseObject(context_handle, srk_handle);
     return false;
@@ -354,7 +376,7 @@
   if ((result = Tspi_ChangeAuth(srk_handle,
                                 tpm_handle,
                                 policy_handle))) {
-    LOG(ERROR) << "Error calling Tspi_ChangeAuth: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth";
     Tspi_Context_CloseObject(context_handle, policy_handle);
     Tspi_Context_CloseObject(context_handle, srk_handle);
     return false;
@@ -366,7 +388,7 @@
 }
 
 bool Tpm::UnrestrictSrk(TSS_HCONTEXT context_handle,
-                          const SecureBlob& owner_password) {
+                        const SecureBlob& owner_password) {
   TSS_RESULT result;
   TSS_HTPM tpm_handle;
   if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) {
@@ -378,7 +400,7 @@
   if ((result = Tspi_TPM_GetStatus(tpm_handle,
                                    TSS_TPMSTATUS_DISABLEPUBSRKREAD,
                                    &current_status))) {
-    LOG(ERROR) << "Error calling Tspi_TPM_GetStatus: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetStatus";
     return false;
   }
 
@@ -387,7 +409,7 @@
     if ((result = Tspi_TPM_SetStatus(tpm_handle,
                                      TSS_TPMSTATUS_DISABLEPUBSRKREAD,
                                      false))) {
-      LOG(ERROR) << "Error calling Tspi_TPM_SetStatus: " << result;
+      TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_SetStatus";
       return false;
     }
   }
@@ -409,7 +431,7 @@
                                           TSS_OBJECT_TYPE_POLICY,
                                           TSS_POLICY_USAGE,
                                           &policy_handle))) {
-    LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
     return false;
   }
 
@@ -418,17 +440,228 @@
       owner_password.size(),
       const_cast<BYTE *>(static_cast<const BYTE *>(
           owner_password.const_data()))))) {
-    LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
     Tspi_Context_CloseObject(context_handle, policy_handle);
     return false;
   }
 
   if ((result = Tspi_ChangeAuth(tpm_handle, 0, policy_handle))) {
-    LOG(ERROR) << "Error calling Tspi_ChangeAuth: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth";
     Tspi_Context_CloseObject(context_handle, policy_handle);
     return false;
   }
 
+  Tspi_Context_CloseObject(context_handle, policy_handle);
+  return true;
+}
+
+// TODO(fes): This method is borrowed from cryptohome.  When the tpm_init
+// library is merged into cryptohome, these duplicate methods need to be
+// removed.  Either that, or they should be moved into a separate library.
+bool Tpm::LoadFileBytes(const FilePath& path, chromeos::Blob* blob) {
+  int64 file_size;
+  if (!file_util::PathExists(path)) {
+    return false;
+  }
+  if (!file_util::GetFileSize(path, &file_size)) {
+    LOG(ERROR) << "Could not get size of " << path.value();
+    return false;
+  }
+  // Compare to the max of a 32-bit signed integer
+  if (file_size > static_cast<int64>(INT_MAX)) {
+    LOG(ERROR) << "File " << path.value() << " is too large: " << file_size;
+    return false;
+  }
+  SecureBlob buf(file_size);
+  int data_read = file_util::ReadFile(path, reinterpret_cast<char*>(&buf[0]),
+                                      file_size);
+  // Cast is okay because of comparison to INT_MAX above
+  if (data_read != static_cast<int>(file_size)) {
+    LOG(ERROR) << "Could not read entire file " << file_size;
+    return false;
+  }
+  blob->swap(buf);
+  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;
+  }
+
+  TSS_HCONTEXT context_handle;
+  if (!OpenAndConnectTpm(&context_handle)) {
+    return false;
+  }
+
+  TSS_RESULT result;
+  TSS_HKEY srk_handle;
+  if (!LoadSrk(context_handle, &srk_handle, &result)) {
+    LOG(ERROR) << "Error loading the SRK";
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+
+  TSS_FLAG init_flags = TSS_ENCDATA_SEAL;
+  TSS_HKEY enc_handle;
+  if ((result = Tspi_Context_CreateObject(context_handle,
+                                          TSS_OBJECT_TYPE_ENCDATA,
+                                          init_flags, &enc_handle))) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
+    Tspi_Context_CloseObject(context_handle, srk_handle);
+    Tspi_Context_Close(context_handle);
+    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 ((result = Tspi_SetAttribData(enc_handle,
+      TSS_TSPATTRIB_ENCDATA_BLOB,
+      TSS_TSPATTRIB_ENCDATABLOB_BLOB,
+      local_owner_password.size(),
+      static_cast<BYTE *>(local_owner_password.data())))) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_SetAttribData";
+    Tspi_Context_CloseObject(context_handle, enc_handle);
+    Tspi_Context_CloseObject(context_handle, srk_handle);
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+
+  unsigned char* dec_data = NULL;
+  UINT32 dec_data_length = 0;
+  if ((result = Tspi_Data_Unseal(enc_handle, srk_handle, &dec_data_length,
+                                 &dec_data))) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Data_Unseal";
+    Tspi_Context_CloseObject(context_handle, enc_handle);
+    Tspi_Context_CloseObject(context_handle, srk_handle);
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+
+  Tspi_Context_CloseObject(context_handle, enc_handle);
+
+  SecureBlob local_data(dec_data_length);
+  memcpy(static_cast<char*>(local_data.data()), dec_data, dec_data_length);
+  Tspi_Context_FreeMemory(context_handle, dec_data);
+
+  Tspi_Context_CloseObject(context_handle, srk_handle);
+  Tspi_Context_Close(context_handle);
+
+  owner_password->swap(local_data);
+
+  return true;
+}
+
+bool Tpm::StoreOwnerPassword(const chromeos::Blob& owner_password,
+                             TpmStatus* tpm_status) {
+  TSS_HCONTEXT context_handle;
+  if (!OpenAndConnectTpm(&context_handle)) {
+    return false;
+  }
+
+  TSS_RESULT result;
+  TSS_HKEY srk_handle;
+  if (!LoadSrk(context_handle, &srk_handle, &result)) {
+    LOG(ERROR) << "Error loading the SRK";
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+
+  // Check the SRK public key
+  unsigned int size_n;
+  BYTE *public_srk;
+  if ((result = Tspi_Key_GetPubKey(srk_handle, &size_n, &public_srk))) {
+    TPM_LOG(ERROR, result) << "Unable to get the SRK public key";
+    Tspi_Context_CloseObject(context_handle, srk_handle);
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+  Tspi_Context_FreeMemory(context_handle, public_srk);
+
+  TSS_HTPM tpm_handle;
+  if (!GetTpm(context_handle, &tpm_handle)) {
+    LOG(ERROR) << "Unable to get a handle to the TPM";
+    Tspi_Context_CloseObject(context_handle, srk_handle);
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+
+  // 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.
+  TSS_HPCRS pcrs_handle;
+  if ((result = Tspi_Context_CreateObject(context_handle, TSS_OBJECT_TYPE_PCRS,
+                                          0, &pcrs_handle))) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
+    Tspi_Context_CloseObject(context_handle, srk_handle);
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+
+  UINT32 pcr_len;
+  BYTE* pcr_value;
+  Tspi_TPM_PcrRead(tpm_handle, 0, &pcr_len, &pcr_value);
+  Tspi_PcrComposite_SetPcrValue(pcrs_handle, 0, pcr_len, pcr_value);
+  Tspi_Context_FreeMemory(context_handle, pcr_value);
+
+  TSS_FLAG init_flags = TSS_ENCDATA_SEAL;
+  TSS_HKEY enc_handle;
+  if ((result = Tspi_Context_CreateObject(context_handle,
+                                          TSS_OBJECT_TYPE_ENCDATA,
+                                          init_flags, &enc_handle))) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
+    Tspi_Context_CloseObject(context_handle, pcrs_handle);
+    Tspi_Context_CloseObject(context_handle, srk_handle);
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+
+  if ((result = Tspi_Data_Seal(enc_handle, srk_handle, owner_password.size(),
+                               const_cast<BYTE *>(&owner_password[0]),
+                               pcrs_handle))) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Data_Seal";
+    Tspi_Context_CloseObject(context_handle, pcrs_handle);
+    Tspi_Context_CloseObject(context_handle, enc_handle);
+    Tspi_Context_CloseObject(context_handle, srk_handle);
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+  Tspi_Context_CloseObject(context_handle, pcrs_handle);
+
+  unsigned char* enc_data = NULL;
+  UINT32 enc_data_length = 0;
+  if ((result = Tspi_GetAttribData(enc_handle, TSS_TSPATTRIB_ENCDATA_BLOB,
+                                   TSS_TSPATTRIB_ENCDATABLOB_BLOB,
+                                   &enc_data_length, &enc_data))) {
+    TPM_LOG(ERROR, result) << "Error calling Tspi_GetAttribData";
+    Tspi_Context_CloseObject(context_handle, enc_handle);
+    Tspi_Context_CloseObject(context_handle, srk_handle);
+    Tspi_Context_Close(context_handle);
+    return false;
+  }
+  Tspi_Context_CloseObject(context_handle, enc_handle);
+
+  tpm_status->set_owner_password(enc_data, enc_data_length);
+
+  Tspi_Context_FreeMemory(context_handle, enc_data);
+  Tspi_Context_CloseObject(context_handle, srk_handle);
+  Tspi_Context_Close(context_handle);
+
   return true;
 }
 
@@ -436,7 +669,7 @@
   TSS_RESULT result;
   TSS_HTPM local_tpm_handle;
   if ((result = Tspi_Context_GetTpmObject(context_handle, &local_tpm_handle))) {
-    LOG(ERROR) << "Error calling Tspi_Context_GetTpmObject: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_GetTpmObject";
     return false;
   }
 
@@ -456,7 +689,7 @@
   TSS_HPOLICY tpm_usage_policy;
   if ((result = Tspi_GetPolicyObject(local_tpm_handle, TSS_POLICY_USAGE,
                                      &tpm_usage_policy))) {
-    LOG(ERROR) << "Error calling Tspi_GetPolicyObject: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject";
     return false;
   }
 
@@ -464,7 +697,7 @@
       owner_password.size(),
       const_cast<BYTE *>(static_cast<const BYTE *>(
           owner_password.const_data()))))) {
-    LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result;
+    TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
     return false;
   }
 
@@ -497,20 +730,25 @@
 }
 
 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 (!IsConnected()) {
-    Connect();
-  }
-
-  if (!IsConnected()) {
-    LOG(ERROR) << "Failed to connect to TPM";
+  if (is_disabled_) {
     return false;
   }
 
-  if (is_disabled_) {
+  TSS_HCONTEXT context_handle = Connect();
+
+  if (!context_handle) {
+    LOG(ERROR) << "Failed to connect to TPM";
     return false;
   }
 
@@ -523,30 +761,39 @@
     is_being_owned_ = true;
     file_util::Delete(FilePath(kOpenCryptokiPath), true);
     file_util::Delete(FilePath(kTpmOwnedFile), false);
+    file_util::Delete(FilePath(kTpmStatusFile), false);
 
-    if (!IsEndorsementKeyAvailable(context_handle_)) {
-      if (!CreateEndorsementKey(context_handle_)) {
+    if (!IsEndorsementKeyAvailable(context_handle)) {
+      if (!CreateEndorsementKey(context_handle)) {
         LOG(ERROR) << "Failed to create endorsement key";
         is_being_owned_ = false;
+        Disconnect(context_handle);
         return false;
       }
     }
 
-    if (!IsEndorsementKeyAvailable(context_handle_)) {
+    if (!IsEndorsementKeyAvailable(context_handle)) {
       LOG(ERROR) << "Endorsement key is not available";
       is_being_owned_ = false;
+      Disconnect(context_handle);
       return false;
     }
 
-    if (!TakeOwnership(context_handle_, kMaxTimeoutRetries,
+    if (!TakeOwnership(context_handle, kMaxTimeoutRetries,
                        default_owner_password)) {
       LOG(ERROR) << "Take Ownership failed";
       is_being_owned_ = false;
+      Disconnect(context_handle);
       return false;
     }
 
     is_owned_ = true;
     took_ownership = true;
+
+    tpm_status.set_flags(TpmStatus::OWNED_BY_THIS_INSTALL |
+                         TpmStatus::USES_WELL_KNOWN_OWNER);
+    tpm_status.clear_owner_password();
+    StoreTpmStatus(tpm_status);
   }
 
   if (OUT_took_ownership) {
@@ -557,11 +804,11 @@
   TSS_RESULT result;
   TSS_HKEY srk_handle;
   TSS_UUID SRK_UUID = TSS_UUID_SRK;
-  if ((result = Tspi_Context_LoadKeyByUUID(context_handle_, TSS_PS_TYPE_SYSTEM,
+  if ((result = Tspi_Context_LoadKeyByUUID(context_handle, TSS_PS_TYPE_SYSTEM,
                                            SRK_UUID, &srk_handle))) {
     is_srk_available_ = false;
   } else {
-    Tspi_Context_CloseObject(context_handle_, srk_handle);
+    Tspi_Context_CloseObject(context_handle, srk_handle);
     is_srk_available_ = true;
   }
 
@@ -569,38 +816,52 @@
   // zero the SRK password and unrestrict it, then change the owner password.
   TSS_HTPM tpm_handle;
   if (!file_util::PathExists(FilePath(kTpmOwnedFile)) &&
-      GetTpmWithAuth(context_handle_, default_owner_password, &tpm_handle) &&
+      GetTpmWithAuth(context_handle, default_owner_password, &tpm_handle) &&
       TestTpmAuth(tpm_handle)) {
-    if (!ZeroSrkPassword(context_handle_, default_owner_password)) {
+    if (!ZeroSrkPassword(context_handle, default_owner_password)) {
       LOG(ERROR) << "Couldn't zero SRK password";
       is_being_owned_ = false;
+      Disconnect(context_handle);
       return false;
     }
 
-    if (!UnrestrictSrk(context_handle_, default_owner_password)) {
+    if (!UnrestrictSrk(context_handle, default_owner_password)) {
       LOG(ERROR) << "Couldn't unrestrict the SRK";
       is_being_owned_ = false;
+      Disconnect(context_handle);
       return false;
     }
+
     SecureBlob owner_password;
     CreateOwnerPassword(&owner_password);
 
-    if (!ChangeOwnerPassword(context_handle_, default_owner_password,
-                             owner_password)) {
-      LOG(ERROR) << "Couldn't set the owner password";
-      is_being_owned_ = false;
-      return false;
+    tpm_status.set_flags(TpmStatus::OWNED_BY_THIS_INSTALL |
+                         TpmStatus::USES_RANDOM_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();
     }
 
-    password_sync_lock_.Acquire();
-    owner_password_.assign(owner_password.begin(), owner_password.end());
-    password_sync_lock_.Release();
-
     file_util::WriteFile(FilePath(kTpmOwnedFile), NULL, 0);
+  } 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 (!file_util::PathExists(FilePath(kTpmOwnedFile))) {
+      file_util::WriteFile(FilePath(kTpmOwnedFile), NULL, 0);
+    }
   }
 
   is_being_owned_ = false;
-
+  Disconnect(context_handle);
   return true;
 }
 
@@ -622,7 +883,7 @@
   SecureBlob random(length);
   BYTE* tpm_data = NULL;
   if ((result = Tspi_TPM_GetRandom(tpm_handle, random.size(), &tpm_data))) {
-    LOG(ERROR) << "Could not get random data from the TPM: " << result;
+    TPM_LOG(ERROR, result) << "Could not get random data from the TPM";
     Tspi_Context_Close(context_handle);
     return false;
   }
@@ -634,4 +895,124 @@
   return true;
 }
 
+bool Tpm::LoadSrk(TSS_HCONTEXT context_handle, TSS_HKEY* srk_handle,
+                  TSS_RESULT* result) {
+  *result = TSS_SUCCESS;
+
+  // Load the Storage Root Key
+  TSS_UUID SRK_UUID = TSS_UUID_SRK;
+  TSS_HKEY local_srk_handle;
+  if ((*result = Tspi_Context_LoadKeyByUUID(context_handle,
+                                            TSS_PS_TYPE_SYSTEM,
+                                            SRK_UUID,
+                                            &local_srk_handle))) {
+    return false;
+  }
+
+  // Check if the SRK wants a password
+  UINT32 srk_authusage;
+  if ((*result = Tspi_GetAttribUint32(local_srk_handle,
+                                      TSS_TSPATTRIB_KEY_INFO,
+                                      TSS_TSPATTRIB_KEYINFO_AUTHUSAGE,
+                                      &srk_authusage))) {
+    Tspi_Context_CloseObject(context_handle,
+                             local_srk_handle);
+    return false;
+  }
+
+  // Give it the password if needed
+  if (srk_authusage) {
+    TSS_HPOLICY srk_usage_policy;
+    if ((*result = Tspi_GetPolicyObject(local_srk_handle,
+                                        TSS_POLICY_USAGE,
+                                        &srk_usage_policy))) {
+      Tspi_Context_CloseObject(context_handle, local_srk_handle);
+      return false;
+    }
+
+    BYTE new_password[0];
+    if ((*result = Tspi_Policy_SetSecret(srk_usage_policy,
+                                         TSS_SECRET_MODE_PLAIN,
+                                         0, new_password))) {
+      Tspi_Context_CloseObject(context_handle, local_srk_handle);
+      return false;
+    }
+  }
+
+  *srk_handle = local_srk_handle;
+  return true;
+}
+
+void Tpm::ClearStoredOwnerPassword() {
+  TpmStatus tpm_status;
+  if (LoadTpmStatus(&tpm_status)) {
+    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::LoadTpmStatus(TpmStatus* serialized) {
+  FilePath tpm_status_file(kTpmStatusFile);
+  if (!file_util::PathExists(tpm_status_file)) {
+    return false;
+  }
+  SecureBlob file_data;
+  if (!LoadFileBytes(tpm_status_file, &file_data)) {
+    return 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);
+  FilePath tpm_status_file(kTpmStatusFile);
+  if (file_util::PathExists(tpm_status_file)) {
+    do {
+      int64 file_size;
+      if (!file_util::GetFileSize(tpm_status_file, &file_size)) {
+        break;
+      }
+      SecureBlob random;
+      if (!GetRandomData(file_size, &random)) {
+        break;
+      }
+      FILE* file = file_util::OpenFile(tpm_status_file, "wb+");
+      if (!file) {
+        break;
+      }
+      if (fwrite(random.const_data(), 1, random.size(), file) !=
+          random.size()) {
+        file_util::CloseFile(file);
+        break;
+      }
+      file_util::CloseFile(file);
+    } while(false);
+    file_util::Delete(tpm_status_file, false);
+  }
+  SecureBlob final_blob(serialized.ByteSize());
+  serialized.SerializeWithCachedSizesToArray(
+      static_cast<google::protobuf::uint8*>(final_blob.data()));
+  unsigned int data_written = file_util::WriteFile(
+      tpm_status_file,
+      static_cast<const char*>(final_blob.const_data()),
+      final_blob.size());
+
+  if (data_written != final_blob.size()) {
+    platform_->SetMask(old_mask);
+    return false;
+  }
+  platform_->SetMask(old_mask);
+  return true;
+}
+
 } // namespace tpm_init
diff --git a/tpm.h b/tpm.h
index 27bec22..d209bbe 100644
--- a/tpm.h
+++ b/tpm.h
@@ -12,7 +12,9 @@
 #include <trousers/trousers.h>
 
 #include "crypto.h"
+#include "platform.h"
 #include "secure_blob.h"
+#include "tpm_status.pb.h"
 
 #ifndef TPM_INIT_TPM_H_
 #define TPM_INIT_TPM_H_
@@ -32,15 +34,6 @@
   // Parameters
   virtual bool Init();
 
-  // Tries to connect to the TPM
-  virtual bool Connect();
-
-  // Returns true if this instance is connected to the TPM
-  virtual bool IsConnected();
-
-  // Disconnects from the TPM
-  virtual void Disconnect();
-
   // Returns the number of simultaneously-loaded RSA keys that this TPM supports
   int GetMaxRsaKeyCount();
 
@@ -51,6 +44,9 @@
   //   owner_password (OUT) - The random owner password used
   bool GetOwnerPassword(chromeos::Blob* owner_password);
 
+  // Clears the owner password from storage
+  void ClearStoredOwnerPassword();
+
   // 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).
@@ -79,6 +75,33 @@
   bool GetRandomData(size_t length, chromeos::Blob* data);
 
  private:
+  // Tries to connect to the TPM
+  virtual TSS_HCONTEXT Connect();
+
+  // Disconnects from the TPM
+  virtual void Disconnect(TSS_HCONTEXT context_handle);
+
+  // Gets a handle to the SRK
+  bool LoadSrk(TSS_HCONTEXT context_handle, TSS_HKEY* srk_handle,
+               TSS_RESULT* result);
+
+  // Loads the contents of the file specified into a blob
+  bool LoadFileBytes(const FilePath& path, chromeos::Blob* blob);
+
+  // 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);
+
   // Attempts to connect to tcsd
   //
   // Parameters
@@ -116,6 +139,13 @@
   //   context_handle - The context handle for the TPM session
   bool CreateEndorsementKey(TSS_HCONTEXT context_handle);
 
+  // Delegates ownership authority
+  //
+  // Parameters
+  //   context_handle - The context handle for the TPM session
+  bool DelegateTpmOwnership(TSS_HCONTEXT context_handle, TSS_HTPM tpm_handle,
+                            SecureBlob* delegation_blob);
+
   // Checks to see if the endorsement key is available by attempting to get its
   // public key
   //
@@ -188,9 +218,6 @@
   //   tpm_handle = The TPM handle
   bool TestTpmAuth(TSS_HTPM tpm_handle);
 
-  // The context handle for this TPM session
-  TSS_HCONTEXT context_handle_;
-
   // The default Crypto instance to use (for generating the random owner
   // password)
   scoped_ptr<Crypto> default_crypto_;
@@ -198,6 +225,12 @@
   // The actual Crypto instance to use
   Crypto* crypto_;
 
+  // The default Platform instance to use
+  scoped_ptr<Platform> default_platform_;
+
+  // The actual Platform instance to use
+  Platform* platform_;
+
   // If TPM ownership is taken, owner_password_ contains the password used
   SecureBlob owner_password_;
 
diff --git a/tpm_init.cc b/tpm_init.cc
index ddd287a..3178790 100644
--- a/tpm_init.cc
+++ b/tpm_init.cc
@@ -7,6 +7,7 @@
 #include "tpm_init.h"
 
 #include <base/logging.h>
+#include <base/platform_thread.h>
 #include <base/time.h>
 
 #include "tpm.h"
@@ -17,33 +18,47 @@
 // the TPM.
 class TpmInitTask : public PlatformThread::Delegate {
  public:
-  TpmInitTask();
-  virtual ~TpmInitTask();
+  TpmInitTask()
+      : default_tpm_(new tpm_init::Tpm()),
+        tpm_(default_tpm_.get()),
+        init_(NULL) {
+  }
 
-  void Init(TpmInit::TpmInitCallback* notify_callback);
+  virtual ~TpmInitTask() {
+  }
 
-  virtual void ThreadMain();
+  void Init(TpmInit* init) {
+    init_ = init;
+    tpm_->Init();
+  }
 
-  bool IsTpmReady();
-  bool IsTpmEnabled();
-  bool IsTpmOwned();
-  bool IsTpmBeingOwned();
-  bool GetTpmPassword(chromeos::Blob* password);
-  long GetInitializationMillis();
-  bool GetRandomData(int length, chromeos::Blob* data);
+  virtual void ThreadMain() {
+    if (init_) {
+      init_->ThreadMain();
+    }
+  }
+
+  void set_tpm(tpm_init::Tpm* tpm) {
+    tpm_ = tpm;
+  }
+
+  tpm_init::Tpm* get_tpm() {
+    return tpm_;
+  }
 
  private:
   scoped_ptr<tpm_init::Tpm> default_tpm_;
   tpm_init::Tpm* tpm_;
-  bool initialize_took_ownership_;
-  bool task_done_;
-  long initialization_time_;
-  TpmInit::TpmInitCallback* notify_callback_;
+  TpmInit* init_;
 };
 
 TpmInit::TpmInit()
     : tpm_init_task_(new TpmInitTask()),
-      notify_callback_(NULL) {
+      notify_callback_(NULL),
+      initialize_called_(false),
+      task_done_(false),
+      initialize_took_ownership_(false),
+      initialization_time_(0) {
 }
 
 TpmInit::~TpmInit() {
@@ -51,14 +66,15 @@
 
 void TpmInit::Init(TpmInitCallback* notify_callback) {
   notify_callback_ = notify_callback;
+  tpm_init_task_->Init(this);
 }
 
 bool TpmInit::GetRandomData(int length, chromeos::Blob* data) {
-  return tpm_init_task_->GetRandomData(length, data);
+  return tpm_init_task_->get_tpm()->GetRandomData(length, data);
 }
 
 bool TpmInit::StartInitializeTpm() {
-  tpm_init_task_->Init(notify_callback_);
+  initialize_called_ = true;
   if (!PlatformThread::CreateNonJoinable(0, tpm_init_task_.get())) {
     LOG(ERROR) << "Unable to create TPM initialization background thread.";
     return false;
@@ -67,62 +83,6 @@
 }
 
 bool TpmInit::IsTpmReady() {
-  return tpm_init_task_->IsTpmReady();
-}
-
-bool TpmInit::IsTpmEnabled() {
-  return tpm_init_task_->IsTpmEnabled();
-}
-
-bool TpmInit::IsTpmOwned() {
-  return tpm_init_task_->IsTpmOwned();
-}
-
-bool TpmInit::IsTpmBeingOwned() {
-  return tpm_init_task_->IsTpmBeingOwned();
-}
-
-bool TpmInit::GetTpmPassword(chromeos::Blob* password) {
-  return tpm_init_task_->GetTpmPassword(password);
-}
-
-long TpmInit::GetInitializationMillis() {
-  return tpm_init_task_->GetInitializationMillis();
-}
-
-TpmInitTask::TpmInitTask()
-    : default_tpm_(new tpm_init::Tpm()),
-      tpm_(default_tpm_.get()),
-      initialize_took_ownership_(false),
-      task_done_(false),
-      initialization_time_(-1),
-      notify_callback_(NULL) {
-}
-
-TpmInitTask::~TpmInitTask() {
-}
-
-void TpmInitTask::Init(TpmInit::TpmInitCallback* notify_callback) {
-  notify_callback_ = notify_callback;
-  tpm_->Init();
-}
-
-void TpmInitTask::ThreadMain() {
-  base::TimeTicks start = base::TimeTicks::Now();
-  bool initialize_result = tpm_->InitializeTpm(&initialize_took_ownership_);
-  base::TimeDelta delta = (base::TimeTicks::Now() - start);
-  initialization_time_ = delta.InMilliseconds();
-  if (initialize_took_ownership_) {
-    LOG(ERROR) << "TPM initialization took " << initialization_time_ << "ms";
-  }
-  task_done_ = true;
-  if (notify_callback_) {
-    notify_callback_->InitializeTpmComplete(initialize_result,
-                                            initialize_took_ownership_);
-  }
-}
-
-bool TpmInitTask::IsTpmReady() {
   // The TPM is not "ready" if the init call has not completed.  It may be in
   // the middle of taking ownership.
   if (!task_done_) {
@@ -137,31 +97,52 @@
   // returned false.  That merely means that it did not successfully take
   // ownership, which is the common case after ownership is established on OOBE.
   // In that case, the TPM is ready if it is enabled and owned.
-  return (tpm_->IsEnabled() && tpm_->IsOwned());
+  return (tpm_init_task_->get_tpm()->IsEnabled() &&
+          tpm_init_task_->get_tpm()->IsOwned());
 }
 
-bool TpmInitTask::IsTpmEnabled() {
-  return tpm_->IsEnabled();
+bool TpmInit::IsTpmEnabled() {
+  return tpm_init_task_->get_tpm()->IsEnabled();
 }
 
-bool TpmInitTask::IsTpmOwned() {
-  return tpm_->IsOwned();
+bool TpmInit::IsTpmOwned() {
+  return tpm_init_task_->get_tpm()->IsOwned();
 }
 
-bool TpmInitTask::IsTpmBeingOwned() {
-  return tpm_->IsBeingOwned();
+bool TpmInit::IsTpmBeingOwned() {
+  return tpm_init_task_->get_tpm()->IsBeingOwned();
 }
 
-bool TpmInitTask::GetTpmPassword(chromeos::Blob* password) {
-  return tpm_->GetOwnerPassword(password);
+bool TpmInit::HasInitializeBeenCalled() {
+  return initialize_called_;
 }
 
-long TpmInitTask::GetInitializationMillis() {
+bool TpmInit::GetTpmPassword(chromeos::Blob* password) {
+  return tpm_init_task_->get_tpm()->GetOwnerPassword(password);
+}
+
+void TpmInit::ClearStoredTpmPassword() {
+  tpm_init_task_->get_tpm()->ClearStoredOwnerPassword();
+}
+
+long TpmInit::GetInitializationMillis() {
   return initialization_time_;
 }
 
-bool TpmInitTask::GetRandomData(int length, chromeos::Blob* data) {
-  return tpm_->GetRandomData(length, data);
+void TpmInit::ThreadMain() {
+  base::TimeTicks start = base::TimeTicks::Now();
+  bool initialize_result = tpm_init_task_->get_tpm()->InitializeTpm(
+      &initialize_took_ownership_);
+  base::TimeDelta delta = (base::TimeTicks::Now() - start);
+  initialization_time_ = delta.InMilliseconds();
+  if (initialize_took_ownership_) {
+    LOG(ERROR) << "TPM initialization took " << initialization_time_ << "ms";
+  }
+  task_done_ = true;
+  if (notify_callback_) {
+    notify_callback_->InitializeTpmComplete(initialize_result,
+                                            initialize_took_ownership_);
+  }
 }
 
 }  // namespace tpm_init
diff --git a/tpm_init.h b/tpm_init.h
index 8a0024f..5cb00c7 100644
--- a/tpm_init.h
+++ b/tpm_init.h
@@ -4,8 +4,8 @@
 
 // TpmInit - public interface class for initializing the TPM
 
+#include <base/basictypes.h>
 #include <base/scoped_ptr.h>
-#include <base/platform_thread.h>
 #include <chromeos/utility.h>
 
 #ifndef TPM_INIT_TPM_INIT_H_
@@ -16,6 +16,10 @@
 class TpmInitTask;
 
 class TpmInit {
+  // Friend class TpmInitTask as it is a glue class to allow ThreadMain to be
+  // called on a separate thread without inheriting from
+  // PlatformThread::Delegate
+  friend class TpmInitTask;
  public:
 
   class TpmInitCallback {
@@ -52,22 +56,35 @@
   // Returns true if the TPM is being owned
   virtual bool IsTpmBeingOwned();
 
+  // Returns true if initialization has been called
+  virtual bool HasInitializeBeenCalled();
+
   // Gets the TPM password if the TPM initialization took ownership
   //
   // Parameters
   //   password (OUT) - The owner password used for the TPM
   virtual bool GetTpmPassword(chromeos::Blob* password);
 
+  // Clears the TPM password from memory and disk
+  virtual void ClearStoredTpmPassword();
+
   // Returns the number of milliseconds it took to initialize the TPM
   virtual long GetInitializationMillis();
 
  private:
+  virtual void ThreadMain();
+
   // The background task for initializing the TPM, implemented as a
   // PlatformThread::Delegate
   scoped_ptr<TpmInitTask> tpm_init_task_;
 
   TpmInitCallback* notify_callback_;
 
+  bool initialize_called_;
+  bool task_done_;
+  bool initialize_took_ownership_;
+  long initialization_time_;
+
   DISALLOW_COPY_AND_ASSIGN(TpmInit);
 };
 
diff --git a/tpm_status.proto b/tpm_status.proto
new file mode 100644
index 0000000..273faa2
--- /dev/null
+++ b/tpm_status.proto
@@ -0,0 +1,17 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package tpm_init;
+
+message TpmStatus {
+  enum Flags {
+    NONE = 0;
+    OWNED_BY_THIS_INSTALL = 1;
+    USES_WELL_KNOWN_OWNER = 2;
+    USES_RANDOM_OWNER = 4;
+  }
+  required int32 flags = 1;
+  optional bytes delegation_credentials = 2;
+  optional bytes owner_password = 3;
+}