blob: 08a7bb57b7ba90fa4f4c9ad86dfb6ceb06632f57 [file] [log] [blame]
Marri Devender Rao13bf74e2019-03-26 01:52:17 -05001#include "config.h"
2
Marri Devender Rao8841dbd2019-03-04 05:43:55 -06003#include "certificate.hpp"
Marri Devender Rao947258d2018-09-25 10:52:24 -05004#include "certs_manager.hpp"
Nan Zhou014be0b2021-12-28 18:00:14 -08005#include "csr.hpp"
Marri Devender Rao947258d2018-09-25 10:52:24 -05006
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01007#include <openssl/bio.h>
Nan Zhou014be0b2021-12-28 18:00:14 -08008#include <openssl/ossl_typ.h>
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01009#include <openssl/pem.h>
Nan Zhou014be0b2021-12-28 18:00:14 -080010#include <openssl/x509.h>
11#include <systemd/sd-event.h>
12#include <unistd.h>
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +010013
Patrick Williams223e4602023-05-10 07:51:11 -050014#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
Nan Zhou014be0b2021-12-28 18:00:14 -080019#include <cstdint>
20#include <cstdio>
21#include <cstdlib>
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060022#include <filesystem>
Marri Devender Rao947258d2018-09-25 10:52:24 -050023#include <fstream>
Nan Zhou014be0b2021-12-28 18:00:14 -080024#include <iostream>
Marri Devender Rao947258d2018-09-25 10:52:24 -050025#include <iterator>
Nan Zhou014be0b2021-12-28 18:00:14 -080026#include <memory>
27#include <new>
Marri Devender Rao947258d2018-09-25 10:52:24 -050028#include <string>
Nan Zhou6ec13c82021-12-30 11:34:50 -080029#include <unordered_set>
Nan Zhou014be0b2021-12-28 18:00:14 -080030#include <utility>
31#include <vector>
Marri Devender Rao947258d2018-09-25 10:52:24 -050032
Nan Zhou6ec13c82021-12-30 11:34:50 -080033#include <gmock/gmock.h>
Marri Devender Rao947258d2018-09-25 10:52:24 -050034#include <gtest/gtest.h>
Nan Zhoue1289ad2021-12-28 11:02:56 -080035
36namespace phosphor::certs
37{
38namespace
39{
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060040namespace fs = std::filesystem;
Nan Zhoucf06ccd2021-12-28 16:25:45 -080041using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
42using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Nan Zhou6ec13c82021-12-30 11:34:50 -080043using ::testing::Eq;
44using ::testing::Return;
45// Compares two files; returns true only if the two are the same
46bool 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}
Marri Devender Raoe6597c52018-10-01 06:36:55 -050068
Marri Devender Raoddf64862018-10-03 07:11:02 -050069/**
70 * Class to generate certificate file and test verification of certificate file
71 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060072class TestCertificates : public ::testing::Test
Marri Devender Rao947258d2018-09-25 10:52:24 -050073{
74 public:
Patrick Williams223e4602023-05-10 07:51:11 -050075 TestCertificates() : bus(sdbusplus::bus::new_default()) {}
Marri Devender Rao947258d2018-09-25 10:52:24 -050076 void SetUp() override
77 {
78 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
79 auto dirPtr = mkdtemp(dirTemplate);
Nan Zhoucfb58022021-12-28 11:02:26 -080080 if (dirPtr == nullptr)
Marri Devender Rao947258d2018-09-25 10:52:24 -050081 {
82 throw std::bad_alloc();
83 }
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +010084 certDir = std::string(dirPtr) + "/certs";
85 fs::create_directories(certDir);
Kowalski, Kamildb029c92019-07-08 17:09:39 +020086
87 createNewCertificate();
Marri Devender Rao947258d2018-09-25 10:52:24 -050088 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +020089
Marri Devender Rao947258d2018-09-25 10:52:24 -050090 void TearDown() override
91 {
92 fs::remove_all(certDir);
93 fs::remove(certificateFile);
Marri Devender Raof4682712019-03-19 05:00:28 -050094 fs::remove(CSRFile);
95 fs::remove(privateKeyFile);
Nan Zhoucf811c42021-12-02 14:56:17 -080096 fs::remove_all("demoCA");
Marri Devender Rao947258d2018-09-25 10:52:24 -050097 }
98
Kowalski, Kamildb029c92019-07-08 17:09:39 +020099 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 ";
Nan Zhoucf811c42021-12-02 14:56:17 -0800106 cmd += "-keyout cert.pem -out cert.pem -days 365000 -nodes";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200107 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
Nan Zhoucf811c42021-12-02 14:56:17 -0800121 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
Marri Devender Rao947258d2018-09-25 10:52:24 -0500153 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
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100176 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());
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000199 static constexpr auto authCertHashLength = 9;
200 char hashBuf[authCertHashLength];
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100201 sprintf(hashBuf, "%08lx", hash);
202 return std::string(hashBuf);
203 }
204
Marri Devender Rao947258d2018-09-25 10:52:24 -0500205 protected:
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500206 sdbusplus::bus_t bus;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500207 std::string certificateFile, CSRFile, privateKeyFile, rsaPrivateKeyFilePath;
Marri Devender Rao947258d2018-09-25 10:52:24 -0500208
209 std::string certDir;
Ravi Teja887ba5b2024-06-19 04:37:31 -0500210 uint64_t certId = 1;
Marri Devender Rao947258d2018-09-25 10:52:24 -0500211};
212
213class MainApp
214{
215 public:
Marri Devender Raof4682712019-03-19 05:00:28 -0500216 MainApp(phosphor::certs::Manager* manager,
Patrick Williamsa2f68d82024-08-16 15:21:36 -0400217 phosphor::certs::CSR* csr = nullptr) : manager(manager), csr_(csr)
Patrick Williams223e4602023-05-10 07:51:11 -0500218 {}
Marri Devender Rao947258d2018-09-25 10:52:24 -0500219 void install(std::string& path)
220 {
221 manager->install(path);
222 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500223
Patrick Williamsa2f68d82024-08-16 15:21:36 -0400224 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)
Marri Devender Raof4682712019-03-19 05:00:28 -0500233 {
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 }
Patrick Williamse129be32021-04-30 20:35:19 -0500240 std::string csr()
241 {
242 return (csr_->csr());
243 }
Marri Devender Rao947258d2018-09-25 10:52:24 -0500244 phosphor::certs::Manager* manager;
Patrick Williamse129be32021-04-30 20:35:19 -0500245 phosphor::certs::CSR* csr_;
Marri Devender Rao947258d2018-09-25 10:52:24 -0500246};
247
Nan Zhou6ec13c82021-12-30 11:34:50 -0800248class ManagerInTest : public phosphor::certs::Manager
249{
250 public:
251 static constexpr std::string_view unitToRestartInTest =
252 "xyz.openbmc_project.awesome-service";
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500253 ManagerInTest(sdbusplus::bus_t& bus, sdeventplus::Event& event,
Nan Zhou6ec13c82021-12-30 11:34:50 -0800254 const char* path, CertificateType type,
255 const std::string& unit, const std::string& installPath) :
256 Manager(bus, event, path, type, unit, installPath)
Patrick Williams223e4602023-05-10 07:51:11 -0500257 {}
Nan Zhou6ec13c82021-12-30 11:34:50 -0800258
259 MOCK_METHOD(void, reloadOrReset, (const std::string&), (override));
260};
261
Marri Devender Rao947258d2018-09-25 10:52:24 -0500262/** @brief Check if server install routine is invoked for server setup
263 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600264TEST_F(TestCertificates, InvokeServerInstall)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500265{
266 std::string endpoint("https");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000267 CertificateType type = CertificateType::server;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600268 std::string installPath(certDir + "/" + certificateFile);
269 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800270 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800271 auto objPath = std::string(objectNamePrefix) + '/' +
272 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500273 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800276 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
277 installPath);
278 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
279 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500280 MainApp mainApp(&manager);
281 mainApp.install(certificateFile);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500282 EXPECT_TRUE(fs::exists(verifyPath));
283}
284
285/** @brief Check if client install routine is invoked for client setup
286 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600287TEST_F(TestCertificates, InvokeClientInstall)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500288{
289 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000290 CertificateType type = CertificateType::server;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600291 std::string installPath(certDir + "/" + certificateFile);
292 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800293 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800294 auto objPath = std::string(objectNamePrefix) + '/' +
295 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500296 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800299 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
300 installPath);
301 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
302 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500303 MainApp mainApp(&manager);
304 mainApp.install(certificateFile);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500305 EXPECT_TRUE(fs::exists(verifyPath));
306}
307
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200308/** @brief Check if storage install routine is invoked for storage setup
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500309 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600310TEST_F(TestCertificates, InvokeAuthorityInstall)
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500311{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200312 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000313 CertificateType type = CertificateType::authority;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200314 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800315 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800316 auto objPath = std::string(objectNamePrefix) + '/' +
317 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500318 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800321 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
322 verifyDir);
323 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
324 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500325 MainApp mainApp(&manager);
Nan Zhoucf811c42021-12-02 14:56:17 -0800326 // install the default certificate that's valid from today to 100 years
327 // later
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500328 mainApp.install(certificateFile);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200329
330 std::vector<std::unique_ptr<Certificate>>& certs =
331 manager.getCertificates();
332
Nan Zhoucf811c42021-12-02 14:56:17 -0800333 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
Patrick Williamsa2f68d82024-08-16 15:21:36 -0400340 std::string verifyPath =
341 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
Nan Zhoucf811c42021-12-02 14:56:17 -0800342
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 */
353TEST_F(TestCertificates, InvokeAuthorityInstallNeverExpiredRootCert)
354{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200355 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000356 CertificateType type = CertificateType::authority;
Nan Zhoucf811c42021-12-02 14:56:17 -0800357 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800358 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800359 auto objPath = std::string(objectNamePrefix) + '/' +
360 certificateTypeToString(type) + '/' + endpoint;
Nan Zhoucf811c42021-12-02 14:56:17 -0800361 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800364 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
365 certDir);
366 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
367 .WillOnce(Return());
Nan Zhoucf811c42021-12-02 14:56:17 -0800368 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);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200379
Patrick Williamsa2f68d82024-08-16 15:21:36 -0400380 std::string verifyPath =
381 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200382
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
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100391/** @brief Check if in authority mode user can't install the same
392 * certificate twice.
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200393 */
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100394TEST_F(TestCertificates, InvokeInstallSameCertTwice)
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200395{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200396 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000397 CertificateType type = CertificateType::authority;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200398 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800399 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800400 auto objPath = std::string(objectNamePrefix) + '/' +
401 certificateTypeToString(type) + '/' + endpoint;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200402 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800405 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
406 std::move(certDir));
407 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
408 .WillOnce(Return());
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200409 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
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200417 // Check that certificate has been created at installation directory
Patrick Williamsa2f68d82024-08-16 15:21:36 -0400418 std::string verifyPath =
419 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200420 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
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100426 using NotAllowed =
427 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200428 EXPECT_THROW(
429 {
430 try
431 {
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100432 // Try to install the same certificate second time
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200433 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));
Marri Devender Rao947258d2018-09-25 10:52:24 -0500444 EXPECT_TRUE(fs::exists(verifyPath));
445}
446
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100447/** @brief Check if in authority mode user can install a certificate with
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100448 * certain subject hash twice.
449 */
450TEST_F(TestCertificates, InvokeInstallSameSubjectTwice)
451{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200452 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000453 CertificateType type = CertificateType::authority;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100454 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800455 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800456 auto objPath = std::string(objectNamePrefix) + '/' +
457 certificateTypeToString(type) + '/' + endpoint;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100458 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800461 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());
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100466 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
Patrick Williamsa2f68d82024-08-16 15:21:36 -0400475 std::string verifyPath0 =
476 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100477 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
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100486 // Install second certificate
487 mainApp.install(certificateFile);
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100488
489 // Expect there are exactly two certificates in the collection
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100490 EXPECT_EQ(certs.size(), 2);
491
492 // Check that certificate has been created at installation directory
Patrick Williamsa2f68d82024-08-16 15:21:36 -0400493 std::string verifyPath1 =
494 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".1";
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100495 EXPECT_TRUE(fs::exists(verifyPath1));
496
497 // Check that installed cert is identical to input one
498 EXPECT_TRUE(compareFiles(certificateFile, verifyPath1));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100499
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
Nan Zhou718eef32021-12-28 11:03:30 -0800506 * maxNumAuthorityCertificates certificates.
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100507 */
508TEST_F(TestCertificates, InvokeInstallAuthCertLimit)
509{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200510 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000511 CertificateType type = CertificateType::authority;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100512 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800513 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800514 auto objPath = std::string(objectNamePrefix) + '/' +
515 certificateTypeToString(type) + '/' + endpoint;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100516 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800519 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
520 certDir);
521 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
522 .WillRepeatedly(Return());
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100523 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
Nan Zhou718eef32021-12-28 11:03:30 -0800531 for (std::size_t i = 0; i < maxNumAuthorityCertificates; ++i)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100532 {
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
Patrick Williamsa2f68d82024-08-16 15:21:36 -0400543 std::string verifyPath =
544 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100545 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));
Nan Zhou718eef32021-12-28 11:03:30 -0800576 for (size_t i = 0; i < maxNumAuthorityCertificates; ++i)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100577 {
578 EXPECT_TRUE(fs::exists(verifyPaths[i]));
579 }
580}
581
Marri Devender Rao947258d2018-09-25 10:52:24 -0500582/** @brief Compare the installed certificate with the copied certificate
583 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600584TEST_F(TestCertificates, CompareInstalledCertificate)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500585{
586 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000587 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600588 std::string installPath(certDir + "/" + certificateFile);
589 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800590 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800591 auto objPath = std::string(objectNamePrefix) + '/' +
592 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500593 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800596 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
597 installPath);
598 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
599 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500600 MainApp mainApp(&manager);
601 mainApp.install(certificateFile);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500602 EXPECT_TRUE(fs::exists(verifyPath));
603 EXPECT_TRUE(compareFiles(verifyPath, certificateFile));
604}
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500605
606/** @brief Check if install fails if certificate file is not found
607 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600608TEST_F(TestCertificates, TestNoCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500609{
610 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000611 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600612 std::string installPath(certDir + "/" + certificateFile);
613 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800614 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800615 auto objPath = std::string(objectNamePrefix) + '/' +
616 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600617 std::string uploadFile = "nofile.pem";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500618 EXPECT_THROW(
619 {
620 try
621 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500622 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800625 ManagerInTest manager(bus, event, objPath.c_str(), type,
626 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500627 MainApp mainApp(&manager);
628 mainApp.install(uploadFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500629 }
630 catch (const InternalFailure& e)
631 {
632 throw;
633 }
634 },
635 InternalFailure);
636 EXPECT_FALSE(fs::exists(verifyPath));
637}
638
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500639/** @brief Test replacing existing certificate
640 */
641TEST_F(TestCertificates, TestReplaceCertificate)
642{
643 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000644 CertificateType type = CertificateType::server;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500645 std::string installPath(certDir + "/" + certificateFile);
646 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800647 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800648 auto objPath = std::string(objectNamePrefix) + '/' +
649 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500650 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800653 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());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500658 MainApp mainApp(&manager);
659 mainApp.install(certificateFile);
660 EXPECT_TRUE(fs::exists(verifyPath));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200661 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);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500666 EXPECT_TRUE(fs::exists(verifyPath));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200667}
668
669/** @brief Test replacing existing certificate
670 */
671TEST_F(TestCertificates, TestAuthorityReplaceCertificate)
672{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200673 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000674 CertificateType type = CertificateType::authority;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200675 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800676 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800677 auto objPath = std::string(objectNamePrefix) + '/' +
678 certificateTypeToString(type) + '/' + endpoint;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200679 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800682 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
683 certDir);
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000684 constexpr const unsigned int replaceIterations = 10;
Nan Zhou6ec13c82021-12-30 11:34:50 -0800685 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000686 .Times(replaceIterations + 1)
Nan Zhou6ec13c82021-12-30 11:34:50 -0800687 .WillRepeatedly(Return());
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200688 MainApp mainApp(&manager);
689 mainApp.install(certificateFile);
690
691 std::vector<std::unique_ptr<Certificate>>& certs =
692 manager.getCertificates();
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200693
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000694 for (unsigned int i = 0; i < replaceIterations; i++)
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200695 {
696 // Certificate successfully installed
697 EXPECT_FALSE(certs.empty());
698
Patrick Williamsa2f68d82024-08-16 15:21:36 -0400699 std::string verifyPath =
700 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200701
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 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500717}
718
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200719/** @brief Test verifiing if delete function works.
720 */
721TEST_F(TestCertificates, TestStorageDeleteCertificate)
722{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200723 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000724 CertificateType type = CertificateType::authority;
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200725 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800726 std::string verifyUnit((ManagerInTest::unitToRestartInTest));
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800727 auto objPath = std::string(objectNamePrefix) + '/' +
728 certificateTypeToString(type) + '/' + endpoint;
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200729 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800732 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
733 certDir);
734 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
735 .WillRepeatedly(Return());
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200736 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
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500772/** @brief Check if install fails if certificate file is empty
773 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600774TEST_F(TestCertificates, TestEmptyCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500775{
776 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000777 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600778 std::string installPath(certDir + "/" + certificateFile);
779 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800780 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800781 auto objPath = std::string(objectNamePrefix) + '/' +
782 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500783 std::string emptyFile("emptycert.pem");
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500784 std::ofstream ofs;
785 ofs.open(emptyFile, std::ofstream::out);
786 ofs.close();
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500787 EXPECT_THROW(
788 {
789 try
790 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500791 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800794 ManagerInTest manager(bus, event, objPath.c_str(), type,
795 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500796 MainApp mainApp(&manager);
797 mainApp.install(emptyFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500798 }
799 catch (const InvalidCertificate& e)
800 {
801 throw;
802 }
803 },
804 InvalidCertificate);
805 EXPECT_FALSE(fs::exists(verifyPath));
806 fs::remove(emptyFile);
807}
808
Marri Devender Raoddf64862018-10-03 07:11:02 -0500809/** @brief Check if install fails if certificate file is corrupted
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500810 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600811TEST_F(TestCertificates, TestInvalidCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500812{
813 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000814 CertificateType type = CertificateType::client;
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500815
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500816 std::ofstream ofs;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500817 ofs.open(certificateFile, std::ofstream::out);
818 ofs << "-----BEGIN CERTIFICATE-----";
819 ofs << "ADD_SOME_INVALID_DATA_INTO_FILE";
820 ofs << "-----END CERTIFICATE-----";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500821 ofs.close();
822
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600823 std::string installPath(certDir + "/" + certificateFile);
824 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800825 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800826 auto objPath = std::string(objectNamePrefix) + '/' +
827 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500828 EXPECT_THROW(
829 {
830 try
831 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500832 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800835 ManagerInTest manager(bus, event, objPath.c_str(), type,
836 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500837 MainApp mainApp(&manager);
838 mainApp.install(certificateFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500839 }
840 catch (const InvalidCertificate& e)
841 {
842 throw;
843 }
844 },
845 InvalidCertificate);
846 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500847}
Marri Devender Raoddf64862018-10-03 07:11:02 -0500848
849/**
850 * Class to generate private and certificate only file and test verification
851 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600852class TestInvalidCertificate : public ::testing::Test
Marri Devender Raoddf64862018-10-03 07:11:02 -0500853{
854 public:
Patrick Williams223e4602023-05-10 07:51:11 -0500855 TestInvalidCertificate() : bus(sdbusplus::bus::new_default()) {}
Marri Devender Raoddf64862018-10-03 07:11:02 -0500856 void SetUp() override
857 {
858 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
859 auto dirPtr = mkdtemp(dirTemplate);
Nan Zhoucfb58022021-12-28 11:02:26 -0800860 if (dirPtr == nullptr)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500861 {
862 throw std::bad_alloc();
863 }
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100864 certDir = std::string(dirPtr) + "/certs";
865 fs::create_directories(certDir);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500866 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 }
880 void TearDown() override
881 {
882 fs::remove_all(certDir);
883 fs::remove(certificateFile);
884 fs::remove(keyFile);
885 }
886
887 protected:
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500888 sdbusplus::bus_t bus;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500889 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 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600896TEST_F(TestInvalidCertificate, TestMissingPrivateKey)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500897{
898 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000899 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600900 std::string installPath(certDir + "/" + certificateFile);
901 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800902 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800903 auto objPath = std::string(objectNamePrefix) + '/' +
904 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600905 EXPECT_THROW(
906 {
907 try
908 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500909 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800912 ManagerInTest manager(bus, event, objPath.c_str(), type,
913 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500914 MainApp mainApp(&manager);
915 mainApp.install(certificateFile);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600916 }
Marri Devender Raocd30c492019-06-12 01:40:17 -0500917 catch (const InternalFailure& e)
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600918 {
919 throw;
920 }
921 },
Marri Devender Raocd30c492019-06-12 01:40:17 -0500922 InternalFailure);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600923 EXPECT_FALSE(fs::exists(verifyPath));
924}
925
926/** @brief Check install fails if ceritificate is missing in certificate file
927 */
928TEST_F(TestInvalidCertificate, TestMissingCeritificate)
929{
930 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000931 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600932 std::string installPath(certDir + "/" + keyFile);
933 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800934 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800935 auto objPath = std::string(objectNamePrefix) + '/' +
936 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600937 EXPECT_THROW(
938 {
939 try
940 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500941 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800944 ManagerInTest manager(bus, event, objPath.c_str(), type,
945 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500946 MainApp mainApp(&manager);
947 mainApp.install(keyFile);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500948 }
Marri Devender Raocd30c492019-06-12 01:40:17 -0500949 catch (const InternalFailure& e)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500950 {
951 throw;
952 }
953 },
954 InvalidCertificate);
955 EXPECT_FALSE(fs::exists(verifyPath));
956}
957
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600958/** @brief Check if error is thrown when multiple certificates are installed
959 * At present only one certificate per service is allowed
Marri Devender Raoddf64862018-10-03 07:11:02 -0500960 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600961TEST_F(TestCertificates, TestCertInstallNotAllowed)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500962{
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600963 using NotAllowed =
964 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500965 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000966 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600967 std::string installPath(certDir + "/" + certificateFile);
968 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800969 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800970 auto objPath = std::string(objectNamePrefix) + '/' +
971 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -0500972 auto event = sdeventplus::Event::get_default();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500973 // Attach the bus to sd_event to service user requests
974 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800975 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
976 installPath);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500977 MainApp mainApp(&manager);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600978 mainApp.install(certificateFile);
979 EXPECT_TRUE(fs::exists(verifyPath));
Marri Devender Raoddf64862018-10-03 07:11:02 -0500980 EXPECT_THROW(
981 {
982 try
983 {
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600984 // install second certificate
985 mainApp.install(certificateFile);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500986 }
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600987 catch (const NotAllowed& e)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500988 {
989 throw;
990 }
991 },
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600992 NotAllowed);
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500993}
Marri Devender Raof4682712019-03-19 05:00:28 -0500994
995TEST_F(TestCertificates, TestGenerateCSR)
996{
997 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800998 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000999 CertificateType type = CertificateType::server;
Marri Devender Raof4682712019-03-19 05:00:28 -05001000 std::string installPath(certDir + "/" + certificateFile);
1001 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001002 std::string csrPath(certDir + "/" + CSRFile);
Marri Devender Raof4682712019-03-19 05:00:28 -05001003 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1004 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001005 std::string challengePassword("Password");
Marri Devender Raof4682712019-03-19 05:00:28 -05001006 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");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001018 std::string organizationalUnit("orgUnit");
Marri Devender Raof4682712019-03-19 05:00:28 -05001019 std::string state("TS");
1020 std::string surname("surname");
1021 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001022 auto objPath = std::string(objectNamePrefix) + '/' +
1023 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -05001024 auto event = sdeventplus::Event::get_default();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -05001025 // Attach the bus to sd_event to service user requests
1026 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Marri Devender Raof4682712019-03-19 05:00:28 -05001027 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1028 std::move(installPath));
Ravi Teja887ba5b2024-06-19 04:37:31 -05001029 Status status = Status::success;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001030 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Marri Devender Raof4682712019-03-19 05:00:28 -05001031 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);
Ravi Teja887ba5b2024-06-19 04:37:31 -05001037 std::string csrData{};
Marri Devender Raof4682712019-03-19 05:00:28 -05001038 // generateCSR takes considerable time to create CSR and privateKey Files
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001039 EXPECT_FALSE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001040 EXPECT_FALSE(fs::exists(privateKeyPath));
1041 EXPECT_THROW(
1042 {
1043 try
1044 {
Patrick Williamse129be32021-04-30 20:35:19 -05001045 csrData = csr.csr();
Marri Devender Raof4682712019-03-19 05:00:28 -05001046 }
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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001055 EXPECT_TRUE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001056 EXPECT_TRUE(fs::exists(privateKeyPath));
Patrick Williamse129be32021-04-30 20:35:19 -05001057 csrData = csr.csr();
Marri Devender Raof4682712019-03-19 05:00:28 -05001058 ASSERT_NE("", csrData.c_str());
1059}
1060
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001061/** @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 */
1064TEST_F(TestCertificates, TestGenerateCSRwithEmptyKeyPairAlgorithm)
1065{
1066 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001067 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001068 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001069 std::string installPath(certDir + "/" + certificateFile);
1070 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001071 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001072 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001091 auto objPath = std::string(objectNamePrefix) + '/' +
1092 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -05001093 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001097 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Marri Devender Raof4682712019-03-19 05:00:28 -05001098 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001105 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001106 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 */
1112TEST_F(TestCertificates, TestGenerateCSRwithUnsupportedKeyPairAlgorithm)
1113{
1114 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001115 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001116 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001117 std::string installPath(certDir + "/" + certificateFile);
1118 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001119 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001120 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001139 auto objPath = std::string(objectNamePrefix) + '/' +
1140 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001141 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001145 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001146 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001152 EXPECT_FALSE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001153 EXPECT_FALSE(fs::exists(privateKeyPath));
1154}
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001155
1156/** @brief Check if error is thrown when NID_undef is returned for given key
1157 * curve id
1158 */
1159TEST_F(TestCertificates, TestECKeyGenerationwithNIDundefCase)
1160{
1161 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001162 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001163 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001164 std::string installPath(certDir + "/" + certificateFile);
1165 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001166 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001167 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001186 auto objPath = std::string(objectNamePrefix) + '/' +
1187 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001188 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001192 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001193 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001199 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001200 EXPECT_FALSE(fs::exists(privateKeyPath));
1201}
1202
1203/** @brief Check default Key Curve Id is used if given curve id is empty
1204 */
1205TEST_F(TestCertificates, TestECKeyGenerationwithDefaultKeyCurveId)
1206{
1207 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001208 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001209 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001210 std::string installPath(certDir + "/" + certificateFile);
1211 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001212 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001213 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001232 auto objPath = std::string(objectNamePrefix) + '/' +
1233 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001234 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001238 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001239 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001246 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001247 EXPECT_TRUE(fs::exists(privateKeyPath));
1248}
1249
1250/** @brief Check if error is not thrown to generate EC key pair
1251 */
1252TEST_F(TestCertificates, TestECKeyGeneration)
1253{
1254 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001255 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001256 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001257 std::string installPath(certDir + "/" + certificateFile);
1258 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001259 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001260 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001279 auto objPath = std::string(objectNamePrefix) + '/' +
1280 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001281 auto event = sdeventplus::Event::get_default();
1282 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1283 std::move(installPath));
Ravi Teja887ba5b2024-06-19 04:37:31 -05001284 Status status = Status::success;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001285 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001286 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001292 std::cout << "CSRPath: " << csrPath << std::endl
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001293 << "privateKeyPath: " << privateKeyPath << std::endl;
1294 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001295 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001296 EXPECT_TRUE(fs::exists(privateKeyPath));
1297}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001298
Nan Zhoubf3cf752021-12-28 11:02:07 -08001299/** @brief Check error is thrown if giving unsupported key bit length to
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001300 * generate rsa key
1301 */
1302TEST_F(TestCertificates, TestRSAKeyWithUnsupportedKeyBitLength)
1303{
1304 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001305 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001306 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001307 std::string installPath(certDir + "/" + certificateFile);
1308 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001309 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001310 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001329 auto objPath = std::string(objectNamePrefix) + '/' +
1330 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001331 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001335 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001336 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001342 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001343 EXPECT_FALSE(fs::exists(privateKeyPath));
1344}
1345
1346/** @brief Check error is thrown if generated rsa key file is not present
1347 */
1348TEST_F(TestCertificates, TestRSAKeyFileNotPresentCase)
1349{
1350 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001351 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001352 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001353 std::string installPath(certDir + "/" + certificateFile);
1354 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001355 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001356 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001375 auto objPath = std::string(objectNamePrefix) + '/' +
1376 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001377 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001385 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001386 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001392 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001393 EXPECT_FALSE(fs::exists(privateKeyPath));
1394}
1395
1396/** @brief Check private key file is created from generated rsa key file is
1397 * `present
1398 */
1399TEST_F(TestCertificates, TestRSAKeyFromRSAKeyFileIsWrittenIntoPrivateKeyFile)
1400{
1401 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001402 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001403 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001404 std::string installPath(certDir + "/" + certificateFile);
1405 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001406 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001407 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001426 auto objPath = std::string(objectNamePrefix) + '/' +
1427 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001428 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001432 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001433 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001440 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001441 EXPECT_TRUE(fs::exists(privateKeyPath));
1442}
1443
Nan Zhoubf3cf752021-12-28 11:02:07 -08001444/** @brief Check RSA key is generated during application startup*/
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001445TEST_F(TestCertificates, TestGenerateRSAPrivateKeyFile)
1446{
1447 std::string endpoint("https");
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001448 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001449 std::string installPath(certDir + "/" + certificateFile);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001450 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001451 auto objPath = std::string(objectNamePrefix) + '/' +
1452 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001453 auto event = sdeventplus::Event::get_default();
1454
1455 EXPECT_FALSE(fs::exists(rsaPrivateKeyFilePath));
Nan Zhou6ec13c82021-12-30 11:34:50 -08001456 Manager manager(bus, event, objPath.c_str(), type, verifyUnit, installPath);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001457 EXPECT_TRUE(fs::exists(rsaPrivateKeyFilePath));
1458}
Nan Zhou6ec13c82021-12-30 11:34:50 -08001459
1460/**
1461 * Class to test Authorities List installation and replacement
1462 */
1463class AuthoritiesListTest : public testing::Test
1464{
1465 public:
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 }
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
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|"
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.
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;
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001519 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001525 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.
1534 static void setContentFromString(const std::string& to,
1535 const std::string& from)
1536 {
1537 ASSERT_NO_THROW({
1538 std::ofstream outputCertFileStream;
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001539 outputCertFileStream.exceptions(
1540 std::ofstream::failbit | std::ofstream::badbit |
1541 std::ofstream::eofbit);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001542 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
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|.
1573 static void compareFileAgainstString(const std::string& path,
1574 const std::string& buffer)
1575 {
1576 ASSERT_NO_THROW({
1577 std::ifstream inputCertFileStream;
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001578 inputCertFileStream.exceptions(
1579 std::ifstream::failbit | std::ifstream::badbit |
1580 std::ifstream::eofbit);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001581 inputCertFileStream.open(path);
1582 std::stringstream read;
1583 read << inputCertFileStream.rdbuf();
1584 inputCertFileStream.close();
1585 EXPECT_EQ(read.str(), buffer);
1586 });
1587 };
1588
Patrick Williamsb3dbfb32022-07-22 19:26:57 -05001589 sdbusplus::bus_t bus;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001590 fs::path authoritiesListFolder;
1591 fs::path sourceAuthoritiesListFile;
1592};
1593
1594// Tests that the Authority Manager installs all the certificates in an
1595// authorities list
1596TEST_F(AuthoritiesListTest, InstallAll)
1597{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001598 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001599 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001600 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001601
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
1624TEST_F(AuthoritiesListTest, RecoverAtBootUp)
1625{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001626 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001627 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001628 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001629
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
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001650 std::unordered_set<std::string> expectedFiles = {
1651 authoritiesListFolder / "trust_bundle"};
Nan Zhou6ec13c82021-12-30 11:34:50 -08001652 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);
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001659 std::string symbolLink =
1660 authoritiesListFolder / (certs[i]->getCertId().substr(0, 8) + ".0");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001661 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
1676TEST_F(AuthoritiesListTest, InstallAndDelete)
1677{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001678 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001679 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001680 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001681
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
1705TEST_F(AuthoritiesListTest, InstallAllWrongManagerType)
1706{
1707 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001708 CertificateType type = CertificateType::server;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001709
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
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001721 type = CertificateType::client;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001722 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
1730TEST_F(AuthoritiesListTest, InstallAllTwice)
1731{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001732 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001733 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001734 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001735
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);
Nan Zhou56bfa732022-09-16 01:15:29 +00001750 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
Nan Zhou6ec13c82021-12-30 11:34:50 -08001751 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1752}
1753
1754TEST_F(AuthoritiesListTest, InstallAllMissSourceFile)
1755{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001756 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001757 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001758 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001759
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
1773TEST_F(AuthoritiesListTest, TooManyRootCertificates)
1774{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001775 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001776 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001777 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001778
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
1792TEST_F(AuthoritiesListTest, CertInWrongFormat)
1793{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001794 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001795 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001796 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001797
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
1818TEST_F(AuthoritiesListTest, ReplaceAll)
1819{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001820 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001821 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001822 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001823
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
Nan Zhoue1289ad2021-12-28 11:02:56 -08001850} // namespace
1851} // namespace phosphor::certs