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
GetContext()37 TSS_HCONTEXT TpmConnection::GetContext() {
38 if (!ConnectContextIfNeeded()) {
39 return 0;
40 }
41 return context_.value();
42 }
43
GetTpm()44 TSS_HTPM TpmConnection::GetTpm() {
45 if (!ConnectContextIfNeeded()) {
46 return 0;
47 }
48 TSS_RESULT result;
49 TSS_HTPM tpm_handle;
50 if (TPM_ERROR(result = Tspi_Context_GetTpmObject(context_.value(),
51 &tpm_handle))) {
52 TPM_LOG(ERROR, result) << "Error getting a handle to the TPM.";
53 return 0;
54 }
55 return tpm_handle;
56 }
57
GetTpmWithAuth(const std::string & owner_password)58 TSS_HTPM TpmConnection::GetTpmWithAuth(const std::string& owner_password) {
59 TSS_HTPM tpm_handle = GetTpm();
60 if (tpm_handle == 0) {
61 return 0;
62 }
63 TSS_RESULT result;
64 TSS_HPOLICY tpm_usage_policy;
65 if (TPM_ERROR(result = Tspi_GetPolicyObject(tpm_handle,
66 TSS_POLICY_USAGE,
67 &tpm_usage_policy))) {
68 TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject";
69 return false;
70 }
71 if (TPM_ERROR(result = Tspi_Policy_SetSecret(
72 tpm_usage_policy,
73 TSS_SECRET_MODE_PLAIN,
74 owner_password.size(),
75 reinterpret_cast<BYTE *>(const_cast<char*>(owner_password.data()))))) {
76 TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
77 return false;
78 }
79 return tpm_handle;
80 }
81
ConnectContextIfNeeded()82 bool TpmConnection::ConnectContextIfNeeded() {
83 if (context_.value() != 0) {
84 return true;
85 }
86 TSS_RESULT result;
87 if (TPM_ERROR(result = Tspi_Context_Create(context_.ptr()))) {
88 TPM_LOG(ERROR, result) << "Error connecting to TPM.";
89 return false;
90 }
91 // We retry on failure. It might be that tcsd is starting up.
92 for (int i = 0; i < kTpmConnectRetries; i++) {
93 if (TPM_ERROR(result = Tspi_Context_Connect(context_, nullptr))) {
94 if (ERROR_CODE(result) == TSS_E_COMM_FAILURE) {
95 base::PlatformThread::Sleep(
96 base::TimeDelta::FromMilliseconds(kTpmConnectIntervalMs));
97 } else {
98 TPM_LOG(ERROR, result) << "Error connecting to TPM.";
99 return false;
100 }
101 } else {
102 break;
103 }
104 }
105 return (context_.value() != 0);
106 }
107
108 } // namespace tpm_manager
109