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