1 #include "file_io_type_cert.hpp"
2
3 #include "common/utils.hpp"
4
5 #include <libpldm/base.h>
6 #include <libpldm/oem/ibm/file_io.h>
7
8 #include <phosphor-logging/lg2.hpp>
9
10 #include <cstdint>
11
12 PHOSPHOR_LOG2_USING;
13
14 namespace pldm
15 {
16 using namespace utils;
17
18 namespace responder
19 {
20 constexpr auto certObjPath = "/xyz/openbmc_project/certs/ca/entry/";
21 constexpr auto certEntryIntf = "xyz.openbmc_project.Certs.Entry";
22 static constexpr auto certFilePath = "/var/lib/ibm/bmcweb/";
23
24 CertMap CertHandler::certMap;
25
writeFromMemory(uint32_t offset,uint32_t length,uint64_t address,oem_platform::Handler *)26 int CertHandler::writeFromMemory(uint32_t offset, uint32_t length,
27 uint64_t address,
28 oem_platform::Handler* /*oemPlatformHandler*/)
29 {
30 auto it = certMap.find(certType);
31 if (it == certMap.end())
32 {
33 error(
34 "Failed to find file type '{TYPE}' in certificate map. Write from memory during certificate exchange failed",
35 "TYPE", certType);
36 return PLDM_ERROR;
37 }
38
39 auto fd = std::get<0>(it->second);
40 auto& remSize = std::get<1>(it->second);
41 auto rc = transferFileData(fd, false, offset, length, address);
42 if (rc == PLDM_SUCCESS)
43 {
44 remSize -= length;
45 if (!remSize)
46 {
47 close(fd);
48 certMap.erase(it);
49 }
50 }
51 return rc;
52 }
53
readIntoMemory(uint32_t offset,uint32_t length,uint64_t address,oem_platform::Handler *)54 int CertHandler::readIntoMemory(uint32_t offset, uint32_t length,
55 uint64_t address,
56 oem_platform::Handler* /*oemPlatformHandler*/)
57 {
58 std::string filePath = certFilePath;
59 filePath += "CSR_" + std::to_string(fileHandle);
60 if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
61 {
62 return PLDM_ERROR_INVALID_DATA;
63 }
64 auto rc = transferFileData(filePath.c_str(), true, offset, length, address);
65 fs::remove(filePath);
66 if (rc)
67 {
68 return PLDM_ERROR;
69 }
70 return PLDM_SUCCESS;
71 }
72
read(uint32_t offset,uint32_t & length,Response & response,oem_platform::Handler *)73 int CertHandler::read(uint32_t offset, uint32_t& length, Response& response,
74 oem_platform::Handler* /*oemPlatformHandler*/)
75 {
76 info(
77 "Read file response for Sign CSR failed and file handle '{FILE_HANDLE}'",
78 "FILE_HANDLE", fileHandle);
79 std::string filePath = certFilePath;
80 filePath += "CSR_" + std::to_string(fileHandle);
81 if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
82 {
83 return PLDM_ERROR_INVALID_DATA;
84 }
85 auto rc = readFile(filePath.c_str(), offset, length, response);
86 fs::remove(filePath);
87 if (rc)
88 {
89 return PLDM_ERROR;
90 }
91 return PLDM_SUCCESS;
92 }
93
write(const char * buffer,uint32_t offset,uint32_t & length,oem_platform::Handler *)94 int CertHandler::write(const char* buffer, uint32_t offset, uint32_t& length,
95 oem_platform::Handler* /*oemPlatformHandler*/)
96 {
97 auto it = certMap.find(certType);
98 if (it == certMap.end())
99 {
100 error(
101 "Failed to find file type '{TYPE}' in certificate map. Write during certificate exchange failed",
102 "TYPE", certType);
103 return PLDM_ERROR;
104 }
105
106 auto fd = std::get<0>(it->second);
107 int rc = lseek(fd, offset, SEEK_SET);
108 if (rc == -1)
109 {
110 error(
111 "Failed to write certificate lseek at offset '{OFFSET}' of length '{LENGTH}', error number - {ERROR_NUM}",
112 "OFFSET", offset, "LENGTH", length, "ERROR_NUM", errno);
113 return PLDM_ERROR;
114 }
115 rc = ::write(fd, buffer, length);
116 if (rc == -1)
117 {
118 error(
119 "Failed to write certificate at offset '{OFFSET}' of length '{LENGTH}', error number - {ERROR_NUM}",
120 "LENGTH", length, "OFFSET", offset, "ERROR_NUM", errno);
121 return PLDM_ERROR;
122 }
123 length = rc;
124 auto& remSize = std::get<1>(it->second);
125 remSize -= length;
126 if (!remSize)
127 {
128 close(fd);
129 certMap.erase(it);
130 }
131
132 if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
133 {
134 constexpr auto certObjPath = "/xyz/openbmc_project/certs/ca/entry/";
135 constexpr auto certEntryIntf = "xyz.openbmc_project.Certs.Entry";
136
137 std::string filePath = certFilePath;
138 filePath += "ClientCert_" + std::to_string(fileHandle);
139
140 std::ifstream inFile;
141 inFile.open(filePath);
142 std::stringstream strStream;
143 strStream << inFile.rdbuf();
144 std::string str = strStream.str();
145 inFile.close();
146
147 if (!str.empty())
148 {
149 PropertyValue value{str};
150
151 DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
152 certEntryIntf, "ClientCertificate",
153 "string"};
154 try
155 {
156 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
157 }
158 catch (const std::exception& e)
159 {
160 error(
161 "Failed to write for set client certificate, error - {ERROR}",
162 "ERROR", e);
163 return PLDM_ERROR;
164 }
165 PropertyValue valueStatus{
166 "xyz.openbmc_project.Certs.Entry.State.Complete"};
167 DBusMapping dbusMappingStatus{
168 certObjPath + std::to_string(fileHandle), certEntryIntf,
169 "Status", "string"};
170 try
171 {
172 info(
173 "Client certificate write status 'complete' for file handle '{FILE_HANDLE}'",
174 "FILE_HANDLE", fileHandle);
175 pldm::utils::DBusHandler().setDbusProperty(dbusMappingStatus,
176 valueStatus);
177 }
178 catch (const std::exception& e)
179 {
180 error(
181 "Failed to write the set status property for certificate entry, error - {ERROR}",
182 "ERROR", e);
183 return PLDM_ERROR;
184 }
185 fs::remove(filePath);
186 }
187 else
188 {
189 PropertyValue value{"xyz.openbmc_project.Certs.Entry.State.BadCSR"};
190 DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
191 certEntryIntf, "Status", "string"};
192 try
193 {
194 info(
195 "Client certificate write status 'Bad CSR' for file handle '{FILE_HANDLE}'",
196 "FILE_HANDLE", fileHandle);
197 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
198 }
199 catch (const std::exception& e)
200 {
201 error(
202 "Failed to write the set status property for certificate entry, error - {ERROR}",
203 "ERROR", e);
204 return PLDM_ERROR;
205 }
206 }
207 }
208 return PLDM_SUCCESS;
209 }
210
newFileAvailable(uint64_t length)211 int CertHandler::newFileAvailable(uint64_t length)
212 {
213 fs::create_directories(certFilePath);
214 fs::permissions(certFilePath,
215 fs::perms::others_read | fs::perms::owner_write);
216 int fileFd = -1;
217 int flags = O_WRONLY | O_CREAT | O_TRUNC;
218 std::string filePath = certFilePath;
219
220 if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
221 {
222 return PLDM_ERROR_INVALID_DATA;
223 }
224 if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
225 {
226 info(
227 "New file available for client certificate file with file handle {FILE_HANDLE}",
228 "FILE_HANDLE", fileHandle);
229 fileFd = open(
230 (filePath + "ClientCert_" + std::to_string(fileHandle)).c_str(),
231 flags, S_IRUSR | S_IWUSR);
232 }
233 else if (certType == PLDM_FILE_TYPE_ROOT_CERT)
234 {
235 fileFd =
236 open((filePath + "RootCert").c_str(), flags, S_IRUSR | S_IWUSR);
237 }
238 if (fileFd == -1)
239 {
240 error(
241 "Failed to open new file available with file type '{TYPE}', error number - {ERROR_NUM}",
242 "TYPE", certType, "ERROR_NUM", errno);
243 return PLDM_ERROR;
244 }
245 certMap.emplace(certType, std::tuple(fileFd, length));
246 return PLDM_SUCCESS;
247 }
248
newFileAvailableWithMetaData(uint64_t length,uint32_t metaDataValue1,uint32_t,uint32_t,uint32_t)249 int CertHandler::newFileAvailableWithMetaData(
250 uint64_t length, uint32_t metaDataValue1, uint32_t /*metaDataValue2*/,
251 uint32_t /*metaDataValue3*/, uint32_t /*metaDataValue4*/)
252 {
253 fs::create_directories(certFilePath);
254 fs::permissions(certFilePath,
255 fs::perms::others_read | fs::perms::owner_write);
256 int fileFd = -1;
257 int flags = O_WRONLY | O_CREAT | O_TRUNC;
258 std::string filePath = certFilePath;
259
260 if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
261 {
262 return PLDM_ERROR_INVALID_DATA;
263 }
264 if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
265 {
266 if (metaDataValue1 == PLDM_SUCCESS)
267 {
268 info(
269 "Client certificate new file available with meta data for file handle '{FILE_HANDLE}'",
270 "FILE_HANDLE", fileHandle);
271 fileFd = open(
272 (filePath + "ClientCert_" + std::to_string(fileHandle)).c_str(),
273 flags, S_IRUSR | S_IWUSR);
274 }
275 else if (metaDataValue1 == PLDM_INVALID_CERT_DATA)
276 {
277 error(
278 "New file available with meta data for client certificate file has invalid data '{META_DATA}' with file handle '{FILE_HANDLE}'",
279 "META_DATA", metaDataValue1, "FILE_HANDLE", fileHandle);
280 DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
281 certEntryIntf, "Status", "string"};
282 std::string status = "xyz.openbmc_project.Certs.Entry.State.BadCSR";
283 PropertyValue value{status};
284 try
285 {
286 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
287 }
288 catch (const std::exception& e)
289 {
290 error(
291 "Failed to set set status property of certificate entry in new file available with meta data, error - {ERROR}",
292 "ERROR", e);
293 return PLDM_ERROR;
294 }
295 }
296 }
297 else if (certType == PLDM_FILE_TYPE_ROOT_CERT)
298 {
299 fileFd =
300 open((filePath + "RootCert").c_str(), flags, S_IRUSR | S_IWUSR);
301 }
302 if (fileFd == -1)
303 {
304 error(
305 "Failed to open file type '{TYPE}' but New file available with meta data, error number - {ERROR_NUM}",
306 "TYPE", certType, "ERROR_NUM", errno);
307 return PLDM_ERROR;
308 }
309 certMap.emplace(certType, std::tuple(fileFd, length));
310 return PLDM_SUCCESS;
311 }
312
fileAckWithMetaData(uint8_t fileStatus,uint32_t,uint32_t,uint32_t,uint32_t)313 int CertHandler::fileAckWithMetaData(
314 uint8_t fileStatus, uint32_t /*metaDataValue1*/,
315 uint32_t /*metaDataValue2*/, uint32_t /*metaDataValue3*/,
316 uint32_t /*metaDataValue4*/)
317 {
318 if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
319 {
320 DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
321 certEntryIntf, "Status", "string"};
322 PropertyValue value = "xyz.openbmc_project.Certs.Entry.State.Pending";
323 if (fileStatus == PLDM_ERROR_INVALID_DATA)
324 {
325 value = "xyz.openbmc_project.Certs.Entry.State.BadCSR";
326 }
327 else if (fileStatus == PLDM_ERROR_NOT_READY)
328 {
329 value = "xyz.openbmc_project.Certs.Entry.State.Pending";
330 }
331 try
332 {
333 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
334 }
335 catch (const std::exception& e)
336 {
337 error(
338 "Failed to set status property of certificate entry for file ack with meta data, error - {ERROR}",
339 "ERROR", e);
340 return PLDM_ERROR;
341 }
342 }
343 return PLDM_SUCCESS;
344 }
345
346 } // namespace responder
347 } // namespace pldm
348