blob: bd0ed100df0b127a9f8272bd340c94c201125700 [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 }
Marri Devender Rao947258d2018-09-25 10:52:24 -0500119};
120
121/** @brief Check if server install routine is invoked for server setup
122 */
123TEST_F(TestCertsManager, InvokeServerInstall)
124{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600125 // TODO due to refactoring test cases will be pushed as last patch
126 // in the patch set
127 /*
Marri Devender Rao947258d2018-09-25 10:52:24 -0500128 std::string endpoint("https");
129 std::string unit("nginx.service");
130 std::string type("server");
131 std::string path(certDir + "/" + certificateFile);
132 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500133 std::string verifyUnit(unit);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500134 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
135 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
136 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500137 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500138
139 MainApp mainApp(&manager);
140 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
141 EXPECT_TRUE(fs::exists(verifyPath));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600142 */
Marri Devender Rao947258d2018-09-25 10:52:24 -0500143}
144
145/** @brief Check if client install routine is invoked for client setup
146 */
147TEST_F(TestCertsManager, InvokeClientInstall)
148{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600149 // TODO due to refactoring test cases will be pushed as last patch
150 // in the patch set
151 /*
Marri Devender Rao947258d2018-09-25 10:52:24 -0500152 std::string endpoint("ldap");
153 std::string unit("nslcd.service");
154 std::string type("client");
155 std::string path(certDir + "/" + certificateFile);
156 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500157 std::string verifyUnit(unit);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500158 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
159 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
160 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500161 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
162 MainApp mainApp(&manager);
163 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
164 EXPECT_TRUE(fs::exists(verifyPath));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600165 */
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500166}
167
168/** @brief Check if authority install routine is invoked for authority setup
169 */
170TEST_F(TestCertsManager, InvokeAuthorityInstall)
171{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600172 // TODO due to refactoring test cases will be pushed as last patch
173 // in the patch set
174 /*
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500175 std::string endpoint("ldap");
176 std::string unit("nslcd.service");
177 std::string type("authority");
178 std::string path(certDir + "/" + certificateFile);
179 std::string verifyPath(path);
180 std::string verifyUnit(unit);
181 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
182 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
183 std::move(path));
184 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
185
Marri Devender Rao947258d2018-09-25 10:52:24 -0500186 MainApp mainApp(&manager);
187 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
188 EXPECT_TRUE(fs::exists(verifyPath));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600189 */
Marri Devender Rao947258d2018-09-25 10:52:24 -0500190}
191
192/** @brief Compare the installed certificate with the copied certificate
193 */
194TEST_F(TestCertsManager, CompareInstalledCertificate)
195{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600196 // TODO due to refactoring test cases will be pushed as last patch
197 // in the patch set
198 /*
Marri Devender Rao947258d2018-09-25 10:52:24 -0500199 std::string endpoint("ldap");
200 std::string unit("nslcd.service");
201 std::string type("client");
202 std::string path(certDir + "/" + certificateFile);
203 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500204 std::string verifyUnit(unit);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500205 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
206 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
207 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500208 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500209 MainApp mainApp(&manager);
210 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
211 EXPECT_TRUE(fs::exists(verifyPath));
212 EXPECT_TRUE(compareFiles(verifyPath, certificateFile));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600213 */
Marri Devender Rao947258d2018-09-25 10:52:24 -0500214}
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500215
216/** @brief Check if install fails if certificate file is not found
217 */
218TEST_F(TestCertsManager, TestNoCertificateFile)
219{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600220 // TODO due to refactoring test cases will be pushed as last patch
221 // in the patch set
222 /*
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500223 std::string endpoint("ldap");
224 std::string unit("nslcd.service");
225 std::string type("client");
226 std::string path(certDir + "/" + certificateFile);
227 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500228 std::string verifyUnit(unit);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500229 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
230 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
231 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500232 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500233 MainApp mainApp(&manager);
234 std::string certpath = "nofile.pem";
235 EXPECT_THROW(
236 {
237 try
238 {
239 mainApp.install(certpath);
240 }
241 catch (const InternalFailure& e)
242 {
243 throw;
244 }
245 },
246 InternalFailure);
247 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600248 */
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500249}
250
251/** @brief Check if install fails if certificate file is empty
252 */
253TEST_F(TestCertsManager, TestEmptyCertificateFile)
254{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600255 // TODO due to refactoring test cases will be pushed as last patch
256 // in the patch set
257 /*
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500258 std::string endpoint("ldap");
259 std::string unit("nslcd.service");
260 std::string type("client");
261
Marri Devender Raoddf64862018-10-03 07:11:02 -0500262 std::string emptyFile("emptycert.pem");
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500263 std::ofstream ofs;
264 ofs.open(emptyFile, std::ofstream::out);
265 ofs.close();
266
267 std::string path(certDir + "/" + emptyFile);
268 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500269 std::string verifyUnit(unit);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500270 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
271 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
272 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500273 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500274 MainApp mainApp(&manager);
275 EXPECT_THROW(
276 {
277 try
278 {
279 mainApp.install(emptyFile);
280 }
281 catch (const InvalidCertificate& e)
282 {
283 throw;
284 }
285 },
286 InvalidCertificate);
287 EXPECT_FALSE(fs::exists(verifyPath));
288 fs::remove(emptyFile);
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600289 */
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500290}
291
Marri Devender Raoddf64862018-10-03 07:11:02 -0500292/** @brief Check if install fails if certificate file is corrupted
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500293 */
294TEST_F(TestCertsManager, TestInvalidCertificateFile)
295{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600296 // TODO due to refactoring test cases will be pushed as last patch
297 // in the patch set
298 /*
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500299 std::string endpoint("ldap");
300 std::string unit("nslcd.service");
301 std::string type("client");
302
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500303 std::ofstream ofs;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500304 ofs.open(certificateFile, std::ofstream::out);
305 ofs << "-----BEGIN CERTIFICATE-----";
306 ofs << "ADD_SOME_INVALID_DATA_INTO_FILE";
307 ofs << "-----END CERTIFICATE-----";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500308 ofs.close();
309
Marri Devender Raoddf64862018-10-03 07:11:02 -0500310 std::string path(certDir + "/" + certificateFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500311 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500312 std::string verifyUnit(unit);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500313 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
314 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
315 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500316 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500317 MainApp mainApp(&manager);
318 EXPECT_THROW(
319 {
320 try
321 {
Marri Devender Raoddf64862018-10-03 07:11:02 -0500322 mainApp.install(certificateFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500323 }
324 catch (const InvalidCertificate& e)
325 {
326 throw;
327 }
328 },
329 InvalidCertificate);
330 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600331 */
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500332}
Marri Devender Raoddf64862018-10-03 07:11:02 -0500333
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500334TEST_F(TestCertsManager, TestDeleteCertificate)
335{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600336 // TODO due to refactoring test cases will be pushed as last patch
337 // in the patch set
338 /*
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500339 std::string endpoint("ldap");
340 std::string unit("nslcd.service");
341 std::string type("client");
342 std::string path(certDir + "/" + certificateFile);
343 std::string verifyPath(path);
344 std::string verifyUnit(unit);
345 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500346 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500347 std::move(path));
348 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(2);
349 MainApp mainApp(&manager);
350 EXPECT_NO_THROW({ mainApp.install(certificateFile); });
351 EXPECT_TRUE(fs::exists(verifyPath));
352
353 // delete certificate file and verify file is deleted
354 mainApp.delete_();
355 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600356 */
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500357}
358
Marri Devender Raoddf64862018-10-03 07:11:02 -0500359/**
360 * Class to generate private and certificate only file and test verification
361 */
362class TestInvalidCertsManager : public ::testing::Test
363{
364 public:
365 TestInvalidCertsManager() : bus(sdbusplus::bus::new_default())
366 {
367 }
368 void SetUp() override
369 {
370 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
371 auto dirPtr = mkdtemp(dirTemplate);
372 if (dirPtr == NULL)
373 {
374 throw std::bad_alloc();
375 }
376 certDir = dirPtr;
377 certificateFile = "cert.pem";
378 keyFile = "key.pem";
379 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
380 cmd += "-keyout key.pem -out cert.pem -days 3650 ";
381 cmd += "-subj "
382 "/O=openbmc-project.xyz/CN=localhost"
383 " -nodes";
384
385 auto val = std::system(cmd.c_str());
386 if (val)
387 {
388 std::cout << "command Error: " << val << std::endl;
389 }
390 }
391 void TearDown() override
392 {
393 fs::remove_all(certDir);
394 fs::remove(certificateFile);
395 fs::remove(keyFile);
396 }
397
398 protected:
399 sdbusplus::bus::bus bus;
400 std::string certificateFile;
401 std::string keyFile;
402 std::string certDir;
403};
404
405/** @brief Check install fails if private key is missing in certificate file
406 */
407TEST_F(TestInvalidCertsManager, TestMissingPrivateKey)
408{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600409 // TODO due to refactoring test cases will be pushed as last patch
410 // in the patch set
411 /*
Marri Devender Raoddf64862018-10-03 07:11:02 -0500412 std::string endpoint("ldap");
413 std::string unit("nslcd.service");
414 std::string type("client");
415 std::string path(certDir + "/" + certificateFile);
416 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500417 std::string verifyUnit(unit);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500418 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
419 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
420 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500421 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500422 MainApp mainApp(&manager);
423 EXPECT_THROW(
424 {
425 try
426 {
427 mainApp.install(certificateFile);
428 }
429 catch (const InvalidCertificate& e)
430 {
431 throw;
432 }
433 },
434 InvalidCertificate);
435 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600436 */
Marri Devender Raoddf64862018-10-03 07:11:02 -0500437}
438
439/** @brief Check install fails if ceritificate is missing in certificate file
440 */
441TEST_F(TestInvalidCertsManager, TestMissingCeritificate)
442{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600443 // TODO due to refactoring test cases will be pushed as last patch
444 // in the patch set
445 /*
Marri Devender Raoddf64862018-10-03 07:11:02 -0500446 std::string endpoint("ldap");
447 std::string unit("nslcd.service");
448 std::string type("client");
449 std::string path(certDir + "/" + keyFile);
450 std::string verifyPath(path);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500451 std::string verifyUnit(unit);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500452
453 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
454 MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
455 std::move(path));
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500456 EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500457 MainApp mainApp(&manager);
458 EXPECT_THROW(
459 {
460 try
461 {
462 mainApp.install(keyFile);
463 }
464 catch (const InvalidCertificate& e)
465 {
466 throw;
467 }
468 },
469 InvalidCertificate);
470 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600471 */
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500472}