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 138 bool ReadFileToString(const std::string& filename, std::string* data) { 139 return base::ReadFileToString(base::FilePath(filename), data); 140 } 141 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 148 uint32_t StringToUint32(const std::string& s) { 149 return strtoul(s.c_str(), nullptr, 0); 150 } 151 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: 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 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. 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> 302 void PrintReplyAndQuit(const ProtobufType& reply) { 303 LOG(INFO) << "Message Reply: " << GetProtoDebugString(reply); 304 Quit(); 305 } 306 307 void HandleGetTpmStatus() { 308 GetTpmStatusRequest request; 309 tpm_ownership_->GetTpmStatus( 310 request, base::Bind(&ClientLoop::PrintReplyAndQuit<GetTpmStatusReply>, 311 weak_factory_.GetWeakPtr())); 312 } 313 314 void HandleTakeOwnership() { 315 TakeOwnershipRequest request; 316 tpm_ownership_->TakeOwnership( 317 request, base::Bind(&ClientLoop::PrintReplyAndQuit<TakeOwnershipReply>, 318 weak_factory_.GetWeakPtr())); 319 } 320 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 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 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 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 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 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 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 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 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 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 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