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 } 143