blob: 6d5149e98e4ae6e9287bd695ab2e0e22f735e462 [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;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200210 uint64_t certId;
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,
217 phosphor::certs::CSR* csr = nullptr) :
218 manager(manager),
Patrick Williamse129be32021-04-30 20:35:19 -0500219 csr_(csr)
Patrick Williams223e4602023-05-10 07:51:11 -0500220 {}
Marri Devender Rao947258d2018-09-25 10:52:24 -0500221 void install(std::string& path)
222 {
223 manager->install(path);
224 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500225
226 std::string generateCSR(std::vector<std::string> alternativeNames,
227 std::string challengePassword, std::string city,
228 std::string commonName, std::string contactPerson,
229 std::string country, std::string email,
230 std::string givenName, std::string initials,
231 int64_t keyBitLength, std::string keyCurveId,
232 std::string keyPairAlgorithm,
233 std::vector<std::string> keyUsage,
234 std::string organization,
235 std::string organizationalUnit, std::string state,
236 std::string surname, std::string unstructuredName)
237 {
238 return (manager->generateCSR(
239 alternativeNames, challengePassword, city, commonName,
240 contactPerson, country, email, givenName, initials, keyBitLength,
241 keyCurveId, keyPairAlgorithm, keyUsage, organization,
242 organizationalUnit, state, surname, unstructuredName));
243 }
Patrick Williamse129be32021-04-30 20:35:19 -0500244 std::string csr()
245 {
246 return (csr_->csr());
247 }
Marri Devender Rao947258d2018-09-25 10:52:24 -0500248 phosphor::certs::Manager* manager;
Patrick Williamse129be32021-04-30 20:35:19 -0500249 phosphor::certs::CSR* csr_;
Marri Devender Rao947258d2018-09-25 10:52:24 -0500250};
251
Nan Zhou6ec13c82021-12-30 11:34:50 -0800252class ManagerInTest : public phosphor::certs::Manager
253{
254 public:
255 static constexpr std::string_view unitToRestartInTest =
256 "xyz.openbmc_project.awesome-service";
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500257 ManagerInTest(sdbusplus::bus_t& bus, sdeventplus::Event& event,
Nan Zhou6ec13c82021-12-30 11:34:50 -0800258 const char* path, CertificateType type,
259 const std::string& unit, const std::string& installPath) :
260 Manager(bus, event, path, type, unit, installPath)
Patrick Williams223e4602023-05-10 07:51:11 -0500261 {}
Nan Zhou6ec13c82021-12-30 11:34:50 -0800262
263 MOCK_METHOD(void, reloadOrReset, (const std::string&), (override));
264};
265
Marri Devender Rao947258d2018-09-25 10:52:24 -0500266/** @brief Check if server install routine is invoked for server setup
267 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600268TEST_F(TestCertificates, InvokeServerInstall)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500269{
270 std::string endpoint("https");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000271 CertificateType type = CertificateType::server;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600272 std::string installPath(certDir + "/" + certificateFile);
273 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800274 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800275 auto objPath = std::string(objectNamePrefix) + '/' +
276 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500277 auto event = sdeventplus::Event::get_default();
278 // Attach the bus to sd_event to service user requests
279 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800280 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
281 installPath);
282 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
283 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500284 MainApp mainApp(&manager);
285 mainApp.install(certificateFile);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500286 EXPECT_TRUE(fs::exists(verifyPath));
287}
288
289/** @brief Check if client install routine is invoked for client setup
290 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600291TEST_F(TestCertificates, InvokeClientInstall)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500292{
293 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000294 CertificateType type = CertificateType::server;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600295 std::string installPath(certDir + "/" + certificateFile);
296 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800297 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800298 auto objPath = std::string(objectNamePrefix) + '/' +
299 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500300 auto event = sdeventplus::Event::get_default();
301 // Attach the bus to sd_event to service user requests
302 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800303 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
304 installPath);
305 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
306 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500307 MainApp mainApp(&manager);
308 mainApp.install(certificateFile);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500309 EXPECT_TRUE(fs::exists(verifyPath));
310}
311
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200312/** @brief Check if storage install routine is invoked for storage setup
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500313 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600314TEST_F(TestCertificates, InvokeAuthorityInstall)
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500315{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200316 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000317 CertificateType type = CertificateType::authority;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200318 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800319 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800320 auto objPath = std::string(objectNamePrefix) + '/' +
321 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500322 auto event = sdeventplus::Event::get_default();
323 // Attach the bus to sd_event to service user requests
324 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800325 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
326 verifyDir);
327 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
328 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500329 MainApp mainApp(&manager);
Nan Zhoucf811c42021-12-02 14:56:17 -0800330 // install the default certificate that's valid from today to 100 years
331 // later
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500332 mainApp.install(certificateFile);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200333
334 std::vector<std::unique_ptr<Certificate>>& certs =
335 manager.getCertificates();
336
Nan Zhoucf811c42021-12-02 14:56:17 -0800337 ASSERT_EQ(certs.size(), 1);
338 // check some attributes as well
339 EXPECT_EQ(certs.front()->validNotAfter() - certs.front()->validNotBefore(),
340 365000ULL * 24 * 3600);
341 EXPECT_EQ(certs.front()->subject(), "O=openbmc-project.xyz,CN=localhost");
342 EXPECT_EQ(certs.front()->issuer(), "O=openbmc-project.xyz,CN=localhost");
343
Patrick Williams223e4602023-05-10 07:51:11 -0500344 std::string verifyPath = verifyDir + "/" +
345 getCertSubjectNameHash(certificateFile) + ".0";
Nan Zhoucf811c42021-12-02 14:56:17 -0800346
347 // Check that certificate has been created at installation directory
348 EXPECT_FALSE(fs::is_empty(verifyDir));
349 EXPECT_TRUE(fs::exists(verifyPath));
350
351 // Check that installed cert is identical to input one
352 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
353}
354
355/** @brief Check if storage install routine is invoked for storage setup
356 */
357TEST_F(TestCertificates, InvokeAuthorityInstallNeverExpiredRootCert)
358{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200359 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000360 CertificateType type = CertificateType::authority;
Nan Zhoucf811c42021-12-02 14:56:17 -0800361 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800362 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800363 auto objPath = std::string(objectNamePrefix) + '/' +
364 certificateTypeToString(type) + '/' + endpoint;
Nan Zhoucf811c42021-12-02 14:56:17 -0800365 auto event = sdeventplus::Event::get_default();
366 // Attach the bus to sd_event to service user requests
367 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800368 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
369 certDir);
370 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
371 .WillOnce(Return());
Nan Zhoucf811c42021-12-02 14:56:17 -0800372 MainApp mainApp(&manager);
373
374 // install the certificate that's valid from the Unix Epoch to Dec 31, 9999
375 createNeverExpiredRootCertificate();
376 mainApp.install(certificateFile);
377
378 std::vector<std::unique_ptr<Certificate>>& certs =
379 manager.getCertificates();
380
381 EXPECT_EQ(certs.front()->validNotBefore(), 0);
382 EXPECT_EQ(certs.front()->validNotAfter(), 253402300799ULL);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200383
Patrick Williams223e4602023-05-10 07:51:11 -0500384 std::string verifyPath = verifyDir + "/" +
385 getCertSubjectNameHash(certificateFile) + ".0";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200386
387 // Check that certificate has been created at installation directory
388 EXPECT_FALSE(fs::is_empty(verifyDir));
389 EXPECT_TRUE(fs::exists(verifyPath));
390
391 // Check that installed cert is identical to input one
392 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
393}
394
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100395/** @brief Check if in authority mode user can't install the same
396 * certificate twice.
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200397 */
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100398TEST_F(TestCertificates, InvokeInstallSameCertTwice)
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200399{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200400 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000401 CertificateType type = CertificateType::authority;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200402 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800403 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800404 auto objPath = std::string(objectNamePrefix) + '/' +
405 certificateTypeToString(type) + '/' + endpoint;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200406 auto event = sdeventplus::Event::get_default();
407 // Attach the bus to sd_event to service user requests
408 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800409 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
410 std::move(certDir));
411 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
412 .WillOnce(Return());
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200413 MainApp mainApp(&manager);
414 mainApp.install(certificateFile);
415
416 std::vector<std::unique_ptr<Certificate>>& certs =
417 manager.getCertificates();
418
419 EXPECT_FALSE(certs.empty());
420
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200421 // Check that certificate has been created at installation directory
Patrick Williams223e4602023-05-10 07:51:11 -0500422 std::string verifyPath = verifyDir + "/" +
423 getCertSubjectNameHash(certificateFile) + ".0";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200424 EXPECT_FALSE(fs::is_empty(verifyDir));
425 EXPECT_TRUE(fs::exists(verifyPath));
426
427 // Check that installed cert is identical to input one
428 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
429
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100430 using NotAllowed =
431 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200432 EXPECT_THROW(
433 {
434 try
435 {
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100436 // Try to install the same certificate second time
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200437 mainApp.install(certificateFile);
438 }
439 catch (const NotAllowed& e)
440 {
441 throw;
442 }
443 },
444 NotAllowed);
445
446 // Check that the original certificate has been not removed
447 EXPECT_FALSE(fs::is_empty(verifyDir));
Marri Devender Rao947258d2018-09-25 10:52:24 -0500448 EXPECT_TRUE(fs::exists(verifyPath));
449}
450
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100451/** @brief Check if in authority mode user can install a certificate with
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100452 * certain subject hash twice.
453 */
454TEST_F(TestCertificates, InvokeInstallSameSubjectTwice)
455{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200456 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000457 CertificateType type = CertificateType::authority;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100458 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800459 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800460 auto objPath = std::string(objectNamePrefix) + '/' +
461 certificateTypeToString(type) + '/' + endpoint;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100462 auto event = sdeventplus::Event::get_default();
463 // Attach the bus to sd_event to service user requests
464 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800465 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
466 certDir);
467 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
468 .WillOnce(Return())
469 .WillOnce(Return());
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100470 MainApp mainApp(&manager);
471 mainApp.install(certificateFile);
472
473 std::vector<std::unique_ptr<Certificate>>& certs =
474 manager.getCertificates();
475
476 EXPECT_FALSE(certs.empty());
477
478 // Check that certificate has been created at installation directory
Patrick Williams223e4602023-05-10 07:51:11 -0500479 std::string verifyPath0 = verifyDir + "/" +
480 getCertSubjectNameHash(certificateFile) + ".0";
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100481 EXPECT_FALSE(fs::is_empty(verifyDir));
482 EXPECT_TRUE(fs::exists(verifyPath0));
483
484 // Check that installed cert is identical to input one
485 EXPECT_TRUE(compareFiles(certificateFile, verifyPath0));
486
487 // Prepare second certificate with the same subject
488 createNewCertificate();
489
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100490 // Install second certificate
491 mainApp.install(certificateFile);
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100492
493 // Expect there are exactly two certificates in the collection
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100494 EXPECT_EQ(certs.size(), 2);
495
496 // Check that certificate has been created at installation directory
Patrick Williams223e4602023-05-10 07:51:11 -0500497 std::string verifyPath1 = verifyDir + "/" +
498 getCertSubjectNameHash(certificateFile) + ".1";
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100499 EXPECT_TRUE(fs::exists(verifyPath1));
500
501 // Check that installed cert is identical to input one
502 EXPECT_TRUE(compareFiles(certificateFile, verifyPath1));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100503
504 // Check that the original/first certificate has been not removed
505 EXPECT_FALSE(fs::is_empty(verifyDir));
506 EXPECT_TRUE(fs::exists(verifyPath0));
507}
508
509/** @brief Check if in authority mode user can't install more than
Nan Zhou718eef32021-12-28 11:03:30 -0800510 * maxNumAuthorityCertificates certificates.
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100511 */
512TEST_F(TestCertificates, InvokeInstallAuthCertLimit)
513{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200514 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000515 CertificateType type = CertificateType::authority;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100516 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800517 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800518 auto objPath = std::string(objectNamePrefix) + '/' +
519 certificateTypeToString(type) + '/' + endpoint;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100520 auto event = sdeventplus::Event::get_default();
521 // Attach the bus to sd_event to service user requests
522 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800523 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
524 certDir);
525 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
526 .WillRepeatedly(Return());
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100527 MainApp mainApp(&manager);
528
529 std::vector<std::unique_ptr<Certificate>>& certs =
530 manager.getCertificates();
531
532 std::vector<std::string> verifyPaths;
533
534 // Prepare maximum number of ceritificates
Nan Zhou718eef32021-12-28 11:03:30 -0800535 for (std::size_t i = 0; i < maxNumAuthorityCertificates; ++i)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100536 {
537 // Prepare new certificatate
538 createNewCertificate(true);
539
540 // Install ceritificate
541 mainApp.install(certificateFile);
542
543 // Check number of certificates in the collection
544 EXPECT_EQ(certs.size(), i + 1);
545
546 // Check that certificate has been created at installation directory
Patrick Williams223e4602023-05-10 07:51:11 -0500547 std::string verifyPath = verifyDir + "/" +
548 getCertSubjectNameHash(certificateFile) + ".0";
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100549 EXPECT_FALSE(fs::is_empty(verifyDir));
550 EXPECT_TRUE(fs::exists(verifyPath));
551
552 // Check that installed cert is identical to input one
553 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
554
555 // Save current certificate file for later check
556 verifyPaths.push_back(verifyPath);
557 }
558
559 // Prepare new certificatate
560 createNewCertificate(true);
561
562 using NotAllowed =
563 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
564 EXPECT_THROW(
565 {
566 try
567 {
568 // Try to install one more certificate
569 mainApp.install(certificateFile);
570 }
571 catch (const NotAllowed& e)
572 {
573 throw;
574 }
575 },
576 NotAllowed);
577
578 // Check that the original certificate has been not removed
579 EXPECT_FALSE(fs::is_empty(verifyDir));
Nan Zhou718eef32021-12-28 11:03:30 -0800580 for (size_t i = 0; i < maxNumAuthorityCertificates; ++i)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100581 {
582 EXPECT_TRUE(fs::exists(verifyPaths[i]));
583 }
584}
585
Marri Devender Rao947258d2018-09-25 10:52:24 -0500586/** @brief Compare the installed certificate with the copied certificate
587 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600588TEST_F(TestCertificates, CompareInstalledCertificate)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500589{
590 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000591 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600592 std::string installPath(certDir + "/" + certificateFile);
593 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800594 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800595 auto objPath = std::string(objectNamePrefix) + '/' +
596 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500597 auto event = sdeventplus::Event::get_default();
598 // Attach the bus to sd_event to service user requests
599 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800600 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
601 installPath);
602 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
603 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500604 MainApp mainApp(&manager);
605 mainApp.install(certificateFile);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500606 EXPECT_TRUE(fs::exists(verifyPath));
607 EXPECT_TRUE(compareFiles(verifyPath, certificateFile));
608}
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500609
610/** @brief Check if install fails if certificate file is not found
611 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600612TEST_F(TestCertificates, TestNoCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500613{
614 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000615 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600616 std::string installPath(certDir + "/" + certificateFile);
617 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800618 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800619 auto objPath = std::string(objectNamePrefix) + '/' +
620 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600621 std::string uploadFile = "nofile.pem";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500622 EXPECT_THROW(
623 {
624 try
625 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500626 auto event = sdeventplus::Event::get_default();
627 // Attach the bus to sd_event to service user requests
628 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800629 ManagerInTest manager(bus, event, objPath.c_str(), type,
630 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500631 MainApp mainApp(&manager);
632 mainApp.install(uploadFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500633 }
634 catch (const InternalFailure& e)
635 {
636 throw;
637 }
638 },
639 InternalFailure);
640 EXPECT_FALSE(fs::exists(verifyPath));
641}
642
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500643/** @brief Test replacing existing certificate
644 */
645TEST_F(TestCertificates, TestReplaceCertificate)
646{
647 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000648 CertificateType type = CertificateType::server;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500649 std::string installPath(certDir + "/" + certificateFile);
650 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800651 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800652 auto objPath = std::string(objectNamePrefix) + '/' +
653 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500654 auto event = sdeventplus::Event::get_default();
655 // Attach the bus to sd_event to service user requests
656 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800657 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
658 std::move(installPath));
659 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
660 .WillOnce(Return())
661 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500662 MainApp mainApp(&manager);
663 mainApp.install(certificateFile);
664 EXPECT_TRUE(fs::exists(verifyPath));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200665 std::vector<std::unique_ptr<Certificate>>& certs =
666 manager.getCertificates();
667 EXPECT_FALSE(certs.empty());
668 EXPECT_NE(certs[0], nullptr);
669 certs[0]->replace(certificateFile);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500670 EXPECT_TRUE(fs::exists(verifyPath));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200671}
672
673/** @brief Test replacing existing certificate
674 */
675TEST_F(TestCertificates, TestAuthorityReplaceCertificate)
676{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200677 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000678 CertificateType type = CertificateType::authority;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200679 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800680 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800681 auto objPath = std::string(objectNamePrefix) + '/' +
682 certificateTypeToString(type) + '/' + endpoint;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200683 auto event = sdeventplus::Event::get_default();
684 // Attach the bus to sd_event to service user requests
685 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800686 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
687 certDir);
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000688 constexpr const unsigned int replaceIterations = 10;
Nan Zhou6ec13c82021-12-30 11:34:50 -0800689 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000690 .Times(replaceIterations + 1)
Nan Zhou6ec13c82021-12-30 11:34:50 -0800691 .WillRepeatedly(Return());
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200692 MainApp mainApp(&manager);
693 mainApp.install(certificateFile);
694
695 std::vector<std::unique_ptr<Certificate>>& certs =
696 manager.getCertificates();
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200697
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000698 for (unsigned int i = 0; i < replaceIterations; i++)
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200699 {
700 // Certificate successfully installed
701 EXPECT_FALSE(certs.empty());
702
Patrick Williams223e4602023-05-10 07:51:11 -0500703 std::string verifyPath = verifyDir + "/" +
704 getCertSubjectNameHash(certificateFile) + ".0";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200705
706 // Check that certificate has been created at installation directory
707 EXPECT_FALSE(fs::is_empty(verifyDir));
708 EXPECT_TRUE(fs::exists(verifyPath));
709
710 // Check that installed cert is identical to input one
711 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
712
713 // Create new certificate
714 createNewCertificate(true);
715
716 certs[0]->replace(certificateFile);
717
718 // Verify that old certificate has been removed
719 EXPECT_FALSE(fs::exists(verifyPath));
720 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500721}
722
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200723/** @brief Test verifiing if delete function works.
724 */
725TEST_F(TestCertificates, TestStorageDeleteCertificate)
726{
Michal Orzel2e8fa882023-07-27 13:14:56 +0200727 std::string endpoint("truststore");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000728 CertificateType type = CertificateType::authority;
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200729 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800730 std::string verifyUnit((ManagerInTest::unitToRestartInTest));
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800731 auto objPath = std::string(objectNamePrefix) + '/' +
732 certificateTypeToString(type) + '/' + endpoint;
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200733 auto event = sdeventplus::Event::get_default();
734 // Attach the bus to sd_event to service user requests
735 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800736 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
737 certDir);
738 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
739 .WillRepeatedly(Return());
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200740 MainApp mainApp(&manager);
741
742 // Check if certificate placeholder dir is empty
743 EXPECT_TRUE(fs::is_empty(verifyDir));
744 mainApp.install(certificateFile);
745
746 // Create new certificate
747 createNewCertificate(true);
748 mainApp.install(certificateFile);
749
750 createNewCertificate(true);
751 mainApp.install(certificateFile);
752
753 std::vector<std::unique_ptr<Certificate>>& certs =
754 manager.getCertificates();
755
756 // All 3 certificates successfully installed and added to manager
757 EXPECT_EQ(certs.size(), 3);
758
759 // Check if certificate placeholder is not empty, there should be 3
760 // certificates
761 EXPECT_FALSE(fs::is_empty(verifyDir));
762
763 certs[0]->delete_();
764 EXPECT_EQ(certs.size(), 2);
765
766 certs[0]->delete_();
767 EXPECT_EQ(certs.size(), 1);
768
769 certs[0]->delete_();
770 EXPECT_EQ(certs.size(), 0);
771
772 // Check if certificate placeholder is empty.
773 EXPECT_TRUE(fs::is_empty(verifyDir));
774}
775
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500776/** @brief Check if install fails if certificate file is empty
777 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600778TEST_F(TestCertificates, TestEmptyCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500779{
780 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000781 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600782 std::string installPath(certDir + "/" + certificateFile);
783 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800784 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800785 auto objPath = std::string(objectNamePrefix) + '/' +
786 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500787 std::string emptyFile("emptycert.pem");
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500788 std::ofstream ofs;
789 ofs.open(emptyFile, std::ofstream::out);
790 ofs.close();
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500791 EXPECT_THROW(
792 {
793 try
794 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500795 auto event = sdeventplus::Event::get_default();
796 // Attach the bus to sd_event to service user requests
797 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800798 ManagerInTest manager(bus, event, objPath.c_str(), type,
799 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500800 MainApp mainApp(&manager);
801 mainApp.install(emptyFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500802 }
803 catch (const InvalidCertificate& e)
804 {
805 throw;
806 }
807 },
808 InvalidCertificate);
809 EXPECT_FALSE(fs::exists(verifyPath));
810 fs::remove(emptyFile);
811}
812
Marri Devender Raoddf64862018-10-03 07:11:02 -0500813/** @brief Check if install fails if certificate file is corrupted
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500814 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600815TEST_F(TestCertificates, TestInvalidCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500816{
817 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000818 CertificateType type = CertificateType::client;
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500819
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500820 std::ofstream ofs;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500821 ofs.open(certificateFile, std::ofstream::out);
822 ofs << "-----BEGIN CERTIFICATE-----";
823 ofs << "ADD_SOME_INVALID_DATA_INTO_FILE";
824 ofs << "-----END CERTIFICATE-----";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500825 ofs.close();
826
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600827 std::string installPath(certDir + "/" + certificateFile);
828 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800829 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800830 auto objPath = std::string(objectNamePrefix) + '/' +
831 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500832 EXPECT_THROW(
833 {
834 try
835 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500836 auto event = sdeventplus::Event::get_default();
837 // Attach the bus to sd_event to service user requests
838 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800839 ManagerInTest manager(bus, event, objPath.c_str(), type,
840 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500841 MainApp mainApp(&manager);
842 mainApp.install(certificateFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500843 }
844 catch (const InvalidCertificate& e)
845 {
846 throw;
847 }
848 },
849 InvalidCertificate);
850 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500851}
Marri Devender Raoddf64862018-10-03 07:11:02 -0500852
853/**
854 * Class to generate private and certificate only file and test verification
855 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600856class TestInvalidCertificate : public ::testing::Test
Marri Devender Raoddf64862018-10-03 07:11:02 -0500857{
858 public:
Patrick Williams223e4602023-05-10 07:51:11 -0500859 TestInvalidCertificate() : bus(sdbusplus::bus::new_default()) {}
Marri Devender Raoddf64862018-10-03 07:11:02 -0500860 void SetUp() override
861 {
862 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
863 auto dirPtr = mkdtemp(dirTemplate);
Nan Zhoucfb58022021-12-28 11:02:26 -0800864 if (dirPtr == nullptr)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500865 {
866 throw std::bad_alloc();
867 }
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100868 certDir = std::string(dirPtr) + "/certs";
869 fs::create_directories(certDir);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500870 certificateFile = "cert.pem";
871 keyFile = "key.pem";
872 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
873 cmd += "-keyout key.pem -out cert.pem -days 3650 ";
874 cmd += "-subj "
875 "/O=openbmc-project.xyz/CN=localhost"
876 " -nodes";
877
878 auto val = std::system(cmd.c_str());
879 if (val)
880 {
881 std::cout << "command Error: " << val << std::endl;
882 }
883 }
884 void TearDown() override
885 {
886 fs::remove_all(certDir);
887 fs::remove(certificateFile);
888 fs::remove(keyFile);
889 }
890
891 protected:
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500892 sdbusplus::bus_t bus;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500893 std::string certificateFile;
894 std::string keyFile;
895 std::string certDir;
896};
897
898/** @brief Check install fails if private key is missing in certificate file
899 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600900TEST_F(TestInvalidCertificate, TestMissingPrivateKey)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500901{
902 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000903 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600904 std::string installPath(certDir + "/" + certificateFile);
905 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800906 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800907 auto objPath = std::string(objectNamePrefix) + '/' +
908 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600909 EXPECT_THROW(
910 {
911 try
912 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500913 auto event = sdeventplus::Event::get_default();
914 // Attach the bus to sd_event to service user requests
915 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800916 ManagerInTest manager(bus, event, objPath.c_str(), type,
917 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500918 MainApp mainApp(&manager);
919 mainApp.install(certificateFile);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600920 }
Marri Devender Raocd30c492019-06-12 01:40:17 -0500921 catch (const InternalFailure& e)
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600922 {
923 throw;
924 }
925 },
Marri Devender Raocd30c492019-06-12 01:40:17 -0500926 InternalFailure);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600927 EXPECT_FALSE(fs::exists(verifyPath));
928}
929
930/** @brief Check install fails if ceritificate is missing in certificate file
931 */
932TEST_F(TestInvalidCertificate, TestMissingCeritificate)
933{
934 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000935 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600936 std::string installPath(certDir + "/" + keyFile);
937 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800938 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800939 auto objPath = std::string(objectNamePrefix) + '/' +
940 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600941 EXPECT_THROW(
942 {
943 try
944 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500945 auto event = sdeventplus::Event::get_default();
946 // Attach the bus to sd_event to service user requests
947 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800948 ManagerInTest manager(bus, event, objPath.c_str(), type,
949 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500950 MainApp mainApp(&manager);
951 mainApp.install(keyFile);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500952 }
Marri Devender Raocd30c492019-06-12 01:40:17 -0500953 catch (const InternalFailure& e)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500954 {
955 throw;
956 }
957 },
958 InvalidCertificate);
959 EXPECT_FALSE(fs::exists(verifyPath));
960}
961
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600962/** @brief Check if error is thrown when multiple certificates are installed
963 * At present only one certificate per service is allowed
Marri Devender Raoddf64862018-10-03 07:11:02 -0500964 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600965TEST_F(TestCertificates, TestCertInstallNotAllowed)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500966{
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600967 using NotAllowed =
968 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500969 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000970 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600971 std::string installPath(certDir + "/" + certificateFile);
972 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800973 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800974 auto objPath = std::string(objectNamePrefix) + '/' +
975 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -0500976 auto event = sdeventplus::Event::get_default();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500977 // Attach the bus to sd_event to service user requests
978 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800979 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
980 installPath);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500981 MainApp mainApp(&manager);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600982 mainApp.install(certificateFile);
983 EXPECT_TRUE(fs::exists(verifyPath));
Marri Devender Raoddf64862018-10-03 07:11:02 -0500984 EXPECT_THROW(
985 {
986 try
987 {
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600988 // install second certificate
989 mainApp.install(certificateFile);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500990 }
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600991 catch (const NotAllowed& e)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500992 {
993 throw;
994 }
995 },
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600996 NotAllowed);
Marri Devender Rao9abfae82018-10-03 08:10:35 -0500997}
Marri Devender Raof4682712019-03-19 05:00:28 -0500998
999TEST_F(TestCertificates, TestGenerateCSR)
1000{
1001 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001002 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001003 CertificateType type = CertificateType::server;
Marri Devender Raof4682712019-03-19 05:00:28 -05001004 std::string installPath(certDir + "/" + certificateFile);
1005 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001006 std::string csrPath(certDir + "/" + CSRFile);
Marri Devender Raof4682712019-03-19 05:00:28 -05001007 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1008 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001009 std::string challengePassword("Password");
Marri Devender Raof4682712019-03-19 05:00:28 -05001010 std::string city("HYB");
1011 std::string commonName("abc.com");
1012 std::string contactPerson("Admin");
1013 std::string country("IN");
1014 std::string email("admin@in.ibm.com");
1015 std::string givenName("givenName");
1016 std::string initials("G");
1017 int64_t keyBitLength(2048);
1018 std::string keyCurveId("0");
1019 std::string keyPairAlgorithm("RSA");
1020 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1021 std::string organization("IBM");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001022 std::string organizationalUnit("orgUnit");
Marri Devender Raof4682712019-03-19 05:00:28 -05001023 std::string state("TS");
1024 std::string surname("surname");
1025 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001026 auto objPath = std::string(objectNamePrefix) + '/' +
1027 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -05001028 auto event = sdeventplus::Event::get_default();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -05001029 // Attach the bus to sd_event to service user requests
1030 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Marri Devender Raof4682712019-03-19 05:00:28 -05001031 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1032 std::move(installPath));
1033 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001034 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Marri Devender Raof4682712019-03-19 05:00:28 -05001035 MainApp mainApp(&manager, &csr);
1036 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1037 contactPerson, country, email, givenName, initials,
1038 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1039 organization, organizationalUnit, state, surname,
1040 unstructuredName);
1041 std::string csrData("");
1042 // generateCSR takes considerable time to create CSR and privateKey Files
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001043 EXPECT_FALSE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001044 EXPECT_FALSE(fs::exists(privateKeyPath));
1045 EXPECT_THROW(
1046 {
1047 try
1048 {
Patrick Williamse129be32021-04-30 20:35:19 -05001049 csrData = csr.csr();
Marri Devender Raof4682712019-03-19 05:00:28 -05001050 }
1051 catch (const InternalFailure& e)
1052 {
1053 throw;
1054 }
1055 },
1056 InternalFailure);
1057 // wait for 10 sec to get CSR and privateKey Files generated
1058 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001059 EXPECT_TRUE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001060 EXPECT_TRUE(fs::exists(privateKeyPath));
Patrick Williamse129be32021-04-30 20:35:19 -05001061 csrData = csr.csr();
Marri Devender Raof4682712019-03-19 05:00:28 -05001062 ASSERT_NE("", csrData.c_str());
1063}
1064
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001065/** @brief Check if ECC key pair is generated when user is not given algorithm
1066 * type. At present RSA and EC key pair algorithm are supported
1067 */
1068TEST_F(TestCertificates, TestGenerateCSRwithEmptyKeyPairAlgorithm)
1069{
1070 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001071 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001072 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001073 std::string installPath(certDir + "/" + certificateFile);
1074 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001075 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001076 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1077 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1078 std::string challengePassword("Password");
1079 std::string city("HYB");
1080 std::string commonName("abc.com");
1081 std::string contactPerson("Admin");
1082 std::string country("IN");
1083 std::string email("admin@in.ibm.com");
1084 std::string givenName("givenName");
1085 std::string initials("G");
1086 int64_t keyBitLength(2048);
1087 std::string keyCurveId("");
1088 std::string keyPairAlgorithm("");
1089 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1090 std::string organization("IBM");
1091 std::string organizationalUnit("orgUnit");
1092 std::string state("TS");
1093 std::string surname("surname");
1094 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001095 auto objPath = std::string(objectNamePrefix) + '/' +
1096 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -05001097 auto event = sdeventplus::Event::get_default();
1098 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1099 std::move(installPath));
1100 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001101 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Marri Devender Raof4682712019-03-19 05:00:28 -05001102 MainApp mainApp(&manager, &csr);
1103 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1104 contactPerson, country, email, givenName, initials,
1105 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1106 organization, organizationalUnit, state, surname,
1107 unstructuredName);
1108 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001109 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001110 EXPECT_TRUE(fs::exists(privateKeyPath));
1111}
1112
1113/** @brief Check if error is thrown when giving un supported key pair
1114 * algorithm. At present RSA and EC key pair algorithm are supported
1115 */
1116TEST_F(TestCertificates, TestGenerateCSRwithUnsupportedKeyPairAlgorithm)
1117{
1118 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001119 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001120 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001121 std::string installPath(certDir + "/" + certificateFile);
1122 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001123 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001124 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1125 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1126 std::string challengePassword("Password");
1127 std::string city("HYB");
1128 std::string commonName("abc.com");
1129 std::string contactPerson("Admin");
1130 std::string country("IN");
1131 std::string email("admin@in.ibm.com");
1132 std::string givenName("givenName");
1133 std::string initials("G");
1134 int64_t keyBitLength(2048);
1135 std::string keyCurveId("secp521r1");
1136 std::string keyPairAlgorithm("UnSupportedAlgorithm");
1137 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1138 std::string organization("IBM");
1139 std::string organizationalUnit("orgUnit");
1140 std::string state("TS");
1141 std::string surname("surname");
1142 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001143 auto objPath = std::string(objectNamePrefix) + '/' +
1144 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001145 auto event = sdeventplus::Event::get_default();
1146 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1147 std::move(installPath));
1148 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001149 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001150 MainApp mainApp(&manager, &csr);
1151 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1152 contactPerson, country, email, givenName, initials,
1153 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1154 organization, organizationalUnit, state, surname,
1155 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001156 EXPECT_FALSE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001157 EXPECT_FALSE(fs::exists(privateKeyPath));
1158}
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001159
1160/** @brief Check if error is thrown when NID_undef is returned for given key
1161 * curve id
1162 */
1163TEST_F(TestCertificates, TestECKeyGenerationwithNIDundefCase)
1164{
1165 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001166 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001167 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001168 std::string installPath(certDir + "/" + certificateFile);
1169 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001170 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001171 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1172 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1173 std::string challengePassword("Password");
1174 std::string city("BLR");
1175 std::string commonName("abc.com");
1176 std::string contactPerson("Admin");
1177 std::string country("IN");
1178 std::string email("admin@in.ibm.com");
1179 std::string givenName("givenName");
1180 std::string initials("G");
1181 int64_t keyBitLength(2048);
1182 std::string keyCurveId("DummyCurveName");
1183 std::string keyPairAlgorithm("EC");
1184 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1185 std::string organization("IBM");
1186 std::string organizationalUnit("orgUnit");
1187 std::string state("TS");
1188 std::string surname("surname");
1189 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001190 auto objPath = std::string(objectNamePrefix) + '/' +
1191 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001192 auto event = sdeventplus::Event::get_default();
1193 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1194 std::move(installPath));
1195 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001196 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001197 MainApp mainApp(&manager, &csr);
1198 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1199 contactPerson, country, email, givenName, initials,
1200 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1201 organization, organizationalUnit, state, surname,
1202 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001203 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001204 EXPECT_FALSE(fs::exists(privateKeyPath));
1205}
1206
1207/** @brief Check default Key Curve Id is used if given curve id is empty
1208 */
1209TEST_F(TestCertificates, TestECKeyGenerationwithDefaultKeyCurveId)
1210{
1211 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001212 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001213 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001214 std::string installPath(certDir + "/" + certificateFile);
1215 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001216 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001217 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1218 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1219 std::string challengePassword("Password");
1220 std::string city("BLR");
1221 std::string commonName("abc.com");
1222 std::string contactPerson("Admin");
1223 std::string country("IN");
1224 std::string email("admin@in.ibm.com");
1225 std::string givenName("givenName");
1226 std::string initials("G");
1227 int64_t keyBitLength(2048);
1228 std::string keyCurveId("");
1229 std::string keyPairAlgorithm("EC");
1230 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1231 std::string organization("IBM");
1232 std::string organizationalUnit("orgUnit");
1233 std::string state("TS");
1234 std::string surname("surname");
1235 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001236 auto objPath = std::string(objectNamePrefix) + '/' +
1237 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001238 auto event = sdeventplus::Event::get_default();
1239 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1240 std::move(installPath));
1241 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001242 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001243 MainApp mainApp(&manager, &csr);
1244 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1245 contactPerson, country, email, givenName, initials,
1246 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1247 organization, organizationalUnit, state, surname,
1248 unstructuredName);
1249 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001250 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001251 EXPECT_TRUE(fs::exists(privateKeyPath));
1252}
1253
1254/** @brief Check if error is not thrown to generate EC key pair
1255 */
1256TEST_F(TestCertificates, TestECKeyGeneration)
1257{
1258 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001259 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001260 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001261 std::string installPath(certDir + "/" + certificateFile);
1262 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001263 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001264 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1265 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1266 std::string challengePassword("Password");
1267 std::string city("BLR");
1268 std::string commonName("abc.com");
1269 std::string contactPerson("Admin");
1270 std::string country("IN");
1271 std::string email("admin@in.ibm.com");
1272 std::string givenName("givenName");
1273 std::string initials("G");
1274 int64_t keyBitLength(2048);
1275 std::string keyCurveId("secp521r1");
1276 std::string keyPairAlgorithm("EC");
1277 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1278 std::string organization("IBM");
1279 std::string organizationalUnit("orgUnit");
1280 std::string state("TS");
1281 std::string surname("surname");
1282 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001283 auto objPath = std::string(objectNamePrefix) + '/' +
1284 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001285 auto event = sdeventplus::Event::get_default();
1286 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1287 std::move(installPath));
1288 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001289 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001290 MainApp mainApp(&manager, &csr);
1291 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1292 contactPerson, country, email, givenName, initials,
1293 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1294 organization, organizationalUnit, state, surname,
1295 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001296 std::cout << "CSRPath: " << csrPath << std::endl
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001297 << "privateKeyPath: " << privateKeyPath << std::endl;
1298 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001299 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001300 EXPECT_TRUE(fs::exists(privateKeyPath));
1301}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001302
Nan Zhoubf3cf752021-12-28 11:02:07 -08001303/** @brief Check error is thrown if giving unsupported key bit length to
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001304 * generate rsa key
1305 */
1306TEST_F(TestCertificates, TestRSAKeyWithUnsupportedKeyBitLength)
1307{
1308 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001309 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001310 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001311 std::string installPath(certDir + "/" + certificateFile);
1312 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001313 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001314 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1315 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1316 std::string challengePassword("Password");
1317 std::string city("BLR");
1318 std::string commonName("abc.com");
1319 std::string contactPerson("Admin");
1320 std::string country("IN");
1321 std::string email("admin@in.ibm.com");
1322 std::string givenName("givenName");
1323 std::string initials("G");
1324 int64_t keyBitLength(4096);
1325 std::string keyCurveId("secp521r1");
1326 std::string keyPairAlgorithm("RSA");
1327 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1328 std::string organization("IBM");
1329 std::string organizationalUnit("orgUnit");
1330 std::string state("TS");
1331 std::string surname("surname");
1332 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001333 auto objPath = std::string(objectNamePrefix) + '/' +
1334 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001335 auto event = sdeventplus::Event::get_default();
1336 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1337 std::move(installPath));
1338 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001339 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001340 MainApp mainApp(&manager, &csr);
1341 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1342 contactPerson, country, email, givenName, initials,
1343 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1344 organization, organizationalUnit, state, surname,
1345 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001346 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001347 EXPECT_FALSE(fs::exists(privateKeyPath));
1348}
1349
1350/** @brief Check error is thrown if generated rsa key file is not present
1351 */
1352TEST_F(TestCertificates, TestRSAKeyFileNotPresentCase)
1353{
1354 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001355 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001356 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001357 std::string installPath(certDir + "/" + certificateFile);
1358 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001359 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001360 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1361 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1362 std::string challengePassword("Password");
1363 std::string city("BLR");
1364 std::string commonName("abc.com");
1365 std::string contactPerson("Admin");
1366 std::string country("IN");
1367 std::string email("admin@in.ibm.com");
1368 std::string givenName("givenName");
1369 std::string initials("G");
1370 int64_t keyBitLength(2048);
1371 std::string keyCurveId("secp521r1");
1372 std::string keyPairAlgorithm("RSA");
1373 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1374 std::string organization("IBM");
1375 std::string organizationalUnit("orgUnit");
1376 std::string state("TS");
1377 std::string surname("surname");
1378 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001379 auto objPath = std::string(objectNamePrefix) + '/' +
1380 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001381 auto event = sdeventplus::Event::get_default();
1382 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1383 std::move(installPath));
1384
1385 // Removing generated RSA key file
1386 fs::remove(rsaPrivateKeyFilePath);
1387
1388 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001389 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001390 MainApp mainApp(&manager, &csr);
1391 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1392 contactPerson, country, email, givenName, initials,
1393 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1394 organization, organizationalUnit, state, surname,
1395 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001396 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001397 EXPECT_FALSE(fs::exists(privateKeyPath));
1398}
1399
1400/** @brief Check private key file is created from generated rsa key file is
1401 * `present
1402 */
1403TEST_F(TestCertificates, TestRSAKeyFromRSAKeyFileIsWrittenIntoPrivateKeyFile)
1404{
1405 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001406 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001407 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001408 std::string installPath(certDir + "/" + certificateFile);
1409 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001410 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001411 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1412 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1413 std::string challengePassword("Password");
1414 std::string city("BLR");
1415 std::string commonName("abc.com");
1416 std::string contactPerson("Admin");
1417 std::string country("IN");
1418 std::string email("admin@in.ibm.com");
1419 std::string givenName("givenName");
1420 std::string initials("G");
1421 int64_t keyBitLength(2048);
1422 std::string keyCurveId("secp521r1");
1423 std::string keyPairAlgorithm("RSA");
1424 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1425 std::string organization("IBM");
1426 std::string organizationalUnit("orgUnit");
1427 std::string state("TS");
1428 std::string surname("surname");
1429 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001430 auto objPath = std::string(objectNamePrefix) + '/' +
1431 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001432 auto event = sdeventplus::Event::get_default();
1433 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1434 std::move(installPath));
1435 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001436 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001437 MainApp mainApp(&manager, &csr);
1438 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1439 contactPerson, country, email, givenName, initials,
1440 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1441 organization, organizationalUnit, state, surname,
1442 unstructuredName);
1443 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001444 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001445 EXPECT_TRUE(fs::exists(privateKeyPath));
1446}
1447
Nan Zhoubf3cf752021-12-28 11:02:07 -08001448/** @brief Check RSA key is generated during application startup*/
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001449TEST_F(TestCertificates, TestGenerateRSAPrivateKeyFile)
1450{
1451 std::string endpoint("https");
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001452 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001453 std::string installPath(certDir + "/" + certificateFile);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001454 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001455 auto objPath = std::string(objectNamePrefix) + '/' +
1456 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001457 auto event = sdeventplus::Event::get_default();
1458
1459 EXPECT_FALSE(fs::exists(rsaPrivateKeyFilePath));
Nan Zhou6ec13c82021-12-30 11:34:50 -08001460 Manager manager(bus, event, objPath.c_str(), type, verifyUnit, installPath);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001461 EXPECT_TRUE(fs::exists(rsaPrivateKeyFilePath));
1462}
Nan Zhou6ec13c82021-12-30 11:34:50 -08001463
1464/**
1465 * Class to test Authorities List installation and replacement
1466 */
1467class AuthoritiesListTest : public testing::Test
1468{
1469 public:
1470 AuthoritiesListTest() :
1471 bus(sdbusplus::bus::new_default()),
1472 authoritiesListFolder(
1473 Certificate::generateUniqueFilePath(fs::temp_directory_path()))
1474 {
1475 fs::create_directory(authoritiesListFolder);
1476 createAuthoritiesList(maxNumAuthorityCertificates);
1477 }
1478 ~AuthoritiesListTest() override
1479 {
1480 fs::remove_all(authoritiesListFolder);
1481 }
1482
1483 protected:
1484 // Creates a testing authorities list which consists of |count| root
1485 // certificates
1486 void createAuthoritiesList(int count)
1487 {
1488 fs::path srcFolder = fs::temp_directory_path();
1489 srcFolder = Certificate::generateUniqueFilePath(srcFolder);
1490 fs::create_directory(srcFolder);
1491 createSingleAuthority(srcFolder, "root_0");
1492 sourceAuthoritiesListFile = srcFolder / "root_0_cert";
1493 for (int i = 1; i < count; ++i)
1494 {
1495 std::string name = "root_" + std::to_string(i);
1496 createSingleAuthority(srcFolder, name);
1497 appendContentFromFile(sourceAuthoritiesListFile,
1498 srcFolder / (name + "_cert"));
1499 }
1500 }
1501
1502 // Creates a single self-signed root certificate in given |path|; the key
1503 // will be |path|/|cn|_key, the cert will be |path|/|cn|_cert, and the cn
1504 // will be "/O=openbmc-project.xyz/C=US/ST=CA/CN=|cn|"
1505 static void createSingleAuthority(const std::string& path,
1506 const std::string& cn)
1507 {
1508 std::string key = fs::path(path) / (cn + "_key");
1509 std::string cert = fs::path(path) / (cn + "_cert");
1510 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 -keyout ";
1511 cmd += key + " -out " + cert + " -nodes --days 365000 ";
1512 cmd += "-subj /O=openbmc-project.xyz/CN=" + cn;
1513 ASSERT_EQ(std::system(cmd.c_str()), 0);
1514 }
1515
1516 // Appends the content of the |from| file to the |to| file.
1517 static void appendContentFromFile(const std::string& to,
1518 const std::string& from)
1519 {
1520 ASSERT_NO_THROW({
1521 std::ifstream inputCertFileStream;
1522 std::ofstream outputCertFileStream;
1523 inputCertFileStream.exceptions(std::ifstream::failbit |
1524 std::ifstream::badbit |
1525 std::ifstream::eofbit);
1526 outputCertFileStream.exceptions(std::ofstream::failbit |
1527 std::ofstream::badbit |
1528 std::ofstream::eofbit);
1529 inputCertFileStream.open(from);
1530 outputCertFileStream.open(to, std::ios::app);
1531 outputCertFileStream << inputCertFileStream.rdbuf() << std::flush;
1532 inputCertFileStream.close();
1533 outputCertFileStream.close();
1534 });
1535 }
1536
1537 // Appends the content of the |from| buffer to the |to| file.
1538 static void setContentFromString(const std::string& to,
1539 const std::string& from)
1540 {
1541 ASSERT_NO_THROW({
1542 std::ofstream outputCertFileStream;
1543 outputCertFileStream.exceptions(std::ofstream::failbit |
1544 std::ofstream::badbit |
1545 std::ofstream::eofbit);
1546 outputCertFileStream.open(to, std::ios::out);
1547 outputCertFileStream << from << std::flush;
1548 outputCertFileStream.close();
1549 });
1550 }
1551
1552 // Verifies the effect of InstallAll or ReplaceAll
1553 void verifyCertificates(std::vector<std::unique_ptr<Certificate>>& certs)
1554 {
1555 // The trust bundle file has been copied over
1556 EXPECT_FALSE(fs::is_empty(authoritiesListFolder));
1557 EXPECT_TRUE(
1558 compareFiles(authoritiesListFolder / defaultAuthoritiesListFileName,
1559 sourceAuthoritiesListFile));
1560
1561 ASSERT_EQ(certs.size(), maxNumAuthorityCertificates);
1562 // Check attributes and alias
1563 for (size_t i = 0; i < certs.size(); ++i)
1564 {
1565 std::string name = "root_" + std::to_string(i);
1566 EXPECT_EQ(certs[i]->subject(), "O=openbmc-project.xyz,CN=" + name);
1567 EXPECT_EQ(certs[i]->issuer(), "O=openbmc-project.xyz,CN=" + name);
1568 std::string symbolLink =
1569 authoritiesListFolder /
1570 (certs[i]->getCertId().substr(0, 8) + ".0");
1571 ASSERT_TRUE(fs::exists(symbolLink));
1572 compareFileAgainstString(symbolLink, certs[i]->certificateString());
1573 }
1574 }
1575
1576 // Expects that the content of |path| file is |buffer|.
1577 static void compareFileAgainstString(const std::string& path,
1578 const std::string& buffer)
1579 {
1580 ASSERT_NO_THROW({
1581 std::ifstream inputCertFileStream;
1582 inputCertFileStream.exceptions(std::ifstream::failbit |
1583 std::ifstream::badbit |
1584 std::ifstream::eofbit);
1585 inputCertFileStream.open(path);
1586 std::stringstream read;
1587 read << inputCertFileStream.rdbuf();
1588 inputCertFileStream.close();
1589 EXPECT_EQ(read.str(), buffer);
1590 });
1591 };
1592
Patrick Williamsb3dbfb32022-07-22 19:26:57 -05001593 sdbusplus::bus_t bus;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001594 fs::path authoritiesListFolder;
1595 fs::path sourceAuthoritiesListFile;
1596};
1597
1598// Tests that the Authority Manager installs all the certificates in an
1599// authorities list
1600TEST_F(AuthoritiesListTest, InstallAll)
1601{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001602 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001603 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001604 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001605
1606 std::string object = std::string(objectNamePrefix) + '/' +
1607 certificateTypeToString(type) + '/' + endpoint;
1608 auto event = sdeventplus::Event::get_default();
1609 // Attach the bus to sd_event to service user requests
1610 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1611 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1612 authoritiesListFolder);
1613 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1614 .WillOnce(Return());
1615 ASSERT_TRUE(manager.getCertificates().empty());
1616
1617 std::vector<sdbusplus::message::object_path> objects =
1618 manager.installAll(sourceAuthoritiesListFile);
1619 for (size_t i = 0; i < manager.getCertificates().size(); ++i)
1620 {
1621 EXPECT_EQ(manager.getCertificates()[i]->getObjectPath(), objects[i]);
1622 }
1623 verifyCertificates(manager.getCertificates());
1624}
1625
1626// Tests that the Authority Manager recovers from the authorities list persisted
1627// in the installation path at boot up
1628TEST_F(AuthoritiesListTest, RecoverAtBootUp)
1629{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001630 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001631 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001632 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001633
1634 std::string object = std::string(objectNamePrefix) + '/' +
1635 certificateTypeToString(type) + '/' + endpoint;
1636 auto event = sdeventplus::Event::get_default();
1637 // Attach the bus to sd_event to service user requests
1638 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1639
1640 // Copy the trust bundle into the installation path before creating an
1641 // Authority Manager
1642 fs::copy_file(/*from=*/sourceAuthoritiesListFile,
1643 authoritiesListFolder / defaultAuthoritiesListFileName);
1644 // Create some noise as well
1645 fs::copy_file(/*from=*/sourceAuthoritiesListFile,
1646 authoritiesListFolder / "should_be_deleted");
1647
1648 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1649 authoritiesListFolder);
1650
1651 ASSERT_EQ(manager.getCertificates().size(), maxNumAuthorityCertificates);
1652
1653 // Check attributes and alias
1654 std::unordered_set<std::string> expectedFiles = {authoritiesListFolder /
1655 "trust_bundle"};
1656 std::vector<std::unique_ptr<Certificate>>& certs =
1657 manager.getCertificates();
1658 for (size_t i = 0; i < certs.size(); ++i)
1659 {
1660 std::string name = "root_" + std::to_string(i);
1661 EXPECT_EQ(certs[i]->subject(), "O=openbmc-project.xyz,CN=" + name);
1662 EXPECT_EQ(certs[i]->issuer(), "O=openbmc-project.xyz,CN=" + name);
Patrick Williams223e4602023-05-10 07:51:11 -05001663 std::string symbolLink = authoritiesListFolder /
1664 (certs[i]->getCertId().substr(0, 8) + ".0");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001665 expectedFiles.insert(symbolLink);
1666 expectedFiles.insert(certs[i]->getCertFilePath());
1667 ASSERT_TRUE(fs::exists(symbolLink));
1668 compareFileAgainstString(symbolLink, certs[i]->certificateString());
1669 }
1670
1671 // Check folder content
1672 for (auto& path : fs::directory_iterator(authoritiesListFolder))
1673 {
1674 EXPECT_NE(path, authoritiesListFolder / "should_be_deleted");
1675 expectedFiles.erase(path.path());
1676 }
1677 EXPECT_TRUE(expectedFiles.empty());
1678}
1679
1680TEST_F(AuthoritiesListTest, InstallAndDelete)
1681{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001682 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001683 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001684 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001685
1686 std::string object = std::string(objectNamePrefix) + '/' +
1687 certificateTypeToString(type) + '/' + endpoint;
1688
1689 auto event = sdeventplus::Event::get_default();
1690 // Attach the bus to sd_event to service user requests
1691 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1692 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1693 authoritiesListFolder);
1694 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1695 .WillOnce(Return())
1696 .WillOnce(Return());
1697 ASSERT_TRUE(manager.getCertificates().empty());
1698 ASSERT_EQ(manager.installAll(sourceAuthoritiesListFile).size(),
1699 maxNumAuthorityCertificates);
1700 manager.deleteAll();
1701 EXPECT_TRUE(manager.getCertificates().empty());
1702 // Check folder content
1703 for (const fs::path& f : fs::directory_iterator(authoritiesListFolder))
1704 {
1705 EXPECT_THAT(f.filename(), testing::AnyOf(".", ".."));
1706 }
1707}
1708
1709TEST_F(AuthoritiesListTest, InstallAllWrongManagerType)
1710{
1711 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001712 CertificateType type = CertificateType::server;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001713
1714 std::string object = std::string(objectNamePrefix) + '/' +
1715 certificateTypeToString(type) + '/' + endpoint;
1716
1717 auto event = sdeventplus::Event::get_default();
1718 // Attach the bus to sd_event to service user requests
1719 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1720 ManagerInTest serverManager(bus, event, object.c_str(), type, "",
1721 authoritiesListFolder);
1722 EXPECT_THROW(serverManager.installAll(sourceAuthoritiesListFile),
1723 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1724
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001725 type = CertificateType::client;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001726 object = std::string(objectNamePrefix) + '/' +
1727 certificateTypeToString(type) + '/' + endpoint;
1728 ManagerInTest clientManager(bus, event, object.c_str(), type, "",
1729 authoritiesListFolder);
1730 EXPECT_THROW(clientManager.installAll(sourceAuthoritiesListFile),
1731 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1732}
1733
1734TEST_F(AuthoritiesListTest, InstallAllTwice)
1735{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001736 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001737 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001738 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001739
1740 std::string object = std::string(objectNamePrefix) + '/' +
1741 certificateTypeToString(type) + '/' + endpoint;
1742
1743 auto event = sdeventplus::Event::get_default();
1744 // Attach the bus to sd_event to service user requests
1745 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1746 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1747 authoritiesListFolder);
1748 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1749 .WillOnce(Return());
1750 ASSERT_TRUE(manager.getCertificates().empty());
1751
1752 ASSERT_EQ(manager.installAll(sourceAuthoritiesListFile).size(),
1753 maxNumAuthorityCertificates);
Nan Zhou56bfa732022-09-16 01:15:29 +00001754 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
Nan Zhou6ec13c82021-12-30 11:34:50 -08001755 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1756}
1757
1758TEST_F(AuthoritiesListTest, InstallAllMissSourceFile)
1759{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001760 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001761 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001762 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001763
1764 std::string object = std::string(objectNamePrefix) + '/' +
1765 certificateTypeToString(type) + '/' + endpoint;
1766
1767 auto event = sdeventplus::Event::get_default();
1768 // Attach the bus to sd_event to service user requests
1769 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1770 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1771 authoritiesListFolder);
1772
1773 EXPECT_THROW(manager.installAll(authoritiesListFolder / "trust_bundle"),
1774 InternalFailure);
1775}
1776
1777TEST_F(AuthoritiesListTest, TooManyRootCertificates)
1778{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001779 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001780 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001781 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001782
1783 std::string object = std::string(objectNamePrefix) + '/' +
1784 certificateTypeToString(type) + '/' + endpoint;
1785
1786 auto event = sdeventplus::Event::get_default();
1787 // Attach the bus to sd_event to service user requests
1788 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1789 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1790 authoritiesListFolder);
1791 createAuthoritiesList(maxNumAuthorityCertificates + 1);
1792 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1793 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1794}
1795
1796TEST_F(AuthoritiesListTest, CertInWrongFormat)
1797{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001798 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001799 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001800 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001801
1802 std::string object = std::string(objectNamePrefix) + '/' +
1803 certificateTypeToString(type) + '/' + endpoint;
1804
1805 auto event = sdeventplus::Event::get_default();
1806 // Attach the bus to sd_event to service user requests
1807 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1808
1809 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1810 authoritiesListFolder);
1811
1812 // Replace the authorities list with non-valid PEM encoded x509 certificate
1813 setContentFromString(sourceAuthoritiesListFile, "blah-blah");
1814 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1815 InvalidCertificate);
1816 setContentFromString(sourceAuthoritiesListFile,
1817 "-----BEGIN CERTIFICATE-----");
1818 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1819 InvalidCertificate);
1820}
1821
1822TEST_F(AuthoritiesListTest, ReplaceAll)
1823{
Michal Orzel2e8fa882023-07-27 13:14:56 +02001824 std::string endpoint("truststore");
Nan Zhou6ec13c82021-12-30 11:34:50 -08001825 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001826 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001827
1828 std::string object = std::string(objectNamePrefix) + '/' +
1829 certificateTypeToString(type) + '/' + endpoint;
1830
1831 auto event = sdeventplus::Event::get_default();
1832 // Attach the bus to sd_event to service user requests
1833 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1834 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1835 authoritiesListFolder);
1836 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1837 .WillOnce(Return())
1838 .WillOnce(Return());
1839 manager.installAll(sourceAuthoritiesListFile);
1840
1841 // Replace the current list with a different list
1842 fs::remove_all(sourceAuthoritiesListFile.parent_path());
1843 createAuthoritiesList(maxNumAuthorityCertificates);
1844 std::vector<sdbusplus::message::object_path> objects =
1845 manager.replaceAll(sourceAuthoritiesListFile);
1846
1847 for (size_t i = 0; i < manager.getCertificates().size(); ++i)
1848 {
1849 EXPECT_EQ(manager.getCertificates()[i]->getObjectPath(), objects[i]);
1850 }
1851 verifyCertificates(manager.getCertificates());
1852}
1853
Nan Zhoue1289ad2021-12-28 11:02:56 -08001854} // namespace
1855} // namespace phosphor::certs