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 
39 namespace {
40 
41 using trunks::CommandTransceiver;
42 using trunks::TrunksFactory;
43 using trunks::TrunksFactoryImpl;
44 
PrintUsage()45 void 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 
HexEncode(const std::string & bytes)63 std::string HexEncode(const std::string& bytes) {
64   return base::HexEncode(bytes.data(), bytes.size());
65 }
66 
Startup(const TrunksFactory & factory)67 int Startup(const TrunksFactory& factory) {
68   factory.GetTpmUtility()->Shutdown();
69   return factory.GetTpmUtility()->Startup();
70 }
71 
Clear(const TrunksFactory & factory)72 int Clear(const TrunksFactory& factory) {
73   return factory.GetTpmUtility()->Clear();
74 }
75 
InitializeTpm(const TrunksFactory & factory)76 int InitializeTpm(const TrunksFactory& factory) {
77   return factory.GetTpmUtility()->InitializeTpm();
78 }
79 
AllocatePCR(const TrunksFactory & factory)80 int 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 
TakeOwnership(const std::string & owner_password,const TrunksFactory & factory)91 int 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 
DumpStatus(const TrunksFactory & factory)103 int 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 
ReadPCR(const TrunksFactory & factory,int index)137 int 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 
ExtendPCR(const TrunksFactory & factory,int index,const std::string & value)149 int 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 
main(int argc,char ** argv)163 int 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