blob: 9caa9d36e125f1af81929e63bb5979abb49b9c27 [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
Nan Zhou014be0b2021-12-28 18:00:14 -080014#include <cstdint>
15#include <cstdio>
16#include <cstdlib>
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060017#include <filesystem>
Marri Devender Rao947258d2018-09-25 10:52:24 -050018#include <fstream>
Nan Zhou014be0b2021-12-28 18:00:14 -080019#include <iostream>
Marri Devender Rao947258d2018-09-25 10:52:24 -050020#include <iterator>
Nan Zhou014be0b2021-12-28 18:00:14 -080021#include <memory>
22#include <new>
23#include <sdbusplus/bus.hpp>
Marri Devender Raof4682712019-03-19 05:00:28 -050024#include <sdeventplus/event.hpp>
Marri Devender Rao947258d2018-09-25 10:52:24 -050025#include <string>
Nan Zhou6ec13c82021-12-30 11:34:50 -080026#include <unordered_set>
Nan Zhou014be0b2021-12-28 18:00:14 -080027#include <utility>
28#include <vector>
Marri Devender Rao13bf74e2019-03-26 01:52:17 -050029#include <xyz/openbmc_project/Certs/error.hpp>
Marri Devender Rao947258d2018-09-25 10:52:24 -050030#include <xyz/openbmc_project/Common/error.hpp>
31
Nan Zhou6ec13c82021-12-30 11:34:50 -080032#include <gmock/gmock.h>
Marri Devender Rao947258d2018-09-25 10:52:24 -050033#include <gtest/gtest.h>
Nan Zhoue1289ad2021-12-28 11:02:56 -080034
35namespace phosphor::certs
36{
37namespace
38{
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060039namespace fs = std::filesystem;
Nan Zhoucf06ccd2021-12-28 16:25:45 -080040using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
41using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Nan Zhou6ec13c82021-12-30 11:34:50 -080042using ::testing::Eq;
43using ::testing::Return;
44// Compares two files; returns true only if the two are the same
45bool compareFiles(const std::string& file1, const std::string& file2)
46{
47 std::ifstream f1(file1, std::ifstream::binary | std::ifstream::ate);
48 std::ifstream f2(file2, std::ifstream::binary | std::ifstream::ate);
49
50 if (f1.fail() || f2.fail())
51 {
52 return false; // file problem
53 }
54
55 if (f1.tellg() != f2.tellg())
56 {
57 return false; // size mismatch
58 }
59
60 // seek back to beginning and use std::equal to compare contents
61 f1.seekg(0, std::ifstream::beg);
62 f2.seekg(0, std::ifstream::beg);
63 return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
64 std::istreambuf_iterator<char>(),
65 std::istreambuf_iterator<char>(f2.rdbuf()));
66}
Marri Devender Raoe6597c52018-10-01 06:36:55 -050067
Marri Devender Raoddf64862018-10-03 07:11:02 -050068/**
69 * Class to generate certificate file and test verification of certificate file
70 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060071class TestCertificates : public ::testing::Test
Marri Devender Rao947258d2018-09-25 10:52:24 -050072{
73 public:
Marri Devender Rao8841dbd2019-03-04 05:43:55 -060074 TestCertificates() : bus(sdbusplus::bus::new_default())
Marri Devender Rao947258d2018-09-25 10:52:24 -050075 {
76 }
77 void SetUp() override
78 {
79 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
80 auto dirPtr = mkdtemp(dirTemplate);
Nan Zhoucfb58022021-12-28 11:02:26 -080081 if (dirPtr == nullptr)
Marri Devender Rao947258d2018-09-25 10:52:24 -050082 {
83 throw std::bad_alloc();
84 }
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +010085 certDir = std::string(dirPtr) + "/certs";
86 fs::create_directories(certDir);
Kowalski, Kamildb029c92019-07-08 17:09:39 +020087
88 createNewCertificate();
Marri Devender Rao947258d2018-09-25 10:52:24 -050089 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +020090
Marri Devender Rao947258d2018-09-25 10:52:24 -050091 void TearDown() override
92 {
93 fs::remove_all(certDir);
94 fs::remove(certificateFile);
Marri Devender Raof4682712019-03-19 05:00:28 -050095 fs::remove(CSRFile);
96 fs::remove(privateKeyFile);
Nan Zhoucf811c42021-12-02 14:56:17 -080097 fs::remove_all("demoCA");
Marri Devender Rao947258d2018-09-25 10:52:24 -050098 }
99
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200100 void createNewCertificate(bool setNewCertId = false)
101 {
102 certificateFile = "cert.pem";
103 CSRFile = "domain.csr";
104 privateKeyFile = "privkey.pem";
105 rsaPrivateKeyFilePath = certDir + "/.rsaprivkey.pem";
106 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
Nan Zhoucf811c42021-12-02 14:56:17 -0800107 cmd += "-keyout cert.pem -out cert.pem -days 365000 -nodes";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200108 cmd += " -subj /O=openbmc-project.xyz/CN=localhost";
109
110 if (setNewCertId)
111 {
112 cmd += std::to_string(certId++);
113 }
114
115 auto val = std::system(cmd.c_str());
116 if (val)
117 {
118 std::cout << "COMMAND Error: " << val << std::endl;
119 }
120 }
121
Nan Zhoucf811c42021-12-02 14:56:17 -0800122 void createNeverExpiredRootCertificate()
123 {
124 // remove the old cert
125 fs::remove(certificateFile);
126
127 // The following routines create a cert that has NotBefore
128 // set to 1970/01/01 and NotAfter set to 9999/12/31 via the
129 // OpenSSL CA application.
130 certificateFile = "cert.pem";
131 ASSERT_EQ(std::system("mkdir -p demoCA"), 0);
132 ASSERT_EQ(std::system("mkdir -p demoCA/private/"), 0);
133 ASSERT_EQ(std::system("mkdir -p demoCA/newcerts/"), 0);
134 ASSERT_EQ(std::system("touch demoCA/index.txt"), 0);
135 ASSERT_EQ(std::system("echo 1000 > demoCA/serial"), 0);
136 ASSERT_EQ(
137 std::system(
138 "openssl req -x509 -sha256 -newkey rsa:2048 -keyout "
139 "demoCA/private/cakey.pem -out demoCA/cacert.pem -nodes "
140 "-subj /O=openbmc-project.xyz/C=US/ST=CA/CN=localhost-ca"),
141 0);
142 ASSERT_EQ(std::system(
143 "openssl req -new -newkey rsa:2048 -nodes -keyout "
144 "demoCA/server.key -out demoCA/server.csr -subj "
145 "/O=openbmc-project.xyz/C=US/ST=CA/CN=localhost-server"),
146 0);
147 ASSERT_EQ(
148 std::system(
149 "openssl ca -batch -startdate 19700101000000Z -enddate "
150 "99991231235959Z -out cert.pem -infiles demoCA/server.csr"),
151 0);
152 }
153
Marri Devender Rao947258d2018-09-25 10:52:24 -0500154 bool compareFiles(const std::string& file1, const std::string& file2)
155 {
156 std::ifstream f1(file1, std::ifstream::binary | std::ifstream::ate);
157 std::ifstream f2(file2, std::ifstream::binary | std::ifstream::ate);
158
159 if (f1.fail() || f2.fail())
160 {
161 return false; // file problem
162 }
163
164 if (f1.tellg() != f2.tellg())
165 {
166 return false; // size mismatch
167 }
168
169 // seek back to beginning and use std::equal to compare contents
170 f1.seekg(0, std::ifstream::beg);
171 f2.seekg(0, std::ifstream::beg);
172 return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
173 std::istreambuf_iterator<char>(),
174 std::istreambuf_iterator<char>(f2.rdbuf()));
175 }
176
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100177 std::string getCertSubjectNameHash(const std::string& certFilePath)
178 {
179 std::unique_ptr<X509, decltype(&::X509_free)> cert(X509_new(),
180 ::X509_free);
181 if (!cert)
182 {
183 std::string();
184 }
185
186 std::unique_ptr<BIO, decltype(&::BIO_free)> bioCert(
187 BIO_new_file(certFilePath.c_str(), "rb"), ::BIO_free);
188 if (!bioCert)
189 {
190 std::string();
191 }
192
193 X509* x509 = cert.get();
194 if (!PEM_read_bio_X509(bioCert.get(), &x509, nullptr, nullptr))
195 {
196 std::string();
197 }
198
199 unsigned long hash = X509_subject_name_hash(cert.get());
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000200 static constexpr auto authCertHashLength = 9;
201 char hashBuf[authCertHashLength];
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100202 sprintf(hashBuf, "%08lx", hash);
203 return std::string(hashBuf);
204 }
205
Marri Devender Rao947258d2018-09-25 10:52:24 -0500206 protected:
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500207 sdbusplus::bus_t bus;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500208 std::string certificateFile, CSRFile, privateKeyFile, rsaPrivateKeyFilePath;
Marri Devender Rao947258d2018-09-25 10:52:24 -0500209
210 std::string certDir;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200211 uint64_t certId;
Marri Devender Rao947258d2018-09-25 10:52:24 -0500212};
213
214class MainApp
215{
216 public:
Marri Devender Raof4682712019-03-19 05:00:28 -0500217 MainApp(phosphor::certs::Manager* manager,
218 phosphor::certs::CSR* csr = nullptr) :
219 manager(manager),
Patrick Williamse129be32021-04-30 20:35:19 -0500220 csr_(csr)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500221 {
222 }
223 void install(std::string& path)
224 {
225 manager->install(path);
226 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500227
228 std::string generateCSR(std::vector<std::string> alternativeNames,
229 std::string challengePassword, std::string city,
230 std::string commonName, std::string contactPerson,
231 std::string country, std::string email,
232 std::string givenName, std::string initials,
233 int64_t keyBitLength, std::string keyCurveId,
234 std::string keyPairAlgorithm,
235 std::vector<std::string> keyUsage,
236 std::string organization,
237 std::string organizationalUnit, std::string state,
238 std::string surname, std::string unstructuredName)
239 {
240 return (manager->generateCSR(
241 alternativeNames, challengePassword, city, commonName,
242 contactPerson, country, email, givenName, initials, keyBitLength,
243 keyCurveId, keyPairAlgorithm, keyUsage, organization,
244 organizationalUnit, state, surname, unstructuredName));
245 }
Patrick Williamse129be32021-04-30 20:35:19 -0500246 std::string csr()
247 {
248 return (csr_->csr());
249 }
Marri Devender Rao947258d2018-09-25 10:52:24 -0500250 phosphor::certs::Manager* manager;
Patrick Williamse129be32021-04-30 20:35:19 -0500251 phosphor::certs::CSR* csr_;
Marri Devender Rao947258d2018-09-25 10:52:24 -0500252};
253
Nan Zhou6ec13c82021-12-30 11:34:50 -0800254class ManagerInTest : public phosphor::certs::Manager
255{
256 public:
257 static constexpr std::string_view unitToRestartInTest =
258 "xyz.openbmc_project.awesome-service";
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500259 ManagerInTest(sdbusplus::bus_t& bus, sdeventplus::Event& event,
Nan Zhou6ec13c82021-12-30 11:34:50 -0800260 const char* path, CertificateType type,
261 const std::string& unit, const std::string& installPath) :
262 Manager(bus, event, path, type, unit, installPath)
263 {
264 }
265
266 MOCK_METHOD(void, reloadOrReset, (const std::string&), (override));
267};
268
Marri Devender Rao947258d2018-09-25 10:52:24 -0500269/** @brief Check if server install routine is invoked for server setup
270 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600271TEST_F(TestCertificates, InvokeServerInstall)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500272{
273 std::string endpoint("https");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000274 CertificateType type = CertificateType::server;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600275 std::string installPath(certDir + "/" + certificateFile);
276 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800277 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800278 auto objPath = std::string(objectNamePrefix) + '/' +
279 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500280 auto event = sdeventplus::Event::get_default();
281 // Attach the bus to sd_event to service user requests
282 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800283 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
284 installPath);
285 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
286 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500287 MainApp mainApp(&manager);
288 mainApp.install(certificateFile);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500289 EXPECT_TRUE(fs::exists(verifyPath));
290}
291
292/** @brief Check if client install routine is invoked for client setup
293 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600294TEST_F(TestCertificates, InvokeClientInstall)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500295{
296 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000297 CertificateType type = CertificateType::server;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600298 std::string installPath(certDir + "/" + certificateFile);
299 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800300 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800301 auto objPath = std::string(objectNamePrefix) + '/' +
302 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500303 auto event = sdeventplus::Event::get_default();
304 // Attach the bus to sd_event to service user requests
305 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800306 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
307 installPath);
308 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
309 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500310 MainApp mainApp(&manager);
311 mainApp.install(certificateFile);
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500312 EXPECT_TRUE(fs::exists(verifyPath));
313}
314
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200315/** @brief Check if storage install routine is invoked for storage setup
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500316 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600317TEST_F(TestCertificates, InvokeAuthorityInstall)
Jayanth Othayothb50789c2018-10-09 07:13:54 -0500318{
319 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000320 CertificateType type = CertificateType::authority;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200321 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800322 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800323 auto objPath = std::string(objectNamePrefix) + '/' +
324 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500325 auto event = sdeventplus::Event::get_default();
326 // Attach the bus to sd_event to service user requests
327 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800328 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
329 verifyDir);
330 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
331 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500332 MainApp mainApp(&manager);
Nan Zhoucf811c42021-12-02 14:56:17 -0800333 // install the default certificate that's valid from today to 100 years
334 // later
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500335 mainApp.install(certificateFile);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200336
337 std::vector<std::unique_ptr<Certificate>>& certs =
338 manager.getCertificates();
339
Nan Zhoucf811c42021-12-02 14:56:17 -0800340 ASSERT_EQ(certs.size(), 1);
341 // check some attributes as well
342 EXPECT_EQ(certs.front()->validNotAfter() - certs.front()->validNotBefore(),
343 365000ULL * 24 * 3600);
344 EXPECT_EQ(certs.front()->subject(), "O=openbmc-project.xyz,CN=localhost");
345 EXPECT_EQ(certs.front()->issuer(), "O=openbmc-project.xyz,CN=localhost");
346
347 std::string verifyPath =
348 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
349
350 // Check that certificate has been created at installation directory
351 EXPECT_FALSE(fs::is_empty(verifyDir));
352 EXPECT_TRUE(fs::exists(verifyPath));
353
354 // Check that installed cert is identical to input one
355 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
356}
357
358/** @brief Check if storage install routine is invoked for storage setup
359 */
360TEST_F(TestCertificates, InvokeAuthorityInstallNeverExpiredRootCert)
361{
362 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000363 CertificateType type = CertificateType::authority;
Nan Zhoucf811c42021-12-02 14:56:17 -0800364 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800365 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800366 auto objPath = std::string(objectNamePrefix) + '/' +
367 certificateTypeToString(type) + '/' + endpoint;
Nan Zhoucf811c42021-12-02 14:56:17 -0800368 auto event = sdeventplus::Event::get_default();
369 // Attach the bus to sd_event to service user requests
370 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800371 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
372 certDir);
373 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
374 .WillOnce(Return());
Nan Zhoucf811c42021-12-02 14:56:17 -0800375 MainApp mainApp(&manager);
376
377 // install the certificate that's valid from the Unix Epoch to Dec 31, 9999
378 createNeverExpiredRootCertificate();
379 mainApp.install(certificateFile);
380
381 std::vector<std::unique_ptr<Certificate>>& certs =
382 manager.getCertificates();
383
384 EXPECT_EQ(certs.front()->validNotBefore(), 0);
385 EXPECT_EQ(certs.front()->validNotAfter(), 253402300799ULL);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200386
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100387 std::string verifyPath =
388 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200389
390 // Check that certificate has been created at installation directory
391 EXPECT_FALSE(fs::is_empty(verifyDir));
392 EXPECT_TRUE(fs::exists(verifyPath));
393
394 // Check that installed cert is identical to input one
395 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
396}
397
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100398/** @brief Check if in authority mode user can't install the same
399 * certificate twice.
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200400 */
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100401TEST_F(TestCertificates, InvokeInstallSameCertTwice)
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200402{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200403 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000404 CertificateType type = CertificateType::authority;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200405 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800406 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800407 auto objPath = std::string(objectNamePrefix) + '/' +
408 certificateTypeToString(type) + '/' + endpoint;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200409 auto event = sdeventplus::Event::get_default();
410 // Attach the bus to sd_event to service user requests
411 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800412 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
413 std::move(certDir));
414 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
415 .WillOnce(Return());
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200416 MainApp mainApp(&manager);
417 mainApp.install(certificateFile);
418
419 std::vector<std::unique_ptr<Certificate>>& certs =
420 manager.getCertificates();
421
422 EXPECT_FALSE(certs.empty());
423
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200424 // Check that certificate has been created at installation directory
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100425 std::string verifyPath =
426 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200427 EXPECT_FALSE(fs::is_empty(verifyDir));
428 EXPECT_TRUE(fs::exists(verifyPath));
429
430 // Check that installed cert is identical to input one
431 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
432
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100433 using NotAllowed =
434 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200435 EXPECT_THROW(
436 {
437 try
438 {
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100439 // Try to install the same certificate second time
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200440 mainApp.install(certificateFile);
441 }
442 catch (const NotAllowed& e)
443 {
444 throw;
445 }
446 },
447 NotAllowed);
448
449 // Check that the original certificate has been not removed
450 EXPECT_FALSE(fs::is_empty(verifyDir));
Marri Devender Rao947258d2018-09-25 10:52:24 -0500451 EXPECT_TRUE(fs::exists(verifyPath));
452}
453
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100454/** @brief Check if in authority mode user can install a certificate with
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100455 * certain subject hash twice.
456 */
457TEST_F(TestCertificates, InvokeInstallSameSubjectTwice)
458{
459 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000460 CertificateType type = CertificateType::authority;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100461 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800462 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800463 auto objPath = std::string(objectNamePrefix) + '/' +
464 certificateTypeToString(type) + '/' + endpoint;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100465 auto event = sdeventplus::Event::get_default();
466 // Attach the bus to sd_event to service user requests
467 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800468 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
469 certDir);
470 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
471 .WillOnce(Return())
472 .WillOnce(Return());
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100473 MainApp mainApp(&manager);
474 mainApp.install(certificateFile);
475
476 std::vector<std::unique_ptr<Certificate>>& certs =
477 manager.getCertificates();
478
479 EXPECT_FALSE(certs.empty());
480
481 // Check that certificate has been created at installation directory
482 std::string verifyPath0 =
483 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
484 EXPECT_FALSE(fs::is_empty(verifyDir));
485 EXPECT_TRUE(fs::exists(verifyPath0));
486
487 // Check that installed cert is identical to input one
488 EXPECT_TRUE(compareFiles(certificateFile, verifyPath0));
489
490 // Prepare second certificate with the same subject
491 createNewCertificate();
492
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100493 // Install second certificate
494 mainApp.install(certificateFile);
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100495
496 // Expect there are exactly two certificates in the collection
Zbigniew Lukwinski73d1fbf2020-01-15 15:31:12 +0100497 EXPECT_EQ(certs.size(), 2);
498
499 // Check that certificate has been created at installation directory
500 std::string verifyPath1 =
501 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".1";
502 EXPECT_TRUE(fs::exists(verifyPath1));
503
504 // Check that installed cert is identical to input one
505 EXPECT_TRUE(compareFiles(certificateFile, verifyPath1));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100506
507 // Check that the original/first certificate has been not removed
508 EXPECT_FALSE(fs::is_empty(verifyDir));
509 EXPECT_TRUE(fs::exists(verifyPath0));
510}
511
512/** @brief Check if in authority mode user can't install more than
Nan Zhou718eef32021-12-28 11:03:30 -0800513 * maxNumAuthorityCertificates certificates.
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100514 */
515TEST_F(TestCertificates, InvokeInstallAuthCertLimit)
516{
517 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000518 CertificateType type = CertificateType::authority;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100519 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800520 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800521 auto objPath = std::string(objectNamePrefix) + '/' +
522 certificateTypeToString(type) + '/' + endpoint;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100523 auto event = sdeventplus::Event::get_default();
524 // Attach the bus to sd_event to service user requests
525 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800526 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
527 certDir);
528 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
529 .WillRepeatedly(Return());
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100530 MainApp mainApp(&manager);
531
532 std::vector<std::unique_ptr<Certificate>>& certs =
533 manager.getCertificates();
534
535 std::vector<std::string> verifyPaths;
536
537 // Prepare maximum number of ceritificates
Nan Zhou718eef32021-12-28 11:03:30 -0800538 for (std::size_t i = 0; i < maxNumAuthorityCertificates; ++i)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100539 {
540 // Prepare new certificatate
541 createNewCertificate(true);
542
543 // Install ceritificate
544 mainApp.install(certificateFile);
545
546 // Check number of certificates in the collection
547 EXPECT_EQ(certs.size(), i + 1);
548
549 // Check that certificate has been created at installation directory
550 std::string verifyPath =
551 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
552 EXPECT_FALSE(fs::is_empty(verifyDir));
553 EXPECT_TRUE(fs::exists(verifyPath));
554
555 // Check that installed cert is identical to input one
556 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
557
558 // Save current certificate file for later check
559 verifyPaths.push_back(verifyPath);
560 }
561
562 // Prepare new certificatate
563 createNewCertificate(true);
564
565 using NotAllowed =
566 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
567 EXPECT_THROW(
568 {
569 try
570 {
571 // Try to install one more certificate
572 mainApp.install(certificateFile);
573 }
574 catch (const NotAllowed& e)
575 {
576 throw;
577 }
578 },
579 NotAllowed);
580
581 // Check that the original certificate has been not removed
582 EXPECT_FALSE(fs::is_empty(verifyDir));
Nan Zhou718eef32021-12-28 11:03:30 -0800583 for (size_t i = 0; i < maxNumAuthorityCertificates; ++i)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100584 {
585 EXPECT_TRUE(fs::exists(verifyPaths[i]));
586 }
587}
588
Marri Devender Rao947258d2018-09-25 10:52:24 -0500589/** @brief Compare the installed certificate with the copied certificate
590 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600591TEST_F(TestCertificates, CompareInstalledCertificate)
Marri Devender Rao947258d2018-09-25 10:52:24 -0500592{
593 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000594 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600595 std::string installPath(certDir + "/" + certificateFile);
596 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800597 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800598 auto objPath = std::string(objectNamePrefix) + '/' +
599 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500600 auto event = sdeventplus::Event::get_default();
601 // Attach the bus to sd_event to service user requests
602 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800603 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
604 installPath);
605 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
606 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500607 MainApp mainApp(&manager);
608 mainApp.install(certificateFile);
Marri Devender Rao947258d2018-09-25 10:52:24 -0500609 EXPECT_TRUE(fs::exists(verifyPath));
610 EXPECT_TRUE(compareFiles(verifyPath, certificateFile));
611}
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500612
613/** @brief Check if install fails if certificate file is not found
614 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600615TEST_F(TestCertificates, TestNoCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500616{
617 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000618 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600619 std::string installPath(certDir + "/" + certificateFile);
620 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800621 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800622 auto objPath = std::string(objectNamePrefix) + '/' +
623 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600624 std::string uploadFile = "nofile.pem";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500625 EXPECT_THROW(
626 {
627 try
628 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500629 auto event = sdeventplus::Event::get_default();
630 // Attach the bus to sd_event to service user requests
631 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800632 ManagerInTest manager(bus, event, objPath.c_str(), type,
633 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500634 MainApp mainApp(&manager);
635 mainApp.install(uploadFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500636 }
637 catch (const InternalFailure& e)
638 {
639 throw;
640 }
641 },
642 InternalFailure);
643 EXPECT_FALSE(fs::exists(verifyPath));
644}
645
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500646/** @brief Test replacing existing certificate
647 */
648TEST_F(TestCertificates, TestReplaceCertificate)
649{
650 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000651 CertificateType type = CertificateType::server;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500652 std::string installPath(certDir + "/" + certificateFile);
653 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800654 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800655 auto objPath = std::string(objectNamePrefix) + '/' +
656 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500657 auto event = sdeventplus::Event::get_default();
658 // Attach the bus to sd_event to service user requests
659 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800660 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
661 std::move(installPath));
662 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
663 .WillOnce(Return())
664 .WillOnce(Return());
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500665 MainApp mainApp(&manager);
666 mainApp.install(certificateFile);
667 EXPECT_TRUE(fs::exists(verifyPath));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200668 std::vector<std::unique_ptr<Certificate>>& certs =
669 manager.getCertificates();
670 EXPECT_FALSE(certs.empty());
671 EXPECT_NE(certs[0], nullptr);
672 certs[0]->replace(certificateFile);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500673 EXPECT_TRUE(fs::exists(verifyPath));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200674}
675
676/** @brief Test replacing existing certificate
677 */
678TEST_F(TestCertificates, TestAuthorityReplaceCertificate)
679{
680 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000681 CertificateType type = CertificateType::authority;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200682 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800683 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800684 auto objPath = std::string(objectNamePrefix) + '/' +
685 certificateTypeToString(type) + '/' + endpoint;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200686 auto event = sdeventplus::Event::get_default();
687 // Attach the bus to sd_event to service user requests
688 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800689 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
690 certDir);
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000691 constexpr const unsigned int replaceIterations = 10;
Nan Zhou6ec13c82021-12-30 11:34:50 -0800692 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000693 .Times(replaceIterations + 1)
Nan Zhou6ec13c82021-12-30 11:34:50 -0800694 .WillRepeatedly(Return());
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200695 MainApp mainApp(&manager);
696 mainApp.install(certificateFile);
697
698 std::vector<std::unique_ptr<Certificate>>& certs =
699 manager.getCertificates();
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200700
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000701 for (unsigned int i = 0; i < replaceIterations; i++)
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200702 {
703 // Certificate successfully installed
704 EXPECT_FALSE(certs.empty());
705
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100706 std::string verifyPath =
707 verifyDir + "/" + getCertSubjectNameHash(certificateFile) + ".0";
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200708
709 // Check that certificate has been created at installation directory
710 EXPECT_FALSE(fs::is_empty(verifyDir));
711 EXPECT_TRUE(fs::exists(verifyPath));
712
713 // Check that installed cert is identical to input one
714 EXPECT_TRUE(compareFiles(certificateFile, verifyPath));
715
716 // Create new certificate
717 createNewCertificate(true);
718
719 certs[0]->replace(certificateFile);
720
721 // Verify that old certificate has been removed
722 EXPECT_FALSE(fs::exists(verifyPath));
723 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500724}
725
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200726/** @brief Test verifiing if delete function works.
727 */
728TEST_F(TestCertificates, TestStorageDeleteCertificate)
729{
730 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000731 CertificateType type = CertificateType::authority;
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200732 std::string verifyDir(certDir);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800733 std::string verifyUnit((ManagerInTest::unitToRestartInTest));
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800734 auto objPath = std::string(objectNamePrefix) + '/' +
735 certificateTypeToString(type) + '/' + endpoint;
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200736 auto event = sdeventplus::Event::get_default();
737 // Attach the bus to sd_event to service user requests
738 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800739 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
740 certDir);
741 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
742 .WillRepeatedly(Return());
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200743 MainApp mainApp(&manager);
744
745 // Check if certificate placeholder dir is empty
746 EXPECT_TRUE(fs::is_empty(verifyDir));
747 mainApp.install(certificateFile);
748
749 // Create new certificate
750 createNewCertificate(true);
751 mainApp.install(certificateFile);
752
753 createNewCertificate(true);
754 mainApp.install(certificateFile);
755
756 std::vector<std::unique_ptr<Certificate>>& certs =
757 manager.getCertificates();
758
759 // All 3 certificates successfully installed and added to manager
760 EXPECT_EQ(certs.size(), 3);
761
762 // Check if certificate placeholder is not empty, there should be 3
763 // certificates
764 EXPECT_FALSE(fs::is_empty(verifyDir));
765
766 certs[0]->delete_();
767 EXPECT_EQ(certs.size(), 2);
768
769 certs[0]->delete_();
770 EXPECT_EQ(certs.size(), 1);
771
772 certs[0]->delete_();
773 EXPECT_EQ(certs.size(), 0);
774
775 // Check if certificate placeholder is empty.
776 EXPECT_TRUE(fs::is_empty(verifyDir));
777}
778
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500779/** @brief Check if install fails if certificate file is empty
780 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600781TEST_F(TestCertificates, TestEmptyCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500782{
783 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000784 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600785 std::string installPath(certDir + "/" + certificateFile);
786 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800787 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800788 auto objPath = std::string(objectNamePrefix) + '/' +
789 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500790 std::string emptyFile("emptycert.pem");
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500791 std::ofstream ofs;
792 ofs.open(emptyFile, std::ofstream::out);
793 ofs.close();
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500794 EXPECT_THROW(
795 {
796 try
797 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500798 auto event = sdeventplus::Event::get_default();
799 // Attach the bus to sd_event to service user requests
800 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800801 ManagerInTest manager(bus, event, objPath.c_str(), type,
802 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500803 MainApp mainApp(&manager);
804 mainApp.install(emptyFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500805 }
806 catch (const InvalidCertificate& e)
807 {
808 throw;
809 }
810 },
811 InvalidCertificate);
812 EXPECT_FALSE(fs::exists(verifyPath));
813 fs::remove(emptyFile);
814}
815
Marri Devender Raoddf64862018-10-03 07:11:02 -0500816/** @brief Check if install fails if certificate file is corrupted
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500817 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600818TEST_F(TestCertificates, TestInvalidCertificateFile)
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500819{
820 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000821 CertificateType type = CertificateType::client;
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500822
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500823 std::ofstream ofs;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500824 ofs.open(certificateFile, std::ofstream::out);
825 ofs << "-----BEGIN CERTIFICATE-----";
826 ofs << "ADD_SOME_INVALID_DATA_INTO_FILE";
827 ofs << "-----END CERTIFICATE-----";
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500828 ofs.close();
829
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600830 std::string installPath(certDir + "/" + certificateFile);
831 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800832 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800833 auto objPath = std::string(objectNamePrefix) + '/' +
834 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500835 EXPECT_THROW(
836 {
837 try
838 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500839 auto event = sdeventplus::Event::get_default();
840 // Attach the bus to sd_event to service user requests
841 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800842 ManagerInTest manager(bus, event, objPath.c_str(), type,
843 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500844 MainApp mainApp(&manager);
845 mainApp.install(certificateFile);
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500846 }
847 catch (const InvalidCertificate& e)
848 {
849 throw;
850 }
851 },
852 InvalidCertificate);
853 EXPECT_FALSE(fs::exists(verifyPath));
Marri Devender Raoe6597c52018-10-01 06:36:55 -0500854}
Marri Devender Raoddf64862018-10-03 07:11:02 -0500855
856/**
857 * Class to generate private and certificate only file and test verification
858 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600859class TestInvalidCertificate : public ::testing::Test
Marri Devender Raoddf64862018-10-03 07:11:02 -0500860{
861 public:
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600862 TestInvalidCertificate() : bus(sdbusplus::bus::new_default())
Marri Devender Raoddf64862018-10-03 07:11:02 -0500863 {
864 }
865 void SetUp() override
866 {
867 char dirTemplate[] = "/tmp/FakeCerts.XXXXXX";
868 auto dirPtr = mkdtemp(dirTemplate);
Nan Zhoucfb58022021-12-28 11:02:26 -0800869 if (dirPtr == nullptr)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500870 {
871 throw std::bad_alloc();
872 }
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100873 certDir = std::string(dirPtr) + "/certs";
874 fs::create_directories(certDir);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500875 certificateFile = "cert.pem";
876 keyFile = "key.pem";
877 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 ";
878 cmd += "-keyout key.pem -out cert.pem -days 3650 ";
879 cmd += "-subj "
880 "/O=openbmc-project.xyz/CN=localhost"
881 " -nodes";
882
883 auto val = std::system(cmd.c_str());
884 if (val)
885 {
886 std::cout << "command Error: " << val << std::endl;
887 }
888 }
889 void TearDown() override
890 {
891 fs::remove_all(certDir);
892 fs::remove(certificateFile);
893 fs::remove(keyFile);
894 }
895
896 protected:
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500897 sdbusplus::bus_t bus;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500898 std::string certificateFile;
899 std::string keyFile;
900 std::string certDir;
901};
902
903/** @brief Check install fails if private key is missing in certificate file
904 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600905TEST_F(TestInvalidCertificate, TestMissingPrivateKey)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500906{
907 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000908 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600909 std::string installPath(certDir + "/" + certificateFile);
910 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800911 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800912 auto objPath = std::string(objectNamePrefix) + '/' +
913 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600914 EXPECT_THROW(
915 {
916 try
917 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500918 auto event = sdeventplus::Event::get_default();
919 // Attach the bus to sd_event to service user requests
920 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800921 ManagerInTest manager(bus, event, objPath.c_str(), type,
922 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500923 MainApp mainApp(&manager);
924 mainApp.install(certificateFile);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600925 }
Marri Devender Raocd30c492019-06-12 01:40:17 -0500926 catch (const InternalFailure& e)
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600927 {
928 throw;
929 }
930 },
Marri Devender Raocd30c492019-06-12 01:40:17 -0500931 InternalFailure);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600932 EXPECT_FALSE(fs::exists(verifyPath));
933}
934
935/** @brief Check install fails if ceritificate is missing in certificate file
936 */
937TEST_F(TestInvalidCertificate, TestMissingCeritificate)
938{
939 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000940 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600941 std::string installPath(certDir + "/" + keyFile);
942 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800943 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800944 auto objPath = std::string(objectNamePrefix) + '/' +
945 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600946 EXPECT_THROW(
947 {
948 try
949 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500950 auto event = sdeventplus::Event::get_default();
951 // Attach the bus to sd_event to service user requests
952 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800953 ManagerInTest manager(bus, event, objPath.c_str(), type,
954 verifyUnit, installPath);
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500955 MainApp mainApp(&manager);
956 mainApp.install(keyFile);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500957 }
Marri Devender Raocd30c492019-06-12 01:40:17 -0500958 catch (const InternalFailure& e)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500959 {
960 throw;
961 }
962 },
963 InvalidCertificate);
964 EXPECT_FALSE(fs::exists(verifyPath));
965}
966
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600967/** @brief Check if error is thrown when multiple certificates are installed
968 * At present only one certificate per service is allowed
Marri Devender Raoddf64862018-10-03 07:11:02 -0500969 */
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600970TEST_F(TestCertificates, TestCertInstallNotAllowed)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500971{
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600972 using NotAllowed =
973 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
Marri Devender Raoddf64862018-10-03 07:11:02 -0500974 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000975 CertificateType type = CertificateType::client;
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600976 std::string installPath(certDir + "/" + certificateFile);
977 std::string verifyPath(installPath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800978 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800979 auto objPath = std::string(objectNamePrefix) + '/' +
980 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -0500981 auto event = sdeventplus::Event::get_default();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500982 // Attach the bus to sd_event to service user requests
983 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800984 ManagerInTest manager(bus, event, objPath.c_str(), type, verifyUnit,
985 installPath);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500986 MainApp mainApp(&manager);
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600987 mainApp.install(certificateFile);
988 EXPECT_TRUE(fs::exists(verifyPath));
Marri Devender Raoddf64862018-10-03 07:11:02 -0500989 EXPECT_THROW(
990 {
991 try
992 {
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600993 // install second certificate
994 mainApp.install(certificateFile);
Marri Devender Raoddf64862018-10-03 07:11:02 -0500995 }
Marri Devender Rao8841dbd2019-03-04 05:43:55 -0600996 catch (const NotAllowed& e)
Marri Devender Raoddf64862018-10-03 07:11:02 -0500997 {
998 throw;
999 }
1000 },
Marri Devender Rao8841dbd2019-03-04 05:43:55 -06001001 NotAllowed);
Marri Devender Rao9abfae82018-10-03 08:10:35 -05001002}
Marri Devender Raof4682712019-03-19 05:00:28 -05001003
1004TEST_F(TestCertificates, TestGenerateCSR)
1005{
1006 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001007 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001008 CertificateType type = CertificateType::server;
Marri Devender Raof4682712019-03-19 05:00:28 -05001009 std::string installPath(certDir + "/" + certificateFile);
1010 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001011 std::string csrPath(certDir + "/" + CSRFile);
Marri Devender Raof4682712019-03-19 05:00:28 -05001012 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1013 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001014 std::string challengePassword("Password");
Marri Devender Raof4682712019-03-19 05:00:28 -05001015 std::string city("HYB");
1016 std::string commonName("abc.com");
1017 std::string contactPerson("Admin");
1018 std::string country("IN");
1019 std::string email("admin@in.ibm.com");
1020 std::string givenName("givenName");
1021 std::string initials("G");
1022 int64_t keyBitLength(2048);
1023 std::string keyCurveId("0");
1024 std::string keyPairAlgorithm("RSA");
1025 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1026 std::string organization("IBM");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001027 std::string organizationalUnit("orgUnit");
Marri Devender Raof4682712019-03-19 05:00:28 -05001028 std::string state("TS");
1029 std::string surname("surname");
1030 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001031 auto objPath = std::string(objectNamePrefix) + '/' +
1032 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -05001033 auto event = sdeventplus::Event::get_default();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -05001034 // Attach the bus to sd_event to service user requests
1035 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
Marri Devender Raof4682712019-03-19 05:00:28 -05001036 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1037 std::move(installPath));
1038 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001039 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Marri Devender Raof4682712019-03-19 05:00:28 -05001040 MainApp mainApp(&manager, &csr);
1041 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1042 contactPerson, country, email, givenName, initials,
1043 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1044 organization, organizationalUnit, state, surname,
1045 unstructuredName);
1046 std::string csrData("");
1047 // generateCSR takes considerable time to create CSR and privateKey Files
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001048 EXPECT_FALSE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001049 EXPECT_FALSE(fs::exists(privateKeyPath));
1050 EXPECT_THROW(
1051 {
1052 try
1053 {
Patrick Williamse129be32021-04-30 20:35:19 -05001054 csrData = csr.csr();
Marri Devender Raof4682712019-03-19 05:00:28 -05001055 }
1056 catch (const InternalFailure& e)
1057 {
1058 throw;
1059 }
1060 },
1061 InternalFailure);
1062 // wait for 10 sec to get CSR and privateKey Files generated
1063 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001064 EXPECT_TRUE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001065 EXPECT_TRUE(fs::exists(privateKeyPath));
Patrick Williamse129be32021-04-30 20:35:19 -05001066 csrData = csr.csr();
Marri Devender Raof4682712019-03-19 05:00:28 -05001067 ASSERT_NE("", csrData.c_str());
1068}
1069
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001070/** @brief Check if ECC key pair is generated when user is not given algorithm
1071 * type. At present RSA and EC key pair algorithm are supported
1072 */
1073TEST_F(TestCertificates, TestGenerateCSRwithEmptyKeyPairAlgorithm)
1074{
1075 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001076 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001077 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001078 std::string installPath(certDir + "/" + certificateFile);
1079 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001080 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001081 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1082 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1083 std::string challengePassword("Password");
1084 std::string city("HYB");
1085 std::string commonName("abc.com");
1086 std::string contactPerson("Admin");
1087 std::string country("IN");
1088 std::string email("admin@in.ibm.com");
1089 std::string givenName("givenName");
1090 std::string initials("G");
1091 int64_t keyBitLength(2048);
1092 std::string keyCurveId("");
1093 std::string keyPairAlgorithm("");
1094 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1095 std::string organization("IBM");
1096 std::string organizationalUnit("orgUnit");
1097 std::string state("TS");
1098 std::string surname("surname");
1099 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001100 auto objPath = std::string(objectNamePrefix) + '/' +
1101 certificateTypeToString(type) + '/' + endpoint;
Marri Devender Raof4682712019-03-19 05:00:28 -05001102 auto event = sdeventplus::Event::get_default();
1103 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1104 std::move(installPath));
1105 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001106 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Marri Devender Raof4682712019-03-19 05:00:28 -05001107 MainApp mainApp(&manager, &csr);
1108 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1109 contactPerson, country, email, givenName, initials,
1110 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1111 organization, organizationalUnit, state, surname,
1112 unstructuredName);
1113 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001114 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001115 EXPECT_TRUE(fs::exists(privateKeyPath));
1116}
1117
1118/** @brief Check if error is thrown when giving un supported key pair
1119 * algorithm. At present RSA and EC key pair algorithm are supported
1120 */
1121TEST_F(TestCertificates, TestGenerateCSRwithUnsupportedKeyPairAlgorithm)
1122{
1123 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001124 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001125 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001126 std::string installPath(certDir + "/" + certificateFile);
1127 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001128 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001129 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1130 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1131 std::string challengePassword("Password");
1132 std::string city("HYB");
1133 std::string commonName("abc.com");
1134 std::string contactPerson("Admin");
1135 std::string country("IN");
1136 std::string email("admin@in.ibm.com");
1137 std::string givenName("givenName");
1138 std::string initials("G");
1139 int64_t keyBitLength(2048);
1140 std::string keyCurveId("secp521r1");
1141 std::string keyPairAlgorithm("UnSupportedAlgorithm");
1142 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1143 std::string organization("IBM");
1144 std::string organizationalUnit("orgUnit");
1145 std::string state("TS");
1146 std::string surname("surname");
1147 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001148 auto objPath = std::string(objectNamePrefix) + '/' +
1149 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001150 auto event = sdeventplus::Event::get_default();
1151 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1152 std::move(installPath));
1153 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001154 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001155 MainApp mainApp(&manager, &csr);
1156 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1157 contactPerson, country, email, givenName, initials,
1158 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1159 organization, organizationalUnit, state, surname,
1160 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001161 EXPECT_FALSE(fs::exists(csrPath));
Marri Devender Raof4682712019-03-19 05:00:28 -05001162 EXPECT_FALSE(fs::exists(privateKeyPath));
1163}
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001164
1165/** @brief Check if error is thrown when NID_undef is returned for given key
1166 * curve id
1167 */
1168TEST_F(TestCertificates, TestECKeyGenerationwithNIDundefCase)
1169{
1170 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001171 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001172 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001173 std::string installPath(certDir + "/" + certificateFile);
1174 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001175 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001176 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1177 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1178 std::string challengePassword("Password");
1179 std::string city("BLR");
1180 std::string commonName("abc.com");
1181 std::string contactPerson("Admin");
1182 std::string country("IN");
1183 std::string email("admin@in.ibm.com");
1184 std::string givenName("givenName");
1185 std::string initials("G");
1186 int64_t keyBitLength(2048);
1187 std::string keyCurveId("DummyCurveName");
1188 std::string keyPairAlgorithm("EC");
1189 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1190 std::string organization("IBM");
1191 std::string organizationalUnit("orgUnit");
1192 std::string state("TS");
1193 std::string surname("surname");
1194 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001195 auto objPath = std::string(objectNamePrefix) + '/' +
1196 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001197 auto event = sdeventplus::Event::get_default();
1198 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1199 std::move(installPath));
1200 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001201 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001202 MainApp mainApp(&manager, &csr);
1203 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1204 contactPerson, country, email, givenName, initials,
1205 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1206 organization, organizationalUnit, state, surname,
1207 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001208 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001209 EXPECT_FALSE(fs::exists(privateKeyPath));
1210}
1211
1212/** @brief Check default Key Curve Id is used if given curve id is empty
1213 */
1214TEST_F(TestCertificates, TestECKeyGenerationwithDefaultKeyCurveId)
1215{
1216 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001217 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001218 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001219 std::string installPath(certDir + "/" + certificateFile);
1220 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001221 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001222 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1223 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1224 std::string challengePassword("Password");
1225 std::string city("BLR");
1226 std::string commonName("abc.com");
1227 std::string contactPerson("Admin");
1228 std::string country("IN");
1229 std::string email("admin@in.ibm.com");
1230 std::string givenName("givenName");
1231 std::string initials("G");
1232 int64_t keyBitLength(2048);
1233 std::string keyCurveId("");
1234 std::string keyPairAlgorithm("EC");
1235 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1236 std::string organization("IBM");
1237 std::string organizationalUnit("orgUnit");
1238 std::string state("TS");
1239 std::string surname("surname");
1240 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001241 auto objPath = std::string(objectNamePrefix) + '/' +
1242 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001243 auto event = sdeventplus::Event::get_default();
1244 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1245 std::move(installPath));
1246 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001247 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001248 MainApp mainApp(&manager, &csr);
1249 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1250 contactPerson, country, email, givenName, initials,
1251 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1252 organization, organizationalUnit, state, surname,
1253 unstructuredName);
1254 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001255 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001256 EXPECT_TRUE(fs::exists(privateKeyPath));
1257}
1258
1259/** @brief Check if error is not thrown to generate EC key pair
1260 */
1261TEST_F(TestCertificates, TestECKeyGeneration)
1262{
1263 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001264 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001265 CertificateType type = CertificateType::server;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001266 std::string installPath(certDir + "/" + certificateFile);
1267 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001268 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001269 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1270 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1271 std::string challengePassword("Password");
1272 std::string city("BLR");
1273 std::string commonName("abc.com");
1274 std::string contactPerson("Admin");
1275 std::string country("IN");
1276 std::string email("admin@in.ibm.com");
1277 std::string givenName("givenName");
1278 std::string initials("G");
1279 int64_t keyBitLength(2048);
1280 std::string keyCurveId("secp521r1");
1281 std::string keyPairAlgorithm("EC");
1282 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1283 std::string organization("IBM");
1284 std::string organizationalUnit("orgUnit");
1285 std::string state("TS");
1286 std::string surname("surname");
1287 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001288 auto objPath = std::string(objectNamePrefix) + '/' +
1289 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001290 auto event = sdeventplus::Event::get_default();
1291 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1292 std::move(installPath));
1293 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001294 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001295 MainApp mainApp(&manager, &csr);
1296 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1297 contactPerson, country, email, givenName, initials,
1298 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1299 organization, organizationalUnit, state, surname,
1300 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001301 std::cout << "CSRPath: " << csrPath << std::endl
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001302 << "privateKeyPath: " << privateKeyPath << std::endl;
1303 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001304 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyar8a09b522019-06-07 05:23:29 -05001305 EXPECT_TRUE(fs::exists(privateKeyPath));
1306}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001307
Nan Zhoubf3cf752021-12-28 11:02:07 -08001308/** @brief Check error is thrown if giving unsupported key bit length to
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001309 * generate rsa key
1310 */
1311TEST_F(TestCertificates, TestRSAKeyWithUnsupportedKeyBitLength)
1312{
1313 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001314 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001315 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001316 std::string installPath(certDir + "/" + certificateFile);
1317 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001318 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001319 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1320 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1321 std::string challengePassword("Password");
1322 std::string city("BLR");
1323 std::string commonName("abc.com");
1324 std::string contactPerson("Admin");
1325 std::string country("IN");
1326 std::string email("admin@in.ibm.com");
1327 std::string givenName("givenName");
1328 std::string initials("G");
1329 int64_t keyBitLength(4096);
1330 std::string keyCurveId("secp521r1");
1331 std::string keyPairAlgorithm("RSA");
1332 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1333 std::string organization("IBM");
1334 std::string organizationalUnit("orgUnit");
1335 std::string state("TS");
1336 std::string surname("surname");
1337 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001338 auto objPath = std::string(objectNamePrefix) + '/' +
1339 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001340 auto event = sdeventplus::Event::get_default();
1341 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1342 std::move(installPath));
1343 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001344 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001345 MainApp mainApp(&manager, &csr);
1346 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1347 contactPerson, country, email, givenName, initials,
1348 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1349 organization, organizationalUnit, state, surname,
1350 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001351 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001352 EXPECT_FALSE(fs::exists(privateKeyPath));
1353}
1354
1355/** @brief Check error is thrown if generated rsa key file is not present
1356 */
1357TEST_F(TestCertificates, TestRSAKeyFileNotPresentCase)
1358{
1359 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001360 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001361 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001362 std::string installPath(certDir + "/" + certificateFile);
1363 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001364 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001365 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1366 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1367 std::string challengePassword("Password");
1368 std::string city("BLR");
1369 std::string commonName("abc.com");
1370 std::string contactPerson("Admin");
1371 std::string country("IN");
1372 std::string email("admin@in.ibm.com");
1373 std::string givenName("givenName");
1374 std::string initials("G");
1375 int64_t keyBitLength(2048);
1376 std::string keyCurveId("secp521r1");
1377 std::string keyPairAlgorithm("RSA");
1378 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1379 std::string organization("IBM");
1380 std::string organizationalUnit("orgUnit");
1381 std::string state("TS");
1382 std::string surname("surname");
1383 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001384 auto objPath = std::string(objectNamePrefix) + '/' +
1385 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001386 auto event = sdeventplus::Event::get_default();
1387 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1388 std::move(installPath));
1389
1390 // Removing generated RSA key file
1391 fs::remove(rsaPrivateKeyFilePath);
1392
1393 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001394 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001395 MainApp mainApp(&manager, &csr);
1396 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1397 contactPerson, country, email, givenName, initials,
1398 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1399 organization, organizationalUnit, state, surname,
1400 unstructuredName);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001401 EXPECT_FALSE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001402 EXPECT_FALSE(fs::exists(privateKeyPath));
1403}
1404
1405/** @brief Check private key file is created from generated rsa key file is
1406 * `present
1407 */
1408TEST_F(TestCertificates, TestRSAKeyFromRSAKeyFileIsWrittenIntoPrivateKeyFile)
1409{
1410 std::string endpoint("https");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001411 std::string unit;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001412 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001413 std::string installPath(certDir + "/" + certificateFile);
1414 std::string verifyPath(installPath);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001415 std::string csrPath(certDir + "/" + CSRFile);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001416 std::string privateKeyPath(certDir + "/" + privateKeyFile);
1417 std::vector<std::string> alternativeNames{"localhost1", "localhost2"};
1418 std::string challengePassword("Password");
1419 std::string city("BLR");
1420 std::string commonName("abc.com");
1421 std::string contactPerson("Admin");
1422 std::string country("IN");
1423 std::string email("admin@in.ibm.com");
1424 std::string givenName("givenName");
1425 std::string initials("G");
1426 int64_t keyBitLength(2048);
1427 std::string keyCurveId("secp521r1");
1428 std::string keyPairAlgorithm("RSA");
1429 std::vector<std::string> keyUsage{"serverAuth", "clientAuth"};
1430 std::string organization("IBM");
1431 std::string organizationalUnit("orgUnit");
1432 std::string state("TS");
1433 std::string surname("surname");
1434 std::string unstructuredName("unstructuredName");
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001435 auto objPath = std::string(objectNamePrefix) + '/' +
1436 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001437 auto event = sdeventplus::Event::get_default();
1438 Manager manager(bus, event, objPath.c_str(), type, std::move(unit),
1439 std::move(installPath));
1440 Status status;
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001441 CSR csr(bus, objPath.c_str(), csrPath.c_str(), status);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001442 MainApp mainApp(&manager, &csr);
1443 mainApp.generateCSR(alternativeNames, challengePassword, city, commonName,
1444 contactPerson, country, email, givenName, initials,
1445 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
1446 organization, organizationalUnit, state, surname,
1447 unstructuredName);
1448 sleep(10);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001449 EXPECT_TRUE(fs::exists(csrPath));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001450 EXPECT_TRUE(fs::exists(privateKeyPath));
1451}
1452
Nan Zhoubf3cf752021-12-28 11:02:07 -08001453/** @brief Check RSA key is generated during application startup*/
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001454TEST_F(TestCertificates, TestGenerateRSAPrivateKeyFile)
1455{
1456 std::string endpoint("https");
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001457 CertificateType type = CertificateType::server;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001458 std::string installPath(certDir + "/" + certificateFile);
Nan Zhou6ec13c82021-12-30 11:34:50 -08001459 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001460 auto objPath = std::string(objectNamePrefix) + '/' +
1461 certificateTypeToString(type) + '/' + endpoint;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001462 auto event = sdeventplus::Event::get_default();
1463
1464 EXPECT_FALSE(fs::exists(rsaPrivateKeyFilePath));
Nan Zhou6ec13c82021-12-30 11:34:50 -08001465 Manager manager(bus, event, objPath.c_str(), type, verifyUnit, installPath);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001466 EXPECT_TRUE(fs::exists(rsaPrivateKeyFilePath));
1467}
Nan Zhou6ec13c82021-12-30 11:34:50 -08001468
1469/**
1470 * Class to test Authorities List installation and replacement
1471 */
1472class AuthoritiesListTest : public testing::Test
1473{
1474 public:
1475 AuthoritiesListTest() :
1476 bus(sdbusplus::bus::new_default()),
1477 authoritiesListFolder(
1478 Certificate::generateUniqueFilePath(fs::temp_directory_path()))
1479 {
1480 fs::create_directory(authoritiesListFolder);
1481 createAuthoritiesList(maxNumAuthorityCertificates);
1482 }
1483 ~AuthoritiesListTest() override
1484 {
1485 fs::remove_all(authoritiesListFolder);
1486 }
1487
1488 protected:
1489 // Creates a testing authorities list which consists of |count| root
1490 // certificates
1491 void createAuthoritiesList(int count)
1492 {
1493 fs::path srcFolder = fs::temp_directory_path();
1494 srcFolder = Certificate::generateUniqueFilePath(srcFolder);
1495 fs::create_directory(srcFolder);
1496 createSingleAuthority(srcFolder, "root_0");
1497 sourceAuthoritiesListFile = srcFolder / "root_0_cert";
1498 for (int i = 1; i < count; ++i)
1499 {
1500 std::string name = "root_" + std::to_string(i);
1501 createSingleAuthority(srcFolder, name);
1502 appendContentFromFile(sourceAuthoritiesListFile,
1503 srcFolder / (name + "_cert"));
1504 }
1505 }
1506
1507 // Creates a single self-signed root certificate in given |path|; the key
1508 // will be |path|/|cn|_key, the cert will be |path|/|cn|_cert, and the cn
1509 // will be "/O=openbmc-project.xyz/C=US/ST=CA/CN=|cn|"
1510 static void createSingleAuthority(const std::string& path,
1511 const std::string& cn)
1512 {
1513 std::string key = fs::path(path) / (cn + "_key");
1514 std::string cert = fs::path(path) / (cn + "_cert");
1515 std::string cmd = "openssl req -x509 -sha256 -newkey rsa:2048 -keyout ";
1516 cmd += key + " -out " + cert + " -nodes --days 365000 ";
1517 cmd += "-subj /O=openbmc-project.xyz/CN=" + cn;
1518 ASSERT_EQ(std::system(cmd.c_str()), 0);
1519 }
1520
1521 // Appends the content of the |from| file to the |to| file.
1522 static void appendContentFromFile(const std::string& to,
1523 const std::string& from)
1524 {
1525 ASSERT_NO_THROW({
1526 std::ifstream inputCertFileStream;
1527 std::ofstream outputCertFileStream;
1528 inputCertFileStream.exceptions(std::ifstream::failbit |
1529 std::ifstream::badbit |
1530 std::ifstream::eofbit);
1531 outputCertFileStream.exceptions(std::ofstream::failbit |
1532 std::ofstream::badbit |
1533 std::ofstream::eofbit);
1534 inputCertFileStream.open(from);
1535 outputCertFileStream.open(to, std::ios::app);
1536 outputCertFileStream << inputCertFileStream.rdbuf() << std::flush;
1537 inputCertFileStream.close();
1538 outputCertFileStream.close();
1539 });
1540 }
1541
1542 // Appends the content of the |from| buffer to the |to| file.
1543 static void setContentFromString(const std::string& to,
1544 const std::string& from)
1545 {
1546 ASSERT_NO_THROW({
1547 std::ofstream outputCertFileStream;
1548 outputCertFileStream.exceptions(std::ofstream::failbit |
1549 std::ofstream::badbit |
1550 std::ofstream::eofbit);
1551 outputCertFileStream.open(to, std::ios::out);
1552 outputCertFileStream << from << std::flush;
1553 outputCertFileStream.close();
1554 });
1555 }
1556
1557 // Verifies the effect of InstallAll or ReplaceAll
1558 void verifyCertificates(std::vector<std::unique_ptr<Certificate>>& certs)
1559 {
1560 // The trust bundle file has been copied over
1561 EXPECT_FALSE(fs::is_empty(authoritiesListFolder));
1562 EXPECT_TRUE(
1563 compareFiles(authoritiesListFolder / defaultAuthoritiesListFileName,
1564 sourceAuthoritiesListFile));
1565
1566 ASSERT_EQ(certs.size(), maxNumAuthorityCertificates);
1567 // Check attributes and alias
1568 for (size_t i = 0; i < certs.size(); ++i)
1569 {
1570 std::string name = "root_" + std::to_string(i);
1571 EXPECT_EQ(certs[i]->subject(), "O=openbmc-project.xyz,CN=" + name);
1572 EXPECT_EQ(certs[i]->issuer(), "O=openbmc-project.xyz,CN=" + name);
1573 std::string symbolLink =
1574 authoritiesListFolder /
1575 (certs[i]->getCertId().substr(0, 8) + ".0");
1576 ASSERT_TRUE(fs::exists(symbolLink));
1577 compareFileAgainstString(symbolLink, certs[i]->certificateString());
1578 }
1579 }
1580
1581 // Expects that the content of |path| file is |buffer|.
1582 static void compareFileAgainstString(const std::string& path,
1583 const std::string& buffer)
1584 {
1585 ASSERT_NO_THROW({
1586 std::ifstream inputCertFileStream;
1587 inputCertFileStream.exceptions(std::ifstream::failbit |
1588 std::ifstream::badbit |
1589 std::ifstream::eofbit);
1590 inputCertFileStream.open(path);
1591 std::stringstream read;
1592 read << inputCertFileStream.rdbuf();
1593 inputCertFileStream.close();
1594 EXPECT_EQ(read.str(), buffer);
1595 });
1596 };
1597
Patrick Williamsb3dbfb32022-07-22 19:26:57 -05001598 sdbusplus::bus_t bus;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001599 fs::path authoritiesListFolder;
1600 fs::path sourceAuthoritiesListFile;
1601};
1602
1603// Tests that the Authority Manager installs all the certificates in an
1604// authorities list
1605TEST_F(AuthoritiesListTest, InstallAll)
1606{
1607 std::string endpoint("ldap");
1608 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001609 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001610
1611 std::string object = std::string(objectNamePrefix) + '/' +
1612 certificateTypeToString(type) + '/' + endpoint;
1613 auto event = sdeventplus::Event::get_default();
1614 // Attach the bus to sd_event to service user requests
1615 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1616 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1617 authoritiesListFolder);
1618 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1619 .WillOnce(Return());
1620 ASSERT_TRUE(manager.getCertificates().empty());
1621
1622 std::vector<sdbusplus::message::object_path> objects =
1623 manager.installAll(sourceAuthoritiesListFile);
1624 for (size_t i = 0; i < manager.getCertificates().size(); ++i)
1625 {
1626 EXPECT_EQ(manager.getCertificates()[i]->getObjectPath(), objects[i]);
1627 }
1628 verifyCertificates(manager.getCertificates());
1629}
1630
1631// Tests that the Authority Manager recovers from the authorities list persisted
1632// in the installation path at boot up
1633TEST_F(AuthoritiesListTest, RecoverAtBootUp)
1634{
1635 std::string endpoint("ldap");
1636 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001637 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001638
1639 std::string object = std::string(objectNamePrefix) + '/' +
1640 certificateTypeToString(type) + '/' + endpoint;
1641 auto event = sdeventplus::Event::get_default();
1642 // Attach the bus to sd_event to service user requests
1643 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1644
1645 // Copy the trust bundle into the installation path before creating an
1646 // Authority Manager
1647 fs::copy_file(/*from=*/sourceAuthoritiesListFile,
1648 authoritiesListFolder / defaultAuthoritiesListFileName);
1649 // Create some noise as well
1650 fs::copy_file(/*from=*/sourceAuthoritiesListFile,
1651 authoritiesListFolder / "should_be_deleted");
1652
1653 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1654 authoritiesListFolder);
1655
1656 ASSERT_EQ(manager.getCertificates().size(), maxNumAuthorityCertificates);
1657
1658 // Check attributes and alias
1659 std::unordered_set<std::string> expectedFiles = {authoritiesListFolder /
1660 "trust_bundle"};
1661 std::vector<std::unique_ptr<Certificate>>& certs =
1662 manager.getCertificates();
1663 for (size_t i = 0; i < certs.size(); ++i)
1664 {
1665 std::string name = "root_" + std::to_string(i);
1666 EXPECT_EQ(certs[i]->subject(), "O=openbmc-project.xyz,CN=" + name);
1667 EXPECT_EQ(certs[i]->issuer(), "O=openbmc-project.xyz,CN=" + name);
1668 std::string symbolLink =
1669 authoritiesListFolder / (certs[i]->getCertId().substr(0, 8) + ".0");
1670 expectedFiles.insert(symbolLink);
1671 expectedFiles.insert(certs[i]->getCertFilePath());
1672 ASSERT_TRUE(fs::exists(symbolLink));
1673 compareFileAgainstString(symbolLink, certs[i]->certificateString());
1674 }
1675
1676 // Check folder content
1677 for (auto& path : fs::directory_iterator(authoritiesListFolder))
1678 {
1679 EXPECT_NE(path, authoritiesListFolder / "should_be_deleted");
1680 expectedFiles.erase(path.path());
1681 }
1682 EXPECT_TRUE(expectedFiles.empty());
1683}
1684
1685TEST_F(AuthoritiesListTest, InstallAndDelete)
1686{
1687 std::string endpoint("ldap");
1688 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001689 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001690
1691 std::string object = std::string(objectNamePrefix) + '/' +
1692 certificateTypeToString(type) + '/' + endpoint;
1693
1694 auto event = sdeventplus::Event::get_default();
1695 // Attach the bus to sd_event to service user requests
1696 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1697 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1698 authoritiesListFolder);
1699 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1700 .WillOnce(Return())
1701 .WillOnce(Return());
1702 ASSERT_TRUE(manager.getCertificates().empty());
1703 ASSERT_EQ(manager.installAll(sourceAuthoritiesListFile).size(),
1704 maxNumAuthorityCertificates);
1705 manager.deleteAll();
1706 EXPECT_TRUE(manager.getCertificates().empty());
1707 // Check folder content
1708 for (const fs::path& f : fs::directory_iterator(authoritiesListFolder))
1709 {
1710 EXPECT_THAT(f.filename(), testing::AnyOf(".", ".."));
1711 }
1712}
1713
1714TEST_F(AuthoritiesListTest, InstallAllWrongManagerType)
1715{
1716 std::string endpoint("ldap");
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001717 CertificateType type = CertificateType::server;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001718
1719 std::string object = std::string(objectNamePrefix) + '/' +
1720 certificateTypeToString(type) + '/' + endpoint;
1721
1722 auto event = sdeventplus::Event::get_default();
1723 // Attach the bus to sd_event to service user requests
1724 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1725 ManagerInTest serverManager(bus, event, object.c_str(), type, "",
1726 authoritiesListFolder);
1727 EXPECT_THROW(serverManager.installAll(sourceAuthoritiesListFile),
1728 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1729
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001730 type = CertificateType::client;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001731 object = std::string(objectNamePrefix) + '/' +
1732 certificateTypeToString(type) + '/' + endpoint;
1733 ManagerInTest clientManager(bus, event, object.c_str(), type, "",
1734 authoritiesListFolder);
1735 EXPECT_THROW(clientManager.installAll(sourceAuthoritiesListFile),
1736 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1737}
1738
1739TEST_F(AuthoritiesListTest, InstallAllTwice)
1740{
1741 std::string endpoint("ldap");
1742 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001743 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001744
1745 std::string object = std::string(objectNamePrefix) + '/' +
1746 certificateTypeToString(type) + '/' + endpoint;
1747
1748 auto event = sdeventplus::Event::get_default();
1749 // Attach the bus to sd_event to service user requests
1750 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1751 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1752 authoritiesListFolder);
1753 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1754 .WillOnce(Return());
1755 ASSERT_TRUE(manager.getCertificates().empty());
1756
1757 ASSERT_EQ(manager.installAll(sourceAuthoritiesListFile).size(),
1758 maxNumAuthorityCertificates);
Nan Zhou56bfa732022-09-16 01:15:29 +00001759 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
Nan Zhou6ec13c82021-12-30 11:34:50 -08001760 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1761}
1762
1763TEST_F(AuthoritiesListTest, InstallAllMissSourceFile)
1764{
1765 std::string endpoint("ldap");
1766 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001767 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001768
1769 std::string object = std::string(objectNamePrefix) + '/' +
1770 certificateTypeToString(type) + '/' + endpoint;
1771
1772 auto event = sdeventplus::Event::get_default();
1773 // Attach the bus to sd_event to service user requests
1774 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1775 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1776 authoritiesListFolder);
1777
1778 EXPECT_THROW(manager.installAll(authoritiesListFolder / "trust_bundle"),
1779 InternalFailure);
1780}
1781
1782TEST_F(AuthoritiesListTest, TooManyRootCertificates)
1783{
1784 std::string endpoint("ldap");
1785 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001786 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001787
1788 std::string object = std::string(objectNamePrefix) + '/' +
1789 certificateTypeToString(type) + '/' + endpoint;
1790
1791 auto event = sdeventplus::Event::get_default();
1792 // Attach the bus to sd_event to service user requests
1793 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1794 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1795 authoritiesListFolder);
1796 createAuthoritiesList(maxNumAuthorityCertificates + 1);
1797 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1798 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed);
1799}
1800
1801TEST_F(AuthoritiesListTest, CertInWrongFormat)
1802{
1803 std::string endpoint("ldap");
1804 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001805 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001806
1807 std::string object = std::string(objectNamePrefix) + '/' +
1808 certificateTypeToString(type) + '/' + endpoint;
1809
1810 auto event = sdeventplus::Event::get_default();
1811 // Attach the bus to sd_event to service user requests
1812 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1813
1814 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1815 authoritiesListFolder);
1816
1817 // Replace the authorities list with non-valid PEM encoded x509 certificate
1818 setContentFromString(sourceAuthoritiesListFile, "blah-blah");
1819 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1820 InvalidCertificate);
1821 setContentFromString(sourceAuthoritiesListFile,
1822 "-----BEGIN CERTIFICATE-----");
1823 EXPECT_THROW(manager.installAll(sourceAuthoritiesListFile),
1824 InvalidCertificate);
1825}
1826
1827TEST_F(AuthoritiesListTest, ReplaceAll)
1828{
1829 std::string endpoint("ldap");
1830 std::string verifyUnit(ManagerInTest::unitToRestartInTest);
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001831 CertificateType type = CertificateType::authority;
Nan Zhou6ec13c82021-12-30 11:34:50 -08001832
1833 std::string object = std::string(objectNamePrefix) + '/' +
1834 certificateTypeToString(type) + '/' + endpoint;
1835
1836 auto event = sdeventplus::Event::get_default();
1837 // Attach the bus to sd_event to service user requests
1838 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
1839 ManagerInTest manager(bus, event, object.c_str(), type, verifyUnit,
1840 authoritiesListFolder);
1841 EXPECT_CALL(manager, reloadOrReset(Eq(ManagerInTest::unitToRestartInTest)))
1842 .WillOnce(Return())
1843 .WillOnce(Return());
1844 manager.installAll(sourceAuthoritiesListFile);
1845
1846 // Replace the current list with a different list
1847 fs::remove_all(sourceAuthoritiesListFile.parent_path());
1848 createAuthoritiesList(maxNumAuthorityCertificates);
1849 std::vector<sdbusplus::message::object_path> objects =
1850 manager.replaceAll(sourceAuthoritiesListFile);
1851
1852 for (size_t i = 0; i < manager.getCertificates().size(); ++i)
1853 {
1854 EXPECT_EQ(manager.getCertificates()[i]->getObjectPath(), objects[i]);
1855 }
1856 verifyCertificates(manager.getCertificates());
1857}
1858
Nan Zhoue1289ad2021-12-28 11:02:56 -08001859} // namespace
1860} // namespace phosphor::certs