xref: /openbmc/phosphor-bmc-code-mgmt/tpm/tpm2/tpm2.cpp (revision c538727d70f3673771f18e559d7ecab203abf6d3)
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 
getTPMResourceManagerPath(uint8_t tpmIndex)31 static std::string getTPMResourceManagerPath(uint8_t tpmIndex)
32 {
33     return "/dev/tpmrm" + std::to_string(tpmIndex);
34 }
35 
getProperty(std::string_view property,uint32_t & value)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 
updateFirmware(const uint8_t * image,size_t image_size)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 
getVersion(std::string & version)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