• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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