1 #include "file_io_type_cert.hpp"
2 
3 #include "libpldm/base.h"
4 #include "oem/ibm/libpldm/file_io.h"
5 
6 #include "common/utils.hpp"
7 
8 #include <stdint.h>
9 
10 #include <iostream>
11 
12 namespace pldm
13 {
14 using namespace utils;
15 
16 namespace responder
17 {
18 
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 << "file for type " << certType << " doesn't exist\n";
31         return PLDM_ERROR;
32     }
33 
34     auto fd = std::get<0>(it->second);
35     auto& remSize = std::get<1>(it->second);
36     auto rc = transferFileData(fd, false, offset, length, address);
37     if (rc == PLDM_SUCCESS)
38     {
39         remSize -= length;
40         if (!remSize)
41         {
42             close(fd);
43             certMap.erase(it);
44         }
45     }
46     return rc;
47 }
48 
49 int CertHandler::readIntoMemory(uint32_t offset, uint32_t& length,
50                                 uint64_t address,
51                                 oem_platform::Handler* /*oemPlatformHandler*/)
52 {
53     std::string filePath = certFilePath;
54     filePath += "CSR_" + std::to_string(fileHandle);
55     if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
56     {
57         return PLDM_ERROR_INVALID_DATA;
58     }
59     auto rc = transferFileData(filePath.c_str(), true, offset, length, address);
60     fs::remove(filePath);
61     if (rc)
62     {
63         return PLDM_ERROR;
64     }
65     return PLDM_SUCCESS;
66 }
67 
68 int CertHandler::read(uint32_t offset, uint32_t& length, Response& response,
69                       oem_platform::Handler* /*oemPlatformHandler*/)
70 {
71     std::string filePath = certFilePath;
72     filePath += "CSR_" + std::to_string(fileHandle);
73     if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
74     {
75         return PLDM_ERROR_INVALID_DATA;
76     }
77     auto rc = readFile(filePath.c_str(), offset, length, response);
78     fs::remove(filePath);
79     if (rc)
80     {
81         return PLDM_ERROR;
82     }
83     return PLDM_SUCCESS;
84 }
85 
86 int CertHandler::write(const char* buffer, uint32_t offset, uint32_t& length,
87                        oem_platform::Handler* /*oemPlatformHandler*/)
88 {
89     auto it = certMap.find(certType);
90     if (it == certMap.end())
91     {
92         std::cerr << "file for type " << certType << " doesn't exist\n";
93         return PLDM_ERROR;
94     }
95 
96     auto fd = std::get<0>(it->second);
97     int rc = lseek(fd, offset, SEEK_SET);
98     if (rc == -1)
99     {
100         std::cerr << "lseek failed, ERROR=" << errno << ", OFFSET=" << offset
101                   << "\n";
102         return PLDM_ERROR;
103     }
104     rc = ::write(fd, buffer, length);
105     if (rc == -1)
106     {
107         std::cerr << "file write failed, ERROR=" << errno
108                   << ", LENGTH=" << length << ", OFFSET=" << offset << "\n";
109         return PLDM_ERROR;
110     }
111     length = rc;
112     auto& remSize = std::get<1>(it->second);
113     remSize -= length;
114     if (!remSize)
115     {
116         close(fd);
117         certMap.erase(it);
118     }
119 
120     if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
121     {
122         constexpr auto certObjPath = "/xyz/openbmc_project/certs/ca/entry/";
123         constexpr auto certEntryIntf = "xyz.openbmc_project.Certs.Entry";
124 
125         std::string filePath = certFilePath;
126         filePath += "ClientCert_" + std::to_string(fileHandle);
127 
128         std::ifstream inFile;
129         inFile.open(filePath);
130         std::stringstream strStream;
131         strStream << inFile.rdbuf();
132         std::string str = strStream.str();
133         inFile.close();
134 
135         if (!str.empty())
136         {
137             PropertyValue value{str};
138 
139             DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
140                                     certEntryIntf, "ClientCertificate",
141                                     "string"};
142             try
143             {
144                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
145             }
146             catch (const std::exception& e)
147             {
148                 std::cerr << "failed to set Client certificate, "
149                              "ERROR="
150                           << e.what() << "\n";
151                 return PLDM_ERROR;
152             }
153             PropertyValue valueStatus{
154                 "xyz.openbmc_project.Certs.Entry.State.Complete"};
155             DBusMapping dbusMappingStatus{certObjPath +
156                                               std::to_string(fileHandle),
157                                           certEntryIntf, "Status", "string"};
158             try
159             {
160                 pldm::utils::DBusHandler().setDbusProperty(dbusMappingStatus,
161                                                            valueStatus);
162             }
163             catch (const std::exception& e)
164             {
165                 std::cerr
166                     << "failed to set status property of certicate entry, "
167                        "ERROR="
168                     << e.what() << "\n";
169                 return PLDM_ERROR;
170             }
171             fs::remove(filePath);
172         }
173         else
174         {
175             PropertyValue value{"xyz.openbmc_project.Certs.Entry.State.BadCSR"};
176             DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle),
177                                     certEntryIntf, "Status", "string"};
178             try
179             {
180                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
181             }
182             catch (const std::exception& e)
183             {
184                 std::cerr
185                     << "failed to set status property of certicate entry, "
186                        "ERROR="
187                     << e.what() << "\n";
188                 return PLDM_ERROR;
189             }
190         }
191     }
192     return PLDM_SUCCESS;
193 }
194 
195 int CertHandler::newFileAvailable(uint64_t length)
196 {
197     fs::create_directories(certFilePath);
198     fs::permissions(certFilePath,
199                     fs::perms::others_read | fs::perms::owner_write);
200     int fileFd = -1;
201     int flags = O_WRONLY | O_CREAT | O_TRUNC;
202     std::string filePath = certFilePath;
203 
204     if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST)
205     {
206         return PLDM_ERROR_INVALID_DATA;
207     }
208     if (certType == PLDM_FILE_TYPE_SIGNED_CERT)
209     {
210         fileFd = open(
211             (filePath + "ClientCert_" + std::to_string(fileHandle)).c_str(),
212             flags, S_IRUSR | S_IWUSR);
213     }
214     else if (certType == PLDM_FILE_TYPE_ROOT_CERT)
215     {
216         fileFd =
217             open((filePath + "RootCert").c_str(), flags, S_IRUSR | S_IWUSR);
218     }
219     if (fileFd == -1)
220     {
221         std::cerr << "failed to open file for type " << certType
222                   << " ERROR=" << errno << "\n";
223         return PLDM_ERROR;
224     }
225     certMap.emplace(certType, std::tuple(fileFd, length));
226     return PLDM_SUCCESS;
227 }
228 
229 } // namespace responder
230 } // namespace pldm
231