1// 2// Copyright (C) 2015 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "tpm_manager/server/tpm2_initializer_impl.h" 18 19#include <string> 20 21#include <base/logging.h> 22#include <trunks/error_codes.h> 23#include <trunks/tpm_utility.h> 24#include <trunks/trunks_factory_impl.h> 25 26#include "tpm_manager/common/tpm_manager.pb.h" 27#include "tpm_manager/common/tpm_manager_constants.h" 28#include "tpm_manager/server/openssl_crypto_util_impl.h" 29 30using trunks::TPM_RC; 31using trunks::TPM_RC_SUCCESS; 32 33namespace { 34const size_t kDefaultPasswordSize = 20; 35} // namespace 36 37namespace tpm_manager { 38 39Tpm2InitializerImpl::Tpm2InitializerImpl(const trunks::TrunksFactory& factory, 40 LocalDataStore* local_data_store, 41 TpmStatus* tpm_status) 42 : trunks_factory_(factory), 43 openssl_util_(new OpensslCryptoUtilImpl()), 44 local_data_store_(local_data_store), 45 tpm_status_(tpm_status) {} 46 47Tpm2InitializerImpl::Tpm2InitializerImpl(const trunks::TrunksFactory& factory, 48 OpensslCryptoUtil* openssl_util, 49 LocalDataStore* local_data_store, 50 TpmStatus* tpm_status) 51 : trunks_factory_(factory), 52 openssl_util_(openssl_util), 53 local_data_store_(local_data_store), 54 tpm_status_(tpm_status) {} 55 56bool Tpm2InitializerImpl::InitializeTpm() { 57 if (!SeedTpmRng()) { 58 return false; 59 } 60 if (tpm_status_->IsTpmOwned()) { 61 // Tpm is already owned, so we do not need to do anything. 62 VLOG(1) << "Tpm already owned."; 63 return true; 64 } 65 // First we read the local data. If we did not finish removing owner 66 // dependencies or if TakeOwnership failed, we want to retake ownership 67 // with the same passwords. 68 LocalData local_data; 69 if (!local_data_store_->Read(&local_data)) { 70 LOG(ERROR) << "Error reading local data."; 71 return false; 72 } 73 std::string owner_password; 74 std::string endorsement_password; 75 std::string lockout_password; 76 // If there are valid owner dependencies, we need to reuse the old passwords. 77 if (local_data.owner_dependency_size() > 0) { 78 owner_password.assign(local_data.owner_password()); 79 endorsement_password.assign(local_data.endorsement_password()); 80 lockout_password.assign(local_data.lockout_password()); 81 } else { 82 if (!GetTpmRandomData(kDefaultPasswordSize, &owner_password)) { 83 LOG(ERROR) << "Error generating a random owner password."; 84 return false; 85 } 86 if (!GetTpmRandomData(kDefaultPasswordSize, &endorsement_password)) { 87 LOG(ERROR) << "Error generating a random endorsement password."; 88 return false; 89 } 90 if (!GetTpmRandomData(kDefaultPasswordSize, &lockout_password)) { 91 LOG(ERROR) << "Error generating a random lockout password."; 92 return false; 93 } 94 } 95 // We write the passwords to disk, in case there is an error while taking 96 // ownership. 97 local_data.clear_owner_dependency(); 98 for (auto dependency : kInitialTpmOwnerDependencies) { 99 local_data.add_owner_dependency(dependency); 100 } 101 local_data.set_owner_password(owner_password); 102 local_data.set_endorsement_password(endorsement_password); 103 local_data.set_lockout_password(lockout_password); 104 if (!local_data_store_->Write(local_data)) { 105 LOG(ERROR) << "Error saving local data."; 106 return false; 107 } 108 TPM_RC result = trunks_factory_.GetTpmUtility()->TakeOwnership( 109 owner_password, endorsement_password, lockout_password); 110 if (result != TPM_RC_SUCCESS) { 111 LOG(ERROR) << "Error taking ownership of TPM2.0"; 112 return false; 113 } 114 115 return true; 116} 117 118void Tpm2InitializerImpl::VerifiedBootHelper() { 119 constexpr char kVerifiedBootLateStageTag[] = "BOOT_PCR_LATE_STAGE"; 120 std::unique_ptr<trunks::TpmUtility> tpm_utility = 121 trunks_factory_.GetTpmUtility(); 122 // Make sure PCRs 0-3 can't be spoofed from this point forward. 123 for (int pcr : {0, 1, 2, 3}) { 124 std::string value; 125 TPM_RC result = tpm_utility->ReadPCR(pcr, &value); 126 if (result) { 127 LOG(ERROR) << "Failed to read PCR " << pcr << ": " 128 << trunks::GetErrorString(result); 129 continue; 130 } 131 if (value == std::string(32, 0)) { 132 LOG(WARNING) << "WARNING: Verified boot PCR " << pcr 133 << " is not initialized."; 134 result = tpm_utility->ExtendPCR(pcr, kVerifiedBootLateStageTag, nullptr); 135 if (result) { 136 LOG(ERROR) << "Failed to extend PCR " << pcr << ": " 137 << trunks::GetErrorString(result); 138 } 139 } 140 } 141} 142 143bool Tpm2InitializerImpl::ResetDictionaryAttackLock() { 144 LocalData local_data; 145 if (!local_data_store_->Read(&local_data)) { 146 LOG(ERROR) << __func__ << ": Error reading local data."; 147 return false; 148 } 149 if (!local_data.has_lockout_password()) { 150 LOG(ERROR) << __func__ << ": Lockout password not available."; 151 return false; 152 } 153 std::unique_ptr<trunks::HmacSession> session = 154 trunks_factory_.GetHmacSession(); 155 TPM_RC result = session->StartUnboundSession(false); 156 if (result != TPM_RC_SUCCESS) { 157 LOG(ERROR) << __func__ << ": Error initializing AuthorizationSession: " 158 << trunks::GetErrorString(result); 159 return false; 160 } 161 session->SetEntityAuthorizationValue(local_data.lockout_password()); 162 std::unique_ptr<trunks::TpmUtility> tpm_utility = 163 trunks_factory_.GetTpmUtility(); 164 result = 165 tpm_utility->ResetDictionaryAttackLock(session->GetDelegate()); 166 if (result != TPM_RC_SUCCESS) { 167 LOG(ERROR) << __func__ << ": Error resetting lock: " 168 << trunks::GetErrorString(result); 169 return false; 170 } 171 return true; 172} 173 174bool Tpm2InitializerImpl::SeedTpmRng() { 175 std::string random_bytes; 176 if (!openssl_util_->GetRandomBytes(kDefaultPasswordSize, &random_bytes)) { 177 return false; 178 } 179 TPM_RC result = trunks_factory_.GetTpmUtility()->StirRandom( 180 random_bytes, nullptr /* No Authorization */); 181 if (result != TPM_RC_SUCCESS) { 182 return false; 183 } 184 return true; 185} 186 187bool Tpm2InitializerImpl::GetTpmRandomData(size_t num_bytes, 188 std::string* random_data) { 189 TPM_RC result = trunks_factory_.GetTpmUtility()->GenerateRandom( 190 num_bytes, nullptr /* No Authorization */, random_data); 191 if (result != TPM_RC_SUCCESS) { 192 return false; 193 } 194 return true; 195} 196 197} // namespace tpm_manager 198