| 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
|
|
|