| // Copyright 2015 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "tpm_manager/server/tpm2_status_impl.h" |
| |
| #include <string> |
| |
| #include <base/check.h> |
| #include <base/logging.h> |
| #include <trunks/error_codes.h> |
| #include <trunks/tpm_generated.h> |
| #include <trunks/trunks_factory_impl.h> |
| |
| using trunks::TPM_RC; |
| using trunks::TPM_RC_SUCCESS; |
| |
| namespace tpm_manager { |
| |
| namespace { |
| |
| tpm_manager::RoVerificationStatus MapRoStatus( |
| const trunks::TpmUtility::ApRoStatus& raw_status) { |
| switch (raw_status) { |
| case trunks::TpmUtility::ApRoStatus::kApRoNotRun: |
| return tpm_manager::RO_STATUS_NOT_TRIGGERED; |
| case trunks::TpmUtility::ApRoStatus::kApRoPass: |
| return tpm_manager::RO_STATUS_PASS; |
| case trunks::TpmUtility::ApRoStatus::kApRoFail: |
| return tpm_manager::RO_STATUS_FAIL; |
| case trunks::TpmUtility::ApRoStatus::kApRoUnsupportedUnknown: |
| return tpm_manager::RO_STATUS_UNSUPPORTED; |
| case trunks::TpmUtility::ApRoStatus::kApRoUnsupportedNotTriggered: |
| return tpm_manager::RO_STATUS_UNSUPPORTED_NOT_TRIGGERED; |
| case trunks::TpmUtility::ApRoStatus::kApRoUnsupportedTriggered: |
| return tpm_manager::RO_STATUS_UNSUPPORTED_TRIGGERED; |
| } |
| NOTREACHED(); |
| } |
| |
| } // namespace |
| |
| Tpm2StatusImpl::Tpm2StatusImpl(const trunks::TrunksFactory& factory) |
| : trunks_factory_(factory), |
| trunks_tpm_state_(trunks_factory_.GetTpmState()), |
| trunks_tpm_utility_(trunks_factory_.GetTpmUtility()) {} |
| |
| bool Tpm2StatusImpl::IsTpmEnabled() { |
| // For 2.0, TPM is always enabled. |
| return true; |
| } |
| |
| bool Tpm2StatusImpl::GetTpmOwned(TpmStatus::TpmOwnershipStatus* status) { |
| CHECK(status); |
| if (kTpmOwned == ownership_status_) { |
| *status = kTpmOwned; |
| return true; |
| } |
| |
| if (!Refresh()) { |
| return false; |
| } |
| |
| if (trunks_tpm_state_->IsOwned() && TestTpmSrkAndSaltingSession()) { |
| ownership_status_ = kTpmOwned; |
| } else if (trunks_tpm_state_->IsOwnerPasswordSet()) { |
| ownership_status_ = kTpmPreOwned; |
| } |
| |
| *status = ownership_status_; |
| return true; |
| } |
| |
| bool Tpm2StatusImpl::GetDictionaryAttackInfo(uint32_t* counter, |
| uint32_t* threshold, |
| bool* lockout, |
| uint32_t* seconds_remaining) { |
| CHECK(counter); |
| CHECK(threshold); |
| CHECK(lockout); |
| CHECK(seconds_remaining); |
| |
| if (!Refresh()) { |
| return false; |
| } |
| |
| *counter = trunks_tpm_state_->GetLockoutCounter(); |
| *threshold = trunks_tpm_state_->GetLockoutThreshold(); |
| *lockout = trunks_tpm_state_->IsInLockout(); |
| *seconds_remaining = trunks_tpm_state_->GetLockoutCounter() * |
| trunks_tpm_state_->GetLockoutInterval(); |
| return true; |
| } |
| |
| bool Tpm2StatusImpl::IsDictionaryAttackMitigationEnabled(bool* is_enabled) { |
| CHECK(is_enabled); |
| |
| if (!Refresh()) { |
| return false; |
| } |
| *is_enabled = trunks_tpm_state_->GetLockoutInterval() != 0 || |
| trunks_tpm_state_->GetLockoutRecovery() != 0; |
| return true; |
| } |
| |
| bool Tpm2StatusImpl::GetVersionInfo(uint32_t* family, |
| uint64_t* spec_level, |
| uint32_t* manufacturer, |
| uint32_t* tpm_model, |
| uint64_t* firmware_version, |
| std::vector<uint8_t>* vendor_specific) { |
| CHECK(family); |
| CHECK(spec_level); |
| CHECK(manufacturer); |
| CHECK(tpm_model); |
| CHECK(firmware_version); |
| CHECK(vendor_specific); |
| |
| if (!Refresh()) { |
| return false; |
| } |
| |
| *family = trunks_tpm_state_->GetTpmFamily(); |
| |
| uint64_t level = trunks_tpm_state_->GetSpecificationLevel(); |
| uint64_t revision = trunks_tpm_state_->GetSpecificationRevision(); |
| *spec_level = (level << 32) | revision; |
| |
| *manufacturer = trunks_tpm_state_->GetManufacturer(); |
| *tpm_model = trunks_tpm_state_->GetTpmModel(); |
| *firmware_version = trunks_tpm_state_->GetFirmwareVersion(); |
| |
| std::string vendor_id_string = trunks_tpm_state_->GetVendorIDString(); |
| const uint8_t* data = |
| reinterpret_cast<const uint8_t*>(vendor_id_string.data()); |
| vendor_specific->assign(data, data + vendor_id_string.size()); |
| return true; |
| } |
| |
| bool Tpm2StatusImpl::Refresh() { |
| TPM_RC result = trunks_tpm_state_->Initialize(); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(ERROR) << "Error initializing trunks tpm state: " |
| << trunks::GetErrorString(result); |
| return false; |
| } |
| initialized_ = true; |
| return true; |
| } |
| |
| void Tpm2StatusImpl::MarkRandomOwnerPasswordSet() { |
| LOG(ERROR) << __func__ << ": Not implemented"; |
| } |
| |
| bool Tpm2StatusImpl::SupportU2f() { |
| // We support U2F on Cr50. |
| if (trunks_tpm_utility_->IsCr50()) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool Tpm2StatusImpl::SupportPinweaver() { |
| uint8_t protocol_version; |
| |
| if (trunks_tpm_utility_->PinWeaverIsSupported(0, &protocol_version) == |
| TPM_RC_SUCCESS) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| GscVersion Tpm2StatusImpl::GetGscVersion() { |
| // Currently we don't have method to distinguish Ti50. |
| |
| if (trunks_tpm_utility_->IsCr50()) { |
| return GscVersion::GSC_VERSION_CR50; |
| } |
| |
| return GscVersion::GSC_VERSION_NOT_GSC; |
| } |
| |
| bool Tpm2StatusImpl::TestTpmSrkAndSaltingSession() { |
| trunks::TPMT_PUBLIC public_area; |
| TPM_RC result = trunks_tpm_utility_->GetKeyPublicArea(trunks::kStorageRootKey, |
| &public_area); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(WARNING) << "Failed to get the SRK public area: " |
| << trunks::GetErrorString(result); |
| return false; |
| } |
| if (!(public_area.object_attributes & trunks::kSensitiveDataOrigin)) { |
| LOG(WARNING) << "SRK doesn't have kSensitiveDataOrigin attribute."; |
| return false; |
| } |
| if (!(public_area.object_attributes & trunks::kUserWithAuth)) { |
| LOG(WARNING) << "SRK doesn't have kUserWithAuth attribute."; |
| return false; |
| } |
| if (!(public_area.object_attributes & trunks::kNoDA)) { |
| LOG(WARNING) << "SRK doesn't have kNoDA attribute."; |
| return false; |
| } |
| if (!(public_area.object_attributes & trunks::kRestricted)) { |
| LOG(WARNING) << "SRK doesn't have kRestricted attribute."; |
| return false; |
| } |
| if (!(public_area.object_attributes & trunks::kDecrypt)) { |
| LOG(WARNING) << "SRK doesn't have kDecrypt attribute."; |
| return false; |
| } |
| |
| // Check the salting session. |
| std::unique_ptr<trunks::HmacSession> session = |
| trunks_factory_.GetHmacSession(); |
| result = session->StartUnboundSession(true, false); |
| if (result != TPM_RC_SUCCESS) { |
| LOG(WARNING) << "Failed to create unbound session: " |
| << trunks::GetErrorString(result); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool Tpm2StatusImpl::GetRoVerificationStatus( |
| tpm_manager::RoVerificationStatus* status) { |
| trunks::TpmUtility::ApRoStatus raw_status; |
| TPM_RC result = trunks_tpm_utility_->GetRoVerificationStatus(&raw_status); |
| if (result != TPM_RC_SUCCESS) { |
| return false; |
| } |
| *status = MapRoStatus(raw_status); |
| return true; |
| } |
| |
| } // namespace tpm_manager |