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