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