From d44031615d7ef548c3d78a820035848cb5990288 Mon Sep 17 00:00:00 2001 From: Rainer Schielke <56628927+RainerSchielke@users.noreply.github.com> Date: Mon, 3 Jun 2024 15:37:40 +0200 Subject: [PATCH] New function SSLServer::update_certs. Allows to update certificates while server is running (#1827) * New function SSLServer::update_certs. Allows to update certificates while server is running * New function SSLServer::update_certs. Added unit test --------- Co-authored-by: CEU\schielke --- httplib.h | 16 +++++++++++++++ test/test.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/httplib.h b/httplib.h index a7a5613..69a34d6 100644 --- a/httplib.h +++ b/httplib.h @@ -1819,6 +1819,9 @@ public: bool is_valid() const override; SSL_CTX *ssl_context() const; + + void update_certs (X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store = nullptr); private: bool process_and_close_socket(socket_t sock) override; @@ -8753,6 +8756,19 @@ inline bool SSLServer::is_valid() const { return ctx_; } inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; } +inline void SSLServer::update_certs (X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store) { + + std::lock_guard guard(ctx_mutex_); + + SSL_CTX_use_certificate (ctx_, cert); + SSL_CTX_use_PrivateKey (ctx_, private_key); + + if (client_ca_cert_store != nullptr) { + SSL_CTX_set_cert_store (ctx_, client_ca_cert_store); + } +} + inline bool SSLServer::process_and_close_socket(socket_t sock) { auto ssl = detail::ssl_new( sock, ctx_, ctx_mutex_, diff --git a/test/test.cc b/test/test.cc index aab9db0..7fe39ad 100644 --- a/test/test.cc +++ b/test/test.cc @@ -1747,6 +1747,64 @@ TEST(BindServerTest, BindAndListenSeparatelySSLEncryptedKey) { } #endif +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +X509* readCertificate (const std::string& strFileName) { + std::ifstream inStream (strFileName); + std::string strCertPEM ((std::istreambuf_iterator(inStream)), std::istreambuf_iterator()); + + if (strCertPEM.empty ()) return (nullptr); + + BIO* pbCert = BIO_new (BIO_s_mem ()); + BIO_write (pbCert, strCertPEM.c_str (), (int)strCertPEM.size ()); + X509* pCert = PEM_read_bio_X509 (pbCert, NULL, 0, NULL); + BIO_free (pbCert); + + return (pCert); +} + +EVP_PKEY* readPrivateKey (const std::string& strFileName) { + std::ifstream inStream (strFileName); + std::string strPrivateKeyPEM ((std::istreambuf_iterator(inStream)), std::istreambuf_iterator()); + + if (strPrivateKeyPEM.empty ()) return (nullptr); + + BIO* pbPrivKey = BIO_new (BIO_s_mem ()); + BIO_write (pbPrivKey, strPrivateKeyPEM.c_str (), (int) strPrivateKeyPEM.size ()); + EVP_PKEY* pPrivateKey = PEM_read_bio_PrivateKey (pbPrivKey, NULL, NULL, NULL); + BIO_free (pbPrivKey); + + return (pPrivateKey); +} + +TEST(BindServerTest, UpdateCerts) { + SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE); + int port = svr.bind_to_any_port("0.0.0.0"); + ASSERT_TRUE(svr.is_valid()); + ASSERT_TRUE(port > 0); + + X509* cert = readCertificate (SERVER_CERT_FILE); + X509* ca_cert = readCertificate (CLIENT_CA_CERT_FILE); + EVP_PKEY* key = readPrivateKey (SERVER_PRIVATE_KEY_FILE); + + ASSERT_TRUE(cert != nullptr); + ASSERT_TRUE(ca_cert != nullptr); + ASSERT_TRUE(key != nullptr); + + X509_STORE* cert_store = X509_STORE_new (); + + X509_STORE_add_cert (cert_store, ca_cert); + + svr.update_certs (cert, key, cert_store); + + ASSERT_TRUE(svr.is_valid()); + svr.stop(); + + X509_free (cert); + X509_free (ca_cert); + EVP_PKEY_free (key); +} +#endif + TEST(ErrorHandlerTest, ContentLength) { Server svr;