| // Copyright 2024 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "libhwsec/backend/pinweaver_manager/pinweaver_manager.h" |
| #include <cinttypes> |
| #include <cstdint> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <brillo/secure_blob.h> |
| #include <sysexits.h> |
| |
| #include <base/check.h> |
| #include <base/command_line.h> |
| #include <base/functional/bind.h> |
| #include <base/logging.h> |
| #include <base/strings/string_number_conversions.h> |
| #include <base/strings/string_util.h> |
| #include <brillo/syslog_logging.h> |
| #include <tpm_manager/proto_bindings/tpm_manager.pb.h> |
| |
| #include "base/no_destructor.h" |
| #include "libhwsec/client/command_helpers.h" |
| #include "libhwsec/factory/factory_impl.h" |
| #include "libhwsec/frontend/pinweaver_manager/frontend.h" |
| #include "libhwsec-foundation/status/status_chain_macros.h" |
| |
| using hwsec::ClientArgs; |
| |
| namespace { |
| |
| using DelaySchedule = hwsec::PinWeaverManagerFrontend::DelaySchedule; |
| |
| constexpr int kLEMaxIncorrectAttempt = 5; |
| const DelaySchedule kDefaultDelaySchedule = { |
| {kLEMaxIncorrectAttempt, UINT32_MAX}, |
| }; |
| |
| constexpr char kUsage[] = |
| "Usage: pinweaver_manager_client <command> [<args>]\nCommands:\n"; |
| |
| template <typename... Args> |
| struct Help { |
| static constexpr char kName[] = "help"; |
| static constexpr char kArgs[] = ""; |
| static constexpr char kDesc[] = R"( |
| Print this help message. |
| )"; |
| |
| static int Run(const ClientArgs& args) { |
| PrintUsage(); |
| return EX_USAGE; |
| } |
| |
| static void PrintUsage() { |
| printf("%s", kUsage); |
| (hwsec::PrintCommandUsage<Args>(), ...); |
| } |
| }; |
| |
| struct Initialize { |
| static constexpr char kName[] = "init"; |
| static constexpr char kArgs[] = ""; |
| static constexpr char kDesc[] = R"( |
| Initialize PinWeaverManager (specifically the memory-mapped pinweaver leaf |
| cache file). Returning success indicates that PinWeaverManager is |
| initialized, not locked out, and hash tree is valid. |
| )"; |
| |
| static int Run(const ClientArgs& args) { |
| if (args.size() != 0) { |
| hwsec::PrintCommandUsage<Initialize>(); |
| return EX_USAGE; |
| } |
| |
| RETURN_IF_ERROR( |
| hwsec::FactoryImpl().GetPinWeaverManagerFrontend()->Initialize()) |
| .LogError() |
| .As(EXIT_FAILURE); |
| printf("PinWeaver Manager is in good state.\n"); |
| return EXIT_SUCCESS; |
| } |
| }; |
| |
| struct SyncHashTree { |
| static constexpr char kName[] = "sync"; |
| static constexpr char kArgs[] = ""; |
| static constexpr char kDesc[] = R"( |
| Sync the PinWeaver hash tree between OS and GSC. |
| Returning success indicates that the hash tree is synced. |
| )"; |
| |
| static int Run(const ClientArgs& args) { |
| if (args.size() != 0) { |
| hwsec::PrintCommandUsage<Initialize>(); |
| return EX_USAGE; |
| } |
| |
| RETURN_IF_ERROR( |
| hwsec::FactoryImpl().GetPinWeaverManagerFrontend()->SyncHashTree()) |
| .LogError() |
| .As(EXIT_FAILURE); |
| printf("PinWeaver Manager is synced.\n"); |
| return EXIT_SUCCESS; |
| } |
| }; |
| |
| struct InsertCredential { |
| static constexpr char kName[] = "insert"; |
| static constexpr char kArgs[] = "<le_secret> <he_secret> <reset_secret>"; |
| static constexpr char kDesc[] = R"( |
| Inserts an credential with given LE/HE/ResetSecret into the system. |
| The argument strings are transformed into SecureBlob of size 32. |
| Prints the label of inserted credential on success. |
| )"; |
| |
| static int Run(const ClientArgs& args) { |
| if (args.size() != 3) { |
| hwsec::PrintCommandUsage<InsertCredential>(); |
| return EX_USAGE; |
| } |
| |
| brillo::SecureBlob le_secret(args[0]); |
| le_secret.resize(32); |
| brillo::SecureBlob he_secret(args[1]); |
| he_secret.resize(32); |
| brillo::SecureBlob reset_secret(args[2]); |
| reset_secret.resize(32); |
| |
| ASSIGN_OR_RETURN( |
| uint64_t label, |
| hwsec::FactoryImpl().GetPinWeaverManagerFrontend()->InsertCredential( |
| std::vector<hwsec::OperationPolicySetting>(), le_secret, he_secret, |
| reset_secret, kDefaultDelaySchedule, |
| /*expiration_delay=*/std::nullopt), |
| _.LogError().As(EXIT_FAILURE)); |
| printf( |
| "Succeed to insert credential,\n" |
| "label=%" PRIu64 "\n", |
| label); |
| return EXIT_SUCCESS; |
| } |
| }; |
| struct CheckCredential { |
| static constexpr char kName[] = "auth"; |
| static constexpr char kArgs[] = "<label> <le_secret>"; |
| static constexpr char kDesc[] = R"( |
| Checks whether the LE credential <le_secret> for a <label> is correct. |
| Prints corresponding <he_secret> and <reset_secret> on success. |
| )"; |
| |
| using CheckCredentialReply = |
| hwsec::PinWeaverManagerFrontend::CheckCredentialReply; |
| |
| static int Run(const ClientArgs& args) { |
| if (args.size() != 2) { |
| hwsec::PrintCommandUsage<CheckCredential>(); |
| return EX_USAGE; |
| } |
| |
| uint64_t label; |
| if (!base::StringToUint64(args[0], &label)) { |
| LOG(ERROR) << "Failed to convert label."; |
| return EX_USAGE; |
| } |
| brillo::SecureBlob le_secret(args[1]); |
| le_secret.resize(32); |
| |
| ASSIGN_OR_RETURN( |
| CheckCredentialReply reply, |
| hwsec::FactoryImpl().GetPinWeaverManagerFrontend()->CheckCredential( |
| label, le_secret), |
| _.LogError().As(EXIT_FAILURE)); |
| printf( |
| "Auth succeed,\n" |
| "he_secret=%s\n" |
| "reset_secret=%s\n", |
| reply.he_secret.char_data(), reply.reset_secret.char_data()); |
| return EXIT_SUCCESS; |
| } |
| }; |
| |
| struct ResetCredential { |
| static constexpr char kName[] = "reset"; |
| static constexpr char kArgs[] = "<label> <reset_secret>"; |
| static constexpr char kDesc[] = R"( |
| Attempts to reset tme wrong attempt and the expiration time of a LE |
| Credential. |
| )"; |
| |
| using ResetType = hwsec::PinWeaverManagerFrontend::ResetType; |
| |
| static int Run(const ClientArgs& args) { |
| if (args.size() != 2) { |
| hwsec::PrintCommandUsage<ResetCredential>(); |
| return EX_USAGE; |
| } |
| |
| uint64_t label; |
| if (!base::StringToUint64(args[0], &label)) { |
| LOG(ERROR) << "Failed to convert label."; |
| return EX_USAGE; |
| } |
| brillo::SecureBlob reset_secret(args[1]); |
| reset_secret.resize(32); |
| |
| RETURN_IF_ERROR( |
| hwsec::FactoryImpl().GetPinWeaverManagerFrontend()->ResetCredential( |
| label, reset_secret, ResetType::kWrongAttempts)) |
| .LogError() |
| .As(EXIT_FAILURE); |
| printf("Reset succeed.\n"); |
| return EXIT_SUCCESS; |
| } |
| }; |
| |
| struct RemoveCredential { |
| static constexpr char kName[] = "remove"; |
| static constexpr char kArgs[] = "<label>"; |
| static constexpr char kDesc[] = R"( |
| Remove the credential with label=<label>. |
| )"; |
| |
| static int Run(const ClientArgs& args) { |
| if (args.size() != 1) { |
| hwsec::PrintCommandUsage<RemoveCredential>(); |
| return EX_USAGE; |
| } |
| |
| uint64_t label; |
| if (!base::StringToUint64(args[0], &label)) { |
| LOG(ERROR) << "Failed to convert label."; |
| return EX_USAGE; |
| } |
| |
| RETURN_IF_ERROR( |
| hwsec::FactoryImpl().GetPinWeaverManagerFrontend()->RemoveCredential( |
| label)) |
| .LogError() |
| .As(EXIT_FAILURE); |
| printf("Remove label %" PRIu64 " succeed.\n", label); |
| return EXIT_SUCCESS; |
| } |
| }; |
| |
| #define COMMAND_LIST \ |
| Initialize, SyncHashTree, InsertCredential, CheckCredential, \ |
| ResetCredential, RemoveCredential |
| |
| using Usage = Help<Help<>, COMMAND_LIST>; |
| |
| } // namespace |
| |
| int main(int argc, char** argv) { |
| base::CommandLine::Init(argc, argv); |
| brillo::InitLog(brillo::kLogToStderr); |
| |
| base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); |
| std::vector<std::string> cmd_args = cl->GetArgs(); |
| |
| hwsec::ClientArgs args(cmd_args.data(), cmd_args.size()); |
| |
| if (args.empty()) { |
| return Usage::Run(args); |
| } |
| |
| return hwsec::MatchCommands<Usage, COMMAND_LIST>::Run(args); |
| } |