| // Copyright 2022 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include <cinttypes> | |
| #include <cstdint> | |
| #include <cstdio> | |
| #include <cstdlib> | |
| #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 "libhwsec/backend/vendor.h" | |
| #include "libhwsec/client/command_helpers.h" | |
| #include "libhwsec/factory/factory.h" | |
| #include "libhwsec/factory/factory_impl.h" | |
| #include "libhwsec/frontend/client/frontend.h" | |
| #include "libhwsec-foundation/crypto/secure_blob_util.h" | |
| #include "libhwsec-foundation/status/status_chain_macros.h" | |
| using hwsec::ClientArgs; | |
| namespace { | |
| constexpr char kUsage[] = | |
| "Usage: libhwsec_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 GetRandom { | |
| static constexpr char kName[] = "get_random"; | |
| static constexpr char kArgs[] = "<N>"; | |
| static constexpr char kDesc[] = R"( | |
| Gets |N| random bytes and prints them as a hex-encoded string. | |
| )"; | |
| static int Run(const ClientArgs& args) { | |
| if (args.size() != 1) { | |
| hwsec::PrintCommandUsage<GetRandom>(); | |
| return EX_USAGE; | |
| } | |
| size_t size = 0; | |
| if (!base::StringToSizeT(args[0], &size)) { | |
| LOG(ERROR) << "Failed to convert size."; | |
| return EX_USAGE; | |
| } | |
| ASSIGN_OR_RETURN( | |
| brillo::Blob data, | |
| hwsec::FactoryImpl().GetClientFrontend()->GetRandomBlob(size), | |
| _.LogError().As(EXIT_FAILURE)); | |
| puts(hwsec_foundation::BlobToHex(data).c_str()); | |
| return EXIT_SUCCESS; | |
| } | |
| }; | |
| struct IsSrkRocaVulnerable { | |
| static constexpr char kName[] = "is_srk_roca_vulnerable"; | |
| static constexpr char kArgs[] = ""; | |
| static constexpr char kDesc[] = R"( | |
| Output "true" when the SRK is ROCA vulnerable, otherwise output "false". | |
| )"; | |
| static int Run(const ClientArgs& args) { | |
| if (args.size() != 0) { | |
| hwsec::PrintCommandUsage<IsSrkRocaVulnerable>(); | |
| return EX_USAGE; | |
| } | |
| ASSIGN_OR_RETURN( | |
| bool is_srk_roca_vulnerable, | |
| hwsec::FactoryImpl().GetClientFrontend()->IsSrkRocaVulnerable(), | |
| _.LogError().As(EXIT_FAILURE)); | |
| puts(is_srk_roca_vulnerable ? "true" : "false"); | |
| return EXIT_SUCCESS; | |
| } | |
| }; | |
| struct GetVersionInfo { | |
| static constexpr char kName[] = "get_version_info"; | |
| static constexpr char kArgs[] = ""; | |
| static constexpr char kDesc[] = R"( | |
| Prints TPM software and hardware version information. | |
| )"; | |
| static int Run(const ClientArgs& args) { | |
| if (args.size() != 0) { | |
| hwsec::PrintCommandUsage<GetVersionInfo>(); | |
| return EX_USAGE; | |
| } | |
| hwsec::FactoryImpl factory; | |
| std::unique_ptr<const hwsec::ClientFrontend> hwsec = | |
| factory.GetClientFrontend(); | |
| ASSIGN_OR_RETURN(uint32_t family, hwsec->GetFamily(), | |
| _.LogError().As(EXIT_FAILURE)); | |
| ASSIGN_OR_RETURN(uint64_t spec_level, hwsec->GetSpecLevel(), | |
| _.LogError().As(EXIT_FAILURE)); | |
| ASSIGN_OR_RETURN(uint32_t manufacturer, hwsec->GetManufacturer(), | |
| _.LogError().As(EXIT_FAILURE)); | |
| ASSIGN_OR_RETURN(uint32_t tpm_model, hwsec->GetTpmModel(), | |
| _.LogError().As(EXIT_FAILURE)); | |
| ASSIGN_OR_RETURN(uint64_t firmware_version, hwsec->GetFirmwareVersion(), | |
| _.LogError().As(EXIT_FAILURE)); | |
| ASSIGN_OR_RETURN(brillo::Blob vendor_specific, hwsec->GetVendorSpecific(), | |
| _.LogError().As(EXIT_FAILURE)); | |
| std::string vendor_specific_str = base::ToLowerASCII( | |
| base::HexEncode(vendor_specific.data(), vendor_specific.size())); | |
| printf("tpm_family %08" PRIx32 | |
| "\n" | |
| "spec_level %016" PRIx64 | |
| "\n" | |
| "vendor %08" PRIx32 | |
| "\n" | |
| "tpm_model %08" PRIx32 | |
| "\n" | |
| "firmware_version %016" PRIx64 | |
| "\n" | |
| "vendor_specific %s\n", | |
| family, spec_level, manufacturer, tpm_model, firmware_version, | |
| vendor_specific_str.c_str()); | |
| if (tpm_model == tpm_manager::GscVersion::GSC_VERSION_CR50 || | |
| tpm_model == tpm_manager::GscVersion::GSC_VERSION_TI50) { | |
| ASSIGN_OR_RETURN(hwsec::Vendor::RwVersion rw_version, | |
| hwsec->GetRwVersion(), _.LogError().As(EXIT_FAILURE)); | |
| printf("rw_version %" PRId32 ".%" PRId32 ".%" PRId32 "\n", | |
| rw_version.epoch, rw_version.major, rw_version.minor); | |
| } | |
| return EXIT_SUCCESS; | |
| } | |
| }; | |
| struct GetIfxFieldUpgradeInfo { | |
| static constexpr char kName[] = "get_ifx_field_upgrade_info"; | |
| static constexpr char kArgs[] = ""; | |
| static constexpr char kDesc[] = R"( | |
| Prints status info pertaining to firmware updates on Infineon TPMs. | |
| )"; | |
| static int Run(const ClientArgs& args) { | |
| if (args.size() != 0) { | |
| hwsec::PrintCommandUsage<GetIfxFieldUpgradeInfo>(); | |
| return EX_USAGE; | |
| } | |
| ASSIGN_OR_RETURN( | |
| hwsec::IFXFieldUpgradeInfo info, | |
| hwsec::FactoryImpl().GetClientFrontend()->GetIFXFieldUpgradeInfo(), | |
| _.LogError().As(EXIT_FAILURE)); | |
| printf("max_data_size %u\n", info.max_data_size); | |
| PrintIFXFirmwarePackage(info.bootloader, "bootloader"); | |
| PrintIFXFirmwarePackage(info.firmware[0], "fw0"); | |
| PrintIFXFirmwarePackage(info.firmware[1], "fw1"); | |
| printf("status %04x\n", info.status); | |
| PrintIFXFirmwarePackage(info.process_fw, "process_fw"); | |
| printf("field_upgrade_counter %u\n", info.field_upgrade_counter); | |
| return EXIT_SUCCESS; | |
| } | |
| static void PrintIFXFirmwarePackage( | |
| const hwsec::IFXFieldUpgradeInfo::FirmwarePackage& firmware_package, | |
| const char* prefix) { | |
| printf("%s_package_id %08x\n", prefix, firmware_package.package_id); | |
| printf("%s_version %08x\n", prefix, firmware_package.version); | |
| printf("%s_stale_version %08x\n", prefix, firmware_package.stale_version); | |
| } | |
| }; | |
| #define COMMAND_LIST \ | |
| GetRandom, IsSrkRocaVulnerable, GetVersionInfo, GetIfxFieldUpgradeInfo | |
| 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); | |
| } |