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