1 #include "config.h"
2
3 #include "certificate.hpp"
4 #include "certs_manager.hpp"
5 #include "csr.hpp"
6
7 #include <openssl/bio.h>
8 #include <openssl/ossl_typ.h>
9 #include <openssl/pem.h>
10 #include <openssl/x509.h>
11 #include <systemd/sd-event.h>
12 #include <unistd.h>
13
14 #include <sdbusplus/bus.hpp>
15 #include <sdeventplus/event.hpp>
16 #include <xyz/openbmc_project/Certs/error.hpp>
17 #include <xyz/openbmc_project/Common/error.hpp>
18
19 #include <cstdint>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <filesystem>
23 #include <fstream>
24 #include <iostream>
25 #include <iterator>
26 #include <memory>
27 #include <new>
28 #include <string>
29 #include <unordered_set>
30 #include <utility>
31 #include <vector>
32
33 #include <gmock/gmock.h>
34 #include <gtest/gtest.h>
35
36 namespace phosphor::certs
37 {
38 namespace
39 {
40 namespace fs = std::filesystem;
41 using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
42 using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
43 using ::testing::Eq;
44 using ::testing::Return;
45 // Compares two files; returns true only if the two are the same
compareFiles(const std::string & file1,const std::string & file2)46 bool compareFiles(const std::string& file1, const std::string& file2)
47 {
48 std::ifstream f1(file1, std::ifstream::binary | std::ifstream::ate);
49 std::ifstream f2(file2, std::ifstream::binary | std::ifstream::ate);
50
51 if (f1.fail() || f2.fail())
52 {
53 return false; // file problem
54 }
55
56 if (f1.tellg() != f2.tellg())
57 {
58 return false; // size mismatch
59 }
60
61 // seek back to beginning and use std::equal to compare contents
62 f1.seekg(0, std::ifstream::beg);
63 f2.seekg(0, std::ifstream::beg);
64 return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
65 std::istreambuf_iterator<char>(),
66 std::istreambuf_iterator<char>(f2.rdbuf()));
67 }
68
69 /**
70 * Class to generate certificate file and test verification of certificate file
71 */
72 class TestCertificates : public ::testing::Test
73 {
74 public:
TestCertificates()75 TestCertificates() : bus(sdbusplus::bus::new_default()) {}
SetUp()76 void SetUp() override
77 {
78 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
79 auto dirPtr = mkdtemp(dirTemplate);
80 if (dirPtr == nullptr)
81 {
82 throw std::bad_alloc();
83 }
84 certDir = std::string(dirPtr) + "/certs";
85 fs::create_directories(certDir);
86
87 createNewCertificate();
88 }
89
TearDown()90 void TearDown() override
91 {
92 fs::remove_all(certDir);
93 fs::remove(certificateFile);
94 fs::remove(CSRFile);
95 fs::remove(privateKeyFile);
96 fs::remove_all("demoCA");
97 }
98
createNewCertificate(bool setNewCertId=false)99 void createNewCertificate(bool setNewCertId = false)
100 {
101 certificateFile = "cert.pem";
102 CSRFile = "domain.csr";
103 privateKeyFile = "privkey.pem";
104 rsaPrivateKeyFilePath = certDir + "/.rsaprivkey.pem";
105 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
106 cmd += "-keyout cert.pem -out cert.pem -days 365000 -nodes";
107 cmd += " -subj /O=openbmc-project.xyz/CN=localhost";
108
109 if (setNewCertId)
110 {
111 cmd += std::to_string(certId++);
112 }
113
114 auto val = std::system(cmd.c_str());
115 if (val)
116 {
117 std::cout << "COMMAND Error: " << val << std::endl;
118 }
119 }
120
createNeverExpiredRootCertificate()121 void createNeverExpiredRootCertificate()
122 {
123 // remove the old cert
124 fs::remove(certificateFile);
125
126 // The following routines create a cert that has NotBefore
127 // set to 1970/01/01 and NotAfter set to 9999/12/31 via the
128 // OpenSSL CA application.
129 certificateFile = "cert.pem";
130 ASSERT_EQ(std::system("mkdir -p demoCA"), 0);
131 ASSERT_EQ(std::system("mkdir -p demoCA/private/"), 0);
132 ASSERT_EQ(std::system("mkdir -p demoCA/newcerts/"), 0);
133 ASSERT_EQ(std::system("touch demoCA/index.txt"), 0);
134 ASSERT_EQ(std::system("echo 1000 > demoCA/serial"), 0);
135 ASSERT_EQ(
136 std::system(
137 "openssl req -x509 -sha256 -newkey rsa:2048 -keyout "
138 "demoCA/private/cakey.pem -out demoCA/cacert.pem -nodes "
139 "-subj /O=openbmc-project.xyz/C=US/ST=CA/CN=localhost-ca"),
140 0);
141 ASSERT_EQ(std::system(
142 "openssl req -new -newkey rsa:2048 -nodes -keyout "
143 "demoCA/server.key -out demoCA/server.csr -subj "
144 "/O=openbmc-project.xyz/C=US/ST=CA/CN=localhost-server"),
145 0);
146 ASSERT_EQ(
147 std::system(
148 "openssl ca -batch -startdate 19700101000000Z -enddate "
149 "99991231235959Z -out cert.pem -infiles demoCA/server.csr"),
150 0);
151 }
152
compareFiles(const std::string & file1,const std::string & file2)153 bool compareFiles(const std::string& file1, const std::string& file2)
154 {
155 std::ifstream f1(file1, std::ifstream::binary | std::ifstream::ate);
156 std::ifstream f2(file2, std::ifstream::binary | std::ifstream::ate);
157
158 if (f1.fail() || f2.fail())
159 {
160 return false; // file problem
161 }
162
163 if (f1.tellg() != f2.tellg())
164 {
165 return false; // size mismatch
166 }
167
168 // seek back to beginning and use std::equal to compare contents
169 f1.seekg(0, std::ifstream::beg);
170 f2.seekg(0, std::ifstream::beg);
171 return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
172 std::istreambuf_iterator<char>(),
173 std::istreambuf_iterator<char>(f2.rdbuf()));
174 }
175
getCertSubjectNameHash(const std::string & certFilePath)176 std::string getCertSubjectNameHash(const std::string& certFilePath)
177 {
178 std::unique_ptr<X509, decltype(&::X509_free)> cert(X509_new(),
179 ::X509_free);
180 if (!cert)
181 {
182 std::string();
183 }
184
185 std::unique_ptr<BIO, decltype(&::BIO_free)> bioCert(
186 BIO_new_file(certFilePath.c_str(), "rb"), ::BIO_free);
187 if (!bioCert)
188 {
189 std::string();
190 }
191
192 X509* x509 = cert.get();
193 if (!PEM_read_bio_X509(bioCert.get(), &x509, nullptr, nullptr))
194 {
195 std::string();
196 }
197
198 unsigned long hash = X509_subject_name_hash(cert.get());
199 static constexpr auto authCertHashLength = 9;
200 char hashBuf[authCertHashLength];
201 sprintf(hashBuf, "%08lx", hash);
202 return std::string(hashBuf);
203 }
204
205 protected:
206 sdbusplus::bus_t bus;
207 std::string certificateFile, CSRFile, privateKeyFile, rsaPrivateKeyFilePath;
208
209 std::string certDir;
210 uint64_t certId = 1;
211 };
212
213 class MainApp
214 {
215 public:
MainApp(phosphor::certs::Manager * manager,phosphor::certs::CSR * csr=nullptr)216 MainApp(phosphor::certs::Manager* manager,
217 phosphor::certs::CSR* csr = nullptr) :
218 manager(manager),
219 csr_(csr)
220 {}
install(std::string & path)221 void install(std::string& path)
222 {
223 manager->install(path);
224 }
225
generateCSR(std::vector<std::string> alternativeNames,std::string challengePassword,std::string city,std::string commonName,std::string contactPerson,std::string country,std::string email,std::string givenName,std::string initials,int64_t keyBitLength,std::string keyCurveId,std::string keyPairAlgorithm,std::vector<std::string> keyUsage,std::string organization,std::string organizationalUnit,std::string state,std::string surname,std::string unstructuredName)226 std::string generateCSR(std::vector<std::string> alternativeNames,
227 std::string challengePassword, std::string city,
228 std::string commonName, std::string contactPerson,
229 std::string country, std::string email,
230 std::string givenName, std::string initials,
231 int64_t keyBitLength, std::string keyCurveId,
232 std::string keyPairAlgorithm,
233 std::vector<std::string> keyUsage,
234 std::string organization,
235 std::string organizationalUnit, std::string state,
236 std::string surname, std::string unstructuredName)
237 {
238 return (manager->generateCSR(
239 alternativeNames, challengePassword, city, commonName,
240 contactPerson, country, email, givenName, initials, keyBitLength,
241 keyCurveId, keyPairAlgorithm, keyUsage, organization,
242 organizationalUnit, state, surname, unstructuredName));
243 }
csr()244 std::string csr()
245 {
246 return (csr_->csr());
247 }
248 phosphor::certs::Manager* manager;
249 phosphor::certs::CSR* csr_;
250 };
251
252 class ManagerInTest : public phosphor::certs::Manager
253 {
254 public:
255 static constexpr std::string_view unitToRestartInTest =
256 "xyz.openbmc_project.awesome-service";
ManagerInTest(sdbusplus::bus_t & bus,sdeventplus::Event & event,const char * path,CertificateType type,const std::string & unit,const std::string & installPath)257 ManagerInTest(sdbusplus::bus_t& bus, sdeventplus::Event& event,
258 const char* path, CertificateType type,
259 const std::string& unit, const std::string& installPath) :
260 Manager(bus, event, path, type, unit, installPath)
261 {}
262
263 MOCK_METHOD(void, reloadOrReset, (const std::string&), (override));
264 };
265
266 /** @brief Check if server install routine is invoked for server setup
267 */
TEST_F(TestCertificates,InvokeServerInstall)268 TEST_F(TestCertificates, InvokeServerInstall)
269 {
270 std::string endpoint("https");
271 CertificateType type = CertificateType::server;
272 std::string installPath(certDir + "/" + certificateFile);
273 std::string verifyPath(installPath);
274 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
275 auto objPath = std::string(objectNamePrefix) + '/' +
276 certificateTypeToString(type) + '/' + endpoint;
277 auto event = sdeventplus::Event::get_default();
278 // Attach the bus to sd_event to service user requests
279 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
280 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
281 installPath);
282 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
283 .WillOnce(Return());
284 MainApp mainApp(&manager);
285 mainApp.install(certificateFile);
286 EXPECT_TRUE(fs::exists(verifyPath));
287 }
288
289 /** @brief Check if client install routine is invoked for client setup
290 */
TEST_F(TestCertificates,InvokeClientInstall)291 TEST_F(TestCertificates, InvokeClientInstall)
292 {
293 std::string endpoint("ldap");
294 CertificateType type = CertificateType::server;
295 std::string installPath(certDir + "/" + certificateFile);
296 std::string verifyPath(installPath);
297 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
298 auto objPath = std::string(objectNamePrefix) + '/' +
299 certificateTypeToString(type) + '/' + endpoint;
300 auto event = sdeventplus::Event::get_default();
301 // Attach the bus to sd_event to service user requests
302 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
303 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
304 installPath);
305 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
306 .WillOnce(Return());
307 MainApp mainApp(&manager);
308 mainApp.install(certificateFile);
309 EXPECT_TRUE(fs::exists(verifyPath));
310 }
311
312 /** @brief Check if storage install routine is invoked for storage setup
313 */
TEST_F(TestCertificates,InvokeAuthorityInstall)314 TEST_F(TestCertificates, InvokeAuthorityInstall)
315 {
316 std::string endpoint("truststore");
317 CertificateType type = CertificateType::authority;
318 std::string verifyDir(certDir);
319 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
320 auto objPath = std::string(objectNamePrefix) + '/' +
321 certificateTypeToString(type) + '/' + endpoint;
322 auto event = sdeventplus::Event::get_default();
323 // Attach the bus to sd_event to service user requests
324 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
325 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
326 verifyDir);
327 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
328 .WillOnce(Return());
329 MainApp mainApp(&manager);
330 // install the default certificate that's valid from today to 100 years
331 // later
332 mainApp.install(certificateFile);
333
334 std::vector<std::unique_ptr<Certificate>>& certs =
335 manager.getCertificates();
336
337 ASSERT_EQ(certs.size(), 1);
338 // check some attributes as well
339 EXPECT_EQ(certs.front()->validNotAfter() - certs.front()->validNotBefore(),
340 365000ULL * 24 * 3600);
341 EXPECT_EQ(certs.front()->subject(), "O=openbmc-project.xyz,CN=localhost");
342 EXPECT_EQ(certs.front()->issuer(), "O=openbmc-project.xyz,CN=localhost");
343
344 std::string verifyPath = verifyDir + "/" +
345 getCertSubjectNameHash(certificateFile) + ".0";
346
347 // Check that certificate has been created at installation directory
348 EXPECT_FALSE(fs::is_empty(verifyDir));
349 EXPECT_TRUE(fs::exists(verifyPath));
350
351 // Check that installed cert is identical to input one
352 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
353 }
354
355 /** @brief Check if storage install routine is invoked for storage setup
356 */
TEST_F(TestCertificates,InvokeAuthorityInstallNeverExpiredRootCert)357 TEST_F(TestCertificates, InvokeAuthorityInstallNeverExpiredRootCert)
358 {
359 std::string endpoint("truststore");
360 CertificateType type = CertificateType::authority;
361 std::string verifyDir(certDir);
362 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
363 auto objPath = std::string(objectNamePrefix) + '/' +
364 certificateTypeToString(type) + '/' + endpoint;
365 auto event = sdeventplus::Event::get_default();
366 // Attach the bus to sd_event to service user requests
367 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
368 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
369 certDir);
370 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
371 .WillOnce(Return());
372 MainApp mainApp(&manager);
373
374 // install the certificate that's valid from the Unix Epoch to Dec 31, 9999
375 createNeverExpiredRootCertificate();
376 mainApp.install(certificateFile);
377
378 std::vector<std::unique_ptr<Certificate>>& certs =
379 manager.getCertificates();
380
381 EXPECT_EQ(certs.front()->validNotBefore(), 0);
382 EXPECT_EQ(certs.front()->validNotAfter(), 253402300799ULL);
383
384 std::string verifyPath = verifyDir + "/" +
385 getCertSubjectNameHash(certificateFile) + ".0";
386
387 // Check that certificate has been created at installation directory
388 EXPECT_FALSE(fs::is_empty(verifyDir));
389 EXPECT_TRUE(fs::exists(verifyPath));
390
391 // Check that installed cert is identical to input one
392 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
393 }
394
395 /** @brief Check if in authority mode user can't install the same
396 * certificate twice.
397 */
TEST_F(TestCertificates,InvokeInstallSameCertTwice)398 TEST_F(TestCertificates, InvokeInstallSameCertTwice)
399 {
400 std::string endpoint("truststore");
401 CertificateType type = CertificateType::authority;
402 std::string verifyDir(certDir);
403 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
404 auto objPath = std::string(objectNamePrefix) + '/' +
405 certificateTypeToString(type) + '/' + endpoint;
406 auto event = sdeventplus::Event::get_default();
407 // Attach the bus to sd_event to service user requests
408 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
409 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
410 std::move(certDir));
411 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
412 .WillOnce(Return());
413 MainApp mainApp(&manager);
414 mainApp.install(certificateFile);
415
416 std::vector<std::unique_ptr<Certificate>>& certs =
417 manager.getCertificates();
418
419 EXPECT_FALSE(certs.empty());
420
421 // Check that certificate has been created at installation directory
422 std::string verifyPath = verifyDir + "/" +
423 getCertSubjectNameHash(certificateFile) + ".0";
424 EXPECT_FALSE(fs::is_empty(verifyDir));
425 EXPECT_TRUE(fs::exists(verifyPath));
426
427 // Check that installed cert is identical to input one
428 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
429
430 using NotAllowed =
431 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
432 EXPECT_THROW(
433 {
434 try
435 {
436 // Try to install the same certificate second time
437 mainApp.install(certificateFile);
438 }
439 catch (const NotAllowed& e)
440 {
441 throw;
442 }
443 },
444 NotAllowed);
445
446 // Check that the original certificate has been not removed
447 EXPECT_FALSE(fs::is_empty(verifyDir));
448 EXPECT_TRUE(fs::exists(verifyPath));
449 }
450
451 /** @brief Check if in authority mode user can install a certificate with
452 * certain subject hash twice.
453 */
TEST_F(TestCertificates,InvokeInstallSameSubjectTwice)454 TEST_F(TestCertificates, InvokeInstallSameSubjectTwice)
455 {
456 std::string endpoint("truststore");
457 CertificateType type = CertificateType::authority;
458 std::string verifyDir(certDir);
459 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
460 auto objPath = std::string(objectNamePrefix) + '/' +
461 certificateTypeToString(type) + '/' + endpoint;
462 auto event = sdeventplus::Event::get_default();
463 // Attach the bus to sd_event to service user requests
464 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
465 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
466 certDir);
467 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
468 .WillOnce(Return())
469 .WillOnce(Return());
470 MainApp mainApp(&manager);
471 mainApp.install(certificateFile);
472
473 std::vector<std::unique_ptr<Certificate>>& certs =
474 manager.getCertificates();
475
476 EXPECT_FALSE(certs.empty());
477
478 // Check that certificate has been created at installation directory
479 std::string verifyPath0 = verifyDir + "/" +
480 getCertSubjectNameHash(certificateFile) + ".0";
481 EXPECT_FALSE(fs::is_empty(verifyDir));
482 EXPECT_TRUE(fs::exists(verifyPath0));
483
484 // Check that installed cert is identical to input one
485 EXPECT_TRUE(compareFiles(certificateFile, verifyPath0));
486
487 // Prepare second certificate with the same subject
488 createNewCertificate();
489
490 // Install second certificate
491 mainApp.install(certificateFile);
492
493 // Expect there are exactly two certificates in the collection
494 EXPECT_EQ(certs.size(), 2);
495
496 // Check that certificate has been created at installation directory
497 std::string verifyPath1 = verifyDir + "/" +
498 getCertSubjectNameHash(certificateFile) + ".1";
499 EXPECT_TRUE(fs::exists(verifyPath1));
500
501 // Check that installed cert is identical to input one
502 EXPECT_TRUE(compareFiles(certificateFile, verifyPath1));
503
504 // Check that the original/first certificate has been not removed
505 EXPECT_FALSE(fs::is_empty(verifyDir));
506 EXPECT_TRUE(fs::exists(verifyPath0));
507 }
508
509 /** @brief Check if in authority mode user can't install more than
510 * maxNumAuthorityCertificates certificates.
511 */
TEST_F(TestCertificates,InvokeInstallAuthCertLimit)512 TEST_F(TestCertificates, InvokeInstallAuthCertLimit)
513 {
514 std::string endpoint("truststore");
515 CertificateType type = CertificateType::authority;
516 std::string verifyDir(certDir);
517 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
518 auto objPath = std::string(objectNamePrefix) + '/' +
519 certificateTypeToString(type) + '/' + endpoint;
520 auto event = sdeventplus::Event::get_default();
521 // Attach the bus to sd_event to service user requests
522 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
523 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
524 certDir);
525 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
526 .WillRepeatedly(Return());
527 MainApp mainApp(&manager);
528
529 std::vector<std::unique_ptr<Certificate>>& certs =
530 manager.getCertificates();
531
532 std::vector<std::string> verifyPaths;
533
534 // Prepare maximum number of ceritificates
535 for (std::size_t i = 0; i < maxNumAuthorityCertificates; ++i)
536 {
537 // Prepare new certificatate
538 createNewCertificate(true);
539
540 // Install ceritificate
541 mainApp.install(certificateFile);
542
543 // Check number of certificates in the collection
544 EXPECT_EQ(certs.size(), i + 1);
545
546 // Check that certificate has been created at installation directory
547 std::string verifyPath = verifyDir + "/" +
548 getCertSubjectNameHash(certificateFile) + ".0";
549 EXPECT_FALSE(fs::is_empty(verifyDir));
550 EXPECT_TRUE(fs::exists(verifyPath));
551
552 // Check that installed cert is identical to input one
553 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
554
555 // Save current certificate file for later check
556 verifyPaths.push_back(verifyPath);
557 }
558
559 // Prepare new certificatate
560 createNewCertificate(true);
561
562 using NotAllowed =
563 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
564 EXPECT_THROW(
565 {
566 try
567 {
568 // Try to install one more certificate
569 mainApp.install(certificateFile);
570 }
571 catch (const NotAllowed& e)
572 {
573 throw;
574 }
575 },
576 NotAllowed);
577
578 // Check that the original certificate has been not removed
579 EXPECT_FALSE(fs::is_empty(verifyDir));
580 for (size_t i = 0; i < maxNumAuthorityCertificates; ++i)
581 {
582 EXPECT_TRUE(fs::exists(verifyPaths[i]));
583 }
584 }
585
586 /** @brief Compare the installed certificate with the copied certificate
587 */
TEST_F(TestCertificates,CompareInstalledCertificate)588 TEST_F(TestCertificates, CompareInstalledCertificate)
589 {
590 std::string endpoint("ldap");
591 CertificateType type = CertificateType::client;
592 std::string installPath(certDir + "/" + certificateFile);
593 std::string verifyPath(installPath);
594 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
595 auto objPath = std::string(objectNamePrefix) + '/' +
596 certificateTypeToString(type) + '/' + endpoint;
597 auto event = sdeventplus::Event::get_default();
598 // Attach the bus to sd_event to service user requests
599 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
600 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
601 installPath);
602 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
603 .WillOnce(Return());
604 MainApp mainApp(&manager);
605 mainApp.install(certificateFile);
606 EXPECT_TRUE(fs::exists(verifyPath));
607 EXPECT_TRUE(compareFiles(verifyPath, certificateFile));
608 }
609
610 /** @brief Check if install fails if certificate file is not found
611 */
TEST_F(TestCertificates,TestNoCertificateFile)612 TEST_F(TestCertificates, TestNoCertificateFile)
613 {
614 std::string endpoint("ldap");
615 CertificateType type = CertificateType::client;
616 std::string installPath(certDir + "/" + certificateFile);
617 std::string verifyPath(installPath);
618 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
619 auto objPath = std::string(objectNamePrefix) + '/' +
620 certificateTypeToString(type) + '/' + endpoint;
621 std::string uploadFile = "nofile.pem";
622 EXPECT_THROW(
623 {
624 try
625 {
626 auto event = sdeventplus::Event::get_default();
627 // Attach the bus to sd_event to service user requests
628 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
629 ManagerInTest manager(bus, event, objPath.c_str(), type,
630 verifyUnit, installPath);
631 MainApp mainApp(&manager);
632 mainApp.install(uploadFile);
633 }
634 catch (const InternalFailure& e)
635 {
636 throw;
637 }
638 },
639 InternalFailure);
640 EXPECT_FALSE(fs::exists(verifyPath));
641 }
642
643 /** @brief Test replacing existing certificate
644 */
TEST_F(TestCertificates,TestReplaceCertificate)645 TEST_F(TestCertificates, TestReplaceCertificate)
646 {
647 std::string endpoint("ldap");
648 CertificateType type = CertificateType::server;
649 std::string installPath(certDir + "/" + certificateFile);
650 std::string verifyPath(installPath);
651 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
652 auto objPath = std::string(objectNamePrefix) + '/' +
653 certificateTypeToString(type) + '/' + endpoint;
654 auto event = sdeventplus::Event::get_default();
655 // Attach the bus to sd_event to service user requests
656 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
657 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
658 std::move(installPath));
659 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
660 .WillOnce(Return())
661 .WillOnce(Return());
662 MainApp mainApp(&manager);
663 mainApp.install(certificateFile);
664 EXPECT_TRUE(fs::exists(verifyPath));
665 std::vector<std::unique_ptr<Certificate>>& certs =
666 manager.getCertificates();
667 EXPECT_FALSE(certs.empty());
668 EXPECT_NE(certs[0], nullptr);
669 certs[0]->replace(certificateFile);
670 EXPECT_TRUE(fs::exists(verifyPath));
671 }
672
673 /** @brief Test replacing existing certificate
674 */
TEST_F(TestCertificates,TestAuthorityReplaceCertificate)675 TEST_F(TestCertificates, TestAuthorityReplaceCertificate)
676 {
677 std::string endpoint("truststore");
678 CertificateType type = CertificateType::authority;
679 std::string verifyDir(certDir);
680 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
681 auto objPath = std::string(objectNamePrefix) + '/' +
682 certificateTypeToString(type) + '/' + endpoint;
683 auto event = sdeventplus::Event::get_default();
684 // Attach the bus to sd_event to service user requests
685 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
686 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
687 certDir);
688 constexpr const unsigned int replaceIterations = 10;
689 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
690 .Times(replaceIterations + 1)
691 .WillRepeatedly(Return());
692 MainApp mainApp(&manager);
693 mainApp.install(certificateFile);
694
695 std::vector<std::unique_ptr<Certificate>>& certs =
696 manager.getCertificates();
697
698 for (unsigned int i = 0; i < replaceIterations; i++)
699 {
700 // Certificate successfully installed
701 EXPECT_FALSE(certs.empty());
702
703 std::string verifyPath = verifyDir + "/" +
704 getCertSubjectNameHash(certificateFile) + ".0";
705
706 // Check that certificate has been created at installation directory
707 EXPECT_FALSE(fs::is_empty(verifyDir));
708 EXPECT_TRUE(fs::exists(verifyPath));
709
710 // Check that installed cert is identical to input one
711 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
712
713 // Create new certificate
714 createNewCertificate(true);
715
716 certs[0]->replace(certificateFile);
717
718 // Verify that old certificate has been removed
719 EXPECT_FALSE(fs::exists(verifyPath));
720 }
721 }
722
723 /** @brief Test verifiing if delete function works.
724 */
TEST_F(TestCertificates,TestStorageDeleteCertificate)725 TEST_F(TestCertificates, TestStorageDeleteCertificate)
726 {
727 std::string endpoint("truststore");
728 CertificateType type = CertificateType::authority;
729 std::string verifyDir(certDir);
730 std::string verifyUnit((ManagerInTest::unitToRestartInTest));
731 auto objPath = std::string(objectNamePrefix) + '/' +
732 certificateTypeToString(type) + '/' + endpoint;
733 auto event = sdeventplus::Event::get_default();
734 // Attach the bus to sd_event to service user requests
735 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
736 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
737 certDir);
738 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
739 .WillRepeatedly(Return());
740 MainApp mainApp(&manager);
741
742 // Check if certificate placeholder dir is empty
743 EXPECT_TRUE(fs::is_empty(verifyDir));
744 mainApp.install(certificateFile);
745
746 // Create new certificate
747 createNewCertificate(true);
748 mainApp.install(certificateFile);
749
750 createNewCertificate(true);
751 mainApp.install(certificateFile);
752
753 std::vector<std::unique_ptr<Certificate>>& certs =
754 manager.getCertificates();
755
756 // All 3 certificates successfully installed and added to manager
757 EXPECT_EQ(certs.size(), 3);
758
759 // Check if certificate placeholder is not empty, there should be 3
760 // certificates
761 EXPECT_FALSE(fs::is_empty(verifyDir));
762
763 certs[0]->delete_();
764 EXPECT_EQ(certs.size(), 2);
765
766 certs[0]->delete_();
767 EXPECT_EQ(certs.size(), 1);
768
769 certs[0]->delete_();
770 EXPECT_EQ(certs.size(), 0);
771
772 // Check if certificate placeholder is empty.
773 EXPECT_TRUE(fs::is_empty(verifyDir));
774 }
775
776 /** @brief Check if install fails if certificate file is empty
777 */
TEST_F(TestCertificates,TestEmptyCertificateFile)778 TEST_F(TestCertificates, TestEmptyCertificateFile)
779 {
780 std::string endpoint("ldap");
781 CertificateType type = CertificateType::client;
782 std::string installPath(certDir + "/" + certificateFile);
783 std::string verifyPath(installPath);
784 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
785 auto objPath = std::string(objectNamePrefix) + '/' +
786 certificateTypeToString(type) + '/' + endpoint;
787 std::string emptyFile("emptycert.pem");
788 std::ofstream ofs;
789 ofs.open(emptyFile, std::ofstream::out);
790 ofs.close();
791 EXPECT_THROW(
792 {
793 try
794 {
795 auto event = sdeventplus::Event::get_default();
796 // Attach the bus to sd_event to service user requests
797 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
798 ManagerInTest manager(bus, event, objPath.c_str(), type,
799 verifyUnit, installPath);
800 MainApp mainApp(&manager);
801 mainApp.install(emptyFile);
802 }
803 catch (const InvalidCertificate& e)
804 {
805 throw;
806 }
807 },
808 InvalidCertificate);
809 EXPECT_FALSE(fs::exists(verifyPath));
810 fs::remove(emptyFile);
811 }
812
813 /** @brief Check if install fails if certificate file is corrupted
814 */
TEST_F(TestCertificates,TestInvalidCertificateFile)815 TEST_F(TestCertificates, TestInvalidCertificateFile)
816 {
817 std::string endpoint("ldap");
818 CertificateType type = CertificateType::client;
819
820 std::ofstream ofs;
821 ofs.open(certificateFile, std::ofstream::out);
822 ofs << "-----BEGIN CERTIFICATE-----";
823 ofs << "ADD_SOME_INVALID_DATA_INTO_FILE";
824 ofs << "-----END CERTIFICATE-----";
825 ofs.close();
826
827 std::string installPath(certDir + "/" + certificateFile);
828 std::string verifyPath(installPath);
829 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
830 auto objPath = std::string(objectNamePrefix) + '/' +
831 certificateTypeToString(type) + '/' + endpoint;
832 EXPECT_THROW(
833 {
834 try
835 {
836 auto event = sdeventplus::Event::get_default();
837 // Attach the bus to sd_event to service user requests
838 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
839 ManagerInTest manager(bus, event, objPath.c_str(), type,
840 verifyUnit, installPath);
841 MainApp mainApp(&manager);
842 mainApp.install(certificateFile);
843 }
844 catch (const InvalidCertificate& e)
845 {
846 throw;
847 }
848 },
849 InvalidCertificate);
850 EXPECT_FALSE(fs::exists(verifyPath));
851 }
852
853 /**
854 * Class to generate private and certificate only file and test verification
855 */
856 class TestInvalidCertificate : public ::testing::Test
857 {
858 public:
TestInvalidCertificate()859 TestInvalidCertificate() : bus(sdbusplus::bus::new_default()) {}
SetUp()860 void SetUp() override
861 {
862 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
863 auto dirPtr = mkdtemp(dirTemplate);
864 if (dirPtr == nullptr)
865 {
866 throw std::bad_alloc();
867 }
868 certDir = std::string(dirPtr) + "/certs";
869 fs::create_directories(certDir);
870 certificateFile = "cert.pem";
871 keyFile = "key.pem";
872 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
873 cmd += "-keyout key.pem -out cert.pem -days 3650 ";
874 cmd += "-subj "
875 "/O=openbmc-project.xyz/CN=localhost"
876 " -nodes";
877
878 auto val = std::system(cmd.c_str());
879 if (val)
880 {
881 std::cout << "command Error: " << val << std::endl;
882 }
883 }
TearDown()884 void TearDown() override
885 {
886 fs::remove_all(certDir);
887 fs::remove(certificateFile);
888 fs::remove(keyFile);
889 }
890
891 protected:
892 sdbusplus::bus_t bus;
893 std::string certificateFile;
894 std::string keyFile;
895 std::string certDir;
896 };
897
898 /** @brief Check install fails if private key is missing in certificate file
899 */
TEST_F(TestInvalidCertificate,TestMissingPrivateKey)900 TEST_F(TestInvalidCertificate, TestMissingPrivateKey)
901 {
902 std::string endpoint("ldap");
903 CertificateType type = CertificateType::client;
904 std::string installPath(certDir + "/" + certificateFile);
905 std::string verifyPath(installPath);
906 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
907 auto objPath = std::string(objectNamePrefix) + '/' +
908 certificateTypeToString(type) + '/' + endpoint;
909 EXPECT_THROW(
910 {
911 try
912 {
913 auto event = sdeventplus::Event::get_default();
914 // Attach the bus to sd_event to service user requests
915 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
916 ManagerInTest manager(bus, event, objPath.c_str(), type,
917 verifyUnit, installPath);
918 MainApp mainApp(&manager);
919 mainApp.install(certificateFile);
920 }
921 catch (const InternalFailure& e)
922 {
923 throw;
924 }
925 },
926 InternalFailure);
927 EXPECT_FALSE(fs::exists(verifyPath));
928 }
929
930 /** @brief Check install fails if ceritificate is missing in certificate file
931 */
TEST_F(TestInvalidCertificate,TestMissingCeritificate)932 TEST_F(TestInvalidCertificate, TestMissingCeritificate)
933 {
934 std::string endpoint("ldap");
935 CertificateType type = CertificateType::client;
936 std::string installPath(certDir + "/" + keyFile);
937 std::string verifyPath(installPath);
938 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
939 auto objPath = std::string(objectNamePrefix) + '/' +
940 certificateTypeToString(type) + '/' + endpoint;
941 EXPECT_THROW(
942 {
943 try
944 {
945 auto event = sdeventplus::Event::get_default();
946 // Attach the bus to sd_event to service user requests
947 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
948 ManagerInTest manager(bus, event, objPath.c_str(), type,
949 verifyUnit, installPath);
950 MainApp mainApp(&manager);
951 mainApp.install(keyFile);
952 }
953 catch (const InternalFailure& e)
954 {
955 throw;
956 }
957 },
958 InvalidCertificate);
959 EXPECT_FALSE(fs::exists(verifyPath));
960 }
961
962 /** @brief Check if error is thrown when multiple certificates are installed
963 * At present only one certificate per service is allowed
964 */
TEST_F(TestCertificates,TestCertInstallNotAllowed)965 TEST_F(TestCertificates, TestCertInstallNotAllowed)
966 {
967 using NotAllowed =
968 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
969 std::string endpoint("ldap");
970 CertificateType type = CertificateType::client;
971 std::string installPath(certDir + "/" + certificateFile);
972 std::string verifyPath(installPath);
973 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
974 auto objPath = std::string(objectNamePrefix) + '/' +
975 certificateTypeToString(type) + '/' + endpoint;
976 auto event = sdeventplus::Event::get_default();
977 // Attach the bus to sd_event to service user requests
978 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
979 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
980 installPath);
981 MainApp mainApp(&manager);
982 mainApp.install(certificateFile);
983 EXPECT_TRUE(fs::exists(verifyPath));
984 EXPECT_THROW(
985 {
986 try
987 {
988 // install second certificate
989 mainApp.install(certificateFile);
990 }
991 catch (const NotAllowed& e)
992 {
993 throw;
994 }
995 },
996 NotAllowed);
997 }
998
TEST_F(TestCertificates,TestGenerateCSR)999 TEST_F(TestCertificates, TestGenerateCSR)
1000 {
1001 std::string endpoint("https");
1002 std::string unit;
1003 CertificateType type = CertificateType::server;
1004 std::string installPath(certDir + "/" + certificateFile);
1005 std::string verifyPath(installPath);
1006 std::string csrPath(certDir + "/" + CSRFile);
1007 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1008 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1009 std::string challengePassword("Password");
1010 std::string city("HYB");
1011 std::string commonName("abc.com");
1012 std::string contactPerson("Admin");
1013 std::string country("IN");
1014 std::string email("admin@in.ibm.com");
1015 std::string givenName("givenName");
1016 std::string initials("G");
1017 int64_t keyBitLength(2048);
1018 std::string keyCurveId("0");
1019 std::string keyPairAlgorithm("RSA");
1020 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1021 std::string organization("IBM");
1022 std::string organizationalUnit("orgUnit");
1023 std::string state("TS");
1024 std::string surname("surname");
1025 std::string unstructuredName("unstructuredName");
1026 auto objPath = std::string(objectNamePrefix) + '/' +
1027 certificateTypeToString(type) + '/' + endpoint;
1028 auto event = sdeventplus::Event::get_default();
1029 // Attach the bus to sd_event to service user requests
1030 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1031 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1032 std::move(installPath));
1033 Status status = Status::success;
1034 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1035 MainApp mainApp(&manager, &csr);
1036 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1037 contactPerson, country, email, givenName, initials,
1038 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1039 organization, organizationalUnit, state, surname,
1040 unstructuredName);
1041 std::string csrData{};
1042 // generateCSR takes considerable time to create CSR and privateKey Files
1043 EXPECT_FALSE(fs::exists(csrPath));
1044 EXPECT_FALSE(fs::exists(privateKeyPath));
1045 EXPECT_THROW(
1046 {
1047 try
1048 {
1049 csrData = csr.csr();
1050 }
1051 catch (const InternalFailure& e)
1052 {
1053 throw;
1054 }
1055 },
1056 InternalFailure);
1057 // wait for 10 sec to get CSR and privateKey Files generated
1058 sleep(10);
1059 EXPECT_TRUE(fs::exists(csrPath));
1060 EXPECT_TRUE(fs::exists(privateKeyPath));
1061 csrData = csr.csr();
1062 ASSERT_NE("", csrData.c_str());
1063 }
1064
1065 /** @brief Check if ECC key pair is generated when user is not given algorithm
1066 * type. At present RSA and EC key pair algorithm are supported
1067 */
TEST_F(TestCertificates,TestGenerateCSRwithEmptyKeyPairAlgorithm)1068 TEST_F(TestCertificates, TestGenerateCSRwithEmptyKeyPairAlgorithm)
1069 {
1070 std::string endpoint("https");
1071 std::string unit;
1072 CertificateType type = CertificateType::server;
1073 std::string installPath(certDir + "/" + certificateFile);
1074 std::string verifyPath(installPath);
1075 std::string csrPath(certDir + "/" + CSRFile);
1076 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1077 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1078 std::string challengePassword("Password");
1079 std::string city("HYB");
1080 std::string commonName("abc.com");
1081 std::string contactPerson("Admin");
1082 std::string country("IN");
1083 std::string email("admin@in.ibm.com");
1084 std::string givenName("givenName");
1085 std::string initials("G");
1086 int64_t keyBitLength(2048);
1087 std::string keyCurveId("");
1088 std::string keyPairAlgorithm("");
1089 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1090 std::string organization("IBM");
1091 std::string organizationalUnit("orgUnit");
1092 std::string state("TS");
1093 std::string surname("surname");
1094 std::string unstructuredName("unstructuredName");
1095 auto objPath = std::string(objectNamePrefix) + '/' +
1096 certificateTypeToString(type) + '/' + endpoint;
1097 auto event = sdeventplus::Event::get_default();
1098 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1099 std::move(installPath));
1100 Status status;
1101 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1102 MainApp mainApp(&manager, &csr);
1103 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1104 contactPerson, country, email, givenName, initials,
1105 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1106 organization, organizationalUnit, state, surname,
1107 unstructuredName);
1108 sleep(10);
1109 EXPECT_TRUE(fs::exists(csrPath));
1110 EXPECT_TRUE(fs::exists(privateKeyPath));
1111 }
1112
1113 /** @brief Check if error is thrown when giving un supported key pair
1114 * algorithm. At present RSA and EC key pair algorithm are supported
1115 */
TEST_F(TestCertificates,TestGenerateCSRwithUnsupportedKeyPairAlgorithm)1116 TEST_F(TestCertificates, TestGenerateCSRwithUnsupportedKeyPairAlgorithm)
1117 {
1118 std::string endpoint("https");
1119 std::string unit;
1120 CertificateType type = CertificateType::server;
1121 std::string installPath(certDir + "/" + certificateFile);
1122 std::string verifyPath(installPath);
1123 std::string csrPath(certDir + "/" + CSRFile);
1124 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1125 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1126 std::string challengePassword("Password");
1127 std::string city("HYB");
1128 std::string commonName("abc.com");
1129 std::string contactPerson("Admin");
1130 std::string country("IN");
1131 std::string email("admin@in.ibm.com");
1132 std::string givenName("givenName");
1133 std::string initials("G");
1134 int64_t keyBitLength(2048);
1135 std::string keyCurveId("secp521r1");
1136 std::string keyPairAlgorithm("UnSupportedAlgorithm");
1137 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1138 std::string organization("IBM");
1139 std::string organizationalUnit("orgUnit");
1140 std::string state("TS");
1141 std::string surname("surname");
1142 std::string unstructuredName("unstructuredName");
1143 auto objPath = std::string(objectNamePrefix) + '/' +
1144 certificateTypeToString(type) + '/' + endpoint;
1145 auto event = sdeventplus::Event::get_default();
1146 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1147 std::move(installPath));
1148 Status status;
1149 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1150 MainApp mainApp(&manager, &csr);
1151 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1152 contactPerson, country, email, givenName, initials,
1153 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1154 organization, organizationalUnit, state, surname,
1155 unstructuredName);
1156 EXPECT_FALSE(fs::exists(csrPath));
1157 EXPECT_FALSE(fs::exists(privateKeyPath));
1158 }
1159
1160 /** @brief Check if error is thrown when NID_undef is returned for given key
1161 * curve id
1162 */
TEST_F(TestCertificates,TestECKeyGenerationwithNIDundefCase)1163 TEST_F(TestCertificates, TestECKeyGenerationwithNIDundefCase)
1164 {
1165 std::string endpoint("https");
1166 std::string unit;
1167 CertificateType type = CertificateType::server;
1168 std::string installPath(certDir + "/" + certificateFile);
1169 std::string verifyPath(installPath);
1170 std::string csrPath(certDir + "/" + CSRFile);
1171 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1172 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1173 std::string challengePassword("Password");
1174 std::string city("BLR");
1175 std::string commonName("abc.com");
1176 std::string contactPerson("Admin");
1177 std::string country("IN");
1178 std::string email("admin@in.ibm.com");
1179 std::string givenName("givenName");
1180 std::string initials("G");
1181 int64_t keyBitLength(2048);
1182 std::string keyCurveId("DummyCurveName");
1183 std::string keyPairAlgorithm("EC");
1184 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1185 std::string organization("IBM");
1186 std::string organizationalUnit("orgUnit");
1187 std::string state("TS");
1188 std::string surname("surname");
1189 std::string unstructuredName("unstructuredName");
1190 auto objPath = std::string(objectNamePrefix) + '/' +
1191 certificateTypeToString(type) + '/' + endpoint;
1192 auto event = sdeventplus::Event::get_default();
1193 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1194 std::move(installPath));
1195 Status status;
1196 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1197 MainApp mainApp(&manager, &csr);
1198 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1199 contactPerson, country, email, givenName, initials,
1200 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1201 organization, organizationalUnit, state, surname,
1202 unstructuredName);
1203 EXPECT_FALSE(fs::exists(csrPath));
1204 EXPECT_FALSE(fs::exists(privateKeyPath));
1205 }
1206
1207 /** @brief Check default Key Curve Id is used if given curve id is empty
1208 */
TEST_F(TestCertificates,TestECKeyGenerationwithDefaultKeyCurveId)1209 TEST_F(TestCertificates, TestECKeyGenerationwithDefaultKeyCurveId)
1210 {
1211 std::string endpoint("https");
1212 std::string unit;
1213 CertificateType type = CertificateType::server;
1214 std::string installPath(certDir + "/" + certificateFile);
1215 std::string verifyPath(installPath);
1216 std::string csrPath(certDir + "/" + CSRFile);
1217 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1218 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1219 std::string challengePassword("Password");
1220 std::string city("BLR");
1221 std::string commonName("abc.com");
1222 std::string contactPerson("Admin");
1223 std::string country("IN");
1224 std::string email("admin@in.ibm.com");
1225 std::string givenName("givenName");
1226 std::string initials("G");
1227 int64_t keyBitLength(2048);
1228 std::string keyCurveId("");
1229 std::string keyPairAlgorithm("EC");
1230 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1231 std::string organization("IBM");
1232 std::string organizationalUnit("orgUnit");
1233 std::string state("TS");
1234 std::string surname("surname");
1235 std::string unstructuredName("unstructuredName");
1236 auto objPath = std::string(objectNamePrefix) + '/' +
1237 certificateTypeToString(type) + '/' + endpoint;
1238 auto event = sdeventplus::Event::get_default();
1239 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1240 std::move(installPath));
1241 Status status;
1242 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1243 MainApp mainApp(&manager, &csr);
1244 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1245 contactPerson, country, email, givenName, initials,
1246 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1247 organization, organizationalUnit, state, surname,
1248 unstructuredName);
1249 sleep(10);
1250 EXPECT_TRUE(fs::exists(csrPath));
1251 EXPECT_TRUE(fs::exists(privateKeyPath));
1252 }
1253
1254 /** @brief Check if error is not thrown to generate EC key pair
1255 */
TEST_F(TestCertificates,TestECKeyGeneration)1256 TEST_F(TestCertificates, TestECKeyGeneration)
1257 {
1258 std::string endpoint("https");
1259 std::string unit;
1260 CertificateType type = CertificateType::server;
1261 std::string installPath(certDir + "/" + certificateFile);
1262 std::string verifyPath(installPath);
1263 std::string csrPath(certDir + "/" + CSRFile);
1264 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1265 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1266 std::string challengePassword("Password");
1267 std::string city("BLR");
1268 std::string commonName("abc.com");
1269 std::string contactPerson("Admin");
1270 std::string country("IN");
1271 std::string email("admin@in.ibm.com");
1272 std::string givenName("givenName");
1273 std::string initials("G");
1274 int64_t keyBitLength(2048);
1275 std::string keyCurveId("secp521r1");
1276 std::string keyPairAlgorithm("EC");
1277 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1278 std::string organization("IBM");
1279 std::string organizationalUnit("orgUnit");
1280 std::string state("TS");
1281 std::string surname("surname");
1282 std::string unstructuredName("unstructuredName");
1283 auto objPath = std::string(objectNamePrefix) + '/' +
1284 certificateTypeToString(type) + '/' + endpoint;
1285 auto event = sdeventplus::Event::get_default();
1286 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1287 std::move(installPath));
1288 Status status = Status::success;
1289 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1290 MainApp mainApp(&manager, &csr);
1291 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1292 contactPerson, country, email, givenName, initials,
1293 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1294 organization, organizationalUnit, state, surname,
1295 unstructuredName);
1296 std::cout << "CSRPath: " << csrPath << std::endl
1297 << "privateKeyPath: " << privateKeyPath << std::endl;
1298 sleep(10);
1299 EXPECT_TRUE(fs::exists(csrPath));
1300 EXPECT_TRUE(fs::exists(privateKeyPath));
1301 }
1302
1303 /** @brief Check error is thrown if giving unsupported key bit length to
1304 * generate rsa key
1305 */
TEST_F(TestCertificates,TestRSAKeyWithUnsupportedKeyBitLength)1306 TEST_F(TestCertificates, TestRSAKeyWithUnsupportedKeyBitLength)
1307 {
1308 std::string endpoint("https");
1309 std::string unit;
1310 CertificateType type = CertificateType::server;
1311 std::string installPath(certDir + "/" + certificateFile);
1312 std::string verifyPath(installPath);
1313 std::string csrPath(certDir + "/" + CSRFile);
1314 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1315 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1316 std::string challengePassword("Password");
1317 std::string city("BLR");
1318 std::string commonName("abc.com");
1319 std::string contactPerson("Admin");
1320 std::string country("IN");
1321 std::string email("admin@in.ibm.com");
1322 std::string givenName("givenName");
1323 std::string initials("G");
1324 int64_t keyBitLength(4096);
1325 std::string keyCurveId("secp521r1");
1326 std::string keyPairAlgorithm("RSA");
1327 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1328 std::string organization("IBM");
1329 std::string organizationalUnit("orgUnit");
1330 std::string state("TS");
1331 std::string surname("surname");
1332 std::string unstructuredName("unstructuredName");
1333 auto objPath = std::string(objectNamePrefix) + '/' +
1334 certificateTypeToString(type) + '/' + endpoint;
1335 auto event = sdeventplus::Event::get_default();
1336 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1337 std::move(installPath));
1338 Status status;
1339 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1340 MainApp mainApp(&manager, &csr);
1341 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1342 contactPerson, country, email, givenName, initials,
1343 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1344 organization, organizationalUnit, state, surname,
1345 unstructuredName);
1346 EXPECT_FALSE(fs::exists(csrPath));
1347 EXPECT_FALSE(fs::exists(privateKeyPath));
1348 }
1349
1350 /** @brief Check error is thrown if generated rsa key file is not present
1351 */
TEST_F(TestCertificates,TestRSAKeyFileNotPresentCase)1352 TEST_F(TestCertificates, TestRSAKeyFileNotPresentCase)
1353 {
1354 std::string endpoint("https");
1355 std::string unit;
1356 CertificateType type = CertificateType::server;
1357 std::string installPath(certDir + "/" + certificateFile);
1358 std::string verifyPath(installPath);
1359 std::string csrPath(certDir + "/" + CSRFile);
1360 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1361 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1362 std::string challengePassword("Password");
1363 std::string city("BLR");
1364 std::string commonName("abc.com");
1365 std::string contactPerson("Admin");
1366 std::string country("IN");
1367 std::string email("admin@in.ibm.com");
1368 std::string givenName("givenName");
1369 std::string initials("G");
1370 int64_t keyBitLength(2048);
1371 std::string keyCurveId("secp521r1");
1372 std::string keyPairAlgorithm("RSA");
1373 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1374 std::string organization("IBM");
1375 std::string organizationalUnit("orgUnit");
1376 std::string state("TS");
1377 std::string surname("surname");
1378 std::string unstructuredName("unstructuredName");
1379 auto objPath = std::string(objectNamePrefix) + '/' +
1380 certificateTypeToString(type) + '/' + endpoint;
1381 auto event = sdeventplus::Event::get_default();
1382 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1383 std::move(installPath));
1384
1385 // Removing generated RSA key file
1386 fs::remove(rsaPrivateKeyFilePath);
1387
1388 Status status;
1389 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1390 MainApp mainApp(&manager, &csr);
1391 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1392 contactPerson, country, email, givenName, initials,
1393 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1394 organization, organizationalUnit, state, surname,
1395 unstructuredName);
1396 EXPECT_FALSE(fs::exists(csrPath));
1397 EXPECT_FALSE(fs::exists(privateKeyPath));
1398 }
1399
1400 /** @brief Check private key file is created from generated rsa key file is
1401 * `present
1402 */
TEST_F(TestCertificates,TestRSAKeyFromRSAKeyFileIsWrittenIntoPrivateKeyFile)1403 TEST_F(TestCertificates, TestRSAKeyFromRSAKeyFileIsWrittenIntoPrivateKeyFile)
1404 {
1405 std::string endpoint("https");
1406 std::string unit;
1407 CertificateType type = CertificateType::server;
1408 std::string installPath(certDir + "/" + certificateFile);
1409 std::string verifyPath(installPath);
1410 std::string csrPath(certDir + "/" + CSRFile);
1411 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1412 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1413 std::string challengePassword("Password");
1414 std::string city("BLR");
1415 std::string commonName("abc.com");
1416 std::string contactPerson("Admin");
1417 std::string country("IN");
1418 std::string email("admin@in.ibm.com");
1419 std::string givenName("givenName");
1420 std::string initials("G");
1421 int64_t keyBitLength(2048);
1422 std::string keyCurveId("secp521r1");
1423 std::string keyPairAlgorithm("RSA");
1424 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1425 std::string organization("IBM");
1426 std::string organizationalUnit("orgUnit");
1427 std::string state("TS");
1428 std::string surname("surname");
1429 std::string unstructuredName("unstructuredName");
1430 auto objPath = std::string(objectNamePrefix) + '/' +
1431 certificateTypeToString(type) + '/' + endpoint;
1432 auto event = sdeventplus::Event::get_default();
1433 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1434 std::move(installPath));
1435 Status status;
1436 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1437 MainApp mainApp(&manager, &csr);
1438 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1439 contactPerson, country, email, givenName, initials,
1440 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1441 organization, organizationalUnit, state, surname,
1442 unstructuredName);
1443 sleep(10);
1444 EXPECT_TRUE(fs::exists(csrPath));
1445 EXPECT_TRUE(fs::exists(privateKeyPath));
1446 }
1447
1448 /** @brief Check RSA key is generated during application startup*/
TEST_F(TestCertificates,TestGenerateRSAPrivateKeyFile)1449 TEST_F(TestCertificates, TestGenerateRSAPrivateKeyFile)
1450 {
1451 std::string endpoint("https");
1452 CertificateType type = CertificateType::server;
1453 std::string installPath(certDir + "/" + certificateFile);
1454 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1455 auto objPath = std::string(objectNamePrefix) + '/' +
1456 certificateTypeToString(type) + '/' + endpoint;
1457 auto event = sdeventplus::Event::get_default();
1458
1459 EXPECT_FALSE(fs::exists(rsaPrivateKeyFilePath));
1460 Manager manager(bus, event, objPath.c_str(), type, verifyUnit, installPath);
1461 EXPECT_TRUE(fs::exists(rsaPrivateKeyFilePath));
1462 }
1463
1464 /**
1465 * Class to test Authorities List installation and replacement
1466 */
1467 class AuthoritiesListTest : public testing::Test
1468 {
1469 public:
AuthoritiesListTest()1470 AuthoritiesListTest() :
1471 bus(sdbusplus::bus::new_default()),
1472 authoritiesListFolder(
1473 Certificate::generateUniqueFilePath(fs::temp_directory_path()))
1474 {
1475 fs::create_directory(authoritiesListFolder);
1476 createAuthoritiesList(maxNumAuthorityCertificates);
1477 }
~AuthoritiesListTest()1478 ~AuthoritiesListTest() override
1479 {
1480 fs::remove_all(authoritiesListFolder);
1481 }
1482
1483 protected:
1484 // Creates a testing authorities list which consists of |count| root
1485 // certificates
createAuthoritiesList(int count)1486 void createAuthoritiesList(int count)
1487 {
1488 fs::path srcFolder = fs::temp_directory_path();
1489 srcFolder = Certificate::generateUniqueFilePath(srcFolder);
1490 fs::create_directory(srcFolder);
1491 createSingleAuthority(srcFolder, "root_0");
1492 sourceAuthoritiesListFile = srcFolder / "root_0_cert";
1493 for (int i = 1; i < count; ++i)
1494 {
1495 std::string name = "root_" + std::to_string(i);
1496 createSingleAuthority(srcFolder, name);
1497 appendContentFromFile(sourceAuthoritiesListFile,
1498 srcFolder / (name + "_cert"));
1499 }
1500 }
1501
1502 // Creates a single self-signed root certificate in given |path|; the key
1503 // will be |path|/|cn|_key, the cert will be |path|/|cn|_cert, and the cn
1504 // will be "/O=openbmc-project.xyz/C=US/ST=CA/CN=|cn|"
createSingleAuthority(const std::string & path,const std::string & cn)1505 static void createSingleAuthority(const std::string& path,
1506 const std::string& cn)
1507 {
1508 std::string key = fs::path(path) / (cn + "_key");
1509 std::string cert = fs::path(path) / (cn + "_cert");
1510 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 -keyout ";
1511 cmd += key + " -out " + cert + " -nodes --days 365000 ";
1512 cmd += "-subj /O=openbmc-project.xyz/CN=" + cn;
1513 ASSERT_EQ(std::system(cmd.c_str()), 0);
1514 }
1515
1516 // Appends the content of the |from| file to the |to| file.
appendContentFromFile(const std::string & to,const std::string & from)1517 static void appendContentFromFile(const std::string& to,
1518 const std::string& from)
1519 {
1520 ASSERT_NO_THROW({
1521 std::ifstream inputCertFileStream;
1522 std::ofstream outputCertFileStream;
1523 inputCertFileStream.exceptions(std::ifstream::failbit |
1524 std::ifstream::badbit |
1525 std::ifstream::eofbit);
1526 outputCertFileStream.exceptions(std::ofstream::failbit |
1527 std::ofstream::badbit |
1528 std::ofstream::eofbit);
1529 inputCertFileStream.open(from);
1530 outputCertFileStream.open(to, std::ios::app);
1531 outputCertFileStream << inputCertFileStream.rdbuf() << std::flush;
1532 inputCertFileStream.close();
1533 outputCertFileStream.close();
1534 });
1535 }
1536
1537 // Appends the content of the |from| buffer to the |to| file.
setContentFromString(const std::string & to,const std::string & from)1538 static void setContentFromString(const std::string& to,
1539 const std::string& from)
1540 {
1541 ASSERT_NO_THROW({
1542 std::ofstream outputCertFileStream;
1543 outputCertFileStream.exceptions(std::ofstream::failbit |
1544 std::ofstream::badbit |
1545 std::ofstream::eofbit);
1546 outputCertFileStream.open(to, std::ios::out);
1547 outputCertFileStream << from << std::flush;
1548 outputCertFileStream.close();
1549 });
1550 }
1551
1552 // Verifies the effect of InstallAll or ReplaceAll
verifyCertificates(std::vector<std::unique_ptr<Certificate>> & certs)1553 void verifyCertificates(std::vector<std::unique_ptr<Certificate>>& certs)
1554 {
1555 // The trust bundle file has been copied over
1556 EXPECT_FALSE(fs::is_empty(authoritiesListFolder));
1557 EXPECT_TRUE(
1558 compareFiles(authoritiesListFolder / defaultAuthoritiesListFileName,
1559 sourceAuthoritiesListFile));
1560
1561 ASSERT_EQ(certs.size(), maxNumAuthorityCertificates);
1562 // Check attributes and alias
1563 for (size_t i = 0; i < certs.size(); ++i)
1564 {
1565 std::string name = "root_" + std::to_string(i);
1566 EXPECT_EQ(certs[i]->subject(), "O=openbmc-project.xyz,CN=" + name);
1567 EXPECT_EQ(certs[i]->issuer(), "O=openbmc-project.xyz,CN=" + name);
1568 std::string symbolLink =
1569 authoritiesListFolder /
1570 (certs[i]->getCertId().substr(0, 8) + ".0");
1571 ASSERT_TRUE(fs::exists(symbolLink));
1572 compareFileAgainstString(symbolLink, certs[i]->certificateString());
1573 }
1574 }
1575
1576 // Expects that the content of |path| file is |buffer|.
compareFileAgainstString(const std::string & path,const std::string & buffer)1577 static void compareFileAgainstString(const std::string& path,
1578 const std::string& buffer)
1579 {
1580 ASSERT_NO_THROW({
1581 std::ifstream inputCertFileStream;
1582 inputCertFileStream.exceptions(std::ifstream::failbit |
1583 std::ifstream::badbit |
1584 std::ifstream::eofbit);
1585 inputCertFileStream.open(path);
1586 std::stringstream read;
1587 read << inputCertFileStream.rdbuf();
1588 inputCertFileStream.close();
1589 EXPECT_EQ(read.str(), buffer);
1590 });
1591 };
1592
1593 sdbusplus::bus_t bus;
1594 fs::path authoritiesListFolder;
1595 fs::path sourceAuthoritiesListFile;
1596 };
1597
1598 // Tests that the Authority Manager installs all the certificates in an
1599 // authorities list
TEST_F(AuthoritiesListTest,InstallAll)1600 TEST_F(AuthoritiesListTest, InstallAll)
1601 {
1602 std::string endpoint("truststore");
1603 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1604 CertificateType type = CertificateType::authority;
1605
1606 std::string object = std::string(objectNamePrefix) + '/' +
1607 certificateTypeToString(type) + '/' + endpoint;
1608 auto event = sdeventplus::Event::get_default();
1609 // Attach the bus to sd_event to service user requests
1610 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1611 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1612 authoritiesListFolder);
1613 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1614 .WillOnce(Return());
1615 ASSERT_TRUE(manager.getCertificates().empty());
1616
1617 std::vector<sdbusplus::message::object_path> objects =
1618 manager.installAll(sourceAuthoritiesListFile);
1619 for (size_t i = 0; i < manager.getCertificates().size(); ++i)
1620 {
1621 EXPECT_EQ(manager.getCertificates()[i]->getObjectPath(), objects[i]);
1622 }
1623 verifyCertificates(manager.getCertificates());
1624 }
1625
1626 // Tests that the Authority Manager recovers from the authorities list persisted
1627 // in the installation path at boot up
TEST_F(AuthoritiesListTest,RecoverAtBootUp)1628 TEST_F(AuthoritiesListTest, RecoverAtBootUp)
1629 {
1630 std::string endpoint("truststore");
1631 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1632 CertificateType type = CertificateType::authority;
1633
1634 std::string object = std::string(objectNamePrefix) + '/' +
1635 certificateTypeToString(type) + '/' + endpoint;
1636 auto event = sdeventplus::Event::get_default();
1637 // Attach the bus to sd_event to service user requests
1638 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1639
1640 // Copy the trust bundle into the installation path before creating an
1641 // Authority Manager
1642 fs::copy_file(/*from=*/sourceAuthoritiesListFile,
1643 authoritiesListFolder / defaultAuthoritiesListFileName);
1644 // Create some noise as well
1645 fs::copy_file(/*from=*/sourceAuthoritiesListFile,
1646 authoritiesListFolder / "should_be_deleted");
1647
1648 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1649 authoritiesListFolder);
1650
1651 ASSERT_EQ(manager.getCertificates().size(), maxNumAuthorityCertificates);
1652
1653 // Check attributes and alias
1654 std::unordered_set<std::string> expectedFiles = {authoritiesListFolder /
1655 "trust_bundle"};
1656 std::vector<std::unique_ptr<Certificate>>& certs =
1657 manager.getCertificates();
1658 for (size_t i = 0; i < certs.size(); ++i)
1659 {
1660 std::string name = "root_" + std::to_string(i);
1661 EXPECT_EQ(certs[i]->subject(), "O=openbmc-project.xyz,CN=" + name);
1662 EXPECT_EQ(certs[i]->issuer(), "O=openbmc-project.xyz,CN=" + name);
1663 std::string symbolLink = authoritiesListFolder /
1664 (certs[i]->getCertId().substr(0, 8) + ".0");
1665 expectedFiles.insert(symbolLink);
1666 expectedFiles.insert(certs[i]->getCertFilePath());
1667 ASSERT_TRUE(fs::exists(symbolLink));
1668 compareFileAgainstString(symbolLink, certs[i]->certificateString());
1669 }
1670
1671 // Check folder content
1672 for (auto& path : fs::directory_iterator(authoritiesListFolder))
1673 {
1674 EXPECT_NE(path, authoritiesListFolder / "should_be_deleted");
1675 expectedFiles.erase(path.path());
1676 }
1677 EXPECT_TRUE(expectedFiles.empty());
1678 }
1679
TEST_F(AuthoritiesListTest,InstallAndDelete)1680 TEST_F(AuthoritiesListTest, InstallAndDelete)
1681 {
1682 std::string endpoint("truststore");
1683 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1684 CertificateType type = CertificateType::authority;
1685
1686 std::string object = std::string(objectNamePrefix) + '/' +
1687 certificateTypeToString(type) + '/' + endpoint;
1688
1689 auto event = sdeventplus::Event::get_default();
1690 // Attach the bus to sd_event to service user requests
1691 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1692 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1693 authoritiesListFolder);
1694 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1695 .WillOnce(Return())
1696 .WillOnce(Return());
1697 ASSERT_TRUE(manager.getCertificates().empty());
1698 ASSERT_EQ(manager.installAll(sourceAuthoritiesListFile).size(),
1699 maxNumAuthorityCertificates);
1700 manager.deleteAll();
1701 EXPECT_TRUE(manager.getCertificates().empty());
1702 // Check folder content
1703 for (const fs::path& f : fs::directory_iterator(authoritiesListFolder))
1704 {
1705 EXPECT_THAT(f.filename(), testing::AnyOf(".", ".."));
1706 }
1707 }
1708
TEST_F(AuthoritiesListTest,InstallAllWrongManagerType)1709 TEST_F(AuthoritiesListTest, InstallAllWrongManagerType)
1710 {
1711 std::string endpoint("ldap");
1712 CertificateType type = CertificateType::server;
1713
1714 std::string object = std::string(objectNamePrefix) + '/' +
1715 certificateTypeToString(type) + '/' + endpoint;
1716
1717 auto event = sdeventplus::Event::get_default();
1718 // Attach the bus to sd_event to service user requests
1719 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1720 ManagerInTest serverManager(bus, event, object.c_str(), type, "",
1721 authoritiesListFolder);
1722 EXPECT_THROW(serverManager.installAll(sourceAuthoritiesListFile),
1723 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1724
1725 type = CertificateType::client;
1726 object = std::string(objectNamePrefix) + '/' +
1727 certificateTypeToString(type) + '/' + endpoint;
1728 ManagerInTest clientManager(bus, event, object.c_str(), type, "",
1729 authoritiesListFolder);
1730 EXPECT_THROW(clientManager.installAll(sourceAuthoritiesListFile),
1731 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1732 }
1733
TEST_F(AuthoritiesListTest,InstallAllTwice)1734 TEST_F(AuthoritiesListTest, InstallAllTwice)
1735 {
1736 std::string endpoint("truststore");
1737 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1738 CertificateType type = CertificateType::authority;
1739
1740 std::string object = std::string(objectNamePrefix) + '/' +
1741 certificateTypeToString(type) + '/' + endpoint;
1742
1743 auto event = sdeventplus::Event::get_default();
1744 // Attach the bus to sd_event to service user requests
1745 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1746 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1747 authoritiesListFolder);
1748 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1749 .WillOnce(Return());
1750 ASSERT_TRUE(manager.getCertificates().empty());
1751
1752 ASSERT_EQ(manager.installAll(sourceAuthoritiesListFile).size(),
1753 maxNumAuthorityCertificates);
1754 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1755 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1756 }
1757
TEST_F(AuthoritiesListTest,InstallAllMissSourceFile)1758 TEST_F(AuthoritiesListTest, InstallAllMissSourceFile)
1759 {
1760 std::string endpoint("truststore");
1761 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1762 CertificateType type = CertificateType::authority;
1763
1764 std::string object = std::string(objectNamePrefix) + '/' +
1765 certificateTypeToString(type) + '/' + endpoint;
1766
1767 auto event = sdeventplus::Event::get_default();
1768 // Attach the bus to sd_event to service user requests
1769 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1770 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1771 authoritiesListFolder);
1772
1773 EXPECT_THROW(manager.installAll(authoritiesListFolder / "trust_bundle"),
1774 InternalFailure);
1775 }
1776
TEST_F(AuthoritiesListTest,TooManyRootCertificates)1777 TEST_F(AuthoritiesListTest, TooManyRootCertificates)
1778 {
1779 std::string endpoint("truststore");
1780 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1781 CertificateType type = CertificateType::authority;
1782
1783 std::string object = std::string(objectNamePrefix) + '/' +
1784 certificateTypeToString(type) + '/' + endpoint;
1785
1786 auto event = sdeventplus::Event::get_default();
1787 // Attach the bus to sd_event to service user requests
1788 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1789 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1790 authoritiesListFolder);
1791 createAuthoritiesList(maxNumAuthorityCertificates + 1);
1792 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1793 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1794 }
1795
TEST_F(AuthoritiesListTest,CertInWrongFormat)1796 TEST_F(AuthoritiesListTest, CertInWrongFormat)
1797 {
1798 std::string endpoint("truststore");
1799 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1800 CertificateType type = CertificateType::authority;
1801
1802 std::string object = std::string(objectNamePrefix) + '/' +
1803 certificateTypeToString(type) + '/' + endpoint;
1804
1805 auto event = sdeventplus::Event::get_default();
1806 // Attach the bus to sd_event to service user requests
1807 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1808
1809 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1810 authoritiesListFolder);
1811
1812 // Replace the authorities list with non-valid PEM encoded x509 certificate
1813 setContentFromString(sourceAuthoritiesListFile, "blah-blah");
1814 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1815 InvalidCertificate);
1816 setContentFromString(sourceAuthoritiesListFile,
1817 "-----BEGIN CERTIFICATE-----");
1818 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1819 InvalidCertificate);
1820 }
1821
TEST_F(AuthoritiesListTest,ReplaceAll)1822 TEST_F(AuthoritiesListTest, ReplaceAll)
1823 {
1824 std::string endpoint("truststore");
1825 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1826 CertificateType type = CertificateType::authority;
1827
1828 std::string object = std::string(objectNamePrefix) + '/' +
1829 certificateTypeToString(type) + '/' + endpoint;
1830
1831 auto event = sdeventplus::Event::get_default();
1832 // Attach the bus to sd_event to service user requests
1833 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1834 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1835 authoritiesListFolder);
1836 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1837 .WillOnce(Return())
1838 .WillOnce(Return());
1839 manager.installAll(sourceAuthoritiesListFile);
1840
1841 // Replace the current list with a different list
1842 fs::remove_all(sourceAuthoritiesListFile.parent_path());
1843 createAuthoritiesList(maxNumAuthorityCertificates);
1844 std::vector<sdbusplus::message::object_path> objects =
1845 manager.replaceAll(sourceAuthoritiesListFile);
1846
1847 for (size_t i = 0; i < manager.getCertificates().size(); ++i)
1848 {
1849 EXPECT_EQ(manager.getCertificates()[i]->getObjectPath(), objects[i]);
1850 }
1851 verifyCertificates(manager.getCertificates());
1852 }
1853
1854 } // namespace
1855 } // namespace phosphor::certs
1856