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
25namespace tpm_manager {
26
27// Minimum size of TPM_DA_INFO struct.
28const size_t kMinimumDaInfoSize = 21;
29
30bool TpmStatusImpl::IsTpmEnabled() {
31  if (!is_enable_initialized_) {
32    RefreshOwnedEnabledInfo();
33  }
34  return is_enabled_;
35}
36
37bool TpmStatusImpl::IsTpmOwned() {
38  if (!is_owned_) {
39    RefreshOwnedEnabledInfo();
40  }
41  return is_owned_;
42}
43
44bool 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
76void 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
98bool 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