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