]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3553] Checkpoint
authorFrancis Dupont <fdupont@isc.org>
Sat, 31 Aug 2024 10:15:38 +0000 (12:15 +0200)
committerFrancis Dupont <fdupont@isc.org>
Tue, 22 Jul 2025 14:49:16 +0000 (16:49 +0200)
src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc
src/lib/asiolink/botan_tls.cc
src/lib/asiolink/botan_tls.h
src/lib/asiolink/tests/tls_unittest.cc
src/lib/asiolink/testutils/botan_sample_client.cc
src/lib/asiolink/testutils/botan_sample_server.cc

index dc3be6abf9e34c78eee30ebace46a1a5960c9f4b..eee6a1c561381ebc8e9c0ac8d415d03a1a021583 100644 (file)
@@ -1658,7 +1658,12 @@ TEST_F(HAConfigTest, badTrustAnchor) {
 #ifdef WITH_OPENSSL
     expected += "No such file or directory";
 #else
-    expected += "I/O error: DataSource: Failure opening file /this-file-does-not-exist";
+    expected += "I/O error: DataSource: Failure opening file ";
+#if BOTAN_VERSION_MAJOR > 2
+    expected += "'/this-file-does-not-exist'";
+#else
+    expected += "/this-file-does-not-exist";
+#endif
 #endif
     testInvalidConfig(patched, expected);
 }
@@ -1698,7 +1703,12 @@ TEST_F(HAConfigTest, badCertFile) {
 #ifdef WITH_OPENSSL
     expected += "No such file or directory";
 #else
-    expected += "I/O error: DataSource: Failure opening file /this-file-does-not-exist";
+    expected += "I/O error: DataSource: Failure opening file ";
+#if BOTAN_VERSION_MAJOR > 2
+    expected += "'/this-file-does-not-exist'";
+#else
+    expected += "/this-file-does-not-exist";
+#endif
 #endif
     testInvalidConfig(patched, expected);
 }
@@ -1738,7 +1748,12 @@ TEST_F(HAConfigTest, badKeyFile) {
 #ifdef WITH_OPENSSL
     expected += "No such file or directory";
 #else
-    expected += "I/O error: DataSource: Failure opening file /this-file-does-not-exist";
+    expected += "I/O error: DataSource: Failure opening file ";
+#if BOTAN_VERSION_MAJOR > 2
+    expected += "'/this-file-does-not-exist'";
+#else
+    expected += "/this-file-does-not-exist";
+#endif
 #endif
     testInvalidConfig(patched, expected);
 }
index 0ec0ed5fdb059c1ada65e91a7253d58a0122cd22..18acde5ea8b07d314254af3f72432649e13fdd7a 100644 (file)
@@ -18,6 +18,9 @@
 #include <botan/data_src.h>
 #include <botan/pem.h>
 #include <botan/pkcs8.h>
+#if BOTAN_VERSION_MAJOR > 2
+#include <botan/tls_session_manager_noop.h>
+#endif
 
 using namespace isc::cryptolink;
 
@@ -36,8 +39,7 @@ public:
     }
 
     // Destructor.
-    virtual ~KeaCredentialsManager() {
-    }
+    virtual ~KeaCredentialsManager() = default;
 
     // CA certificate stores.
     // nullptr means do not require or check peer certificate.
@@ -54,17 +56,28 @@ public:
     // Certificate chain.
     std::vector<Botan::X509_Certificate>
     cert_chain(const std::vector<std::string>&,
+#if BOTAN_VERSION_MAJOR > 2
+               const std::vector<Botan::AlgorithmIdentifier>&,
+#endif
                const std::string&,
                const std::string&) override {
         return (certs_);
     }
 
     // Private key.
+#if BOTAN_VERSION_MAJOR > 2
+    std::shared_ptr<Botan::Private_Key>
+#else
     Botan::Private_Key*
+#endif
     private_key_for(const Botan::X509_Certificate&,
                     const std::string&,
                     const std::string&) override {
+#if BOTAN_VERSION_MAJOR > 2
+        return (key_);
+#else
         return (key_.get());
+#endif
     }
 
     // Set the store from a path.
@@ -118,13 +131,27 @@ public:
 
     // Set the private key.
     void setPrivateKey(const std::string& file,
+#if BOTAN_VERSION_MAJOR > 2
+                       Botan::RandomNumberGenerator&,
+#else
                        Botan::RandomNumberGenerator& rng,
+#endif
                        bool& is_rsa) {
-        key_.reset(Botan::PKCS8::load_key(file, rng));
-        if (!key_) {
+#if BOTAN_VERSION_MAJOR > 2
+        Botan::DataSource_Stream source(file);
+        auto priv_key = Botan::PKCS8::load_key(source);
+#else
+        auto priv_key = Botan::PKCS8::load_key(file, rng);
+#endif
+        if (!priv_key) {
             isc_throw(Unexpected,
                       "Botan::PKCS8::load_key failed but not threw?");
         }
+#if BOTAN_VERSION_MAJOR > 2
+        key_ = std::move(priv_key);
+#else
+        key_.reset(priv_key);
+#endif
         is_rsa = (key_->algo_name() == "RSA");
     }
 
@@ -138,7 +165,7 @@ public:
     std::vector<Botan::X509_Certificate> certs_;
 
     // Pointer to the private key.
-    std::unique_ptr<Botan::Private_Key> key_;
+    std::shared_ptr<Botan::Private_Key> key_;
 };
 
 // Class of Kea policy.
@@ -197,29 +224,32 @@ KeaPolicy::AllowedSignatureMethodsECDSA = { "ECDSA", "RSA", "DSA" };
 class TlsContextImpl {
 public:
     // Constructor.
-    TlsContextImpl() : cred_mgr_(), rng_(), sess_mgr_(), policy_() {
+    TlsContextImpl() :
+        cred_mgr_(new KeaCredentialsManager()),
+        rng_(new Botan::AutoSeeded_RNG()),
+        sess_mgr_(new KeaSessionManager()),
+        policy_(new KeaPolicy()) {
     }
 
     // Destructor.
-    virtual ~TlsContextImpl() {
-    }
+    virtual ~TlsContextImpl() = default;
 
     // Get the peer certificate requirement mode.
     virtual bool getCertRequired() const {
-        return (cred_mgr_.getUseStores());
+        return (cred_mgr_->getUseStores());
     }
 
     // Set the peer certificate requirement mode.
     //
     // With Botan this means to provide or not the CA certificate stores.
     virtual void setCertRequired(bool cert_required) {
-        cred_mgr_.setUseStores(cert_required);
+        cred_mgr_->setUseStores(cert_required);
     }
 
     // Load the trust anchor aka certificate authority (path).
     virtual void loadCaPath(const std::string& ca_path) {
         try {
-            cred_mgr_.setStorePath(ca_path);
+            cred_mgr_->setStorePath(ca_path);
         } catch (const std::exception& ex) {
             isc_throw(LibraryError, ex.what());
         }
@@ -228,7 +258,7 @@ public:
     // Load the trust anchor aka certificate authority (file).
     virtual void loadCaFile(const std::string& ca_file) {
         try {
-            cred_mgr_.setStoreFile(ca_file);
+            cred_mgr_->setStoreFile(ca_file);
         } catch (const std::exception& ex) {
             isc_throw(LibraryError, ex.what());
         }
@@ -237,7 +267,7 @@ public:
     /// @brief Load the certificate file.
     virtual void loadCertFile(const std::string& cert_file) {
         try {
-            cred_mgr_.setCertChain(cert_file);
+            cred_mgr_->setCertChain(cert_file);
         } catch (const std::exception& ex) {
             isc_throw(LibraryError, ex.what());
         }
@@ -249,8 +279,8 @@ public:
     virtual void loadKeyFile(const std::string& key_file) {
         try {
             bool is_rsa = true;
-            cred_mgr_.setPrivateKey(key_file, rng_, is_rsa);
-            policy_.setPrefRSA(is_rsa);
+            cred_mgr_->setPrivateKey(key_file, *rng_, is_rsa);
+            policy_->setPrefRSA(is_rsa);
         } catch (const std::exception& ex) {
             isc_throw(LibraryError, ex.what());
         }
@@ -261,28 +291,41 @@ public:
         if (context_) {
             return;
         }
+#if BOTAN_VERSION_MAJOR > 2
         context_.reset(new Botan::TLS::Context(cred_mgr_,
                                                rng_,
                                                sess_mgr_,
                                                policy_));
+#else
+        context_.reset(new Botan::TLS::Context(*cred_mgr_,
+                                               *rng_,
+                                               *sess_mgr_,
+                                               *policy_));
+#endif
     }
 
+#if BOTAN_VERSION_MAJOR > 2
+    virtual std::shared_ptr<Botan::TLS::Context> get() {
+        return (context_);
+    }
+#else
     virtual Botan::TLS::Context& get() {
         return (*context_);
     }
+#endif
 
     // Credentials Manager.
-    KeaCredentialsManager cred_mgr_;
+    std::shared_ptr<KeaCredentialsManager> cred_mgr_;
 
     // Random Number Generator.
-    Botan::AutoSeeded_RNG rng_;
+    std::shared_ptr<Botan::AutoSeeded_RNG> rng_;
 
     // Session Manager.
-    KeaSessionManager sess_mgr_;
+    std::shared_ptr<KeaSessionManager> sess_mgr_;
 
-    KeaPolicy policy_;
+    std::shared_ptr<KeaPolicy> policy_;
 
-    std::unique_ptr<Botan::TLS::Context> context_;
+    std::shared_ptr<Botan::TLS::Context> context_;
 };
 
 TlsContext::~TlsContext() {
@@ -292,11 +335,19 @@ TlsContext::TlsContext(TlsRole role)
     : TlsContextBase(role), impl_(new TlsContextImpl()) {
 }
 
+#if BOTAN_VERSION_MAJOR > 2
+std::shared_ptr<Botan::TLS::Context>
+TlsContext::getContext() {
+    impl_->build();
+    return (impl_->get());
+}
+#else
 Botan::TLS::Context&
 TlsContext::getContext() {
     impl_->build();
     return (impl_->get());
 }
+#endif
 
 void
 TlsContext::setCertRequired(bool cert_required) {
index 8dc9e40b37d1508024e4253df894a3a61ffe0b5e..13afc98d9ce3b1b6590ac35a53ec8989b5428209 100644 (file)
@@ -28,9 +28,17 @@ namespace asiolink {
 /// @brief Translate TLS role into implementation.
 inline Botan::TLS::Connection_Side roleToImpl(TlsRole role) {
     if (role == TlsRole::SERVER) {
+#if BOTAN_VERSION_MAJOR > 2
+        return (Botan::TLS::Connection_Side::Server);
+#else
         return (Botan::TLS::Connection_Side::SERVER);
+#endif
     } else {
+#if BOTAN_VERSION_MAJOR > 2
+        return (Botan::TLS::Connection_Side::Client);
+#else
         return (Botan::TLS::Connection_Side::CLIENT);
+#endif
     }
 }
 
@@ -53,7 +61,11 @@ public:
     explicit TlsContext(TlsRole role);
 
     /// @brief Return the underlying context.
+#if BOTAN_VERSION_MAJOR > 2
+    std::shared_ptr<Botan::TLS::Context> getContext();
+#else
     Botan::TLS::Context& getContext();
+#endif
 
     /// @brief Get the peer certificate requirement mode.
     ///
index 39aa8ade50e62791192e9b38f3013b7acdcefb0b..c6150d60fd49e63b6ece677b4e51eef69f9414c4 100644 (file)
@@ -509,6 +509,7 @@ TEST_F(TLSTest, loadNoCAFile) {
     Expecteds exps;
     // Botan error.
     exps.addThrow("I/O error: DataSource: Failure opening file /no-such-file");
+    exps.addThrow("I/O error: DataSource: Failure opening file '/no-such-file'");
     // OpenSSL errors.
     exps.addThrow("No such file or directory");
     exps.addThrow("No such file or directory (system library)");
@@ -586,6 +587,7 @@ TEST_F(TLSTest, loadNoCertFile) {
     Expecteds exps;
     // Botan error.
     exps.addThrow("I/O error: DataSource: Failure opening file /no-such-file");
+    exps.addThrow("I/O error: DataSource: Failure opening file '/no-such-file'");
     // OpenSSL errors.
     exps.addThrow("No such file or directory");
     exps.addThrow("No such file or directory (system library)");
@@ -632,6 +634,7 @@ TEST_F(TLSTest, loadNoKeyFile) {
     Expecteds exps;
     // Botan error.
     exps.addThrow("I/O error: DataSource: Failure opening file /no-such-file");
+    exps.addThrow("I/O error: DataSource: Failure opening file '/no-such-file'");
     // OpenSSL errors.
     exps.addThrow("No such file or directory");
     exps.addThrow("No such file or directory (system library)");
@@ -655,6 +658,9 @@ TEST_F(TLSTest, loadCertKeyFile) {
     string botan_error = "PKCS #8 private key decoding failed with PKCS #8: ";
     botan_error += "Unknown PEM label CERTIFICATE";
     exps.addThrow(botan_error);
+    botan_error = "PKCS #8 private key decoding failed with PKCS #8: ";
+    botan_error += "Unknown PEM label 'CERTIFICATE'";
+    exps.addThrow(botan_error);
     // OpenSSL errors.
     exps.addThrow("no start line");
     exps.addThrow("no start line (PEM routines)");
@@ -733,6 +739,8 @@ TEST_F(TLSTest, configureError) {
     // Botan error.
     string botan_error = "I/O error: DataSource: Failure opening file /no-such-file";
     exps.addThrow(common_error + botan_error);
+    botan_error = "I/O error: DataSource: Failure opening file '/no-such-file'";
+    exps.addThrow(common_error + botan_error);
     // OpenSSL errors.
     string openssl_error = "No such file or directory";
     exps.addThrow(common_error + openssl_error);
@@ -946,6 +954,7 @@ TEST_F(TLSTest, serverNotConfigured) {
     exps.clear();
     // On Botan and some OpenSSL the client hangs.
     exps.addTimeout();
+    exps.addError("handshake_failure");
     // OpenSSL errors.
     exps.addError("sslv3 alert handshake failure");
     exps.addError("sslv3 alert handshake failure (SSL routines)");
@@ -1027,6 +1036,7 @@ TEST_F(TLSTest, clientNotConfigured) {
     Expecteds exps;
     // On Botan and some OpenSSL the server hangs.
     exps.addTimeout();
+    exps.addError("bad_certificate");
     // OpenSSL errors.
     exps.addError("tlsv1 alert unknown ca");
     exps.addError("tlsv1 alert unknown ca (SSL routines)");
@@ -1128,6 +1138,7 @@ TEST_F(TLSTest, clientHTTPnoS) {
     exps.addTimeout();
     // Botan error.
     exps.addError("protocol_version");
+    exps.addError("unexpected_message");
     // Old LibreSSL error.
     exps.addError("tlsv1 alert protocol version");
     // OpenSSL errors (OpenSSL recognizes HTTP).
@@ -1220,6 +1231,7 @@ TEST_F(TLSTest, unknownClient) {
     // Botan errors.
     exps.addError("record_overflow");
     exps.addError("protocol_version");
+    exps.addError("unexpected_message");
     // Old LibreSSL error.
     exps.addError("tlsv1 alert protocol version");
     // Old OpenSSL error.
@@ -1630,6 +1642,7 @@ TEST_F(TLSTest, serverNotConfiguredCloseonError) {
     exps.clear();
     // Botan and some OpenSSL.
     exps.addError("stream truncated");
+    exps.addError("handshake_failure");
     // Alias on old OpenSSL.
     exps.addError("short read");
     // OpenSSL errors.
@@ -1710,6 +1723,7 @@ TEST_F(TLSTest, clientNotConfiguredCloseonError) {
     Expecteds exps;
     // Botan and some OpenSSL.
     exps.addError("stream truncated");
+    exps.addError("bad_certificate");
     // Alias on old OpenSSL.
     exps.addError("short read");
     // OpenSSL errors.
@@ -1810,6 +1824,7 @@ TEST_F(TLSTest, clientHTTPnoSCloseonError) {
     exps.addTimeout();
     // Botan behavior was reported and fixed.
     exps.addError("protocol_version");
+    exps.addError("unexpected_message");
     // Old LibreSSL error.
     exps.addError("tlsv1 alert protocol version");
     // OpenSSL errors when OpenSSL recognizes HTTP.
index 5930186cb7391563dc9fffbab217bdd5ebe9916a..20527355e8e14c1a156c8265b8dc8303b33aa19b 100644 (file)
@@ -21,6 +21,9 @@
 #include <botan/certstor_flatfile.h>
 #include <botan/pkcs8.h>
 #include <botan/auto_rng.h>
+#if BOTAN_VERSION_MAJOR > 2
+#include <botan/tls_session_manager_noop.h>
+#endif
 
 inline std::string CA_(const std::string& filename) {
   return (std::string(TEST_CA_DIR) + "/" + filename);
@@ -35,19 +38,29 @@ using Client_Certificate_Store = Botan::Flatfile_Certificate_Store;
 class Client_Credentials_Manager : public Botan::Credentials_Manager
 {
 public:
+#if BOTAN_VERSION_MAJOR > 2
+  explicit Client_Credentials_Manager()
+#else
   explicit Client_Credentials_Manager(Botan::RandomNumberGenerator& rng)
+#endif
     : stores_(), certs_(),
       store_(new Client_Certificate_Store(CA_("kea-ca.crt"))),
       cert_(Botan::X509_Certificate(CA_("kea-client.crt"))),
-      key_(Botan::PKCS8::load_key(CA_("kea-client.key"), rng))
+      key_()
   {
+#if BOTAN_VERSION_MAJOR > 2
+    Botan::DataSource_Stream source(CA_("kea-client.key"));
+    auto priv_key = Botan::PKCS8::load_key(source);
+    key_ = std::move(priv_key);
+#else
+    auto priv_key = Botan::PKCS8::load_key(CA_("kea-client.key"), rng);
+    key_.reset(priv_key);
+#endif
     stores_.push_back(store_.get());
     certs_.push_back(cert_);
   }
 
-  virtual ~Client_Credentials_Manager()
-  {
-  }
+  virtual ~Client_Credentials_Manager() = default;
 
   std::vector<Botan::Certificate_Store*>
   trusted_certificate_authorities(const std::string&,
@@ -58,25 +71,36 @@ public:
 
   std::vector<Botan::X509_Certificate>
   cert_chain(const std::vector<std::string>&,
+#if BOTAN_VERSION_MAJOR > 2
+             const std::vector<Botan::AlgorithmIdentifier>&,
+#endif
              const std::string&,
              const std::string&) override
   {
     return certs_;
   }
 
-  Botan::Private_Key*
+#if BOTAN_VERSION_MAJOR > 2
+    std::shared_ptr<Botan::Private_Key>
+#else
+    Botan::Private_Key*
+#endif
   private_key_for(const Botan::X509_Certificate&,
                   const std::string&,
                   const std::string&) override
   {
-    return key_.get();
+#if BOTAN_VERSION_MAJOR > 2
+        return (key_);
+#else
+        return (key_.get());
+#endif
   }
 
   std::vector<Botan::Certificate_Store*> stores_;
   std::vector<Botan::X509_Certificate> certs_;
   std::shared_ptr<Botan::Certificate_Store> store_;
   Botan::X509_Certificate cert_;
-  std::unique_ptr<Botan::Private_Key> key_;
+  std::shared_ptr<Botan::Private_Key> key_;
 };
 
 using Client_Session_Manager = Botan::TLS::Session_Manager_Noop;
@@ -101,8 +125,12 @@ public:
 class client
 {
 public:
-  client(boost::asio::io_context& io_context,
+     client(boost::asio::io_service& io_context,
+#if BOTAN_VERSION_MAJOR > 2
+      std::shared_ptr<Botan::TLS::Context> context,
+#else
       Botan::TLS::Context& context,
+#endif
       const tcp::endpoint& endpoint)
     : socket_(io_context, context)
   {
@@ -128,7 +156,11 @@ private:
 
   void handshake()
   {
+#if BOTAN_VERSION_MAJOR > 2
+    socket_.async_handshake(Botan::TLS::Connection_Side::Client,
+#else
     socket_.async_handshake(Botan::TLS::Connection_Side::CLIENT,
+#endif
         [this](const boost::system::error_code& error)
         {
           if (!error)
@@ -210,11 +242,24 @@ int main(int argc, char* argv[])
     using namespace std; // For atoi.
     tcp::endpoint endpoint(
       boost::asio::ip::make_address(argv[1]), atoi(argv[2]));
+#if BOTAN_VERSION_MAJOR > 2
+    std::shared_ptr<Botan::AutoSeeded_RNG>
+      rng(new Botan::AutoSeeded_RNG());
+    std::shared_ptr<Client_Credentials_Manager>
+      creds_mgr(new Client_Credentials_Manager());
+    std::shared_ptr<Client_Session_Manager>
+      sess_mgr(new Client_Session_Manager());
+    std::shared_ptr<Client_Policy>
+      policy(new Client_Policy());
+    std::shared_ptr<Botan::TLS::Context>
+      ctx(new Botan::TLS::Context(creds_mgr, rng, sess_mgr, policy));
+#else
     Botan::AutoSeeded_RNG rng;
     Client_Credentials_Manager creds_mgr(rng);
     Client_Session_Manager sess_mgr;
     Client_Policy policy;
     Botan::TLS::Context ctx(creds_mgr, rng, sess_mgr, policy);
+#endif
 
     client c(io_context, ctx, endpoint);
 
index b1373b34bdedb1100940aed5317fb1d26e459bc5..78860c08b75d9942e55c195eab73a09eaa02ef0a 100644 (file)
@@ -20,6 +20,9 @@
 #include <botan/certstor_flatfile.h>
 #include <botan/pkcs8.h>
 #include <botan/auto_rng.h>
+#if BOTAN_VERSION_MAJOR > 2
+#include <botan/tls_session_manager_noop.h>
+#endif
 
 inline std::string CA_(const std::string& filename) {
   return (std::string(TEST_CA_DIR) + "/" + filename);
@@ -32,19 +35,29 @@ using Server_Certificate_Store = Botan::Flatfile_Certificate_Store;
 class Server_Credentials_Manager : public Botan::Credentials_Manager
 {
 public:
+#if BOTAN_VERSION_MAJOR > 2
+  explicit Server_Credentials_Manager()
+#else
   explicit Server_Credentials_Manager(Botan::RandomNumberGenerator& rng)
+#endif
     : stores_(), certs_(),
       store_(new Server_Certificate_Store(CA_("kea-ca.crt"))),
       cert_(Botan::X509_Certificate(CA_("kea-server.crt"))),
-      key_(Botan::PKCS8::load_key(CA_("kea-server.key"), rng))
+      key_()
   {
+#if BOTAN_VERSION_MAJOR > 2
+    Botan::DataSource_Stream source(CA_("kea-server.key"));
+    auto priv_key = Botan::PKCS8::load_key(source);
+    key_ = std::move(priv_key);
+#else
+    auto priv_key = Botan::PKCS8::load_key(CA_("kea-server.key"), rng);
+    key_.reset(priv_key);
+#endif
     stores_.push_back(store_.get());
     certs_.push_back(cert_);
   }
 
-  virtual ~Server_Credentials_Manager()
-  {
-  }
+  virtual ~Server_Credentials_Manager() = default;
 
   std::vector<Botan::Certificate_Store*>
   trusted_certificate_authorities(const std::string&,
@@ -55,25 +68,36 @@ public:
 
   std::vector<Botan::X509_Certificate>
   cert_chain(const std::vector<std::string>&,
+#if BOTAN_VERSION_MAJOR > 2
+             const std::vector<Botan::AlgorithmIdentifier>&,
+#endif
              const std::string&,
              const std::string&) override
   {
     return certs_;
   }
 
-  Botan::Private_Key*
+#if BOTAN_VERSION_MAJOR > 2
+    std::shared_ptr<Botan::Private_Key>
+#else
+    Botan::Private_Key*
+#endif
   private_key_for(const Botan::X509_Certificate&,
                   const std::string&,
                   const std::string&) override
   {
-    return key_.get();
+#if BOTAN_VERSION_MAJOR > 2
+        return (key_);
+#else
+        return (key_.get());
+#endif
   }
 
   std::vector<Botan::Certificate_Store*> stores_;
   std::vector<Botan::X509_Certificate> certs_;
   std::shared_ptr<Botan::Certificate_Store> store_;
   Botan::X509_Certificate cert_;
-  std::unique_ptr<Botan::Private_Key> key_;
+  std::shared_ptr<Botan::Private_Key> key_;
 };
 
 using Server_Session_Manager = Botan::TLS::Session_Manager_Noop;
@@ -98,7 +122,11 @@ public:
 class session : public std::enable_shared_from_this<session>
 {
 public:
+#if BOTAN_VERSION_MAJOR > 2
+  session(tcp::socket socket, std::shared_ptr<Botan::TLS::Context> ctx)
+#else
   session(tcp::socket socket, Botan::TLS::Context& ctx)
+#endif
     : socket_(std::move(socket), ctx)
   {
   }
@@ -112,7 +140,11 @@ private:
   void do_handshake()
   {
     auto self(shared_from_this());
+#if BOTAN_VERSION_MAJOR > 2
+    socket_.async_handshake(Botan::TLS::Connection_Side::Server,
+#else
     socket_.async_handshake(Botan::TLS::Connection_Side::SERVER,
+#endif
         [this, self](const boost::system::error_code& error)
         {
           if (!error)
@@ -162,12 +194,24 @@ class server
 public:
   server(boost::asio::io_context& io_context,
          unsigned short port,
+#if BOTAN_VERSION_MAJOR > 2
+         std::shared_ptr<Botan::Credentials_Manager> creds_mgr,
+         std::shared_ptr<Botan::RandomNumberGenerator> rng,
+         std::shared_ptr<Botan::TLS::Session_Manager> sess_mgr,
+         std::shared_ptr<Botan::TLS::Policy> policy
+#else
          Botan::Credentials_Manager& creds_mgr,
          Botan::RandomNumberGenerator& rng,
          Botan::TLS::Session_Manager& sess_mgr,
-         Botan::TLS::Policy& policy)
+         Botan::TLS::Policy& policy
+#endif
+         )
     : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)),
+#if BOTAN_VERSION_MAJOR > 2
+      context_(new Botan::TLS::Context(creds_mgr, rng, sess_mgr, policy))
+#else
       context_(creds_mgr, rng, sess_mgr, policy)
+#endif
   {
     do_accept();
   }
@@ -188,7 +232,11 @@ private:
   }
 
   tcp::acceptor acceptor_;
+#if BOTAN_VERSION_MAJOR > 2
+  std::shared_ptr<Botan::TLS::Context> context_;
+#else
   Botan::TLS::Context context_;
+#endif
 };
 
 int main(int argc, char* argv[])
@@ -203,10 +251,21 @@ int main(int argc, char* argv[])
 
     boost::asio::io_context io_context;
 
+#if BOTAN_VERSION_MAJOR > 2
+    std::shared_ptr<Botan::AutoSeeded_RNG>
+      rng(new Botan::AutoSeeded_RNG());
+    std::shared_ptr<Server_Credentials_Manager>
+      creds_mgr(new Server_Credentials_Manager());
+    std::shared_ptr<Server_Session_Manager>
+      sess_mgr(new Server_Session_Manager());
+    std::shared_ptr<Server_Policy>
+      policy(new Server_Policy());
+#else
     Botan::AutoSeeded_RNG rng;
     Server_Credentials_Manager creds_mgr(rng);
     Server_Session_Manager sess_mgr;
     Server_Policy policy;
+#endif
     server s(io_context, std::atoi(argv[1]), creds_mgr, rng, sess_mgr, policy);
 
     io_context.run();