blob: 85a8f0ad4d366a07074c27c5c01d164265e2a805 [file] [log] [blame] [edit]
// 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);
}