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