blob: 7b318d7754878942595e62746814e11c047bc1ec [file] [log] [blame]
Marri Devender Rao13bf74e2019-03-26 01:52:17 -05001#include "config.h"
2
Marri Devender Rao8841dbd2019-03-04 05:43:55 -06003#include "certificate.hpp"
Marri Devender Rao947258d2018-09-25 10:52:24 -05004#include "certs_manager.hpp"
5
6#include <algorithm>
Marri Devender Rao8841dbd2019-03-04 05:43:55 -06007#include <filesystem>
Marri Devender Rao947258d2018-09-25 10:52:24 -05008#include <fstream>
9#include <iterator>
10#include <string>
Marri Devender Rao13bf74e2019-03-26 01:52:17 -050011#include <xyz/openbmc_project/Certs/error.hpp>
Marri Devender Rao947258d2018-09-25 10:52:24 -050012#include <xyz/openbmc_project/Common/error.hpp>
13
Marri Devender Rao947258d2018-09-25 10:52:24 -050014#include <gtest/gtest.h>
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060015namespace fs = std::filesystem;
Marri Devender Rao947258d2018-09-25 10:52:24 -050016using InternalFailure =
17 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Marri Devender Raoe6597c52018-10-01 06:36:55 -050018using InvalidCertificate =
Marri Devender Rao13bf74e2019-03-26 01:52:17 -050019 sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060020using namespace phosphor::certs;
Marri Devender Raoe6597c52018-10-01 06:36:55 -050021
Marri Devender Raoddf64862018-10-03 07:11:02 -050022/**
23 * Class to generate certificate file and test verification of certificate file
24 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060025class TestCertificates : public ::testing::Test
Marri Devender Rao947258d2018-09-25 10:52:24 -050026{
27 public:
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060028 TestCertificates() : bus(sdbusplus::bus::new_default())
Marri Devender Rao947258d2018-09-25 10:52:24 -050029 {
30 }
31 void SetUp() override
32 {
33 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
34 auto dirPtr = mkdtemp(dirTemplate);
35 if (dirPtr == NULL)
36 {
37 throw std::bad_alloc();
38 }
39 certDir = dirPtr;
40 certificateFile = "cert.pem";
41 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
42 cmd += "-keyout cert.pem -out cert.pem -days 3650 ";
43 cmd += "-subj "
44 "/O=openbmc-project.xyz/CN=localhost"
45 " -nodes";
46 auto val = std::system(cmd.c_str());
47 if (val)
48 {
49 std::cout << "COMMAND Error: " << val << std::endl;
50 }
51 }
52 void TearDown() override
53 {
54 fs::remove_all(certDir);
55 fs::remove(certificateFile);
56 }
57
58 bool compareFiles(const std::string& file1, const std::string& file2)
59 {
60 std::ifstream f1(file1, std::ifstream::binary | std::ifstream::ate);
61 std::ifstream f2(file2, std::ifstream::binary | std::ifstream::ate);
62
63 if (f1.fail() || f2.fail())
64 {
65 return false; // file problem
66 }
67
68 if (f1.tellg() != f2.tellg())
69 {
70 return false; // size mismatch
71 }
72
73 // seek back to beginning and use std::equal to compare contents
74 f1.seekg(0, std::ifstream::beg);
75 f2.seekg(0, std::ifstream::beg);
76 return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
77 std::istreambuf_iterator<char>(),
78 std::istreambuf_iterator<char>(f2.rdbuf()));
79 }
80
81 protected:
82 sdbusplus::bus::bus bus;
83 std::string certificateFile;
84
85 std::string certDir;
86};
87
88class MainApp
89{
90 public:
91 MainApp(phosphor::certs::Manager* manager) : manager(manager)
92 {
93 }
94 void install(std::string& path)
95 {
96 manager->install(path);
97 }
Marri Devender Rao9abfae82018-10-03 08:10:35 -050098 void delete_()
99 {
100 manager->delete_();
101 }
Marri Devender Rao947258d2018-09-25 10:52:24 -0500102 phosphor::certs::Manager* manager;
103};
104
Marri Devender Rao947258d2018-09-25 10:52:24 -0500105/** @brief Check if server install routine is invoked for server setup
106 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600107TEST_F(TestCertificates, InvokeServerInstall)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500108{
109 std::string endpoint("https");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600110 std::string unit("");
Marri Devender Rao947258d2018-09-25 10:52:24 -0500111 std::string type("server");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600112 std::string installPath(certDir + "/" + certificateFile);
113 std::string verifyPath(installPath);
114 UnitsToRestart verifyUnit(unit);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500115 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600116 Certificate certificate(bus, objPath, type, unit, installPath,
117 certificateFile);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500118 EXPECT_TRUE(fs::exists(verifyPath));
119}
120
121/** @brief Check if client install routine is invoked for client setup
122 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600123TEST_F(TestCertificates, InvokeClientInstall)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500124{
125 std::string endpoint("ldap");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600126 std::string unit("");
127 std::string type("server");
128 std::string installPath(certDir + "/" + certificateFile);
129 std::string verifyPath(installPath);
130 UnitsToRestart verifyUnit(unit);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500131 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600132 Certificate certificate(bus, objPath, type, unit, installPath,
133 certificateFile);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500134 EXPECT_TRUE(fs::exists(verifyPath));
135}
136
137/** @brief Check if authority install routine is invoked for authority setup
138 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600139TEST_F(TestCertificates, InvokeAuthorityInstall)
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500140{
141 std::string endpoint("ldap");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600142 std::string unit("");
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500143 std::string type("authority");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600144 std::string installPath(certDir + "/" + certificateFile);
145 std::string verifyPath(installPath);
146 UnitsToRestart verifyUnit(unit);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500147 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600148 Certificate certificate(bus, objPath, type, unit, installPath,
149 certificateFile);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500150 EXPECT_TRUE(fs::exists(verifyPath));
151}
152
153/** @brief Compare the installed certificate with the copied certificate
154 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600155TEST_F(TestCertificates, CompareInstalledCertificate)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500156{
157 std::string endpoint("ldap");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600158 std::string unit("");
Marri Devender Rao947258d2018-09-25 10:52:24 -0500159 std::string type("client");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600160 std::string installPath(certDir + "/" + certificateFile);
161 std::string verifyPath(installPath);
162 UnitsToRestart verifyUnit(unit);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500163 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600164 Certificate certificate(bus, objPath, type, unit, installPath,
165 certificateFile);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500166 EXPECT_TRUE(fs::exists(verifyPath));
167 EXPECT_TRUE(compareFiles(verifyPath, certificateFile));
168}
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500169
170/** @brief Check if install fails if certificate file is not found
171 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600172TEST_F(TestCertificates, TestNoCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500173{
174 std::string endpoint("ldap");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600175 std::string unit("");
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500176 std::string type("client");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600177 std::string installPath(certDir + "/" + certificateFile);
178 std::string verifyPath(installPath);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500179 std::string verifyUnit(unit);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500180 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600181 std::string uploadFile = "nofile.pem";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500182 EXPECT_THROW(
183 {
184 try
185 {
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600186 Certificate certificate(bus, objPath, type, unit, installPath,
187 uploadFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500188 }
189 catch (const InternalFailure& e)
190 {
191 throw;
192 }
193 },
194 InternalFailure);
195 EXPECT_FALSE(fs::exists(verifyPath));
196}
197
198/** @brief Check if install fails if certificate file is empty
199 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600200TEST_F(TestCertificates, TestEmptyCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500201{
202 std::string endpoint("ldap");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600203 std::string unit("");
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500204 std::string type("client");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600205 std::string installPath(certDir + "/" + certificateFile);
206 std::string verifyPath(installPath);
207 std::string verifyUnit(unit);
208 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500209 std::string emptyFile("emptycert.pem");
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500210 std::ofstream ofs;
211 ofs.open(emptyFile, std::ofstream::out);
212 ofs.close();
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500213 EXPECT_THROW(
214 {
215 try
216 {
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600217 Certificate certificate(bus, objPath, type, unit, installPath,
218 emptyFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500219 }
220 catch (const InvalidCertificate& e)
221 {
222 throw;
223 }
224 },
225 InvalidCertificate);
226 EXPECT_FALSE(fs::exists(verifyPath));
227 fs::remove(emptyFile);
228}
229
Marri Devender Raoddf64862018-10-03 07:11:02 -0500230/** @brief Check if install fails if certificate file is corrupted
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500231 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600232TEST_F(TestCertificates, TestInvalidCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500233{
234 std::string endpoint("ldap");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600235 std::string unit("");
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500236 std::string type("client");
237
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500238 std::ofstream ofs;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500239 ofs.open(certificateFile, std::ofstream::out);
240 ofs << "-----BEGIN CERTIFICATE-----";
241 ofs << "ADD_SOME_INVALID_DATA_INTO_FILE";
242 ofs << "-----END CERTIFICATE-----";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500243 ofs.close();
244
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600245 std::string installPath(certDir + "/" + certificateFile);
246 std::string verifyPath(installPath);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500247 std::string verifyUnit(unit);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500248 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500249 EXPECT_THROW(
250 {
251 try
252 {
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600253 Certificate certificate(bus, objPath, type, unit, installPath,
254 certificateFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500255 }
256 catch (const InvalidCertificate& e)
257 {
258 throw;
259 }
260 },
261 InvalidCertificate);
262 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500263}
Marri Devender Raoddf64862018-10-03 07:11:02 -0500264
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600265/** @brief check certificate delete at manager level
266 */
267TEST_F(TestCertificates, TestCertManagerDelete)
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500268{
269 std::string endpoint("ldap");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600270 std::string unit("");
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500271 std::string type("client");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600272 std::string installPath(certDir + "/" + certificateFile);
273 std::string verifyPath(installPath);
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500274 std::string verifyUnit(unit);
275 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600276 Manager manager(bus, objPath.c_str(), type, std::move(unit),
277 std::move(installPath));
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500278 MainApp mainApp(&manager);
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500279 // delete certificate file and verify file is deleted
280 mainApp.delete_();
281 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600282}
283
284/** @brief check certificate install at manager level
285 */
286TEST_F(TestCertificates, TestCertManagerInstall)
287{
288 std::string endpoint("ldap");
289 std::string unit("");
290 std::string type("client");
291 std::string installPath(certDir + "/" + certificateFile);
292 std::string verifyPath(installPath);
293 std::string verifyUnit(unit);
294 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
295 Manager manager(bus, objPath.c_str(), type, std::move(unit),
296 std::move(installPath));
297 MainApp mainApp(&manager);
298 mainApp.install(certificateFile);
299 EXPECT_TRUE(fs::exists(verifyPath));
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500300}
301
Marri Devender Raoddf64862018-10-03 07:11:02 -0500302/**
303 * Class to generate private and certificate only file and test verification
304 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600305class TestInvalidCertificate : public ::testing::Test
Marri Devender Raoddf64862018-10-03 07:11:02 -0500306{
307 public:
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600308 TestInvalidCertificate() : bus(sdbusplus::bus::new_default())
Marri Devender Raoddf64862018-10-03 07:11:02 -0500309 {
310 }
311 void SetUp() override
312 {
313 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
314 auto dirPtr = mkdtemp(dirTemplate);
315 if (dirPtr == NULL)
316 {
317 throw std::bad_alloc();
318 }
319 certDir = dirPtr;
320 certificateFile = "cert.pem";
321 keyFile = "key.pem";
322 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
323 cmd += "-keyout key.pem -out cert.pem -days 3650 ";
324 cmd += "-subj "
325 "/O=openbmc-project.xyz/CN=localhost"
326 " -nodes";
327
328 auto val = std::system(cmd.c_str());
329 if (val)
330 {
331 std::cout << "command Error: " << val << std::endl;
332 }
333 }
334 void TearDown() override
335 {
336 fs::remove_all(certDir);
337 fs::remove(certificateFile);
338 fs::remove(keyFile);
339 }
340
341 protected:
342 sdbusplus::bus::bus bus;
343 std::string certificateFile;
344 std::string keyFile;
345 std::string certDir;
346};
347
348/** @brief Check install fails if private key is missing in certificate file
349 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600350TEST_F(TestInvalidCertificate, TestMissingPrivateKey)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500351{
352 std::string endpoint("ldap");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600353 std::string unit("");
Marri Devender Raoddf64862018-10-03 07:11:02 -0500354 std::string type("client");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600355 std::string installPath(certDir + "/" + certificateFile);
356 std::string verifyPath(installPath);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500357 std::string verifyUnit(unit);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500358 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600359 EXPECT_THROW(
360 {
361 try
362 {
363 Certificate certificate(bus, objPath, type, unit, installPath,
364 certificateFile);
365 }
366 catch (const InvalidCertificate& e)
367 {
368 throw;
369 }
370 },
371 InvalidCertificate);
372 EXPECT_FALSE(fs::exists(verifyPath));
373}
374
375/** @brief Check install fails if ceritificate is missing in certificate file
376 */
377TEST_F(TestInvalidCertificate, TestMissingCeritificate)
378{
379 std::string endpoint("ldap");
380 std::string unit("");
381 std::string type("client");
382 std::string installPath(certDir + "/" + keyFile);
383 std::string verifyPath(installPath);
384 std::string verifyUnit(unit);
385
386 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
387 EXPECT_THROW(
388 {
389 try
390 {
391 Certificate certificate(bus, objPath, type, unit, installPath,
392 keyFile);
393 }
394 catch (const InvalidCertificate& e)
395 {
396 throw;
397 }
398 },
399 InvalidCertificate);
400 EXPECT_FALSE(fs::exists(verifyPath));
401}
402
403/** @brief Check if Manager install method fails for invalid certificate file
404 */
405TEST_F(TestInvalidCertificate, TestCertManagerInstall)
406{
407 std::string endpoint("ldap");
408 std::string unit("");
409 std::string type("client");
410 std::string installPath(certDir + "/" + certificateFile);
411 std::string verifyPath(installPath);
412 std::string verifyUnit(unit);
413 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
414 Manager manager(bus, objPath.c_str(), type, std::move(unit),
415 std::move(installPath));
Marri Devender Raoddf64862018-10-03 07:11:02 -0500416 MainApp mainApp(&manager);
417 EXPECT_THROW(
418 {
419 try
420 {
421 mainApp.install(certificateFile);
422 }
423 catch (const InvalidCertificate& e)
424 {
425 throw;
426 }
427 },
428 InvalidCertificate);
429 EXPECT_FALSE(fs::exists(verifyPath));
430}
431
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600432/** @brief Check if error is thrown when multiple certificates are installed
433 * At present only one certificate per service is allowed
Marri Devender Raoddf64862018-10-03 07:11:02 -0500434 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600435TEST_F(TestCertificates, TestCertInstallNotAllowed)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500436{
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600437 using NotAllowed =
438 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500439 std::string endpoint("ldap");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600440 std::string unit("");
Marri Devender Raoddf64862018-10-03 07:11:02 -0500441 std::string type("client");
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600442 std::string installPath(certDir + "/" + certificateFile);
443 std::string verifyPath(installPath);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500444 std::string verifyUnit(unit);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500445 auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600446 Manager manager(bus, objPath.c_str(), type, std::move(unit),
447 std::move(installPath));
Marri Devender Raoddf64862018-10-03 07:11:02 -0500448 MainApp mainApp(&manager);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600449 mainApp.install(certificateFile);
450 EXPECT_TRUE(fs::exists(verifyPath));
Marri Devender Raoddf64862018-10-03 07:11:02 -0500451 EXPECT_THROW(
452 {
453 try
454 {
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600455 // install second certificate
456 mainApp.install(certificateFile);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500457 }
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600458 catch (const NotAllowed& e)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500459 {
460 throw;
461 }
462 },
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600463 NotAllowed);
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500464}