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