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