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 
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             "CertHandler::writeFromMemory:file for type {CERT_TYPE} doesn't exist",
34             "CERT_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 
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 
72 int CertHandler::read(uint32_t offset, uint32_t& length, Response& response,
73                       oem_platform::Handler* /*oemPlatformHandler*/)
74 {
75     info(
76         "CertHandler::read:Read file response for Sign CSR, 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 
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("CertHandler::write:file for type {CERT_TYPE} doesn't exist",
100               "CERT_TYPE", certType);
101         return PLDM_ERROR;
102     }
103 
104     auto fd = std::get<0>(it->second);
105     int rc = lseek(fd, offset, SEEK_SET);
106     if (rc == -1)
107     {
108         error("CertHandler::write:lseek failed, ERROR={ERR}, OFFSET={OFFSET}",
109               "ERR", errno, "OFFSET", offset);
110         return PLDM_ERROR;
111     }
112     rc = ::write(fd, buffer, length);
113     if (rc == -1)
114     {
115         error(
116             "CertHandler::write:file write failed, ERROR={ERR}, LENGTH={LEN}, OFFSET={OFFSET}",
117             "ERR", errno, "LEN", length, "OFFSET", offset);
118         return PLDM_ERROR;
119     }
120     length = rc;
121     auto& remSize = std::get<1>(it->second);
122     remSize -= length;
123     if (!remSize)
124     {
125         close(fd);
126         certMap.erase(it);
127     }
128 
129     if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
130     {
131         constexpr auto certObjPath = "/xyz/openbmc_project/certs/ca/entry/";
132         constexpr auto certEntryIntf = "xyz.openbmc_project.Certs.Entry";
133 
134         std::string filePath = certFilePath;
135         filePath += "ClientCert_" + std::to_string(fileHandle);
136 
137         std::ifstream inFile;
138         inFile.open(filePath);
139         std::stringstream strStream;
140         strStream << inFile.rdbuf();
141         std::string str = strStream.str();
142         inFile.close();
143 
144         if (!str.empty())
145         {
146             PropertyValue value{str};
147 
148             DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
149                                     certEntryIntf, "ClientCertificate",
150                                     "string"};
151             try
152             {
153                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
154             }
155             catch (const std::exception& e)
156             {
157                 error(
158                     "CertHandler::write:failed to set Client certificate, ERROR={ERR_EXCEP}",
159                     "ERR_EXCEP", e.what());
160                 return PLDM_ERROR;
161             }
162             PropertyValue valueStatus{
163                 "xyz.openbmc_project.Certs.Entry.State.Complete"};
164             DBusMapping dbusMappingStatus{certObjPath +
165                                               std::to_string(fileHandle),
166                                           certEntryIntf, "Status", "string"};
167             try
168             {
169                 info(
170                     "CertHandler::write:Client cert write, status: complete. File handle: {FILE_HANDLE}",
171                     "FILE_HANDLE", fileHandle);
172                 pldm::utils::DBusHandler().setDbusProperty(dbusMappingStatus,
173                                                            valueStatus);
174             }
175             catch (const std::exception& e)
176             {
177                 error(
178                     "CertHandler::write:failed to set status property of certicate entry, ERROR={ERR_EXCEP}",
179                     "ERR_EXCEP", e.what());
180                 return PLDM_ERROR;
181             }
182             fs::remove(filePath);
183         }
184         else
185         {
186             PropertyValue value{"xyz.openbmc_project.Certs.Entry.State.BadCSR"};
187             DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
188                                     certEntryIntf, "Status", "string"};
189             try
190             {
191                 info(
192                     "CertHandler::write:Client cert write, status: Bad CSR. File handle: {FILE_HANDLE}",
193                     "FILE_HANDLE", fileHandle);
194                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
195             }
196             catch (const std::exception& e)
197             {
198                 error(
199                     "CertHandler::write:failed to set status property of certicate entry, {ERR_EXCEP}",
200                     "ERR_EXCEP", e.what());
201                 return PLDM_ERROR;
202             }
203         }
204     }
205     return PLDM_SUCCESS;
206 }
207 
208 int CertHandler::newFileAvailable(uint64_t length)
209 {
210     fs::create_directories(certFilePath);
211     fs::permissions(certFilePath,
212                     fs::perms::others_read | fs::perms::owner_write);
213     int fileFd = -1;
214     int flags = O_WRONLY | O_CREAT | O_TRUNC;
215     std::string filePath = certFilePath;
216 
217     if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
218     {
219         return PLDM_ERROR_INVALID_DATA;
220     }
221     if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
222     {
223         info(
224             "CertHandler::newFileAvailable:new file available client cert file, file handle: {FILE_HANDLE}",
225             "FILE_HANDLE", fileHandle);
226         fileFd = open(
227             (filePath + "ClientCert_" + std::to_string(fileHandle)).c_str(),
228             flags, S_IRUSR | S_IWUSR);
229     }
230     else if (certType == PLDM_FILE_TYPE_ROOT_CERT)
231     {
232         fileFd = open((filePath + "RootCert").c_str(), flags,
233                       S_IRUSR | S_IWUSR);
234     }
235     if (fileFd == -1)
236     {
237         error(
238             "CertHandler::newFileAvailable:failed to open file for type {CERT_TYPE} ERROR={ERR}",
239             "CERT_TYPE", certType, "ERR", errno);
240         return PLDM_ERROR;
241     }
242     certMap.emplace(certType, std::tuple(fileFd, length));
243     return PLDM_SUCCESS;
244 }
245 
246 int CertHandler::newFileAvailableWithMetaData(uint64_t length,
247                                               uint32_t metaDataValue1,
248                                               uint32_t /*metaDataValue2*/,
249                                               uint32_t /*metaDataValue3*/,
250                                               uint32_t /*metaDataValue4*/)
251 {
252     fs::create_directories(certFilePath);
253     fs::permissions(certFilePath,
254                     fs::perms::others_read | fs::perms::owner_write);
255     int fileFd = -1;
256     int flags = O_WRONLY | O_CREAT | O_TRUNC;
257     std::string filePath = certFilePath;
258 
259     if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
260     {
261         return PLDM_ERROR_INVALID_DATA;
262     }
263     if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
264     {
265         if (metaDataValue1 == PLDM_SUCCESS)
266         {
267             error(
268                 "CertHandler::newFileAvailableWithMetaData:new file available client cert file, file handle: {FILE_HANDLE}",
269                 "FILE_HANDLE", fileHandle);
270             fileFd = open(
271                 (filePath + "ClientCert_" + std::to_string(fileHandle)).c_str(),
272                 flags, S_IRUSR | S_IWUSR);
273         }
274         else if (metaDataValue1 == PLDM_INVALID_CERT_DATA)
275         {
276             error(
277                 "newFileAvailableWithMetaData:client cert file Invalid data, file handle: {FILE_HANDLE}",
278                 "FILE_HANDLE", fileHandle);
279             DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
280                                     certEntryIntf, "Status", "string"};
281             std::string status = "xyz.openbmc_project.Certs.Entry.State.BadCSR";
282             PropertyValue value{status};
283             try
284             {
285                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
286             }
287             catch (const std::exception& e)
288             {
289                 error(
290                     "newFileAvailableWithMetaData:Failed to set status property of certicate entry, ERROR= {ERR_EXCEP}",
291                     "ERR_EXCEP", e.what());
292                 return PLDM_ERROR;
293             }
294         }
295     }
296     else if (certType == PLDM_FILE_TYPE_ROOT_CERT)
297     {
298         fileFd = open((filePath + "RootCert").c_str(), flags,
299                       S_IRUSR | S_IWUSR);
300     }
301     if (fileFd == -1)
302     {
303         error(
304             "newFileAvailableWithMetaData:failed to open file for type {CERT_TYPE} ERROR={ERR}",
305             "CERT_TYPE", certType, "ERR", errno);
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             error(
338                 "CertHandler::fileAckWithMetaData:Failed to set status property of certicate entry, ERROR={ERR_EXCEP}",
339                 "ERR_EXCEP", e.what());
340             return PLDM_ERROR;
341         }
342     }
343     return PLDM_SUCCESS;
344 }
345 
346 } // namespace responder
347 } // namespace pldm
348