Kevin Tung | c538727 | 2025-07-28 18:10:43 +0800 | [diff] [blame^] | 1 | #include "tpm2.hpp" |
| 2 | |
| 3 | #include "common/include/utils.hpp" |
| 4 | |
| 5 | #include <phosphor-logging/lg2.hpp> |
| 6 | |
| 7 | #include <cstdio> |
| 8 | #include <regex> |
| 9 | #include <sstream> |
| 10 | |
| 11 | PHOSPHOR_LOG2_USING; |
| 12 | |
| 13 | static constexpr std::string_view getCapPropertiesCmd = |
| 14 | "/usr/bin/tpm2_getcap properties-fixed"; |
| 15 | static constexpr std::string_view fwVer1Property = "TPM2_PT_FIRMWARE_VERSION_1"; |
| 16 | static constexpr std::string_view fwVer2Property = "TPM2_PT_FIRMWARE_VERSION_2"; |
| 17 | static constexpr std::string_view manufacturerProperty = "TPM2_PT_MANUFACTURER"; |
| 18 | |
| 19 | static constexpr std::string_view hexPattern = R"(^\s*raw:\s+0x([0-9a-fA-F]+))"; |
| 20 | |
| 21 | enum class Tpm2Vendor |
| 22 | { |
| 23 | IFX, |
| 24 | Nuvoton |
| 25 | }; |
| 26 | |
| 27 | // Reference: https://trustedcomputinggroup.org/resource/vendor-id-registry/ |
| 28 | static const std::unordered_map<uint32_t, Tpm2Vendor> validManufactureIDs = { |
| 29 | {0x49465800, Tpm2Vendor::IFX}, {0x4E544300, Tpm2Vendor::Nuvoton}}; |
| 30 | |
| 31 | static std::string getTPMResourceManagerPath(uint8_t tpmIndex) |
| 32 | { |
| 33 | return "/dev/tpmrm" + std::to_string(tpmIndex); |
| 34 | } |
| 35 | |
| 36 | sdbusplus::async::task<bool> TPM2Interface::getProperty( |
| 37 | std::string_view property, uint32_t& value) |
| 38 | { |
| 39 | // Reference: https://tpm2-tools.readthedocs.io/en/latest/man/common/tcti/ |
| 40 | // The TCTI or "Transmission Interface" is the communication mechanism |
| 41 | // with the TPM. TCTIs can be changed for communication with TPMs across |
| 42 | // different mediums. |
| 43 | auto tcti = "device:" + getTPMResourceManagerPath(tpmIndex); |
| 44 | auto cmd = std::string(getCapPropertiesCmd) + " --tcti " + tcti + |
| 45 | " | grep -A1 " + std::string(property); |
| 46 | |
| 47 | std::string output; |
| 48 | if (!co_await asyncSystem(ctx, cmd, output)) |
| 49 | { |
| 50 | error("Failed to run command: {CMD}", "CMD", cmd); |
| 51 | co_return false; |
| 52 | } |
| 53 | |
| 54 | const std::regex regexPattern{std::string(hexPattern)}; |
| 55 | std::smatch match; |
| 56 | std::istringstream stream(output); |
| 57 | std::string line; |
| 58 | |
| 59 | while (std::getline(stream, line)) |
| 60 | { |
| 61 | if (std::regex_search(line, match, regexPattern) && match.size() >= 2) |
| 62 | { |
| 63 | try |
| 64 | { |
| 65 | value = std::stoul(match[1].str(), nullptr, 16); |
| 66 | co_return true; |
| 67 | } |
| 68 | catch (const std::exception& e) |
| 69 | { |
| 70 | error("Failed to parse hex value for property {PT}: {ERR}", |
| 71 | "PT", property, "ERR", e.what()); |
| 72 | co_return false; |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | error("No matching hex value found for property: {PT}", "PT", property); |
| 78 | co_return false; |
| 79 | } |
| 80 | |
| 81 | sdbusplus::async::task<bool> TPM2Interface::updateFirmware(const uint8_t* image, |
| 82 | size_t image_size) |
| 83 | { |
| 84 | (void)image; |
| 85 | (void)image_size; |
| 86 | |
| 87 | error("TPM2 firmware update is not supported"); |
| 88 | co_return false; |
| 89 | } |
| 90 | |
| 91 | sdbusplus::async::task<bool> TPM2Interface::getVersion(std::string& version) |
| 92 | { |
| 93 | uint32_t manufacturerId = 0; |
| 94 | uint32_t fwVer = 0; |
| 95 | std::string tpmVer1; |
| 96 | std::string tpmVer2; |
| 97 | |
| 98 | if (!co_await getProperty(manufacturerProperty, manufacturerId)) |
| 99 | { |
| 100 | error("Failed to retrieve TPM manufacturer ID"); |
| 101 | co_return false; |
| 102 | } |
| 103 | |
| 104 | auto it = validManufactureIDs.find(manufacturerId); |
| 105 | |
| 106 | if (it == validManufactureIDs.end()) |
| 107 | { |
| 108 | error("Invalid TPM manufacturer ID: {ID}", "ID", lg2::hex, |
| 109 | manufacturerId); |
| 110 | co_return false; |
| 111 | } |
| 112 | |
| 113 | auto vendor = it->second; |
| 114 | |
| 115 | if (!co_await getProperty(fwVer1Property, fwVer)) |
| 116 | { |
| 117 | error("Failed to retrieve TPM firmware version 1"); |
| 118 | co_return false; |
| 119 | } |
| 120 | |
| 121 | tpmVer1 = std::to_string(fwVer >> 16) + "." + |
| 122 | std::to_string(fwVer & 0xFFFF); |
| 123 | |
| 124 | if (vendor == Tpm2Vendor::Nuvoton) |
| 125 | { |
| 126 | if (!co_await getProperty(fwVer2Property, fwVer)) |
| 127 | { |
| 128 | error("Failed to retrieve TPM firmware version 2"); |
| 129 | co_return false; |
| 130 | } |
| 131 | |
| 132 | tpmVer2 = std::to_string(fwVer >> 16) + "." + |
| 133 | std::to_string(fwVer & 0xFFFF); |
| 134 | version = tpmVer1 + "." + tpmVer2; |
| 135 | } |
| 136 | else |
| 137 | { |
| 138 | version = tpmVer1; |
| 139 | } |
| 140 | |
| 141 | co_return true; |
| 142 | } |