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