Home | History | Annotate | Download | only in client
      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