blob: c381cec8e140492b90c8a187184ecb41cae91fd7 [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 Raoddf64862018-10-03 07:11:02 -050023/**
24 * Class to generate certificate file and test verification of certificate file
25 */
Marri Devender Rao947258d2018-09-25 10:52:24 -050026class TestCertsManager : public ::testing::Test
27{
28 public:
29 TestCertsManager() : bus(sdbusplus::bus::new_default())
30 {
31 }
32 void SetUp() override
33 {
34 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
35 auto dirPtr = mkdtemp(dirTemplate);
36 if (dirPtr == NULL)
37 {
38 throw std::bad_alloc();
39 }
40 certDir = dirPtr;
41 certificateFile = "cert.pem";
42 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
43 cmd += "-keyout cert.pem -out cert.pem -days 3650 ";
44 cmd += "-subj "
45 "/O=openbmc-project.xyz/CN=localhost"
46 " -nodes";
47 auto val = std::system(cmd.c_str());
48 if (val)
49 {
50 std::cout << "COMMAND Error: " << val << std::endl;
51 }
52 }
53 void TearDown() override
54 {
55 fs::remove_all(certDir);
56 fs::remove(certificateFile);
57 }
58
59 bool compareFiles(const std::string& file1, const std::string& file2)
60 {
61 std::ifstream f1(file1, std::ifstream::binary | std::ifstream::ate);
62 std::ifstream f2(file2, std::ifstream::binary | std::ifstream::ate);
63
64 if (f1.fail() || f2.fail())
65 {
66 return false; // file problem
67 }
68
69 if (f1.tellg() != f2.tellg())
70 {
71 return false; // size mismatch
72 }
73
74 // seek back to beginning and use std::equal to compare contents
75 f1.seekg(0, std::ifstream::beg);
76 f2.seekg(0, std::ifstream::beg);
77 return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
78 std::istreambuf_iterator<char>(),
79 std::istreambuf_iterator<char>(f2.rdbuf()));
80 }
81
82 protected:
83 sdbusplus::bus::bus bus;
84 std::string certificateFile;
85
86 std::string certDir;
87};
88
89class MainApp
90{
91 public:
92 MainApp(phosphor::certs::Manager* manager) : manager(manager)
93 {
94 }
95 void install(std::string& path)
96 {
97 manager->install(path);
98 }
Marri Devender Rao9abfae82018-10-03 08:10:35 -050099 void delete_()
100 {
101 manager->delete_();
102 }
Marri Devender Rao947258d2018-09-25 10:52:24 -0500103 phosphor::certs::Manager* manager;
104};
105
106class MockCertManager : public phosphor::certs::Manager
107{
108 public:
109 MockCertManager(sdbusplus::bus::bus& bus, const char* path,
110 std::string& type, std::string&& unit,
111 std::string&& certPath) :
112 Manager(bus, path, type, std::forward<std::string>(unit),
113 std::forward<std::string>(certPath))
114 {
115 }
116 virtual ~MockCertManager()
117 {
118 }
119
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500120 MOCK_METHOD1(reloadOrReset, void(const std::string& unit));
Marri Devender Rao947258d2018-09-25 10:52:24 -0500121};
122
123/** @brief Check if server install routine is invoked for server setup
124 */
125TEST_F(TestCertsManager, InvokeServerInstall)
126{
127 std::string endpoint("https");
128 std::string unit("nginx.service");
129 std::string type("server");
130 std::string path(certDir + "/" + certificateFile);
131 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500132 std::string verifyUnit(unit);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500133 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
134 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
135 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500136 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500137
138 MainApp mainApp(&manager);
139 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
140 EXPECT_TRUE(fs::exists(verifyPath));
141}
142
143/** @brief Check if client install routine is invoked for client setup
144 */
145TEST_F(TestCertsManager, InvokeClientInstall)
146{
147 std::string endpoint("ldap");
148 std::string unit("nslcd.service");
149 std::string type("client");
150 std::string path(certDir + "/" + certificateFile);
151 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500152 std::string verifyUnit(unit);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500153 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
154 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
155 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500156 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
157 MainApp mainApp(&manager);
158 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
159 EXPECT_TRUE(fs::exists(verifyPath));
160}
161
162/** @brief Check if authority install routine is invoked for authority setup
163 */
164TEST_F(TestCertsManager, InvokeAuthorityInstall)
165{
166 std::string endpoint("ldap");
167 std::string unit("nslcd.service");
168 std::string type("authority");
169 std::string path(certDir + "/" + certificateFile);
170 std::string verifyPath(path);
171 std::string verifyUnit(unit);
172 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
173 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
174 std::move(path));
175 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
176
Marri Devender Rao947258d2018-09-25 10:52:24 -0500177 MainApp mainApp(&manager);
178 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
179 EXPECT_TRUE(fs::exists(verifyPath));
180}
181
182/** @brief Compare the installed certificate with the copied certificate
183 */
184TEST_F(TestCertsManager, CompareInstalledCertificate)
185{
186 std::string endpoint("ldap");
187 std::string unit("nslcd.service");
188 std::string type("client");
189 std::string path(certDir + "/" + certificateFile);
190 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500191 std::string verifyUnit(unit);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500192 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
193 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
194 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500195 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500196 MainApp mainApp(&manager);
197 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
198 EXPECT_TRUE(fs::exists(verifyPath));
199 EXPECT_TRUE(compareFiles(verifyPath, certificateFile));
200}
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500201
202/** @brief Check if install fails if certificate file is not found
203 */
204TEST_F(TestCertsManager, TestNoCertificateFile)
205{
206 std::string endpoint("ldap");
207 std::string unit("nslcd.service");
208 std::string type("client");
209 std::string path(certDir + "/" + certificateFile);
210 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500211 std::string verifyUnit(unit);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500212 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
213 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
214 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500215 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500216 MainApp mainApp(&manager);
217 std::string certpath = "nofile.pem";
218 EXPECT_THROW(
219 {
220 try
221 {
222 mainApp.install(certpath);
223 }
224 catch (const InternalFailure& e)
225 {
226 throw;
227 }
228 },
229 InternalFailure);
230 EXPECT_FALSE(fs::exists(verifyPath));
231}
232
233/** @brief Check if install fails if certificate file is empty
234 */
235TEST_F(TestCertsManager, TestEmptyCertificateFile)
236{
237 std::string endpoint("ldap");
238 std::string unit("nslcd.service");
239 std::string type("client");
240
Marri Devender Raoddf64862018-10-03 07:11:02 -0500241 std::string emptyFile("emptycert.pem");
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500242 std::ofstream ofs;
243 ofs.open(emptyFile, std::ofstream::out);
244 ofs.close();
245
246 std::string path(certDir + "/" + emptyFile);
247 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500248 std::string verifyUnit(unit);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500249 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
250 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
251 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500252 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500253 MainApp mainApp(&manager);
254 EXPECT_THROW(
255 {
256 try
257 {
258 mainApp.install(emptyFile);
259 }
260 catch (const InvalidCertificate& e)
261 {
262 throw;
263 }
264 },
265 InvalidCertificate);
266 EXPECT_FALSE(fs::exists(verifyPath));
267 fs::remove(emptyFile);
268}
269
Marri Devender Raoddf64862018-10-03 07:11:02 -0500270/** @brief Check if install fails if certificate file is corrupted
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500271 */
272TEST_F(TestCertsManager, TestInvalidCertificateFile)
273{
274 std::string endpoint("ldap");
275 std::string unit("nslcd.service");
276 std::string type("client");
277
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500278 std::ofstream ofs;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500279 ofs.open(certificateFile, std::ofstream::out);
280 ofs << "-----BEGIN CERTIFICATE-----";
281 ofs << "ADD_SOME_INVALID_DATA_INTO_FILE";
282 ofs << "-----END CERTIFICATE-----";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500283 ofs.close();
284
Marri Devender Raoddf64862018-10-03 07:11:02 -0500285 std::string path(certDir + "/" + certificateFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500286 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500287 std::string verifyUnit(unit);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500288 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
289 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
290 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500291 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500292 MainApp mainApp(&manager);
293 EXPECT_THROW(
294 {
295 try
296 {
Marri Devender Raoddf64862018-10-03 07:11:02 -0500297 mainApp.install(certificateFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500298 }
299 catch (const InvalidCertificate& e)
300 {
301 throw;
302 }
303 },
304 InvalidCertificate);
305 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500306}
Marri Devender Raoddf64862018-10-03 07:11:02 -0500307
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500308TEST_F(TestCertsManager, TestDeleteCertificate)
309{
310 std::string endpoint("ldap");
311 std::string unit("nslcd.service");
312 std::string type("client");
313 std::string path(certDir + "/" + certificateFile);
314 std::string verifyPath(path);
315 std::string verifyUnit(unit);
316 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500317 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500318 std::move(path));
319 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(2);
320 MainApp mainApp(&manager);
321 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
322 EXPECT_TRUE(fs::exists(verifyPath));
323
324 // delete certificate file and verify file is deleted
325 mainApp.delete_();
326 EXPECT_FALSE(fs::exists(verifyPath));
327}
328
Marri Devender Raoddf64862018-10-03 07:11:02 -0500329/**
330 * Class to generate private and certificate only file and test verification
331 */
332class TestInvalidCertsManager : public ::testing::Test
333{
334 public:
335 TestInvalidCertsManager() : bus(sdbusplus::bus::new_default())
336 {
337 }
338 void SetUp() override
339 {
340 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
341 auto dirPtr = mkdtemp(dirTemplate);
342 if (dirPtr == NULL)
343 {
344 throw std::bad_alloc();
345 }
346 certDir = dirPtr;
347 certificateFile = "cert.pem";
348 keyFile = "key.pem";
349 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
350 cmd += "-keyout key.pem -out cert.pem -days 3650 ";
351 cmd += "-subj "
352 "/O=openbmc-project.xyz/CN=localhost"
353 " -nodes";
354
355 auto val = std::system(cmd.c_str());
356 if (val)
357 {
358 std::cout << "command Error: " << val << std::endl;
359 }
360 }
361 void TearDown() override
362 {
363 fs::remove_all(certDir);
364 fs::remove(certificateFile);
365 fs::remove(keyFile);
366 }
367
368 protected:
369 sdbusplus::bus::bus bus;
370 std::string certificateFile;
371 std::string keyFile;
372 std::string certDir;
373};
374
375/** @brief Check install fails if private key is missing in certificate file
376 */
377TEST_F(TestInvalidCertsManager, TestMissingPrivateKey)
378{
379 std::string endpoint("ldap");
380 std::string unit("nslcd.service");
381 std::string type("client");
382 std::string path(certDir + "/" + certificateFile);
383 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500384 std::string verifyUnit(unit);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500385 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
386 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
387 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500388 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500389 MainApp mainApp(&manager);
390 EXPECT_THROW(
391 {
392 try
393 {
394 mainApp.install(certificateFile);
395 }
396 catch (const InvalidCertificate& e)
397 {
398 throw;
399 }
400 },
401 InvalidCertificate);
402 EXPECT_FALSE(fs::exists(verifyPath));
403}
404
405/** @brief Check install fails if ceritificate is missing in certificate file
406 */
407TEST_F(TestInvalidCertsManager, TestMissingCeritificate)
408{
409 std::string endpoint("ldap");
410 std::string unit("nslcd.service");
411 std::string type("client");
412 std::string path(certDir + "/" + keyFile);
413 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500414 std::string verifyUnit(unit);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500415
416 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
417 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
418 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500419 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500420 MainApp mainApp(&manager);
421 EXPECT_THROW(
422 {
423 try
424 {
425 mainApp.install(keyFile);
426 }
427 catch (const InvalidCertificate& e)
428 {
429 throw;
430 }
431 },
432 InvalidCertificate);
433 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500434}