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
30 using trunks::TPM_RC;
31 using trunks::TPM_RC_SUCCESS;
32
33 namespace {
34 const size_t kDefaultPasswordSize = 20;
35 } // namespace
36
37 namespace tpm_manager {
38
Tpm2InitializerImpl(const trunks::TrunksFactory & factory,LocalDataStore * local_data_store,TpmStatus * tpm_status)39 Tpm2InitializerImpl::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
Tpm2InitializerImpl(const trunks::TrunksFactory & factory,OpensslCryptoUtil * openssl_util,LocalDataStore * local_data_store,TpmStatus * tpm_status)47 Tpm2InitializerImpl::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
InitializeTpm()56 bool 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
VerifiedBootHelper()118 void 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
ResetDictionaryAttackLock()143 bool 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
SeedTpmRng()174 bool 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
GetTpmRandomData(size_t num_bytes,std::string * random_data)187 bool 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