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 verifyPath(installPath);
1002     std::string csrPath(certDir + "/" + CSRFile);
1003     std::string privateKeyPath(certDir + "/" + privateKeyFile);
1004     std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1005     std::string challengePassword("Password");
1006     std::string city("HYB");
1007     std::string commonName("abc.com");
1008     std::string contactPerson("Admin");
1009     std::string country("IN");
1010     std::string email("admin@in.ibm.com");
1011     std::string givenName("givenName");
1012     std::string initials("G");
1013     int64_t keyBitLength(2048);
1014     std::string keyCurveId("0");
1015     std::string keyPairAlgorithm("RSA");
1016     std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1017     std::string organization("IBM");
1018     std::string organizationalUnit("orgUnit");
1019     std::string state("TS");
1020     std::string surname("surname");
1021     std::string unstructuredName("unstructuredName");
1022     auto objPath = std::string(objectNamePrefix) + '/' +
1023                    certificateTypeToString(type) + '/' + endpoint;
1024     auto event = sdeventplus::Event::get_default();
1025     // Attach the bus to sd_event to service user requests
1026     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1027     Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1028                     std::move(installPath));
1029     Status status = Status::success;
1030     CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1031     MainApp mainApp(&manager, &csr);
1032     mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1033                         contactPerson, country, email, givenName, initials,
1034                         keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1035                         organization, organizationalUnit, state, surname,
1036                         unstructuredName);
1037     std::string csrData{};
1038     // generateCSR takes considerable time to create CSR and privateKey Files
1039     EXPECT_FALSE(fs::exists(csrPath));
1040     EXPECT_FALSE(fs::exists(privateKeyPath));
1041     EXPECT_THROW(
1042         {
1043             try
1044             {
1045                 csrData = csr.csr();
1046             }
1047             catch (const InternalFailure& e)
1048             {
1049                 throw;
1050             }
1051         },
1052         InternalFailure);
1053     // wait for 10 sec to get CSR and privateKey Files generated
1054     sleep(10);
1055     EXPECT_TRUE(fs::exists(csrPath));
1056     EXPECT_TRUE(fs::exists(privateKeyPath));
1057     csrData = csr.csr();
1058     ASSERT_NE("", csrData.c_str());
1059 }
1060 
1061 /** @brief Check if ECC key pair is generated when user is not given algorithm
1062  * type. At present RSA and EC key pair algorithm are supported
1063  */
TEST_F(TestCertificates,TestGenerateCSRwithEmptyKeyPairAlgorithm)1064 TEST_F(TestCertificates, TestGenerateCSRwithEmptyKeyPairAlgorithm)
1065 {
1066     std::string endpoint("https");
1067     std::string unit;
1068     CertificateType type = CertificateType::server;
1069     std::string installPath(certDir + "/" + certificateFile);
1070     std::string verifyPath(installPath);
1071     std::string csrPath(certDir + "/" + CSRFile);
1072     std::string privateKeyPath(certDir + "/" + privateKeyFile);
1073     std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1074     std::string challengePassword("Password");
1075     std::string city("HYB");
1076     std::string commonName("abc.com");
1077     std::string contactPerson("Admin");
1078     std::string country("IN");
1079     std::string email("admin@in.ibm.com");
1080     std::string givenName("givenName");
1081     std::string initials("G");
1082     int64_t keyBitLength(2048);
1083     std::string keyCurveId("");
1084     std::string keyPairAlgorithm("");
1085     std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1086     std::string organization("IBM");
1087     std::string organizationalUnit("orgUnit");
1088     std::string state("TS");
1089     std::string surname("surname");
1090     std::string unstructuredName("unstructuredName");
1091     auto objPath = std::string(objectNamePrefix) + '/' +
1092                    certificateTypeToString(type) + '/' + endpoint;
1093     auto event = sdeventplus::Event::get_default();
1094     Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1095                     std::move(installPath));
1096     Status status;
1097     CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1098     MainApp mainApp(&manager, &csr);
1099     mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1100                         contactPerson, country, email, givenName, initials,
1101                         keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1102                         organization, organizationalUnit, state, surname,
1103                         unstructuredName);
1104     sleep(10);
1105     EXPECT_TRUE(fs::exists(csrPath));
1106     EXPECT_TRUE(fs::exists(privateKeyPath));
1107 }
1108 
1109 /** @brief Check if error is thrown when giving un supported key pair
1110  * algorithm. At present RSA and EC key pair algorithm are supported
1111  */
TEST_F(TestCertificates,TestGenerateCSRwithUnsupportedKeyPairAlgorithm)1112 TEST_F(TestCertificates, TestGenerateCSRwithUnsupportedKeyPairAlgorithm)
1113 {
1114     std::string endpoint("https");
1115     std::string unit;
1116     CertificateType type = CertificateType::server;
1117     std::string installPath(certDir + "/" + certificateFile);
1118     std::string verifyPath(installPath);
1119     std::string csrPath(certDir + "/" + CSRFile);
1120     std::string privateKeyPath(certDir + "/" + privateKeyFile);
1121     std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1122     std::string challengePassword("Password");
1123     std::string city("HYB");
1124     std::string commonName("abc.com");
1125     std::string contactPerson("Admin");
1126     std::string country("IN");
1127     std::string email("admin@in.ibm.com");
1128     std::string givenName("givenName");
1129     std::string initials("G");
1130     int64_t keyBitLength(2048);
1131     std::string keyCurveId("secp521r1");
1132     std::string keyPairAlgorithm("UnSupportedAlgorithm");
1133     std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1134     std::string organization("IBM");
1135     std::string organizationalUnit("orgUnit");
1136     std::string state("TS");
1137     std::string surname("surname");
1138     std::string unstructuredName("unstructuredName");
1139     auto objPath = std::string(objectNamePrefix) + '/' +
1140                    certificateTypeToString(type) + '/' + endpoint;
1141     auto event = sdeventplus::Event::get_default();
1142     Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1143                     std::move(installPath));
1144     Status status;
1145     CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1146     MainApp mainApp(&manager, &csr);
1147     mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1148                         contactPerson, country, email, givenName, initials,
1149                         keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1150                         organization, organizationalUnit, state, surname,
1151                         unstructuredName);
1152     EXPECT_FALSE(fs::exists(csrPath));
1153     EXPECT_FALSE(fs::exists(privateKeyPath));
1154 }
1155 
1156 /** @brief Check if error is thrown when NID_undef is returned for given key
1157  * curve id
1158  */
TEST_F(TestCertificates,TestECKeyGenerationwithNIDundefCase)1159 TEST_F(TestCertificates, TestECKeyGenerationwithNIDundefCase)
1160 {
1161     std::string endpoint("https");
1162     std::string unit;
1163     CertificateType type = CertificateType::server;
1164     std::string installPath(certDir + "/" + certificateFile);
1165     std::string verifyPath(installPath);
1166     std::string csrPath(certDir + "/" + CSRFile);
1167     std::string privateKeyPath(certDir + "/" + privateKeyFile);
1168     std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1169     std::string challengePassword("Password");
1170     std::string city("BLR");
1171     std::string commonName("abc.com");
1172     std::string contactPerson("Admin");
1173     std::string country("IN");
1174     std::string email("admin@in.ibm.com");
1175     std::string givenName("givenName");
1176     std::string initials("G");
1177     int64_t keyBitLength(2048);
1178     std::string keyCurveId("DummyCurveName");
1179     std::string keyPairAlgorithm("EC");
1180     std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1181     std::string organization("IBM");
1182     std::string organizationalUnit("orgUnit");
1183     std::string state("TS");
1184     std::string surname("surname");
1185     std::string unstructuredName("unstructuredName");
1186     auto objPath = std::string(objectNamePrefix) + '/' +
1187                    certificateTypeToString(type) + '/' + endpoint;
1188     auto event = sdeventplus::Event::get_default();
1189     Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1190                     std::move(installPath));
1191     Status status;
1192     CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1193     MainApp mainApp(&manager, &csr);
1194     mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1195                         contactPerson, country, email, givenName, initials,
1196                         keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1197                         organization, organizationalUnit, state, surname,
1198                         unstructuredName);
1199     EXPECT_FALSE(fs::exists(csrPath));
1200     EXPECT_FALSE(fs::exists(privateKeyPath));
1201 }
1202 
1203 /** @brief Check default Key Curve Id is used if given curve id is empty
1204  */
TEST_F(TestCertificates,TestECKeyGenerationwithDefaultKeyCurveId)1205 TEST_F(TestCertificates, TestECKeyGenerationwithDefaultKeyCurveId)
1206 {
1207     std::string endpoint("https");
1208     std::string unit;
1209     CertificateType type = CertificateType::server;
1210     std::string installPath(certDir + "/" + certificateFile);
1211     std::string verifyPath(installPath);
1212     std::string csrPath(certDir + "/" + CSRFile);
1213     std::string privateKeyPath(certDir + "/" + privateKeyFile);
1214     std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1215     std::string challengePassword("Password");
1216     std::string city("BLR");
1217     std::string commonName("abc.com");
1218     std::string contactPerson("Admin");
1219     std::string country("IN");
1220     std::string email("admin@in.ibm.com");
1221     std::string givenName("givenName");
1222     std::string initials("G");
1223     int64_t keyBitLength(2048);
1224     std::string keyCurveId("");
1225     std::string keyPairAlgorithm("EC");
1226     std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1227     std::string organization("IBM");
1228     std::string organizationalUnit("orgUnit");
1229     std::string state("TS");
1230     std::string surname("surname");
1231     std::string unstructuredName("unstructuredName");
1232     auto objPath = std::string(objectNamePrefix) + '/' +
1233                    certificateTypeToString(type) + '/' + endpoint;
1234     auto event = sdeventplus::Event::get_default();
1235     Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1236                     std::move(installPath));
1237     Status status;
1238     CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1239     MainApp mainApp(&manager, &csr);
1240     mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1241                         contactPerson, country, email, givenName, initials,
1242                         keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1243                         organization, organizationalUnit, state, surname,
1244                         unstructuredName);
1245     sleep(10);
1246     EXPECT_TRUE(fs::exists(csrPath));
1247     EXPECT_TRUE(fs::exists(privateKeyPath));
1248 }
1249 
1250 /** @brief Check if error is not thrown to generate EC key pair
1251  */
TEST_F(TestCertificates,TestECKeyGeneration)1252 TEST_F(TestCertificates, TestECKeyGeneration)
1253 {
1254     std::string endpoint("https");
1255     std::string unit;
1256     CertificateType type = CertificateType::server;
1257     std::string installPath(certDir + "/" + certificateFile);
1258     std::string verifyPath(installPath);
1259     std::string csrPath(certDir + "/" + CSRFile);
1260     std::string privateKeyPath(certDir + "/" + privateKeyFile);
1261     std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1262     std::string challengePassword("Password");
1263     std::string city("BLR");
1264     std::string commonName("abc.com");
1265     std::string contactPerson("Admin");
1266     std::string country("IN");
1267     std::string email("admin@in.ibm.com");
1268     std::string givenName("givenName");
1269     std::string initials("G");
1270     int64_t keyBitLength(2048);
1271     std::string keyCurveId("secp521r1");
1272     std::string keyPairAlgorithm("EC");
1273     std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1274     std::string organization("IBM");
1275     std::string organizationalUnit("orgUnit");
1276     std::string state("TS");
1277     std::string surname("surname");
1278     std::string unstructuredName("unstructuredName");
1279     auto objPath = std::string(objectNamePrefix) + '/' +
1280                    certificateTypeToString(type) + '/' + endpoint;
1281     auto event = sdeventplus::Event::get_default();
1282     Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1283                     std::move(installPath));
1284     Status status = Status::success;
1285     CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1286     MainApp mainApp(&manager, &csr);
1287     mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1288                         contactPerson, country, email, givenName, initials,
1289                         keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1290                         organization, organizationalUnit, state, surname,
1291                         unstructuredName);
1292     std::cout << "CSRPath: " << csrPath << std::endl
1293               << "privateKeyPath: " << privateKeyPath << std::endl;
1294     sleep(10);
1295     EXPECT_TRUE(fs::exists(csrPath));
1296     EXPECT_TRUE(fs::exists(privateKeyPath));
1297 }
1298 
1299 /** @brief Check error is thrown if giving unsupported key bit length to
1300  * generate rsa key
1301  */
TEST_F(TestCertificates,TestRSAKeyWithUnsupportedKeyBitLength)1302 TEST_F(TestCertificates, TestRSAKeyWithUnsupportedKeyBitLength)
1303 {
1304     std::string endpoint("https");
1305     std::string unit;
1306     CertificateType type = CertificateType::server;
1307     std::string installPath(certDir + "/" + certificateFile);
1308     std::string verifyPath(installPath);
1309     std::string csrPath(certDir + "/" + CSRFile);
1310     std::string privateKeyPath(certDir + "/" + privateKeyFile);
1311     std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1312     std::string challengePassword("Password");
1313     std::string city("BLR");
1314     std::string commonName("abc.com");
1315     std::string contactPerson("Admin");
1316     std::string country("IN");
1317     std::string email("admin@in.ibm.com");
1318     std::string givenName("givenName");
1319     std::string initials("G");
1320     int64_t keyBitLength(4096);
1321     std::string keyCurveId("secp521r1");
1322     std::string keyPairAlgorithm("RSA");
1323     std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1324     std::string organization("IBM");
1325     std::string organizationalUnit("orgUnit");
1326     std::string state("TS");
1327     std::string surname("surname");
1328     std::string unstructuredName("unstructuredName");
1329     auto objPath = std::string(objectNamePrefix) + '/' +
1330                    certificateTypeToString(type) + '/' + endpoint;
1331     auto event = sdeventplus::Event::get_default();
1332     Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1333                     std::move(installPath));
1334     Status status;
1335     CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1336     MainApp mainApp(&manager, &csr);
1337     mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1338                         contactPerson, country, email, givenName, initials,
1339                         keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1340                         organization, organizationalUnit, state, surname,
1341                         unstructuredName);
1342     EXPECT_FALSE(fs::exists(csrPath));
1343     EXPECT_FALSE(fs::exists(privateKeyPath));
1344 }
1345 
1346 /** @brief Check error is thrown if generated rsa key file is not present
1347  */
TEST_F(TestCertificates,TestRSAKeyFileNotPresentCase)1348 TEST_F(TestCertificates, TestRSAKeyFileNotPresentCase)
1349 {
1350     std::string endpoint("https");
1351     std::string unit;
1352     CertificateType type = CertificateType::server;
1353     std::string installPath(certDir + "/" + certificateFile);
1354     std::string verifyPath(installPath);
1355     std::string csrPath(certDir + "/" + CSRFile);
1356     std::string privateKeyPath(certDir + "/" + privateKeyFile);
1357     std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1358     std::string challengePassword("Password");
1359     std::string city("BLR");
1360     std::string commonName("abc.com");
1361     std::string contactPerson("Admin");
1362     std::string country("IN");
1363     std::string email("admin@in.ibm.com");
1364     std::string givenName("givenName");
1365     std::string initials("G");
1366     int64_t keyBitLength(2048);
1367     std::string keyCurveId("secp521r1");
1368     std::string keyPairAlgorithm("RSA");
1369     std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1370     std::string organization("IBM");
1371     std::string organizationalUnit("orgUnit");
1372     std::string state("TS");
1373     std::string surname("surname");
1374     std::string unstructuredName("unstructuredName");
1375     auto objPath = std::string(objectNamePrefix) + '/' +
1376                    certificateTypeToString(type) + '/' + endpoint;
1377     auto event = sdeventplus::Event::get_default();
1378     Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1379                     std::move(installPath));
1380 
1381     // Removing generated RSA key file
1382     fs::remove(rsaPrivateKeyFilePath);
1383 
1384     Status status;
1385     CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1386     MainApp mainApp(&manager, &csr);
1387     mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1388                         contactPerson, country, email, givenName, initials,
1389                         keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1390                         organization, organizationalUnit, state, surname,
1391                         unstructuredName);
1392     EXPECT_FALSE(fs::exists(csrPath));
1393     EXPECT_FALSE(fs::exists(privateKeyPath));
1394 }
1395 
1396 /** @brief Check private key file is created from generated rsa key file is
1397  * `present
1398  */
TEST_F(TestCertificates,TestRSAKeyFromRSAKeyFileIsWrittenIntoPrivateKeyFile)1399 TEST_F(TestCertificates, TestRSAKeyFromRSAKeyFileIsWrittenIntoPrivateKeyFile)
1400 {
1401     std::string endpoint("https");
1402     std::string unit;
1403     CertificateType type = CertificateType::server;
1404     std::string installPath(certDir + "/" + certificateFile);
1405     std::string verifyPath(installPath);
1406     std::string csrPath(certDir + "/" + CSRFile);
1407     std::string privateKeyPath(certDir + "/" + privateKeyFile);
1408     std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1409     std::string challengePassword("Password");
1410     std::string city("BLR");
1411     std::string commonName("abc.com");
1412     std::string contactPerson("Admin");
1413     std::string country("IN");
1414     std::string email("admin@in.ibm.com");
1415     std::string givenName("givenName");
1416     std::string initials("G");
1417     int64_t keyBitLength(2048);
1418     std::string keyCurveId("secp521r1");
1419     std::string keyPairAlgorithm("RSA");
1420     std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1421     std::string organization("IBM");
1422     std::string organizationalUnit("orgUnit");
1423     std::string state("TS");
1424     std::string surname("surname");
1425     std::string unstructuredName("unstructuredName");
1426     auto objPath = std::string(objectNamePrefix) + '/' +
1427                    certificateTypeToString(type) + '/' + endpoint;
1428     auto event = sdeventplus::Event::get_default();
1429     Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1430                     std::move(installPath));
1431     Status status;
1432     CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
1433     MainApp mainApp(&manager, &csr);
1434     mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1435                         contactPerson, country, email, givenName, initials,
1436                         keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1437                         organization, organizationalUnit, state, surname,
1438                         unstructuredName);
1439     sleep(10);
1440     EXPECT_TRUE(fs::exists(csrPath));
1441     EXPECT_TRUE(fs::exists(privateKeyPath));
1442 }
1443 
1444 /** @brief Check RSA key is generated during application startup*/
TEST_F(TestCertificates,TestGenerateRSAPrivateKeyFile)1445 TEST_F(TestCertificates, TestGenerateRSAPrivateKeyFile)
1446 {
1447     std::string endpoint("https");
1448     CertificateType type = CertificateType::server;
1449     std::string installPath(certDir + "/" + certificateFile);
1450     std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1451     auto objPath = std::string(objectNamePrefix) + '/' +
1452                    certificateTypeToString(type) + '/' + endpoint;
1453     auto event = sdeventplus::Event::get_default();
1454 
1455     EXPECT_FALSE(fs::exists(rsaPrivateKeyFilePath));
1456     Manager manager(bus, event, objPath.c_str(), type, verifyUnit, installPath);
1457     EXPECT_TRUE(fs::exists(rsaPrivateKeyFilePath));
1458 }
1459 
1460 /**
1461  * Class to test Authorities List installation and replacement
1462  */
1463 class AuthoritiesListTest : public testing::Test
1464 {
1465   public:
AuthoritiesListTest()1466     AuthoritiesListTest() :
1467         bus(sdbusplus::bus::new_default()),
1468         authoritiesListFolder(
1469             Certificate::generateUniqueFilePath(fs::temp_directory_path()))
1470     {
1471         fs::create_directory(authoritiesListFolder);
1472         createAuthoritiesList(maxNumAuthorityCertificates);
1473     }
~AuthoritiesListTest()1474     ~AuthoritiesListTest() override
1475     {
1476         fs::remove_all(authoritiesListFolder);
1477     }
1478 
1479   protected:
1480     // Creates a testing authorities list which consists of |count| root
1481     // certificates
createAuthoritiesList(int count)1482     void createAuthoritiesList(int count)
1483     {
1484         fs::path srcFolder = fs::temp_directory_path();
1485         srcFolder = Certificate::generateUniqueFilePath(srcFolder);
1486         fs::create_directory(srcFolder);
1487         createSingleAuthority(srcFolder, "root_0");
1488         sourceAuthoritiesListFile = srcFolder / "root_0_cert";
1489         for (int i = 1; i < count; ++i)
1490         {
1491             std::string name = "root_" + std::to_string(i);
1492             createSingleAuthority(srcFolder, name);
1493             appendContentFromFile(sourceAuthoritiesListFile,
1494                                   srcFolder / (name + "_cert"));
1495         }
1496     }
1497 
1498     // Creates a single self-signed root certificate in given |path|; the key
1499     // will be |path|/|cn|_key, the cert will be |path|/|cn|_cert, and the cn
1500     // will be "/O=openbmc-project.xyz/C=US/ST=CA/CN=|cn|"
createSingleAuthority(const std::string & path,const std::string & cn)1501     static void createSingleAuthority(const std::string& path,
1502                                       const std::string& cn)
1503     {
1504         std::string key = fs::path(path) / (cn + "_key");
1505         std::string cert = fs::path(path) / (cn + "_cert");
1506         std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 -keyout ";
1507         cmd += key + " -out " + cert + " -nodes --days 365000 ";
1508         cmd += "-subj /O=openbmc-project.xyz/CN=" + cn;
1509         ASSERT_EQ(std::system(cmd.c_str()), 0);
1510     }
1511 
1512     // Appends the content of the |from| file to the |to| file.
appendContentFromFile(const std::string & to,const std::string & from)1513     static void appendContentFromFile(const std::string& to,
1514                                       const std::string& from)
1515     {
1516         ASSERT_NO_THROW({
1517             std::ifstream inputCertFileStream;
1518             std::ofstream outputCertFileStream;
1519             inputCertFileStream.exceptions(
1520                 std::ifstream::failbit | std::ifstream::badbit |
1521                 std::ifstream::eofbit);
1522             outputCertFileStream.exceptions(
1523                 std::ofstream::failbit | std::ofstream::badbit |
1524                 std::ofstream::eofbit);
1525             inputCertFileStream.open(from);
1526             outputCertFileStream.open(to, std::ios::app);
1527             outputCertFileStream << inputCertFileStream.rdbuf() << std::flush;
1528             inputCertFileStream.close();
1529             outputCertFileStream.close();
1530         });
1531     }
1532 
1533     // Appends the content of the |from| buffer to the |to| file.
setContentFromString(const std::string & to,const std::string & from)1534     static void setContentFromString(const std::string& to,
1535                                      const std::string& from)
1536     {
1537         ASSERT_NO_THROW({
1538             std::ofstream outputCertFileStream;
1539             outputCertFileStream.exceptions(
1540                 std::ofstream::failbit | std::ofstream::badbit |
1541                 std::ofstream::eofbit);
1542             outputCertFileStream.open(to, std::ios::out);
1543             outputCertFileStream << from << std::flush;
1544             outputCertFileStream.close();
1545         });
1546     }
1547 
1548     // Verifies the effect of InstallAll or ReplaceAll
verifyCertificates(std::vector<std::unique_ptr<Certificate>> & certs)1549     void verifyCertificates(std::vector<std::unique_ptr<Certificate>>& certs)
1550     {
1551         // The trust bundle file has been copied over
1552         EXPECT_FALSE(fs::is_empty(authoritiesListFolder));
1553         EXPECT_TRUE(
1554             compareFiles(authoritiesListFolder / defaultAuthoritiesListFileName,
1555                          sourceAuthoritiesListFile));
1556 
1557         ASSERT_EQ(certs.size(), maxNumAuthorityCertificates);
1558         // Check attributes and alias
1559         for (size_t i = 0; i < certs.size(); ++i)
1560         {
1561             std::string name = "root_" + std::to_string(i);
1562             EXPECT_EQ(certs[i]->subject(), "O=openbmc-project.xyz,CN=" + name);
1563             EXPECT_EQ(certs[i]->issuer(), "O=openbmc-project.xyz,CN=" + name);
1564             std::string symbolLink =
1565                 authoritiesListFolder /
1566                 (certs[i]->getCertId().substr(0, 8) + ".0");
1567             ASSERT_TRUE(fs::exists(symbolLink));
1568             compareFileAgainstString(symbolLink, certs[i]->certificateString());
1569         }
1570     }
1571 
1572     // Expects that the content of |path| file is |buffer|.
compareFileAgainstString(const std::string & path,const std::string & buffer)1573     static void compareFileAgainstString(const std::string& path,
1574                                          const std::string& buffer)
1575     {
1576         ASSERT_NO_THROW({
1577             std::ifstream inputCertFileStream;
1578             inputCertFileStream.exceptions(
1579                 std::ifstream::failbit | std::ifstream::badbit |
1580                 std::ifstream::eofbit);
1581             inputCertFileStream.open(path);
1582             std::stringstream read;
1583             read << inputCertFileStream.rdbuf();
1584             inputCertFileStream.close();
1585             EXPECT_EQ(read.str(), buffer);
1586         });
1587     };
1588 
1589     sdbusplus::bus_t bus;
1590     fs::path authoritiesListFolder;
1591     fs::path sourceAuthoritiesListFile;
1592 };
1593 
1594 // Tests that the Authority Manager installs all the certificates in an
1595 // authorities list
TEST_F(AuthoritiesListTest,InstallAll)1596 TEST_F(AuthoritiesListTest, InstallAll)
1597 {
1598     std::string endpoint("truststore");
1599     std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1600     CertificateType type = CertificateType::authority;
1601 
1602     std::string object = std::string(objectNamePrefix) + '/' +
1603                          certificateTypeToString(type) + '/' + endpoint;
1604     auto event = sdeventplus::Event::get_default();
1605     // Attach the bus to sd_event to service user requests
1606     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1607     ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1608                           authoritiesListFolder);
1609     EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1610         .WillOnce(Return());
1611     ASSERT_TRUE(manager.getCertificates().empty());
1612 
1613     std::vector<sdbusplus::message::object_path> objects =
1614         manager.installAll(sourceAuthoritiesListFile);
1615     for (size_t i = 0; i < manager.getCertificates().size(); ++i)
1616     {
1617         EXPECT_EQ(manager.getCertificates()[i]->getObjectPath(), objects[i]);
1618     }
1619     verifyCertificates(manager.getCertificates());
1620 }
1621 
1622 // Tests that the Authority Manager recovers from the authorities list persisted
1623 // in the installation path at boot up
TEST_F(AuthoritiesListTest,RecoverAtBootUp)1624 TEST_F(AuthoritiesListTest, RecoverAtBootUp)
1625 {
1626     std::string endpoint("truststore");
1627     std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1628     CertificateType type = CertificateType::authority;
1629 
1630     std::string object = std::string(objectNamePrefix) + '/' +
1631                          certificateTypeToString(type) + '/' + endpoint;
1632     auto event = sdeventplus::Event::get_default();
1633     // Attach the bus to sd_event to service user requests
1634     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1635 
1636     // Copy the trust bundle into the installation path before creating an
1637     // Authority Manager
1638     fs::copy_file(/*from=*/sourceAuthoritiesListFile,
1639                   authoritiesListFolder / defaultAuthoritiesListFileName);
1640     // Create some noise as well
1641     fs::copy_file(/*from=*/sourceAuthoritiesListFile,
1642                   authoritiesListFolder / "should_be_deleted");
1643 
1644     ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1645                           authoritiesListFolder);
1646 
1647     ASSERT_EQ(manager.getCertificates().size(), maxNumAuthorityCertificates);
1648 
1649     // Check attributes and alias
1650     std::unordered_set<std::string> expectedFiles = {
1651         authoritiesListFolder / "trust_bundle"};
1652     std::vector<std::unique_ptr<Certificate>>& certs =
1653         manager.getCertificates();
1654     for (size_t i = 0; i < certs.size(); ++i)
1655     {
1656         std::string name = "root_" + std::to_string(i);
1657         EXPECT_EQ(certs[i]->subject(), "O=openbmc-project.xyz,CN=" + name);
1658         EXPECT_EQ(certs[i]->issuer(), "O=openbmc-project.xyz,CN=" + name);
1659         std::string symbolLink =
1660             authoritiesListFolder / (certs[i]->getCertId().substr(0, 8) + ".0");
1661         expectedFiles.insert(symbolLink);
1662         expectedFiles.insert(certs[i]->getCertFilePath());
1663         ASSERT_TRUE(fs::exists(symbolLink));
1664         compareFileAgainstString(symbolLink, certs[i]->certificateString());
1665     }
1666 
1667     // Check folder content
1668     for (auto& path : fs::directory_iterator(authoritiesListFolder))
1669     {
1670         EXPECT_NE(path, authoritiesListFolder / "should_be_deleted");
1671         expectedFiles.erase(path.path());
1672     }
1673     EXPECT_TRUE(expectedFiles.empty());
1674 }
1675 
TEST_F(AuthoritiesListTest,InstallAndDelete)1676 TEST_F(AuthoritiesListTest, InstallAndDelete)
1677 {
1678     std::string endpoint("truststore");
1679     std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1680     CertificateType type = CertificateType::authority;
1681 
1682     std::string object = std::string(objectNamePrefix) + '/' +
1683                          certificateTypeToString(type) + '/' + endpoint;
1684 
1685     auto event = sdeventplus::Event::get_default();
1686     // Attach the bus to sd_event to service user requests
1687     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1688     ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1689                           authoritiesListFolder);
1690     EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1691         .WillOnce(Return())
1692         .WillOnce(Return());
1693     ASSERT_TRUE(manager.getCertificates().empty());
1694     ASSERT_EQ(manager.installAll(sourceAuthoritiesListFile).size(),
1695               maxNumAuthorityCertificates);
1696     manager.deleteAll();
1697     EXPECT_TRUE(manager.getCertificates().empty());
1698     // Check folder content
1699     for (const fs::path& f : fs::directory_iterator(authoritiesListFolder))
1700     {
1701         EXPECT_THAT(f.filename(), testing::AnyOf(".", ".."));
1702     }
1703 }
1704 
TEST_F(AuthoritiesListTest,InstallAllWrongManagerType)1705 TEST_F(AuthoritiesListTest, InstallAllWrongManagerType)
1706 {
1707     std::string endpoint("ldap");
1708     CertificateType type = CertificateType::server;
1709 
1710     std::string object = std::string(objectNamePrefix) + '/' +
1711                          certificateTypeToString(type) + '/' + endpoint;
1712 
1713     auto event = sdeventplus::Event::get_default();
1714     // Attach the bus to sd_event to service user requests
1715     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1716     ManagerInTest serverManager(bus, event, object.c_str(), type, "",
1717                                 authoritiesListFolder);
1718     EXPECT_THROW(serverManager.installAll(sourceAuthoritiesListFile),
1719                  sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1720 
1721     type = CertificateType::client;
1722     object = std::string(objectNamePrefix) + '/' +
1723              certificateTypeToString(type) + '/' + endpoint;
1724     ManagerInTest clientManager(bus, event, object.c_str(), type, "",
1725                                 authoritiesListFolder);
1726     EXPECT_THROW(clientManager.installAll(sourceAuthoritiesListFile),
1727                  sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1728 }
1729 
TEST_F(AuthoritiesListTest,InstallAllTwice)1730 TEST_F(AuthoritiesListTest, InstallAllTwice)
1731 {
1732     std::string endpoint("truststore");
1733     std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1734     CertificateType type = CertificateType::authority;
1735 
1736     std::string object = std::string(objectNamePrefix) + '/' +
1737                          certificateTypeToString(type) + '/' + endpoint;
1738 
1739     auto event = sdeventplus::Event::get_default();
1740     // Attach the bus to sd_event to service user requests
1741     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1742     ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1743                           authoritiesListFolder);
1744     EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1745         .WillOnce(Return());
1746     ASSERT_TRUE(manager.getCertificates().empty());
1747 
1748     ASSERT_EQ(manager.installAll(sourceAuthoritiesListFile).size(),
1749               maxNumAuthorityCertificates);
1750     EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1751                  sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1752 }
1753 
TEST_F(AuthoritiesListTest,InstallAllMissSourceFile)1754 TEST_F(AuthoritiesListTest, InstallAllMissSourceFile)
1755 {
1756     std::string endpoint("truststore");
1757     std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1758     CertificateType type = CertificateType::authority;
1759 
1760     std::string object = std::string(objectNamePrefix) + '/' +
1761                          certificateTypeToString(type) + '/' + endpoint;
1762 
1763     auto event = sdeventplus::Event::get_default();
1764     // Attach the bus to sd_event to service user requests
1765     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1766     ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1767                           authoritiesListFolder);
1768 
1769     EXPECT_THROW(manager.installAll(authoritiesListFolder / "trust_bundle"),
1770                  InternalFailure);
1771 }
1772 
TEST_F(AuthoritiesListTest,TooManyRootCertificates)1773 TEST_F(AuthoritiesListTest, TooManyRootCertificates)
1774 {
1775     std::string endpoint("truststore");
1776     std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1777     CertificateType type = CertificateType::authority;
1778 
1779     std::string object = std::string(objectNamePrefix) + '/' +
1780                          certificateTypeToString(type) + '/' + endpoint;
1781 
1782     auto event = sdeventplus::Event::get_default();
1783     // Attach the bus to sd_event to service user requests
1784     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1785     ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1786                           authoritiesListFolder);
1787     createAuthoritiesList(maxNumAuthorityCertificates + 1);
1788     EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1789                  sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1790 }
1791 
TEST_F(AuthoritiesListTest,CertInWrongFormat)1792 TEST_F(AuthoritiesListTest, CertInWrongFormat)
1793 {
1794     std::string endpoint("truststore");
1795     std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1796     CertificateType type = CertificateType::authority;
1797 
1798     std::string object = std::string(objectNamePrefix) + '/' +
1799                          certificateTypeToString(type) + '/' + endpoint;
1800 
1801     auto event = sdeventplus::Event::get_default();
1802     // Attach the bus to sd_event to service user requests
1803     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1804 
1805     ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1806                           authoritiesListFolder);
1807 
1808     // Replace the authorities list with non-valid PEM encoded x509 certificate
1809     setContentFromString(sourceAuthoritiesListFile, "blah-blah");
1810     EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1811                  InvalidCertificate);
1812     setContentFromString(sourceAuthoritiesListFile,
1813                          "-----BEGIN CERTIFICATE-----");
1814     EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1815                  InvalidCertificate);
1816 }
1817 
TEST_F(AuthoritiesListTest,ReplaceAll)1818 TEST_F(AuthoritiesListTest, ReplaceAll)
1819 {
1820     std::string endpoint("truststore");
1821     std::string verifyUnit(ManagerInTest::unitToRestartInTest);
1822     CertificateType type = CertificateType::authority;
1823 
1824     std::string object = std::string(objectNamePrefix) + '/' +
1825                          certificateTypeToString(type) + '/' + endpoint;
1826 
1827     auto event = sdeventplus::Event::get_default();
1828     // Attach the bus to sd_event to service user requests
1829     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1830     ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1831                           authoritiesListFolder);
1832     EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1833         .WillOnce(Return())
1834         .WillOnce(Return());
1835     manager.installAll(sourceAuthoritiesListFile);
1836 
1837     // Replace the current list with a different list
1838     fs::remove_all(sourceAuthoritiesListFile.parent_path());
1839     createAuthoritiesList(maxNumAuthorityCertificates);
1840     std::vector<sdbusplus::message::object_path> objects =
1841         manager.replaceAll(sourceAuthoritiesListFile);
1842 
1843     for (size_t i = 0; i < manager.getCertificates().size(); ++i)
1844     {
1845         EXPECT_EQ(manager.getCertificates()[i]->getObjectPath(), objects[i]);
1846     }
1847     verifyCertificates(manager.getCertificates());
1848 }
1849 
1850 } // namespace
1851 } // namespace phosphor::certs
1852