blob: 839faabe215902c76d136bbc21cc6eb4bace763e [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
Alan Kuoa8220702020-11-26 11:15:29 +08003#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08004#include "dbus_singleton.hpp"
5#include "dbus_utility.hpp"
6#include "include/dbus_utility.hpp"
7#include "logging.hpp"
8#include "ssl_key_handler.hpp"
9
Ed Tanousd7857202025-01-28 15:32:26 -080010#include <openssl/asn1.h>
11#include <openssl/crypto.h>
12#include <openssl/evp.h>
13#include <openssl/obj_mac.h>
14#include <openssl/x509.h>
15#include <systemd/sd-bus.h>
16
Alan Kuoa8220702020-11-26 11:15:29 +080017#include <sdbusplus/bus/match.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080018#include <sdbusplus/message.hpp>
19
20#include <array>
21#include <cstddef>
22#include <filesystem>
23#include <iterator>
24#include <memory>
25#include <string_view>
26#include <system_error>
27#include <variant>
Alan Kuoa8220702020-11-26 11:15:29 +080028
29namespace crow
30{
31namespace hostname_monitor
32{
Ed Tanouscf9e4172022-12-21 09:30:16 -080033// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050034static std::unique_ptr<sdbusplus::bus::match_t> hostnameSignalMonitor;
Alan Kuoa8220702020-11-26 11:15:29 +080035
36inline void installCertificate(const std::filesystem::path& certPath)
37{
38 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080039 [certPath](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -040040 if (ec)
41 {
42 BMCWEB_LOG_ERROR("Replace Certificate Fail..");
43 return;
44 }
Alan Kuoa8220702020-11-26 11:15:29 +080045
Patrick Williamsbd79bce2024-08-16 15:22:20 -040046 BMCWEB_LOG_INFO("Replace HTTPs Certificate Success, "
47 "remove temporary certificate file..");
48 std::error_code ec2;
49 std::filesystem::remove(certPath.c_str(), ec2);
50 if (ec2)
51 {
52 BMCWEB_LOG_ERROR("Failed to remove certificate");
53 }
54 },
Alan Kuoa8220702020-11-26 11:15:29 +080055 "xyz.openbmc_project.Certs.Manager.Server.Https",
56 "/xyz/openbmc_project/certs/server/https/1",
57 "xyz.openbmc_project.Certs.Replace", "Replace", certPath.string());
58}
59
60inline int onPropertyUpdate(sd_bus_message* m, void* /* userdata */,
Ed Tanous81ce6092020-12-17 16:54:55 +000061 sd_bus_error* retError)
Alan Kuoa8220702020-11-26 11:15:29 +080062{
Ed Tanouse662eae2022-01-25 10:39:19 -080063 if (retError == nullptr || (sd_bus_error_is_set(retError) != 0))
Alan Kuoa8220702020-11-26 11:15:29 +080064 {
Ed Tanous62598e32023-07-17 17:06:25 -070065 BMCWEB_LOG_ERROR("Got sdbus error on match");
Alan Kuoa8220702020-11-26 11:15:29 +080066 return 0;
67 }
68
Patrick Williams59d494e2022-07-22 19:26:55 -050069 sdbusplus::message_t message(m);
Alan Kuoa8220702020-11-26 11:15:29 +080070 std::string iface;
Ed Tanousb9d36b42022-02-26 21:42:46 -080071 dbus::utility::DBusPropertiesMap changedProperties;
Alan Kuoa8220702020-11-26 11:15:29 +080072
73 message.read(iface, changedProperties);
Ed Tanousb9d36b42022-02-26 21:42:46 -080074 const std::string* hostname = nullptr;
75 for (const auto& propertyPair : changedProperties)
Alan Kuoa8220702020-11-26 11:15:29 +080076 {
Ed Tanousb9d36b42022-02-26 21:42:46 -080077 if (propertyPair.first == "HostName")
78 {
79 hostname = std::get_if<std::string>(&propertyPair.second);
80 }
Alan Kuoa8220702020-11-26 11:15:29 +080081 }
Alan Kuoa8220702020-11-26 11:15:29 +080082 if (hostname == nullptr)
83 {
Alan Kuoa8220702020-11-26 11:15:29 +080084 return 0;
85 }
86
Ed Tanous62598e32023-07-17 17:06:25 -070087 BMCWEB_LOG_DEBUG("Read hostname from signal: {}", *hostname);
Alan Kuoa8220702020-11-26 11:15:29 +080088 const std::string certFile = "/etc/ssl/certs/https/server.pem";
89
90 X509* cert = ensuressl::loadCert(certFile);
91 if (cert == nullptr)
92 {
Ed Tanous62598e32023-07-17 17:06:25 -070093 BMCWEB_LOG_ERROR("Failed to read cert");
Alan Kuoa8220702020-11-26 11:15:29 +080094 return 0;
95 }
96
97 const int maxKeySize = 256;
98 std::array<char, maxKeySize> cnBuffer{};
99
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400100 int cnLength =
101 X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName,
102 cnBuffer.data(), cnBuffer.size());
Alan Kuoa8220702020-11-26 11:15:29 +0800103 if (cnLength == -1)
104 {
Ed Tanous62598e32023-07-17 17:06:25 -0700105 BMCWEB_LOG_ERROR("Failed to read NID_commonName");
Alan Kuoa8220702020-11-26 11:15:29 +0800106 X509_free(cert);
107 return 0;
108 }
109 std::string_view cnValue(std::begin(cnBuffer),
110 static_cast<size_t>(cnLength));
111
112 EVP_PKEY* pPubKey = X509_get_pubkey(cert);
113 if (pPubKey == nullptr)
114 {
Ed Tanous62598e32023-07-17 17:06:25 -0700115 BMCWEB_LOG_ERROR("Failed to get public key");
Alan Kuoa8220702020-11-26 11:15:29 +0800116 X509_free(cert);
117 return 0;
118 }
119 int isSelfSigned = X509_verify(cert, pPubKey);
120 EVP_PKEY_free(pPubKey);
121
Ed Tanous62598e32023-07-17 17:06:25 -0700122 BMCWEB_LOG_DEBUG(
123 "Current HTTPs Certificate Subject CN: {}, New HostName: {}, isSelfSigned: {}",
124 cnValue, *hostname, isSelfSigned);
Alan Kuoa8220702020-11-26 11:15:29 +0800125
126 ASN1_IA5STRING* asn1 = static_cast<ASN1_IA5STRING*>(
127 X509_get_ext_d2i(cert, NID_netscape_comment, nullptr, nullptr));
Ed Tanouse662eae2022-01-25 10:39:19 -0800128 if (asn1 != nullptr)
Alan Kuoa8220702020-11-26 11:15:29 +0800129 {
Ed Tanous46ff87b2022-01-07 09:25:51 -0800130 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Alan Kuoa8220702020-11-26 11:15:29 +0800131 std::string_view comment(reinterpret_cast<const char*>(asn1->data),
132 static_cast<size_t>(asn1->length));
Ed Tanous62598e32023-07-17 17:06:25 -0700133 BMCWEB_LOG_DEBUG("x509Comment: {}", comment);
Alan Kuoa8220702020-11-26 11:15:29 +0800134
135 if (ensuressl::x509Comment == comment && isSelfSigned == 1 &&
136 cnValue != *hostname)
137 {
Ed Tanous62598e32023-07-17 17:06:25 -0700138 BMCWEB_LOG_INFO(
139 "Ready to generate new HTTPs certificate with subject cn: {}",
140 *hostname);
Alan Kuoa8220702020-11-26 11:15:29 +0800141
Ed Tanous099225c2024-03-27 22:03:05 -0700142 std::string certData = ensuressl::generateSslCertificate(*hostname);
143 if (certData.empty())
144 {
145 BMCWEB_LOG_ERROR("Failed to generate cert");
146 return 0;
147 }
148 ensuressl::writeCertificateToFile("/tmp/hostname_cert.tmp",
149 certData);
150
Alan Kuoa8220702020-11-26 11:15:29 +0800151 installCertificate("/tmp/hostname_cert.tmp");
152 }
153 ASN1_STRING_free(asn1);
154 }
155 X509_free(cert);
156 return 0;
157}
158
159inline void registerHostnameSignal()
160{
Ed Tanous62598e32023-07-17 17:06:25 -0700161 BMCWEB_LOG_INFO("Register HostName PropertiesChanged Signal");
Alan Kuoa8220702020-11-26 11:15:29 +0800162 std::string propertiesMatchString =
163 ("type='signal',"
164 "interface='org.freedesktop.DBus.Properties',"
165 "path='/xyz/openbmc_project/network/config',"
166 "arg0='xyz.openbmc_project.Network.SystemConfiguration',"
167 "member='PropertiesChanged'");
168
Patrick Williams59d494e2022-07-22 19:26:55 -0500169 hostnameSignalMonitor = std::make_unique<sdbusplus::bus::match_t>(
Alan Kuoa8220702020-11-26 11:15:29 +0800170 *crow::connections::systemBus, propertiesMatchString, onPropertyUpdate,
171 nullptr);
172}
173} // namespace hostname_monitor
174} // namespace crow