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