blob: 1b04af590bc4520501f56a017e80130e0d7d18bc [file] [log] [blame]
Alan Kuoa8220702020-11-26 11:15:29 +08001#pragma once
2#ifdef BMCWEB_ENABLE_SSL
3#include <boost/container/flat_map.hpp>
4#include <dbus_singleton.hpp>
5#include <sdbusplus/bus/match.hpp>
6#include <sdbusplus/message/types.hpp>
7#include <ssl_key_handler.hpp>
8
9namespace crow
10{
11namespace hostname_monitor
12{
13static std::unique_ptr<sdbusplus::bus::match::match> hostnameSignalMonitor;
14
15inline void installCertificate(const std::filesystem::path& certPath)
16{
17 crow::connections::systemBus->async_method_call(
18 [certPath](boost::system::error_code ec) {
19 if (ec)
20 {
21 BMCWEB_LOG_ERROR << "Replace Certificate Fail..";
22 return;
23 }
24
25 BMCWEB_LOG_INFO << "Replace HTTPs Certificate Success, "
26 "remove temporary certificate file..";
27 remove(certPath.c_str());
28 },
29 "xyz.openbmc_project.Certs.Manager.Server.Https",
30 "/xyz/openbmc_project/certs/server/https/1",
31 "xyz.openbmc_project.Certs.Replace", "Replace", certPath.string());
32}
33
34inline int onPropertyUpdate(sd_bus_message* m, void* /* userdata */,
Ed Tanous81ce6092020-12-17 16:54:55 +000035 sd_bus_error* retError)
Alan Kuoa8220702020-11-26 11:15:29 +080036{
Ed Tanous81ce6092020-12-17 16:54:55 +000037 if (retError == nullptr || sd_bus_error_is_set(retError))
Alan Kuoa8220702020-11-26 11:15:29 +080038 {
39 BMCWEB_LOG_ERROR << "Got sdbus error on match";
40 return 0;
41 }
42
43 sdbusplus::message::message message(m);
44 std::string iface;
45 boost::container::flat_map<std::string, std::variant<std::string>>
46 changedProperties;
47
48 message.read(iface, changedProperties);
49 auto it = changedProperties.find("HostName");
50 if (it == changedProperties.end())
51 {
52 return 0;
53 }
54
55 std::string* hostname = std::get_if<std::string>(&it->second);
56 if (hostname == nullptr)
57 {
58 BMCWEB_LOG_ERROR << "Unable to read hostname";
59 return 0;
60 }
61
62 BMCWEB_LOG_DEBUG << "Read hostname from signal: " << *hostname;
63 const std::string certFile = "/etc/ssl/certs/https/server.pem";
64
65 X509* cert = ensuressl::loadCert(certFile);
66 if (cert == nullptr)
67 {
68 BMCWEB_LOG_ERROR << "Failed to read cert";
69 return 0;
70 }
71
72 const int maxKeySize = 256;
73 std::array<char, maxKeySize> cnBuffer{};
74
75 int cnLength =
76 X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName,
77 cnBuffer.data(), cnBuffer.size());
78 if (cnLength == -1)
79 {
80 BMCWEB_LOG_ERROR << "Failed to read NID_commonName";
81 X509_free(cert);
82 return 0;
83 }
84 std::string_view cnValue(std::begin(cnBuffer),
85 static_cast<size_t>(cnLength));
86
87 EVP_PKEY* pPubKey = X509_get_pubkey(cert);
88 if (pPubKey == nullptr)
89 {
90 BMCWEB_LOG_ERROR << "Failed to get public key";
91 X509_free(cert);
92 return 0;
93 }
94 int isSelfSigned = X509_verify(cert, pPubKey);
95 EVP_PKEY_free(pPubKey);
96
97 BMCWEB_LOG_DEBUG << "Current HTTPs Certificate Subject CN: " << cnValue
98 << ", New HostName: " << *hostname
99 << ", isSelfSigned: " << isSelfSigned;
100
101 ASN1_IA5STRING* asn1 = static_cast<ASN1_IA5STRING*>(
102 X509_get_ext_d2i(cert, NID_netscape_comment, nullptr, nullptr));
103 if (asn1)
104 {
105 std::string_view comment(reinterpret_cast<const char*>(asn1->data),
106 static_cast<size_t>(asn1->length));
107 BMCWEB_LOG_DEBUG << "x509Comment: " << comment;
108
109 if (ensuressl::x509Comment == comment && isSelfSigned == 1 &&
110 cnValue != *hostname)
111 {
112 BMCWEB_LOG_INFO << "Ready to generate new HTTPs "
113 << "certificate with subject cn: " << *hostname;
114
115 ensuressl::generateSslCertificate("/tmp/hostname_cert.tmp",
116 *hostname);
117 installCertificate("/tmp/hostname_cert.tmp");
118 }
119 ASN1_STRING_free(asn1);
120 }
121 X509_free(cert);
122 return 0;
123}
124
125inline void registerHostnameSignal()
126{
127 BMCWEB_LOG_INFO << "Register HostName PropertiesChanged Signal";
128 std::string propertiesMatchString =
129 ("type='signal',"
130 "interface='org.freedesktop.DBus.Properties',"
131 "path='/xyz/openbmc_project/network/config',"
132 "arg0='xyz.openbmc_project.Network.SystemConfiguration',"
133 "member='PropertiesChanged'");
134
135 hostnameSignalMonitor = std::make_unique<sdbusplus::bus::match::match>(
136 *crow::connections::systemBus, propertiesMatchString, onPropertyUpdate,
137 nullptr);
138}
139} // namespace hostname_monitor
140} // namespace crow
141#endif