blob: a2163a092f579d1d3c8aaab7a5113bcc9e8b1c17 [file] [log] [blame]
Marri Devender Rao947258d2018-09-25 10:52:24 -05001#include "certs_manager.hpp"
2
3#include <algorithm>
4#include <experimental/filesystem>
5#include <fstream>
6#include <iterator>
7#include <string>
8#include <xyz/openbmc_project/Certs/Install/error.hpp>
9#include <xyz/openbmc_project/Common/error.hpp>
10
11#include <gmock/gmock.h>
12#include <gtest/gtest.h>
13
14namespace fs = std::experimental::filesystem;
15static constexpr auto BUSNAME = "xyz.openbmc_project.Certs.Manager";
16static constexpr auto OBJPATH = "/xyz/openbmc_project/certs";
17using InternalFailure =
18 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
19
Marri Devender Raoe6597c52018-10-01 06:36:55 -050020using InvalidCertificate =
21 sdbusplus::xyz::openbmc_project::Certs::Install::Error::InvalidCertificate;
22
Marri Devender Rao947258d2018-09-25 10:52:24 -050023class TestCertsManager : public ::testing::Test
24{
25 public:
26 TestCertsManager() : bus(sdbusplus::bus::new_default())
27 {
28 }
29 void SetUp() override
30 {
31 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
32 auto dirPtr = mkdtemp(dirTemplate);
33 if (dirPtr == NULL)
34 {
35 throw std::bad_alloc();
36 }
37 certDir = dirPtr;
38 certificateFile = "cert.pem";
39 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
40 cmd += "-keyout cert.pem -out cert.pem -days 3650 ";
41 cmd += "-subj "
42 "/O=openbmc-project.xyz/CN=localhost"
43 " -nodes";
44 auto val = std::system(cmd.c_str());
45 if (val)
46 {
47 std::cout << "COMMAND Error: " << val << std::endl;
48 }
49 }
50 void TearDown() override
51 {
52 fs::remove_all(certDir);
53 fs::remove(certificateFile);
54 }
55
56 bool compareFiles(const std::string& file1, const std::string& file2)
57 {
58 std::ifstream f1(file1, std::ifstream::binary | std::ifstream::ate);
59 std::ifstream f2(file2, std::ifstream::binary | std::ifstream::ate);
60
61 if (f1.fail() || f2.fail())
62 {
63 return false; // file problem
64 }
65
66 if (f1.tellg() != f2.tellg())
67 {
68 return false; // size mismatch
69 }
70
71 // seek back to beginning and use std::equal to compare contents
72 f1.seekg(0, std::ifstream::beg);
73 f2.seekg(0, std::ifstream::beg);
74 return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
75 std::istreambuf_iterator<char>(),
76 std::istreambuf_iterator<char>(f2.rdbuf()));
77 }
78
79 protected:
80 sdbusplus::bus::bus bus;
81 std::string certificateFile;
82
83 std::string certDir;
84};
85
86class MainApp
87{
88 public:
89 MainApp(phosphor::certs::Manager* manager) : manager(manager)
90 {
91 }
92 void install(std::string& path)
93 {
94 manager->install(path);
95 }
96 phosphor::certs::Manager* manager;
97};
98
99class MockCertManager : public phosphor::certs::Manager
100{
101 public:
102 MockCertManager(sdbusplus::bus::bus& bus, const char* path,
103 std::string& type, std::string&& unit,
104 std::string&& certPath) :
105 Manager(bus, path, type, std::forward<std::string>(unit),
106 std::forward<std::string>(certPath))
107 {
108 }
109 virtual ~MockCertManager()
110 {
111 }
112
113 MOCK_METHOD0(clientInstall, void());
114 MOCK_METHOD0(serverInstall, void());
115};
116
117/** @brief Check if server install routine is invoked for server setup
118 */
119TEST_F(TestCertsManager, InvokeServerInstall)
120{
121 std::string endpoint("https");
122 std::string unit("nginx.service");
123 std::string type("server");
124 std::string path(certDir + "/" + certificateFile);
125 std::string verifyPath(path);
126 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
127 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
128 std::move(path));
129 EXPECT_CALL(manager, serverInstall()).Times(1);
130
131 MainApp mainApp(&manager);
132 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
133 EXPECT_TRUE(fs::exists(verifyPath));
134}
135
136/** @brief Check if client install routine is invoked for client setup
137 */
138TEST_F(TestCertsManager, InvokeClientInstall)
139{
140 std::string endpoint("ldap");
141 std::string unit("nslcd.service");
142 std::string type("client");
143 std::string path(certDir + "/" + certificateFile);
144 std::string verifyPath(path);
145 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
146 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
147 std::move(path));
148 EXPECT_CALL(manager, clientInstall()).Times(1);
149 MainApp mainApp(&manager);
150 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
151 EXPECT_TRUE(fs::exists(verifyPath));
152}
153
154/** @brief Compare the installed certificate with the copied certificate
155 */
156TEST_F(TestCertsManager, CompareInstalledCertificate)
157{
158 std::string endpoint("ldap");
159 std::string unit("nslcd.service");
160 std::string type("client");
161 std::string path(certDir + "/" + certificateFile);
162 std::string verifyPath(path);
163 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
164 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
165 std::move(path));
166 EXPECT_CALL(manager, clientInstall()).Times(1);
167 MainApp mainApp(&manager);
168 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
169 EXPECT_TRUE(fs::exists(verifyPath));
170 EXPECT_TRUE(compareFiles(verifyPath, certificateFile));
171}
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500172
173/** @brief Check if install fails if certificate file is not found
174 */
175TEST_F(TestCertsManager, TestNoCertificateFile)
176{
177 std::string endpoint("ldap");
178 std::string unit("nslcd.service");
179 std::string type("client");
180 std::string path(certDir + "/" + certificateFile);
181 std::string verifyPath(path);
182 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
183 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
184 std::move(path));
185 EXPECT_CALL(manager, clientInstall()).Times(0);
186 MainApp mainApp(&manager);
187 std::string certpath = "nofile.pem";
188 EXPECT_THROW(
189 {
190 try
191 {
192 mainApp.install(certpath);
193 }
194 catch (const InternalFailure& e)
195 {
196 throw;
197 }
198 },
199 InternalFailure);
200 EXPECT_FALSE(fs::exists(verifyPath));
201}
202
203/** @brief Check if install fails if certificate file is empty
204 */
205TEST_F(TestCertsManager, TestEmptyCertificateFile)
206{
207 std::string endpoint("ldap");
208 std::string unit("nslcd.service");
209 std::string type("client");
210
211 std::string emptyFile("certcorrupted.pem");
212 std::ofstream ofs;
213 ofs.open(emptyFile, std::ofstream::out);
214 ofs.close();
215
216 std::string path(certDir + "/" + emptyFile);
217 std::string verifyPath(path);
218 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
219 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
220 std::move(path));
221 EXPECT_CALL(manager, clientInstall()).Times(0);
222 MainApp mainApp(&manager);
223 EXPECT_THROW(
224 {
225 try
226 {
227 mainApp.install(emptyFile);
228 }
229 catch (const InvalidCertificate& e)
230 {
231 throw;
232 }
233 },
234 InvalidCertificate);
235 EXPECT_FALSE(fs::exists(verifyPath));
236 fs::remove(emptyFile);
237}
238
239/** @brief Check if install fails if corrupted certificate file is not found
240 */
241TEST_F(TestCertsManager, TestInvalidCertificateFile)
242{
243 std::string endpoint("ldap");
244 std::string unit("nslcd.service");
245 std::string type("client");
246
247 std::string corrputedFile("certcorrupted.pem");
248 std::ofstream ofs;
249 ofs.open(corrputedFile, std::ofstream::out);
250 ofs << " PUBLIC KEY PRIVATE KEY XXXX YYYY ZZZZ";
251 ofs.close();
252
253 std::string path(certDir + "/" + corrputedFile);
254 std::string verifyPath(path);
255 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
256 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
257 std::move(path));
258 EXPECT_CALL(manager, clientInstall()).Times(0);
259 MainApp mainApp(&manager);
260 EXPECT_THROW(
261 {
262 try
263 {
264 mainApp.install(corrputedFile);
265 }
266 catch (const InvalidCertificate& e)
267 {
268 throw;
269 }
270 },
271 InvalidCertificate);
272 EXPECT_FALSE(fs::exists(verifyPath));
273 fs::remove(corrputedFile);
274}