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