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/tpm_utility.h>
23#include <trunks/trunks_factory_impl.h>
24
25#include "tpm_manager/common/local_data.pb.h"
26#include "tpm_manager/common/tpm_manager_constants.h"
27#include "tpm_manager/server/openssl_crypto_util_impl.h"
28
29namespace {
30const size_t kDefaultPasswordSize = 20;
31}  // namespace
32
33namespace tpm_manager {
34
35Tpm2InitializerImpl::Tpm2InitializerImpl(LocalDataStore* local_data_store,
36                                         TpmStatus* tpm_status)
37    : trunks_factory_(new trunks::TrunksFactoryImpl()),
38      openssl_util_(new OpensslCryptoUtilImpl()),
39      local_data_store_(local_data_store),
40      tpm_status_(tpm_status) {}
41
42Tpm2InitializerImpl::Tpm2InitializerImpl(trunks::TrunksFactory* factory,
43                                         OpensslCryptoUtil* openssl_util,
44                                         LocalDataStore* local_data_store,
45                                         TpmStatus* tpm_status)
46    : trunks_factory_(factory),
47      openssl_util_(openssl_util),
48      local_data_store_(local_data_store),
49      tpm_status_(tpm_status) {}
50
51bool Tpm2InitializerImpl::InitializeTpm() {
52  if (!SeedTpmRng()) {
53    return false;
54  }
55  if (tpm_status_->IsTpmOwned()) {
56    // Tpm is already owned, so we do not need to do anything.
57    VLOG(1) << "Tpm already owned.";
58    return true;
59  }
60  // First we read the local data. If we did not finish removing owner
61  // dependencies or if TakeOwnership failed, we want to retake ownership
62  // with the same passwords.
63  LocalData local_data;
64  if (!local_data_store_->Read(&local_data)) {
65    LOG(ERROR) << "Error reading local data.";
66    return false;
67  }
68  std::string owner_password;
69  std::string endorsement_password;
70  std::string lockout_password;
71  // If there are valid owner dependencies, we need to reuse the old passwords.
72  if (local_data.owner_dependency_size() > 0) {
73    owner_password.assign(local_data.owner_password());
74    endorsement_password.assign(local_data.endorsement_password());
75    lockout_password.assign(local_data.lockout_password());
76  } else {
77    if (!GetTpmRandomData(kDefaultPasswordSize, &owner_password)) {
78      LOG(ERROR) << "Error generating a random owner password.";
79      return false;
80    }
81    if (!GetTpmRandomData(kDefaultPasswordSize, &endorsement_password)) {
82      LOG(ERROR) << "Error generating a random endorsement password.";
83      return false;
84    }
85    if (!GetTpmRandomData(kDefaultPasswordSize, &lockout_password)) {
86      LOG(ERROR) << "Error generating a random lockout password.";
87      return false;
88    }
89  }
90  // We write the passwords to disk, in case there is an error while taking
91  // ownership.
92  local_data.clear_owner_dependency();
93  for (auto dependency: kInitialTpmOwnerDependencies) {
94    local_data.add_owner_dependency(dependency);
95  }
96  local_data.set_owner_password(owner_password);
97  local_data.set_endorsement_password(endorsement_password);
98  local_data.set_lockout_password(lockout_password);
99  if (!local_data_store_->Write(local_data)) {
100    LOG(ERROR) << "Error saving local data.";
101    return false;
102  }
103  trunks::TPM_RC result = trunks_factory_->GetTpmUtility()->TakeOwnership(
104      owner_password, endorsement_password, lockout_password);
105  if (result != trunks::TPM_RC_SUCCESS) {
106    LOG(ERROR) << "Error taking ownership of TPM2.0";
107    return false;
108  }
109  return true;
110}
111
112bool Tpm2InitializerImpl::SeedTpmRng() {
113  std::string random_bytes;
114  if (!openssl_util_->GetRandomBytes(kDefaultPasswordSize, &random_bytes)) {
115    return false;
116  }
117  trunks::TPM_RC result = trunks_factory_->GetTpmUtility()->StirRandom(
118      random_bytes, nullptr  /* No Authorization */);
119  if (result != trunks::TPM_RC_SUCCESS) {
120    return false;
121  }
122  return true;
123}
124
125bool Tpm2InitializerImpl::GetTpmRandomData(size_t num_bytes,
126                                           std::string* random_data) {
127  trunks::TPM_RC result = trunks_factory_->GetTpmUtility()->GenerateRandom(
128      num_bytes, nullptr  /* No Authorization */, random_data);
129  if (result != trunks::TPM_RC_SUCCESS) {
130    return false;
131  }
132  return true;
133}
134
135}  // namespace tpm_manager
136