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/tpm_initializer_impl.h" 18 19#include <string> 20 21#include <base/logging.h> 22#include <base/stl_util.h> 23#include <trousers/scoped_tss_type.h> 24 25#include "tpm_manager/server/local_data_store.h" 26#include "tpm_manager/server/tpm_connection.h" 27#include "tpm_manager/common/tpm_manager_constants.h" 28#include "tpm_manager/server/tpm_status.h" 29#include "tpm_manager/server/tpm_util.h" 30 31namespace { 32 33const char kDefaultOwnerPassword[] = TSS_WELL_KNOWN_SECRET; 34const size_t kDefaultPasswordSize = 20; 35const int kMaxOwnershipTimeoutRetries = 5; 36const char* kWellKnownSrkSecret = "well_known_srk_secret"; 37 38} // namespace 39 40namespace tpm_manager { 41 42TpmInitializerImpl::TpmInitializerImpl(LocalDataStore* local_data_store, 43 TpmStatus* tpm_status) 44 : local_data_store_(local_data_store), 45 tpm_status_(tpm_status) {} 46 47bool TpmInitializerImpl::InitializeTpm() { 48 if (tpm_status_->IsTpmOwned() && !TestTpmAuth(kDefaultOwnerPassword)) { 49 // Tpm is already owned, so we do not need to do anything. 50 VLOG(1) << "Tpm already owned."; 51 return true; 52 } 53 TSS_HTPM tpm_handle = tpm_connection_.GetTpm(); 54 if (tpm_handle == 0) { 55 return false; 56 } 57 if (!InitializeEndorsementKey(tpm_handle) || 58 !TakeOwnership(tpm_handle) || 59 !InitializeSrk(tpm_handle)) { 60 return false; 61 } 62 std::string owner_password; 63 if (!openssl_util_.GetRandomBytes(kDefaultPasswordSize, &owner_password)) { 64 return false; 65 } 66 LocalData local_data; 67 local_data.clear_owner_dependency(); 68 for (auto value: kInitialTpmOwnerDependencies) { 69 local_data.add_owner_dependency(value); 70 } 71 local_data.set_owner_password(owner_password); 72 if (!local_data_store_->Write(local_data)) { 73 LOG(ERROR) << "Error saving local data."; 74 return false; 75 } 76 if (!ChangeOwnerPassword(tpm_handle, owner_password)) { 77 return false; 78 } 79 return true; 80} 81 82bool TpmInitializerImpl::InitializeEndorsementKey(TSS_HTPM tpm_handle) { 83 trousers::ScopedTssKey local_key_handle(tpm_connection_.GetContext()); 84 TSS_RESULT result = Tspi_TPM_GetPubEndorsementKey(tpm_handle, 85 false, 86 nullptr, 87 local_key_handle.ptr()); 88 if (TPM_ERROR(result) == TPM_SUCCESS) { 89 // In this case the EK already exists, so we can return true here. 90 return true; 91 } 92 // At this point the EK does not exist, so we create it. 93 TSS_FLAG init_flags = TSS_KEY_TYPE_LEGACY | TSS_KEY_SIZE_2048; 94 if (TPM_ERROR(result = Tspi_Context_CreateObject(tpm_connection_.GetContext(), 95 TSS_OBJECT_TYPE_RSAKEY, 96 init_flags, 97 local_key_handle.ptr()))) { 98 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; 99 return false; 100 } 101 if (TPM_ERROR(result = Tspi_TPM_CreateEndorsementKey(tpm_handle, 102 local_key_handle, 103 NULL))) { 104 TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_CreateEndorsementKey"; 105 return false; 106 } 107 return true; 108} 109 110bool TpmInitializerImpl::TakeOwnership(TSS_HTPM tpm_handle) { 111 if (TestTpmAuth(kDefaultOwnerPassword)) { 112 VLOG(1) << "The Tpm already has the default owner password."; 113 return true; 114 } 115 TSS_RESULT result; 116 trousers::ScopedTssKey srk_handle(tpm_connection_.GetContext()); 117 TSS_FLAG init_flags = TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION; 118 if (TPM_ERROR(result = Tspi_Context_CreateObject(tpm_connection_.GetContext(), 119 TSS_OBJECT_TYPE_RSAKEY, 120 init_flags, 121 srk_handle.ptr()))) { 122 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; 123 return false; 124 } 125 TSS_HPOLICY srk_usage_policy; 126 if (TPM_ERROR(result = Tspi_GetPolicyObject(srk_handle, 127 TSS_POLICY_USAGE, 128 &srk_usage_policy))) { 129 TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject"; 130 return false; 131 } 132 if (TPM_ERROR(result = Tspi_Policy_SetSecret( 133 srk_usage_policy, 134 TSS_SECRET_MODE_PLAIN, 135 strlen(kWellKnownSrkSecret), 136 const_cast<BYTE *>(reinterpret_cast<const BYTE *>( 137 kWellKnownSrkSecret))))) { 138 TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; 139 return false; 140 } 141 // Tspi_TPM_TakeOwnership can potentailly take a long time to complete, 142 // so we retry if there is a timeout in any layer. I chose 5, because the 143 // longest TakeOwnership call that I have seen took ~2min, and the default 144 // TSS timeout is 30s. This means that after 5 calls, it is quite likely that 145 // this call will succeed. 146 int retry_count = 0; 147 do { 148 result = Tspi_TPM_TakeOwnership(tpm_handle, srk_handle, 0); 149 retry_count++; 150 } while (((result == TDDL_E_TIMEOUT) || 151 (result == (TSS_LAYER_TDDL | TDDL_E_TIMEOUT)) || 152 (result == (TSS_LAYER_TDDL | TDDL_E_IOERROR))) && 153 (retry_count < kMaxOwnershipTimeoutRetries)); 154 if (result) { 155 TPM_LOG(ERROR, result) 156 << "Error calling Tspi_TPM_TakeOwnership, attempts: " << retry_count; 157 return false; 158 } 159 return true; 160} 161 162bool TpmInitializerImpl::InitializeSrk(TSS_HTPM tpm_handle) { 163 TSS_RESULT result; 164 trousers::ScopedTssKey srk_handle(tpm_connection_.GetContext()); 165 TSS_UUID SRK_UUID = TSS_UUID_SRK; 166 if (TPM_ERROR(result = Tspi_Context_LoadKeyByUUID( 167 tpm_connection_.GetContext(), 168 TSS_PS_TYPE_SYSTEM, 169 SRK_UUID, 170 srk_handle.ptr()))) { 171 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_LoadKeyByUUID"; 172 return false; 173 } 174 175 trousers::ScopedTssPolicy policy_handle(tpm_connection_.GetContext()); 176 if (TPM_ERROR(result = Tspi_Context_CreateObject(tpm_connection_.GetContext(), 177 TSS_OBJECT_TYPE_POLICY, 178 TSS_POLICY_USAGE, 179 policy_handle.ptr()))) { 180 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; 181 return false; 182 } 183 BYTE new_password[0]; 184 if (TPM_ERROR(result = Tspi_Policy_SetSecret(policy_handle, 185 TSS_SECRET_MODE_PLAIN, 186 0, 187 new_password))) { 188 TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; 189 return false; 190 } 191 192 if (TPM_ERROR(result = Tspi_ChangeAuth(srk_handle, 193 tpm_handle, 194 policy_handle))) { 195 TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth"; 196 return false; 197 } 198 TSS_BOOL is_srk_restricted = false; 199 if (TPM_ERROR(result = Tspi_TPM_GetStatus(tpm_handle, 200 TSS_TPMSTATUS_DISABLEPUBSRKREAD, 201 &is_srk_restricted))) { 202 TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetStatus"; 203 return false; 204 } 205 // If the SRK is restricted, we unrestrict it. 206 if (is_srk_restricted) { 207 if (TPM_ERROR(result = Tspi_TPM_SetStatus(tpm_handle, 208 TSS_TPMSTATUS_DISABLEPUBSRKREAD, 209 false))) { 210 TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_SetStatus"; 211 return false; 212 } 213 } 214 return true; 215} 216 217bool TpmInitializerImpl::ChangeOwnerPassword( 218 TSS_HTPM tpm_handle, const std::string& owner_password) { 219 TSS_RESULT result; 220 trousers::ScopedTssPolicy policy_handle(tpm_connection_.GetContext()); 221 if (TPM_ERROR(result = Tspi_Context_CreateObject(tpm_connection_.GetContext(), 222 TSS_OBJECT_TYPE_POLICY, 223 TSS_POLICY_USAGE, 224 policy_handle.ptr()))) { 225 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; 226 return false; 227 } 228 std::string mutable_owner_password(owner_password); 229 if (TPM_ERROR(result = Tspi_Policy_SetSecret(policy_handle, 230 TSS_SECRET_MODE_PLAIN, 231 owner_password.size(), 232 reinterpret_cast<BYTE *>(string_as_array(&mutable_owner_password))))) { 233 TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; 234 return false; 235 } 236 237 if (TPM_ERROR(result = Tspi_ChangeAuth(tpm_handle, 0, policy_handle))) { 238 TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth"; 239 return false; 240 } 241 242 return true; 243} 244 245bool TpmInitializerImpl::TestTpmAuth(const std::string& owner_password) { 246 TSS_HTPM tpm_handle = tpm_connection_.GetTpmWithAuth(owner_password); 247 if (tpm_handle == 0) { 248 return false; 249 } 250 // Call Tspi_TPM_GetStatus to test the |owner_password| provided. 251 TSS_RESULT result; 252 TSS_BOOL current_status = false; 253 if (TPM_ERROR(result = Tspi_TPM_GetStatus(tpm_handle, 254 TSS_TPMSTATUS_DISABLED, 255 ¤t_status))) { 256 return false; 257 } 258 return true; 259} 260 261} // namespace tpm_manager 262