Index: tpm.cc |
diff --git a/tpm.cc b/tpm.cc |
index 1efa15c57d68bac73148e49045d460883b01933a..1f7d75c81581478d3da4522a3e9dec23583eb342 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 int kMaxTimeoutRetries = 5; |
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() |
} |
Tpm::~Tpm() { |
- Disconnect(); |
} |
bool Tpm::Init() { |
@@ -49,9 +56,11 @@ bool Tpm::Init() { |
// 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,42 +70,75 @@ bool Tpm::Init() { |
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; |
} |
+ int count = GetMaxRsaKeyCountForContext(context_handle); |
+ Disconnect(context_handle); |
+ return count; |
+} |
+ |
+bool Tpm::IsDisabledCheckViaSysfs() { |
+ std::string contents; |
+ if (!file_util::ReadFileToString(FilePath(kTpmCheckEnabledFile), &contents)) { |
+ return false; |
+ } |
+ if (contents.size() < 1) { |
+ return false; |
+ } |
+ return (contents[0] == '0'); |
+} |
- return GetMaxRsaKeyCountForContext(context_handle_); |
+bool Tpm::IsOwnedCheckViaSysfs() { |
+ std::string contents; |
+ if (!file_util::ReadFileToString(FilePath(kTpmCheckOwnedFile), &contents)) { |
+ return false; |
+ } |
+ if (contents.size() < 1) { |
+ return false; |
+ } |
+ return (contents[0] != '0'); |
} |
int Tpm::GetMaxRsaKeyCountForContext(TSS_HCONTEXT context_handle) { |
@@ -114,7 +156,7 @@ int Tpm::GetMaxRsaKeyCountForContext(TSS_HCONTEXT context_handle) { |
sizeof(subcap), |
reinterpret_cast<BYTE*>(&subcap), |
&cap_length, &cap))) { |
- LOG(ERROR) << "Error calling Tspi_TPM_GetCapability: " << result; |
+ TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability"; |
return count; |
} |
if (cap_length == sizeof(int)) { |
@@ -128,7 +170,7 @@ 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"; |
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_Create"; |
return false; |
} |
@@ -137,7 +179,7 @@ bool Tpm::OpenAndConnectTpm(TSS_HCONTEXT* context_handle) { |
if (result == TSS_E_COMM_FAILURE) { |
PlatformThread::Sleep(kTpmConnectIntervalMs); |
} else { |
- LOG(ERROR) << "Error calling Tspi_Context_Connect: " << result; |
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_Connect"; |
Tspi_Context_Close(local_context_handle); |
return false; |
} |
@@ -147,7 +189,7 @@ bool Tpm::OpenAndConnectTpm(TSS_HCONTEXT* context_handle) { |
} |
if (result) { |
- LOG(ERROR) << "Error calling Tspi_Context_Connect: " << result; |
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_Connect"; |
Tspi_Context_Close(local_context_handle); |
return false; |
} |
@@ -156,28 +198,6 @@ bool Tpm::OpenAndConnectTpm(TSS_HCONTEXT* context_handle) { |
return true; |
} |
-bool Tpm::IsDisabledCheckViaSysfs() { |
- std::string contents; |
- if (!file_util::ReadFileToString(FilePath(kTpmCheckEnabledFile), &contents)) { |
- return false; |
- } |
- if (contents.size() < 1) { |
- return false; |
- } |
- return (contents[0] == '0'); |
-} |
- |
-bool Tpm::IsOwnedCheckViaSysfs() { |
- std::string contents; |
- if (!file_util::ReadFileToString(FilePath(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; |
@@ -218,13 +238,13 @@ bool Tpm::CreateEndorsementKey(TSS_HCONTEXT context_handle) { |
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 @@ bool Tpm::IsEndorsementKeyAvailable(TSS_HCONTEXT context_handle) { |
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 @@ bool Tpm::IsEndorsementKeyAvailable(TSS_HCONTEXT context_handle) { |
} |
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 @@ bool Tpm::TakeOwnership(TSS_HCONTEXT context_handle, int max_timeout_tries, |
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 @@ bool Tpm::TakeOwnership(TSS_HCONTEXT context_handle, int max_timeout_tries, |
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 @@ bool Tpm::TakeOwnership(TSS_HCONTEXT context_handle, int max_timeout_tries, |
(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 @@ bool Tpm::ZeroSrkPassword(TSS_HCONTEXT context_handle, |
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 @@ bool Tpm::ZeroSrkPassword(TSS_HCONTEXT context_handle, |
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 @@ bool Tpm::ZeroSrkPassword(TSS_HCONTEXT context_handle, |
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 @@ bool Tpm::ZeroSrkPassword(TSS_HCONTEXT context_handle, |
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::ZeroSrkPassword(TSS_HCONTEXT context_handle, |
} |
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 @@ bool Tpm::UnrestrictSrk(TSS_HCONTEXT context_handle, |
if ((result = Tspi_TPM_GetStatus(tpm_handle, |
TSS_TPMSTATUS_DISABLEPUBSRKREAD, |
¤t_status))) { |
- LOG(ERROR) << "Error calling Tspi_TPM_GetStatus: " << result; |
+ TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetStatus"; |
return false; |
} |
@@ -387,7 +409,7 @@ bool Tpm::UnrestrictSrk(TSS_HCONTEXT context_handle, |
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 @@ bool Tpm::ChangeOwnerPassword(TSS_HCONTEXT context_handle, |
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 @@ bool Tpm::ChangeOwnerPassword(TSS_HCONTEXT context_handle, |
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 @@ bool Tpm::GetTpm(TSS_HCONTEXT context_handle, TSS_HTPM* tpm_handle) { |
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 @@ bool Tpm::GetTpmWithAuth(TSS_HCONTEXT context_handle, |
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 @@ bool Tpm::GetTpmWithAuth(TSS_HCONTEXT context_handle, |
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::GetOwnerPassword(chromeos::Blob* owner_password) { |
} |
bool Tpm::InitializeTpm(bool* OUT_took_ownership) { |
- if (OUT_took_ownership) { |
- *OUT_took_ownership = false; |
+ TpmStatus tpm_status; |
+ |
+ if (!LoadTpmStatus(&tpm_status)) { |
+ tpm_status.Clear(); |
+ tpm_status.set_flags(TpmStatus::NONE); |
} |
- if (!IsConnected()) { |
- Connect(); |
+ if (OUT_took_ownership) { |
+ *OUT_took_ownership = false; |
} |
- 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 @@ bool Tpm::InitializeTpm(bool* OUT_took_ownership) { |
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 @@ bool Tpm::InitializeTpm(bool* OUT_took_ownership) { |
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 @@ bool Tpm::InitializeTpm(bool* OUT_took_ownership) { |
// 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); |
- password_sync_lock_.Acquire(); |
- owner_password_.assign(owner_password.begin(), owner_password.end()); |
- password_sync_lock_.Release(); |
+ 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(); |
+ } |
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 @@ bool Tpm::GetRandomData(size_t length, chromeos::Blob* data) { |
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 @@ bool Tpm::GetRandomData(size_t length, chromeos::Blob* data) { |
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 |