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_connection.h" 18 19 #include <base/logging.h> 20 #include <base/stl_util.h> 21 #include <base/threading/platform_thread.h> 22 #include <base/time/time.h> 23 #include <trousers/tss.h> 24 #include <trousers/trousers.h> // NOLINT(build/include_alpha) 25 26 #include "tpm_manager/server/tpm_util.h" 27 28 namespace { 29 30 const int kTpmConnectRetries = 10; 31 const int kTpmConnectIntervalMs = 100; 32 33 } // namespace 34 35 namespace tpm_manager { 36 37 TpmConnection::TpmConnection(const std::string& authorization_value) 38 : authorization_value_(authorization_value) {} 39 40 TSS_HCONTEXT TpmConnection::GetContext() { 41 if (!ConnectContextIfNeeded()) { 42 return 0; 43 } 44 return context_.value(); 45 } 46 47 TSS_HTPM TpmConnection::GetTpm() { 48 if (!ConnectContextIfNeeded()) { 49 return 0; 50 } 51 TSS_RESULT result; 52 TSS_HTPM tpm_handle; 53 if (TPM_ERROR(result = 54 Tspi_Context_GetTpmObject(context_.value(), &tpm_handle))) { 55 TPM_LOG(ERROR, result) << "Error getting a handle to the TPM."; 56 return 0; 57 } 58 return tpm_handle; 59 } 60 61 bool TpmConnection::ConnectContextIfNeeded() { 62 if (context_.value() != 0) { 63 return true; 64 } 65 TSS_RESULT result; 66 if (TPM_ERROR(result = Tspi_Context_Create(context_.ptr()))) { 67 TPM_LOG(ERROR, result) << "Error connecting to TPM."; 68 return false; 69 } 70 // We retry on failure. It might be that tcsd is starting up. 71 for (int i = 0; i < kTpmConnectRetries; i++) { 72 if (TPM_ERROR(result = Tspi_Context_Connect(context_, nullptr))) { 73 if (ERROR_CODE(result) == TSS_E_COMM_FAILURE) { 74 base::PlatformThread::Sleep( 75 base::TimeDelta::FromMilliseconds(kTpmConnectIntervalMs)); 76 } else { 77 TPM_LOG(ERROR, result) << "Error connecting to TPM."; 78 return false; 79 } 80 } else { 81 break; 82 } 83 } 84 if (context_.value() == 0) { 85 LOG(ERROR) << "Unexpected NULL context."; 86 return false; 87 } 88 // If we don't need to set an authorization value, we're done. 89 if (authorization_value_.empty()) { 90 return true; 91 } 92 93 TSS_HTPM tpm_handle; 94 if (TPM_ERROR(result = 95 Tspi_Context_GetTpmObject(context_.value(), &tpm_handle))) { 96 TPM_LOG(ERROR, result) << "Error getting a handle to the TPM."; 97 context_.reset(); 98 return false; 99 } 100 TSS_HPOLICY tpm_usage_policy; 101 if (TPM_ERROR(result = Tspi_GetPolicyObject(tpm_handle, TSS_POLICY_USAGE, 102 &tpm_usage_policy))) { 103 TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject"; 104 context_.reset(); 105 return false; 106 } 107 if (TPM_ERROR(result = Tspi_Policy_SetSecret( 108 tpm_usage_policy, TSS_SECRET_MODE_PLAIN, 109 authorization_value_.size(), 110 reinterpret_cast<BYTE*>( 111 const_cast<char*>(authorization_value_.data()))))) { 112 TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; 113 context_.reset(); 114 return false; 115 } 116 return true; 117 } 118 119 } // namespace tpm_manager 120