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