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_status_impl.h"
18 
19 #include <vector>
20 
21 #include <base/logging.h>
22 #include <trousers/tss.h>
23 #include <trousers/trousers.h>  // NOLINT(build/include_alpha)
24 
25 namespace tpm_manager {
26 
27 // Minimum size of TPM_DA_INFO struct.
28 const size_t kMinimumDaInfoSize = 21;
29 
IsTpmEnabled()30 bool TpmStatusImpl::IsTpmEnabled() {
31   if (!is_enable_initialized_) {
32     RefreshOwnedEnabledInfo();
33   }
34   return is_enabled_;
35 }
36 
IsTpmOwned()37 bool TpmStatusImpl::IsTpmOwned() {
38   if (!is_owned_) {
39     RefreshOwnedEnabledInfo();
40   }
41   return is_owned_;
42 }
43 
GetDictionaryAttackInfo(int * counter,int * threshold,bool * lockout,int * seconds_remaining)44 bool TpmStatusImpl::GetDictionaryAttackInfo(int* counter,
45                                             int* threshold,
46                                             bool* lockout,
47                                             int* seconds_remaining) {
48   std::string capability_data;
49   if (!GetCapability(TSS_TPMCAP_DA_LOGIC, TPM_ET_KEYHANDLE, &capability_data,
50                      nullptr) ||
51       capability_data.size() < kMinimumDaInfoSize) {
52     LOG(ERROR) << "Error getting tpm capability data.";
53     return false;
54   }
55   if (static_cast<uint16_t>(capability_data[1]) == TPM_TAG_DA_INFO) {
56     TPM_DA_INFO da_info;
57     uint64_t offset = 0;
58     std::vector<BYTE> bytes(capability_data.begin(), capability_data.end());
59     Trspi_UnloadBlob_DA_INFO(&offset, bytes.data(), &da_info);
60     if (counter) {
61       *counter = da_info.currentCount;
62     }
63     if (threshold) {
64       *threshold = da_info.thresholdCount;
65     }
66     if (lockout) {
67       *lockout = (da_info.state == TPM_DA_STATE_ACTIVE);
68     }
69     if (seconds_remaining) {
70       *seconds_remaining = da_info.actionDependValue;
71     }
72   }
73   return true;
74 }
75 
RefreshOwnedEnabledInfo()76 void TpmStatusImpl::RefreshOwnedEnabledInfo() {
77   TSS_RESULT result;
78   std::string capability_data;
79   if (!GetCapability(TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_OWNER,
80                      &capability_data, &result)) {
81     if (ERROR_CODE(result) == TPM_E_DISABLED) {
82       is_enable_initialized_ = true;
83       is_enabled_ = false;
84     }
85   } else {
86     is_enable_initialized_ = true;
87     is_enabled_ = true;
88     // |capability_data| should be populated with a TSS_BOOL which is true iff
89     // the Tpm is owned.
90     if (capability_data.size() != sizeof(TSS_BOOL)) {
91       LOG(ERROR) << "Error refreshing Tpm ownership information.";
92       return;
93     }
94     is_owned_ = (capability_data[0] != 0);
95   }
96 }
97 
GetCapability(uint32_t capability,uint32_t sub_capability,std::string * data,TSS_RESULT * tpm_result)98 bool TpmStatusImpl::GetCapability(uint32_t capability,
99                                   uint32_t sub_capability,
100                                   std::string* data,
101                                   TSS_RESULT* tpm_result) {
102   CHECK(data);
103   TSS_HTPM tpm_handle = tpm_connection_.GetTpm();
104   if (tpm_handle == 0) {
105     return false;
106   }
107   uint32_t length = 0;
108   trousers::ScopedTssMemory buf(tpm_connection_.GetContext());
109   TSS_RESULT result = Tspi_TPM_GetCapability(
110       tpm_handle, capability, sizeof(uint32_t),
111       reinterpret_cast<BYTE*>(&sub_capability), &length, buf.ptr());
112   if (tpm_result) {
113     *tpm_result = result;
114   }
115   if (TPM_ERROR(result)) {
116     LOG(ERROR) << "Error getting TPM capability data.";
117     return false;
118   }
119   data->assign(buf.value(), buf.value() + length);
120   return true;
121 }
122 
123 }  // namespace tpm_manager
124