1//
2// Copyright (C) 2014 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// trunks_client is a command line tool that supports various TPM operations. It
18// does not provide direct access to the trunksd D-Bus interface.
19
20#include <stdio.h>
21#include <memory>
22#include <string>
23
24#include <base/command_line.h>
25#include <base/logging.h>
26#include <base/strings/string_number_conversions.h>
27#include <brillo/syslog_logging.h>
28
29#include "trunks/error_codes.h"
30#include "trunks/hmac_session.h"
31#include "trunks/password_authorization_delegate.h"
32#include "trunks/policy_session.h"
33#include "trunks/scoped_key_handle.h"
34#include "trunks/tpm_state.h"
35#include "trunks/tpm_utility.h"
36#include "trunks/trunks_client_test.h"
37#include "trunks/trunks_factory_impl.h"
38
39namespace {
40
41using trunks::CommandTransceiver;
42using trunks::TrunksFactory;
43using trunks::TrunksFactoryImpl;
44
45void PrintUsage() {
46  puts("Options:");
47  puts("  --allocate_pcr - Configures PCR 0-15 under the SHA256 bank.");
48  puts("  --clear - Clears the TPM. Use before initializing the TPM.");
49  puts("  --help - Prints this message.");
50  puts("  --init_tpm - Initializes a TPM as CrOS firmware does.");
51  puts("  --own - Takes ownership of the TPM with the provided password.");
52  puts("  --owner_password - used to provide an owner password");
53  puts("  --regression_test - Runs some basic regression tests. If");
54  puts("                      owner_password is supplied, it runs tests that");
55  puts("                      need owner permissions.");
56  puts("  --startup - Performs startup and self-tests.");
57  puts("  --status - Prints TPM status information.");
58  puts("  --stress_test - Runs some basic stress tests.");
59  puts("  --read_pcr --index=<N> - Reads a PCR and prints the value.");
60  puts("  --extend_pcr --index=<N> --value=<value> - Extends a PCR.");
61}
62
63std::string HexEncode(const std::string& bytes) {
64  return base::HexEncode(bytes.data(), bytes.size());
65}
66
67int Startup(const TrunksFactory& factory) {
68  factory.GetTpmUtility()->Shutdown();
69  return factory.GetTpmUtility()->Startup();
70}
71
72int Clear(const TrunksFactory& factory) {
73  return factory.GetTpmUtility()->Clear();
74}
75
76int InitializeTpm(const TrunksFactory& factory) {
77  return factory.GetTpmUtility()->InitializeTpm();
78}
79
80int AllocatePCR(const TrunksFactory& factory) {
81  trunks::TPM_RC result;
82  result = factory.GetTpmUtility()->AllocatePCR("");
83  if (result != trunks::TPM_RC_SUCCESS) {
84    LOG(ERROR) << "Error allocating PCR:" << trunks::GetErrorString(result);
85    return result;
86  }
87  factory.GetTpmUtility()->Shutdown();
88  return factory.GetTpmUtility()->Startup();
89}
90
91int TakeOwnership(const std::string& owner_password,
92                  const TrunksFactory& factory) {
93  trunks::TPM_RC rc;
94  rc = factory.GetTpmUtility()->TakeOwnership(owner_password, owner_password,
95                                              owner_password);
96  if (rc) {
97    LOG(ERROR) << "Error taking ownership: " << trunks::GetErrorString(rc);
98    return rc;
99  }
100  return 0;
101}
102
103int DumpStatus(const TrunksFactory& factory) {
104  std::unique_ptr<trunks::TpmState> state = factory.GetTpmState();
105  trunks::TPM_RC result = state->Initialize();
106  if (result != trunks::TPM_RC_SUCCESS) {
107    LOG(ERROR) << "Failed to read TPM state: "
108               << trunks::GetErrorString(result);
109    return result;
110  }
111  printf("Owner password set: %s\n",
112         state->IsOwnerPasswordSet() ? "true" : "false");
113  printf("Endorsement password set: %s\n",
114         state->IsEndorsementPasswordSet() ? "true" : "false");
115  printf("Lockout password set: %s\n",
116         state->IsLockoutPasswordSet() ? "true" : "false");
117  printf("Ownership status: %s\n", state->IsOwned() ? "true" : "false");
118  printf("In lockout: %s\n", state->IsInLockout() ? "true" : "false");
119  printf("Platform hierarchy enabled: %s\n",
120         state->IsPlatformHierarchyEnabled() ? "true" : "false");
121  printf("Storage hierarchy enabled: %s\n",
122         state->IsStorageHierarchyEnabled() ? "true" : "false");
123  printf("Endorsement hierarchy enabled: %s\n",
124         state->IsEndorsementHierarchyEnabled() ? "true" : "false");
125  printf("Is Tpm enabled: %s\n", state->IsEnabled() ? "true" : "false");
126  printf("Was shutdown orderly: %s\n",
127         state->WasShutdownOrderly() ? "true" : "false");
128  printf("Is RSA supported: %s\n", state->IsRSASupported() ? "true" : "false");
129  printf("Is ECC supported: %s\n", state->IsECCSupported() ? "true" : "false");
130  printf("Lockout Counter: %u\n", state->GetLockoutCounter());
131  printf("Lockout Threshold: %u\n", state->GetLockoutThreshold());
132  printf("Lockout Interval: %u\n", state->GetLockoutInterval());
133  printf("Lockout Recovery: %u\n", state->GetLockoutRecovery());
134  return 0;
135}
136
137int ReadPCR(const TrunksFactory& factory, int index) {
138  std::unique_ptr<trunks::TpmUtility> tpm_utility = factory.GetTpmUtility();
139  std::string value;
140  trunks::TPM_RC result = tpm_utility->ReadPCR(index, &value);
141  if (result) {
142    LOG(ERROR) << "ReadPCR: " << trunks::GetErrorString(result);
143    return result;
144  }
145  printf("PCR Value: %s\n", HexEncode(value).c_str());
146  return 0;
147}
148
149int ExtendPCR(const TrunksFactory& factory,
150              int index,
151              const std::string& value) {
152  std::unique_ptr<trunks::TpmUtility> tpm_utility = factory.GetTpmUtility();
153  trunks::TPM_RC result = tpm_utility->ExtendPCR(index, value, nullptr);
154  if (result) {
155    LOG(ERROR) << "ExtendPCR: " << trunks::GetErrorString(result);
156    return result;
157  }
158  return 0;
159}
160
161}  // namespace
162
163int main(int argc, char** argv) {
164  base::CommandLine::Init(argc, argv);
165  brillo::InitLog(brillo::kLogToStderr);
166  base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
167  if (cl->HasSwitch("help")) {
168    puts("Trunks Client: A command line tool to access the TPM.");
169    PrintUsage();
170    return 0;
171  }
172
173  TrunksFactoryImpl factory;
174  CHECK(factory.Initialize()) << "Failed to initialize trunks factory.";
175
176  if (cl->HasSwitch("status")) {
177    return DumpStatus(factory);
178  }
179  if (cl->HasSwitch("startup")) {
180    return Startup(factory);
181  }
182  if (cl->HasSwitch("clear")) {
183    return Clear(factory);
184  }
185  if (cl->HasSwitch("init_tpm")) {
186    return InitializeTpm(factory);
187  }
188  if (cl->HasSwitch("allocate_pcr")) {
189    return AllocatePCR(factory);
190  }
191
192  if (cl->HasSwitch("own")) {
193    return TakeOwnership(cl->GetSwitchValueASCII("owner_password"), factory);
194  }
195  if (cl->HasSwitch("regression_test")) {
196    trunks::TrunksClientTest test(factory);
197    LOG(INFO) << "Running RNG test.";
198    if (!test.RNGTest()) {
199      LOG(ERROR) << "Error running RNGtest.";
200      return -1;
201    }
202    LOG(INFO) << "Running RSA key tests.";
203    if (!test.SignTest()) {
204      LOG(ERROR) << "Error running SignTest.";
205      return -1;
206    }
207    if (!test.DecryptTest()) {
208      LOG(ERROR) << "Error running DecryptTest.";
209      return -1;
210    }
211    if (!test.ImportTest()) {
212      LOG(ERROR) << "Error running ImportTest.";
213      return -1;
214    }
215    if (!test.AuthChangeTest()) {
216      LOG(ERROR) << "Error running AuthChangeTest.";
217      return -1;
218    }
219    if (!test.VerifyKeyCreationTest()) {
220      LOG(ERROR) << "Error running VerifyKeyCreationTest.";
221      return -1;
222    }
223    LOG(INFO) << "Running Sealed Data test.";
224    if (!test.SealedDataTest()) {
225      LOG(ERROR) << "Error running SealedDataTest.";
226      return -1;
227    }
228    LOG(INFO) << "Running PCR test.";
229    if (!test.PCRTest()) {
230      LOG(ERROR) << "Error running PCRTest.";
231      return -1;
232    }
233    LOG(INFO) << "Running policy tests.";
234    if (!test.PolicyAuthValueTest()) {
235      LOG(ERROR) << "Error running PolicyAuthValueTest.";
236      return -1;
237    }
238    if (!test.PolicyAndTest()) {
239      LOG(ERROR) << "Error running PolicyAndTest.";
240      return -1;
241    }
242    if (!test.PolicyOrTest()) {
243      LOG(ERROR) << "Error running PolicyOrTest.";
244      return -1;
245    }
246    if (cl->HasSwitch("owner_password")) {
247      std::string owner_password = cl->GetSwitchValueASCII("owner_password");
248      LOG(INFO) << "Running NVRAM test.";
249      if (!test.NvramTest(owner_password)) {
250        LOG(ERROR) << "Error running NvramTest.";
251        return -1;
252      }
253    }
254    LOG(INFO) << "All tests were run successfully.";
255    return 0;
256  }
257  if (cl->HasSwitch("stress_test")) {
258    LOG(INFO) << "Running stress tests.";
259    trunks::TrunksClientTest test(factory);
260    if (!test.ManyKeysTest()) {
261      LOG(ERROR) << "Error running ManyKeysTest.";
262      return -1;
263    }
264    if (!test.ManySessionsTest()) {
265      LOG(ERROR) << "Error running ManySessionsTest.";
266      return -1;
267    }
268    return 0;
269  }
270  if (cl->HasSwitch("read_pcr") && cl->HasSwitch("index")) {
271    return ReadPCR(factory, atoi(cl->GetSwitchValueASCII("index").c_str()));
272  }
273  if (cl->HasSwitch("extend_pcr") && cl->HasSwitch("index") &&
274      cl->HasSwitch("value")) {
275    return ExtendPCR(factory, atoi(cl->GetSwitchValueASCII("index").c_str()),
276                     cl->GetSwitchValueASCII("value"));
277  }
278  puts("Invalid options!");
279  PrintUsage();
280  return -1;
281}
282