Home | History | Annotate | Download | only in server
      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 
     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 
     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 
     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 
    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 
    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 
    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 
    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