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 <stdio.h>
18 #include <stdlib.h>
19 #include <sysexits.h>
20
21 #include <memory>
22 #include <string>
23
24 #include <base/command_line.h>
25 #include <base/files/file_util.h>
26 #include <base/logging.h>
27 #include <base/memory/ptr_util.h>
28 #include <base/message_loop/message_loop.h>
29 #include <brillo/bind_lambda.h>
30 #if defined(USE_BINDER_IPC)
31 #include <brillo/binder_watcher.h>
32 #endif
33 #include <brillo/daemons/daemon.h>
34 #include <brillo/syslog_logging.h>
35 #include <crypto/sha2.h>
36
37 #if defined(USE_BINDER_IPC)
38 #include "tpm_manager/client/tpm_nvram_binder_proxy.h"
39 #include "tpm_manager/client/tpm_ownership_binder_proxy.h"
40 #else
41 #include "tpm_manager/client/tpm_nvram_dbus_proxy.h"
42 #include "tpm_manager/client/tpm_ownership_dbus_proxy.h"
43 #endif
44 #include "tpm_manager/common/print_tpm_manager_proto.h"
45 #include "tpm_manager/common/tpm_manager.pb.h"
46 #include "trunks/tpm_generated.h"
47
48 namespace tpm_manager {
49
50 constexpr char kGetTpmStatusCommand[] = "status";
51 constexpr char kTakeOwnershipCommand[] = "take_ownership";
52 constexpr char kRemoveOwnerDependencyCommand[] = "remove_dependency";
53 constexpr char kDefineSpaceCommand[] = "define_space";
54 constexpr char kDestroySpaceCommand[] = "destroy_space";
55 constexpr char kWriteSpaceCommand[] = "write_space";
56 constexpr char kReadSpaceCommand[] = "read_space";
57 constexpr char kLockSpaceCommand[] = "lock_space";
58 constexpr char kListSpacesCommand[] = "list_spaces";
59 constexpr char kGetSpaceInfoCommand[] = "get_space_info";
60
61 constexpr char kDependencySwitch[] = "dependency";
62 constexpr char kIndexSwitch[] = "index";
63 constexpr char kSizeSwitch[] = "size";
64 constexpr char kAttributesSwitch[] = "attributes";
65 constexpr char kPasswordSwitch[] = "password";
66 constexpr char kBindToPCR0Switch[] = "bind_to_pcr0";
67 constexpr char kFileSwitch[] = "file";
68 constexpr char kUseOwnerSwitch[] = "use_owner_authorization";
69 constexpr char kLockRead[] = "lock_read";
70 constexpr char kLockWrite[] = "lock_write";
71
72 constexpr char kUsage[] = R"(
73 Usage: tpm_manager_client <command> [<arguments>]
74 Commands:
75 status
76 Prints TPM status information.
77 take_ownership
78 Takes ownership of the Tpm with a random password.
79 remove_dependency --dependency=<owner_dependency>
80 Removes the named Tpm owner dependency. E.g. \"Nvram\" or \"Attestation\".
81 define_space --index=<index> --size=<size> [--attributes=<attribute_list>]
82 [--password=<password>] [--bind_to_pcr0]
83 Defines an NV space. The attribute format is a '|' separated list of:
84 PERSISTENT_WRITE_LOCK: Allow write lock; stay locked until destroyed.
85 BOOT_WRITE_LOCK: Allow write lock; stay locked until next boot.
86 BOOT_READ_LOCK: Allow read lock; stay locked until next boot.
87 WRITE_AUTHORIZATION: Require authorization to write.
88 READ_AUTHORIZATION: Require authorization to read.
89 WRITE_EXTEND: Allow only extend operations, not direct writes.
90 GLOBAL_LOCK: Engage write lock when the global lock is engaged.
91 PLATFORM_WRITE: Allow write only with 'platform' authorization. This
92 is similar to the TPM 1.2 'physical presence' notion.
93 OWNER_WRITE: Allow write only with TPM owner authorization.
94 OWNER_READ: Allow read only with TPM owner authorization.
95 This command requires that owner authorization is available. If a password
96 is given it will be required only as specified by the attributes. E.g. if
97 READ_AUTHORIZATION is not listed, then the password will not be required
98 in order to read. Similarly, if the --bind_to_pcr0 option is given, the
99 current PCR0 value will be required only as specified by the attributes.
100 destroy_space --index=<index>
101 Destroys an NV space. This command requires that owner authorization is
102 available.
103 write_space --index=<index> --file=<input_file> [--password=<password>]
104 [--use_owner_authorization]
105 Writes data from a file to an NV space. Any existing data will be
106 overwritten.
107 read_space --index=<index> --file=<output_file> [--password=<password>]
108 [--use_owner_authorization]
109 Reads the entire contents of an NV space to a file.
110 lock_space --index=<index> [--lock_read] [--lock_write]
111 [--password=<password>] [--use_owner_authorization]
112 Locks an NV space for read and / or write.
113 list_spaces
114 Prints a list of all defined index values.
115 get_space_info --index=<index>
116 Prints public information about an NV space.
117 )";
118
119 constexpr char kKnownNVRAMSpaces[] = R"(
120 NVRAM Index Reference:
121 TPM 1.2 (32-bit values)
122 0x00001007 - Chrome OS Firmware Version Rollback Protection
123 0x00001008 - Chrome OS Kernel Version Rollback Protection
124 0x00001009 - Chrome OS Firmware Backup
125 0x0000100A - Chrome OS Firmware Management Parameters
126 0x20000004 - Chrome OS Install Attributes (aka LockBox)
127 0x10000001 - Standard TPM_NV_INDEX_DIR (Permanent)
128 0x1000F000 - Endorsement Certificate (Permanent)
129 0x30000001 - Endorsement Authority Certificate (Permanent)
130 0x0000F004 - Standard Test Index (for testing TPM_NV_DefineSpace)
131
132 TPM 2.0 (24-bit values)
133 0x400000 and following - Reserved for Firmware
134 0x800000 and following - Reserved for Software
135 0xC00000 and following - Endorsement Certificates
136 )";
137
ReadFileToString(const std::string & filename,std::string * data)138 bool ReadFileToString(const std::string& filename, std::string* data) {
139 return base::ReadFileToString(base::FilePath(filename), data);
140 }
141
WriteStringToFile(const std::string & data,const std::string & filename)142 bool WriteStringToFile(const std::string& data, const std::string& filename) {
143 int result =
144 base::WriteFile(base::FilePath(filename), data.data(), data.size());
145 return (result != -1 && static_cast<size_t>(result) == data.size());
146 }
147
StringToUint32(const std::string & s)148 uint32_t StringToUint32(const std::string& s) {
149 return strtoul(s.c_str(), nullptr, 0);
150 }
151
StringToNvramIndex(const std::string & s)152 uint32_t StringToNvramIndex(const std::string& s) {
153 return trunks::HR_HANDLE_MASK & StringToUint32(s);
154 }
155
156 using ClientLoopBase = brillo::Daemon;
157 class ClientLoop : public ClientLoopBase {
158 public:
159 ClientLoop() = default;
160 ~ClientLoop() override = default;
161
162 protected:
OnInit()163 int OnInit() override {
164 int exit_code = ClientLoopBase::OnInit();
165 if (exit_code != EX_OK) {
166 LOG(ERROR) << "Error initializing tpm_manager_client.";
167 return exit_code;
168 }
169 #if defined(USE_BINDER_IPC)
170 if (!binder_watcher_.Init()) {
171 LOG(ERROR) << "Error initializing binder watcher.";
172 return EX_UNAVAILABLE;
173 }
174 std::unique_ptr<TpmNvramBinderProxy> nvram_proxy =
175 base::MakeUnique<TpmNvramBinderProxy>();
176 std::unique_ptr<TpmOwnershipBinderProxy> ownership_proxy =
177 base::MakeUnique<TpmOwnershipBinderProxy>();
178 #else
179 std::unique_ptr<TpmNvramDBusProxy> nvram_proxy =
180 base::MakeUnique<TpmNvramDBusProxy>();
181 std::unique_ptr<TpmOwnershipDBusProxy> ownership_proxy =
182 base::MakeUnique<TpmOwnershipDBusProxy>();
183 #endif
184 if (!nvram_proxy->Initialize()) {
185 LOG(ERROR) << "Error initializing nvram proxy.";
186 return EX_UNAVAILABLE;
187 }
188 if (!ownership_proxy->Initialize()) {
189 LOG(ERROR) << "Error initializing ownership proxy.";
190 return EX_UNAVAILABLE;
191 }
192 tpm_nvram_ = std::move(nvram_proxy);
193 tpm_ownership_ = std::move(ownership_proxy);
194 exit_code = ScheduleCommand();
195 if (exit_code == EX_USAGE) {
196 printf("%s%s", kUsage, kKnownNVRAMSpaces);
197 }
198 return exit_code;
199 }
200
OnShutdown(int * exit_code)201 void OnShutdown(int* exit_code) override {
202 tpm_nvram_.reset();
203 tpm_ownership_.reset();
204 ClientLoopBase::OnShutdown(exit_code);
205 }
206
207 private:
208 // Posts tasks on to the message loop based on command line flags.
ScheduleCommand()209 int ScheduleCommand() {
210 base::Closure task;
211 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
212 if (command_line->HasSwitch("help") || command_line->HasSwitch("h") ||
213 command_line->GetArgs().size() == 0) {
214 return EX_USAGE;
215 }
216 std::string command = command_line->GetArgs()[0];
217 if (command == kGetTpmStatusCommand) {
218 task = base::Bind(&ClientLoop::HandleGetTpmStatus,
219 weak_factory_.GetWeakPtr());
220 } else if (command == kTakeOwnershipCommand) {
221 task = base::Bind(&ClientLoop::HandleTakeOwnership,
222 weak_factory_.GetWeakPtr());
223 } else if (command == kRemoveOwnerDependencyCommand) {
224 if (!command_line->HasSwitch(kDependencySwitch)) {
225 return EX_USAGE;
226 }
227 task = base::Bind(&ClientLoop::HandleRemoveOwnerDependency,
228 weak_factory_.GetWeakPtr(),
229 command_line->GetSwitchValueASCII(kDependencySwitch));
230 } else if (command == kDefineSpaceCommand) {
231 if (!command_line->HasSwitch(kIndexSwitch) ||
232 !command_line->HasSwitch(kSizeSwitch)) {
233 return EX_USAGE;
234 }
235 task = base::Bind(
236 &ClientLoop::HandleDefineSpace, weak_factory_.GetWeakPtr(),
237 StringToNvramIndex(command_line->GetSwitchValueASCII(kIndexSwitch)),
238 StringToUint32(command_line->GetSwitchValueASCII(kSizeSwitch)),
239 command_line->GetSwitchValueASCII(kAttributesSwitch),
240 command_line->GetSwitchValueASCII(kPasswordSwitch),
241 command_line->HasSwitch(kBindToPCR0Switch));
242 } else if (command == kDestroySpaceCommand) {
243 if (!command_line->HasSwitch(kIndexSwitch)) {
244 return EX_USAGE;
245 }
246 task = base::Bind(
247 &ClientLoop::HandleDestroySpace, weak_factory_.GetWeakPtr(),
248 StringToNvramIndex(command_line->GetSwitchValueASCII(kIndexSwitch)));
249 } else if (command == kWriteSpaceCommand) {
250 if (!command_line->HasSwitch(kIndexSwitch) ||
251 !command_line->HasSwitch(kFileSwitch)) {
252 return EX_USAGE;
253 }
254 task = base::Bind(
255 &ClientLoop::HandleWriteSpace, weak_factory_.GetWeakPtr(),
256 StringToNvramIndex(command_line->GetSwitchValueASCII(kIndexSwitch)),
257 command_line->GetSwitchValueASCII(kFileSwitch),
258 command_line->GetSwitchValueASCII(kPasswordSwitch),
259 command_line->HasSwitch(kUseOwnerSwitch));
260 } else if (command == kReadSpaceCommand) {
261 if (!command_line->HasSwitch(kIndexSwitch) ||
262 !command_line->HasSwitch(kFileSwitch)) {
263 return EX_USAGE;
264 }
265 task = base::Bind(
266 &ClientLoop::HandleReadSpace, weak_factory_.GetWeakPtr(),
267 StringToNvramIndex(command_line->GetSwitchValueASCII(kIndexSwitch)),
268 command_line->GetSwitchValueASCII(kFileSwitch),
269 command_line->GetSwitchValueASCII(kPasswordSwitch),
270 command_line->HasSwitch(kUseOwnerSwitch));
271 } else if (command == kLockSpaceCommand) {
272 if (!command_line->HasSwitch(kIndexSwitch)) {
273 return EX_USAGE;
274 }
275 task = base::Bind(
276 &ClientLoop::HandleLockSpace, weak_factory_.GetWeakPtr(),
277 StringToNvramIndex(command_line->GetSwitchValueASCII(kIndexSwitch)),
278 command_line->HasSwitch(kLockRead),
279 command_line->HasSwitch(kLockWrite),
280 command_line->GetSwitchValueASCII(kPasswordSwitch),
281 command_line->HasSwitch(kUseOwnerSwitch));
282 } else if (command == kListSpacesCommand) {
283 task =
284 base::Bind(&ClientLoop::HandleListSpaces, weak_factory_.GetWeakPtr());
285 } else if (command == kGetSpaceInfoCommand) {
286 if (!command_line->HasSwitch(kIndexSwitch)) {
287 return EX_USAGE;
288 }
289 task = base::Bind(
290 &ClientLoop::HandleGetSpaceInfo, weak_factory_.GetWeakPtr(),
291 StringToNvramIndex(command_line->GetSwitchValueASCII(kIndexSwitch)));
292 } else {
293 // Command line arguments did not match any valid commands.
294 return EX_USAGE;
295 }
296 base::MessageLoop::current()->task_runner()->PostTask(FROM_HERE, task);
297 return EX_OK;
298 }
299
300 // Template to print reply protobuf.
301 template <typename ProtobufType>
PrintReplyAndQuit(const ProtobufType & reply)302 void PrintReplyAndQuit(const ProtobufType& reply) {
303 LOG(INFO) << "Message Reply: " << GetProtoDebugString(reply);
304 Quit();
305 }
306
HandleGetTpmStatus()307 void HandleGetTpmStatus() {
308 GetTpmStatusRequest request;
309 tpm_ownership_->GetTpmStatus(
310 request, base::Bind(&ClientLoop::PrintReplyAndQuit<GetTpmStatusReply>,
311 weak_factory_.GetWeakPtr()));
312 }
313
HandleTakeOwnership()314 void HandleTakeOwnership() {
315 TakeOwnershipRequest request;
316 tpm_ownership_->TakeOwnership(
317 request, base::Bind(&ClientLoop::PrintReplyAndQuit<TakeOwnershipReply>,
318 weak_factory_.GetWeakPtr()));
319 }
320
HandleRemoveOwnerDependency(const std::string & owner_dependency)321 void HandleRemoveOwnerDependency(const std::string& owner_dependency) {
322 RemoveOwnerDependencyRequest request;
323 request.set_owner_dependency(owner_dependency);
324 tpm_ownership_->RemoveOwnerDependency(
325 request,
326 base::Bind(&ClientLoop::PrintReplyAndQuit<RemoveOwnerDependencyReply>,
327 weak_factory_.GetWeakPtr()));
328 }
329
DecodeAttribute(const std::string & attribute_str,NvramSpaceAttribute * attribute)330 bool DecodeAttribute(const std::string& attribute_str,
331 NvramSpaceAttribute* attribute) {
332 if (attribute_str == "PERSISTENT_WRITE_LOCK") {
333 *attribute = NVRAM_PERSISTENT_WRITE_LOCK;
334 return true;
335 }
336 if (attribute_str == "BOOT_WRITE_LOCK") {
337 *attribute = NVRAM_BOOT_WRITE_LOCK;
338 return true;
339 }
340 if (attribute_str == "BOOT_READ_LOCK") {
341 *attribute = NVRAM_BOOT_READ_LOCK;
342 return true;
343 }
344 if (attribute_str == "WRITE_AUTHORIZATION") {
345 *attribute = NVRAM_WRITE_AUTHORIZATION;
346 return true;
347 }
348 if (attribute_str == "READ_AUTHORIZATION") {
349 *attribute = NVRAM_READ_AUTHORIZATION;
350 return true;
351 }
352 if (attribute_str == "WRITE_EXTEND") {
353 *attribute = NVRAM_WRITE_EXTEND;
354 return true;
355 }
356 if (attribute_str == "GLOBAL_LOCK") {
357 *attribute = NVRAM_GLOBAL_LOCK;
358 return true;
359 }
360 if (attribute_str == "PLATFORM_WRITE") {
361 *attribute = NVRAM_PLATFORM_WRITE;
362 return true;
363 }
364 if (attribute_str == "OWNER_WRITE") {
365 *attribute = NVRAM_OWNER_WRITE;
366 return true;
367 }
368 if (attribute_str == "OWNER_READ") {
369 *attribute = NVRAM_OWNER_READ;
370 return true;
371 }
372 LOG(ERROR) << "Unrecognized attribute: " << attribute_str;
373 return false;
374 }
375
HandleDefineSpace(uint32_t index,size_t size,const std::string & attributes,const std::string & password,bool bind_to_pcr0)376 void HandleDefineSpace(uint32_t index,
377 size_t size,
378 const std::string& attributes,
379 const std::string& password,
380 bool bind_to_pcr0) {
381 DefineSpaceRequest request;
382 request.set_index(index);
383 request.set_size(size);
384 std::string::size_type pos = 0;
385 std::string::size_type next_pos = 0;
386 while (next_pos != std::string::npos) {
387 next_pos = attributes.find('|', pos);
388 std::string attribute_str;
389 if (next_pos == std::string::npos) {
390 attribute_str = attributes.substr(pos);
391 } else {
392 attribute_str = attributes.substr(pos, next_pos - pos);
393 }
394 if (!attribute_str.empty()) {
395 NvramSpaceAttribute attribute;
396 if (!DecodeAttribute(attribute_str, &attribute)) {
397 Quit();
398 return;
399 }
400 request.add_attributes(attribute);
401 }
402 pos = next_pos + 1;
403 }
404 request.set_authorization_value(crypto::SHA256HashString(password));
405 request.set_policy(bind_to_pcr0 ? NVRAM_POLICY_PCR0 : NVRAM_POLICY_NONE);
406 tpm_nvram_->DefineSpace(
407 request, base::Bind(&ClientLoop::PrintReplyAndQuit<DefineSpaceReply>,
408 weak_factory_.GetWeakPtr()));
409 }
410
HandleDestroySpace(uint32_t index)411 void HandleDestroySpace(uint32_t index) {
412 DestroySpaceRequest request;
413 request.set_index(index);
414 tpm_nvram_->DestroySpace(
415 request, base::Bind(&ClientLoop::PrintReplyAndQuit<DestroySpaceReply>,
416 weak_factory_.GetWeakPtr()));
417 }
418
HandleWriteSpace(uint32_t index,const std::string & input_file,const std::string & password,bool use_owner_authorization)419 void HandleWriteSpace(uint32_t index,
420 const std::string& input_file,
421 const std::string& password,
422 bool use_owner_authorization) {
423 WriteSpaceRequest request;
424 request.set_index(index);
425 std::string data;
426 if (!ReadFileToString(input_file, &data)) {
427 LOG(ERROR) << "Failed to read input file.";
428 Quit();
429 return;
430 }
431 request.set_data(data);
432 request.set_authorization_value(crypto::SHA256HashString(password));
433 request.set_use_owner_authorization(use_owner_authorization);
434 tpm_nvram_->WriteSpace(
435 request, base::Bind(&ClientLoop::PrintReplyAndQuit<WriteSpaceReply>,
436 weak_factory_.GetWeakPtr()));
437 }
438
HandleReadSpaceReply(const std::string & output_file,const ReadSpaceReply & reply)439 void HandleReadSpaceReply(const std::string& output_file,
440 const ReadSpaceReply& reply) {
441 if (!WriteStringToFile(reply.data(), output_file)) {
442 LOG(ERROR) << "Failed to write output file.";
443 }
444 LOG(INFO) << "Message Reply: " << GetProtoDebugString(reply);
445 Quit();
446 }
447
HandleReadSpace(uint32_t index,const std::string & output_file,const std::string & password,bool use_owner_authorization)448 void HandleReadSpace(uint32_t index,
449 const std::string& output_file,
450 const std::string& password,
451 bool use_owner_authorization) {
452 ReadSpaceRequest request;
453 request.set_index(index);
454 request.set_authorization_value(crypto::SHA256HashString(password));
455 request.set_use_owner_authorization(use_owner_authorization);
456 tpm_nvram_->ReadSpace(request,
457 base::Bind(&ClientLoop::HandleReadSpaceReply,
458 weak_factory_.GetWeakPtr(), output_file));
459 }
460
HandleLockSpace(uint32_t index,bool lock_read,bool lock_write,const std::string & password,bool use_owner_authorization)461 void HandleLockSpace(uint32_t index,
462 bool lock_read,
463 bool lock_write,
464 const std::string& password,
465 bool use_owner_authorization) {
466 LockSpaceRequest request;
467 request.set_index(index);
468 request.set_lock_read(lock_read);
469 request.set_lock_write(lock_write);
470 request.set_authorization_value(crypto::SHA256HashString(password));
471 request.set_use_owner_authorization(use_owner_authorization);
472 tpm_nvram_->LockSpace(
473 request, base::Bind(&ClientLoop::PrintReplyAndQuit<LockSpaceReply>,
474 weak_factory_.GetWeakPtr()));
475 }
476
HandleListSpaces()477 void HandleListSpaces() {
478 printf("%s\n", kKnownNVRAMSpaces);
479 ListSpacesRequest request;
480 tpm_nvram_->ListSpaces(
481 request, base::Bind(&ClientLoop::PrintReplyAndQuit<ListSpacesReply>,
482 weak_factory_.GetWeakPtr()));
483 }
484
HandleGetSpaceInfo(uint32_t index)485 void HandleGetSpaceInfo(uint32_t index) {
486 GetSpaceInfoRequest request;
487 request.set_index(index);
488 tpm_nvram_->GetSpaceInfo(
489 request, base::Bind(&ClientLoop::PrintReplyAndQuit<GetSpaceInfoReply>,
490 weak_factory_.GetWeakPtr()));
491 }
492
493 // IPC proxy interfaces.
494 std::unique_ptr<tpm_manager::TpmNvramInterface> tpm_nvram_;
495 std::unique_ptr<tpm_manager::TpmOwnershipInterface> tpm_ownership_;
496
497 #if defined(USE_BINDER_IPC)
498 brillo::BinderWatcher binder_watcher_;
499 #endif
500
501 // Declared last so that weak pointers will be destroyed first.
502 base::WeakPtrFactory<ClientLoop> weak_factory_{this};
503
504 DISALLOW_COPY_AND_ASSIGN(ClientLoop);
505 };
506
507 } // namespace tpm_manager
508
main(int argc,char * argv[])509 int main(int argc, char* argv[]) {
510 base::CommandLine::Init(argc, argv);
511 brillo::InitLog(brillo::kLogToStderr);
512 tpm_manager::ClientLoop loop;
513 return loop.Run();
514 }
515