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 #include <iostream>
12 
13 PHOSPHOR_LOG2_USING;
14 
15 namespace pldm
16 {
17 using namespace utils;
18 
19 namespace responder
20 {
21 constexpr auto certObjPath = "/xyz/openbmc_project/certs/ca/entry/";
22 constexpr auto certEntryIntf = "xyz.openbmc_project.Certs.Entry";
23 static constexpr auto certFilePath = "/var/lib/ibm/bmcweb/";
24 
25 CertMap CertHandler::certMap;
26 
27 int CertHandler::writeFromMemory(uint32_t offset, uint32_t length,
28                                  uint64_t address,
29                                  oem_platform::Handler* /*oemPlatformHandler*/)
30 {
31     auto it = certMap.find(certType);
32     if (it == certMap.end())
33     {
34         error(
35             "CertHandler::writeFromMemory:file for type {CERT_TYPE} doesn't exist",
36             "CERT_TYPE", certType);
37         return PLDM_ERROR;
38     }
39 
40     auto fd = std::get<0>(it->second);
41     auto& remSize = std::get<1>(it->second);
42     auto rc = transferFileData(fd, false, offset, length, address);
43     if (rc == PLDM_SUCCESS)
44     {
45         remSize -= length;
46         if (!remSize)
47         {
48             close(fd);
49             certMap.erase(it);
50         }
51     }
52     return rc;
53 }
54 
55 int CertHandler::readIntoMemory(uint32_t offset, uint32_t& length,
56                                 uint64_t address,
57                                 oem_platform::Handler* /*oemPlatformHandler*/)
58 {
59     std::string filePath = certFilePath;
60     filePath += "CSR_" + std::to_string(fileHandle);
61     if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
62     {
63         return PLDM_ERROR_INVALID_DATA;
64     }
65     auto rc = transferFileData(filePath.c_str(), true, offset, length, address);
66     fs::remove(filePath);
67     if (rc)
68     {
69         return PLDM_ERROR;
70     }
71     return PLDM_SUCCESS;
72 }
73 
74 int CertHandler::read(uint32_t offset, uint32_t& length, Response& response,
75                       oem_platform::Handler* /*oemPlatformHandler*/)
76 {
77     info(
78         "CertHandler::read:Read file response for Sign CSR, file handle: {FILE_HANDLE}",
79         "FILE_HANDLE", fileHandle);
80     std::string filePath = certFilePath;
81     filePath += "CSR_" + std::to_string(fileHandle);
82     if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
83     {
84         return PLDM_ERROR_INVALID_DATA;
85     }
86     auto rc = readFile(filePath.c_str(), offset, length, response);
87     fs::remove(filePath);
88     if (rc)
89     {
90         return PLDM_ERROR;
91     }
92     return PLDM_SUCCESS;
93 }
94 
95 int CertHandler::write(const char* buffer, uint32_t offset, uint32_t& length,
96                        oem_platform::Handler* /*oemPlatformHandler*/)
97 {
98     auto it = certMap.find(certType);
99     if (it == certMap.end())
100     {
101         error("CertHandler::write:file for type {CERT_TYPE} doesn't exist",
102               "CERT_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("CertHandler::write:lseek failed, ERROR={ERR}, OFFSET={OFFSET}",
111               "ERR", errno, "OFFSET", offset);
112         return PLDM_ERROR;
113     }
114     rc = ::write(fd, buffer, length);
115     if (rc == -1)
116     {
117         error(
118             "CertHandler::write:file write failed, ERROR={ERR}, LENGTH={LEN}, OFFSET={OFFSET}",
119             "ERR", errno, "LEN", length, "OFFSET", offset);
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                     "CertHandler::write:failed to set Client certificate, ERROR={ERR_EXCEP}",
161                     "ERR_EXCEP", e.what());
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                     "CertHandler::write:Client cert write, status: complete. 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                     "CertHandler::write:failed to set status property of certicate entry, ERROR={ERR_EXCEP}",
181                     "ERR_EXCEP", e.what());
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                     "CertHandler::write:Client cert write, status: Bad CSR. 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                     "CertHandler::write:failed to set status property of certicate entry, {ERR_EXCEP}",
202                     "ERR_EXCEP", e.what());
203                 return PLDM_ERROR;
204             }
205         }
206     }
207     return PLDM_SUCCESS;
208 }
209 
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             "CertHandler::newFileAvailable:new file available client cert file, 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             "CertHandler::newFileAvailable:failed to open file for type {CERT_TYPE} ERROR={ERR}",
241             "CERT_TYPE", certType, "ERR", errno);
242         return PLDM_ERROR;
243     }
244     certMap.emplace(certType, std::tuple(fileFd, length));
245     return PLDM_SUCCESS;
246 }
247 
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             error(
270                 "CertHandler::newFileAvailableWithMetaData:new file available client cert file, 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                 "newFileAvailableWithMetaData:client cert file Invalid data, file handle: {FILE_HANDLE}",
280                 "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                     "newFileAvailableWithMetaData:Failed to set status property of certicate entry, ERROR= {ERR_EXCEP}",
293                     "ERR_EXCEP", e.what());
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             "newFileAvailableWithMetaData:failed to open file for type {CERT_TYPE} ERROR={ERR}",
307             "CERT_TYPE", certType, "ERR", errno);
308         return PLDM_ERROR;
309     }
310     certMap.emplace(certType, std::tuple(fileFd, length));
311     return PLDM_SUCCESS;
312 }
313 
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                 "CertHandler::fileAckWithMetaData:Failed to set status property of certicate entry, ERROR={ERR_EXCEP}",
341                 "ERR_EXCEP", e.what());
342             return PLDM_ERROR;
343         }
344     }
345     return PLDM_SUCCESS;
346 }
347 
348 } // namespace responder
349 } // namespace pldm
350