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