blob: 021c93c1df24071873f97876aa4d1b466d68dcc0 [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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001001 std::string csrPath(certDir + "/" + CSRFile);
Marri Devender Raof4682712019-03-19 05:00:28 -05001002 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1003 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001004 std::string challengePassword("Password");
Marri Devender Raof4682712019-03-19 05:00:28 -05001005 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");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001017 std::string organizationalUnit("orgUnit");
Marri Devender Raof4682712019-03-19 05:00:28 -05001018 std::string state("TS");
1019 std::string surname("surname");
1020 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001021 auto objPath = std::string(objectNamePrefix) + '/' +
1022 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -05001023 auto event = sdeventplus::Event::get_default();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -05001024 // Attach the bus to sd_event to service user requests
1025 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Marri Devender Raof4682712019-03-19 05:00:28 -05001026 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1027 std::move(installPath));
Ravi Teja887ba5b2024-06-19 04:37:31 -05001028 Status status = Status::success;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001029 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Marri Devender Raof4682712019-03-19 05:00:28 -05001030 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);
Ravi Teja887ba5b2024-06-19 04:37:31 -05001036 std::string csrData{};
Marri Devender Raof4682712019-03-19 05:00:28 -05001037 // generateCSR takes considerable time to create CSR and privateKey Files
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001038 EXPECT_FALSE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001039 EXPECT_FALSE(fs::exists(privateKeyPath));
1040 EXPECT_THROW(
1041 {
1042 try
1043 {
Patrick Williamse129be32021-04-30 20:35:19 -05001044 csrData = csr.csr();
Marri Devender Raof4682712019-03-19 05:00:28 -05001045 }
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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001054 EXPECT_TRUE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001055 EXPECT_TRUE(fs::exists(privateKeyPath));
Patrick Williamse129be32021-04-30 20:35:19 -05001056 csrData = csr.csr();
Marri Devender Raof4682712019-03-19 05:00:28 -05001057 ASSERT_NE("", csrData.c_str());
1058}
1059
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001060/** @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 */
1063TEST_F(TestCertificates, TestGenerateCSRwithEmptyKeyPairAlgorithm)
1064{
1065 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001066 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001067 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001068 std::string installPath(certDir + "/" + certificateFile);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001069 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001070 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001089 auto objPath = std::string(objectNamePrefix) + '/' +
1090 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -05001091 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001095 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Marri Devender Raof4682712019-03-19 05:00:28 -05001096 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001103 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001104 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 */
1110TEST_F(TestCertificates, TestGenerateCSRwithUnsupportedKeyPairAlgorithm)
1111{
1112 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001113 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001114 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001115 std::string installPath(certDir + "/" + certificateFile);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001116 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001117 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001136 auto objPath = std::string(objectNamePrefix) + '/' +
1137 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001138 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001142 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001143 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001149 EXPECT_FALSE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001150 EXPECT_FALSE(fs::exists(privateKeyPath));
1151}
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001152
1153/** @brief Check if error is thrown when NID_undef is returned for given key
1154 * curve id
1155 */
1156TEST_F(TestCertificates, TestECKeyGenerationwithNIDundefCase)
1157{
1158 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001159 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001160 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001161 std::string installPath(certDir + "/" + certificateFile);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001162 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001163 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001182 auto objPath = std::string(objectNamePrefix) + '/' +
1183 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001184 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001188 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001189 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001195 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001196 EXPECT_FALSE(fs::exists(privateKeyPath));
1197}
1198
1199/** @brief Check default Key Curve Id is used if given curve id is empty
1200 */
1201TEST_F(TestCertificates, TestECKeyGenerationwithDefaultKeyCurveId)
1202{
1203 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001204 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001205 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001206 std::string installPath(certDir + "/" + certificateFile);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001207 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001208 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001227 auto objPath = std::string(objectNamePrefix) + '/' +
1228 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001229 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001233 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001234 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001241 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001242 EXPECT_TRUE(fs::exists(privateKeyPath));
1243}
1244
1245/** @brief Check if error is not thrown to generate EC key pair
1246 */
1247TEST_F(TestCertificates, TestECKeyGeneration)
1248{
1249 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001250 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001251 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001252 std::string installPath(certDir + "/" + certificateFile);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001253 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001254 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001273 auto objPath = std::string(objectNamePrefix) + '/' +
1274 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001275 auto event = sdeventplus::Event::get_default();
1276 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1277 std::move(installPath));
Ravi Teja887ba5b2024-06-19 04:37:31 -05001278 Status status = Status::success;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001279 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001280 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001286 std::cout << "CSRPath: " << csrPath << std::endl
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001287 << "privateKeyPath: " << privateKeyPath << std::endl;
1288 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001289 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001290 EXPECT_TRUE(fs::exists(privateKeyPath));
1291}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001292
Nan Zhoubf3cf752021-12-28 11:02:07 -08001293/** @brief Check error is thrown if giving unsupported key bit length to
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001294 * generate rsa key
1295 */
1296TEST_F(TestCertificates, TestRSAKeyWithUnsupportedKeyBitLength)
1297{
1298 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001299 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001300 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001301 std::string installPath(certDir + "/" + certificateFile);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001302 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001303 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001322 auto objPath = std::string(objectNamePrefix) + '/' +
1323 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001324 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001328 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001329 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001335 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001336 EXPECT_FALSE(fs::exists(privateKeyPath));
1337}
1338
1339/** @brief Check error is thrown if generated rsa key file is not present
1340 */
1341TEST_F(TestCertificates, TestRSAKeyFileNotPresentCase)
1342{
1343 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001344 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001345 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001346 std::string installPath(certDir + "/" + certificateFile);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001347 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001348 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001367 auto objPath = std::string(objectNamePrefix) + '/' +
1368 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001369 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001377 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001378 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001384 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001385 EXPECT_FALSE(fs::exists(privateKeyPath));
1386}
1387
1388/** @brief Check private key file is created from generated rsa key file is
1389 * `present
1390 */
1391TEST_F(TestCertificates, TestRSAKeyFromRSAKeyFileIsWrittenIntoPrivateKeyFile)
1392{
1393 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001394 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001395 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001396 std::string installPath(certDir + "/" + certificateFile);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001397 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001398 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");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001417 auto objPath = std::string(objectNamePrefix) + '/' +
1418 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001419 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;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001423 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001424 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);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001431 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001432 EXPECT_TRUE(fs::exists(privateKeyPath));
1433}
1434
Nan Zhoubf3cf752021-12-28 11:02:07 -08001435/** @brief Check RSA key is generated during application startup*/
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001436TEST_F(TestCertificates, TestGenerateRSAPrivateKeyFile)
1437{
1438 std::string endpoint("https");
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001439 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001440 std::string installPath(certDir + "/" + certificateFile);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001441 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001442 auto objPath = std::string(objectNamePrefix) + '/' +
1443 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001444 auto event = sdeventplus::Event::get_default();
1445
1446 EXPECT_FALSE(fs::exists(rsaPrivateKeyFilePath));
Nan Zhou6ec13c82021-12-30 11:34:50 -08001447 Manager manager(bus, event, objPath.c_str(), type, verifyUnit, installPath);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001448 EXPECT_TRUE(fs::exists(rsaPrivateKeyFilePath));
1449}
Nan Zhou6ec13c82021-12-30 11:34:50 -08001450
1451/**
1452 * Class to test Authorities List installation and replacement
1453 */
1454class AuthoritiesListTest : public testing::Test
1455{
1456 public:
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 }
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
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|"
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.
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;
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001510 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);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001516 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.
1525 static void setContentFromString(const std::string& to,
1526 const std::string& from)
1527 {
1528 ASSERT_NO_THROW({
1529 std::ofstream outputCertFileStream;
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001530 outputCertFileStream.exceptions(
1531 std::ofstream::failbit | std::ofstream::badbit |
1532 std::ofstream::eofbit);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001533 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
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|.
1564 static void compareFileAgainstString(const std::string& path,
1565 const std::string& buffer)
1566 {
1567 ASSERT_NO_THROW({
1568 std::ifstream inputCertFileStream;
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001569 inputCertFileStream.exceptions(
1570 std::ifstream::failbit | std::ifstream::badbit |
1571 std::ifstream::eofbit);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001572 inputCertFileStream.open(path);
1573 std::stringstream read;
1574 read << inputCertFileStream.rdbuf();
1575 inputCertFileStream.close();
1576 EXPECT_EQ(read.str(), buffer);
1577 });
1578 };
1579
Patrick Williamsb3dbfb32022-07-22 19:26:57 -05001580 sdbusplus::bus_t bus;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001581 fs::path authoritiesListFolder;
1582 fs::path sourceAuthoritiesListFile;
1583};
1584
1585// Tests that the Authority Manager installs all the certificates in an
1586// authorities list
1587TEST_F(AuthoritiesListTest, InstallAll)
1588{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001589 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001590 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001591 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001592
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
1615TEST_F(AuthoritiesListTest, RecoverAtBootUp)
1616{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001617 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001618 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001619 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001620
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
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001641 std::unordered_set<std::string> expectedFiles = {
1642 authoritiesListFolder / "trust_bundle"};
Nan Zhou6ec13c82021-12-30 11:34:50 -08001643 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);
Patrick Williamsa2f68d82024-08-16 15:21:36 -04001650 std::string symbolLink =
1651 authoritiesListFolder / (certs[i]->getCertId().substr(0, 8) + ".0");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001652 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
1667TEST_F(AuthoritiesListTest, InstallAndDelete)
1668{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001669 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001670 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001671 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001672
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
1696TEST_F(AuthoritiesListTest, InstallAllWrongManagerType)
1697{
1698 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001699 CertificateType type = CertificateType::server;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001700
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
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001712 type = CertificateType::client;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001713 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
1721TEST_F(AuthoritiesListTest, InstallAllTwice)
1722{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001723 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001724 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001725 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001726
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);
Nan Zhou56bfa732022-09-16 01:15:29 +00001741 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
Nan Zhou6ec13c82021-12-30 11:34:50 -08001742 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1743}
1744
1745TEST_F(AuthoritiesListTest, InstallAllMissSourceFile)
1746{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001747 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001748 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001749 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001750
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
1764TEST_F(AuthoritiesListTest, TooManyRootCertificates)
1765{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001766 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001767 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001768 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001769
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
1783TEST_F(AuthoritiesListTest, CertInWrongFormat)
1784{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001785 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001786 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001787 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001788
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
1809TEST_F(AuthoritiesListTest, ReplaceAll)
1810{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001811 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001812 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001813 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001814
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
Nan Zhoue1289ad2021-12-28 11:02:56 -08001841} // namespace
1842} // namespace phosphor::certs