Repository: randombit/botan
Pull request #2510 (2020-11-24 08:57:51)

Fix C++17 TODOs
Just did two minor TODOs that we marked to be done with C++17.


Patch:
diff --git a/doc/api_ref/tls.rst b/doc/api_ref/tls.rst
index e4d497a1a..fdffeda26 100644
--- a/doc/api_ref/tls.rst
+++ b/doc/api_ref/tls.rst
@@ -282,9 +282,11 @@ available:
    .. cpp:function:: std::vector<X509_Certificate> peer_cert_chain()
 
       Returns the certificate chain of the counterparty. When acting
-      as a client, this value will be non-empty. Acting as a server,
-      this value will ordinarily be empty, unless the server requested
-      a certificate and the client responded with one.
+      as a client, this value will be non-empty unless the client's
+      policy allowed anonymous connections and the server then chose
+      an anonymous ciphersuite. Acting as a server, this value will
+      ordinarily be empty, unless the server requested a certificate
+      and the client responded with one.
 
    .. cpp:function:: SymmetricKey key_material_export( \
           const std::string& label, \
@@ -333,8 +335,8 @@ TLS Clients
    :ref:`tls_session_managers` for more about session managers.
 
    The *credentials_manager* is an interface that will be called to
-   retrieve any certificates, private keys, or pre-shared keys; see
-   :doc:`credentials_manager` for more information.
+   retrieve any certificates, secret keys, pre-shared keys, or SRP
+   information; see :doc:`credentials_manager` for more information.
 
    Use the optional *server_info* to specify the DNS name of the
    server you are attempting to connect to, if you know it. This helps
@@ -696,6 +698,11 @@ information about that session:
 
        Returns the certificate chain of the peer
 
+   .. cpp:function:: std::string srp_identifier() const
+
+       If an SRP ciphersuite was used, then this is the identifier
+       that was used for authentication.
+
    .. cpp:function:: bool secure_renegotiation() const
 
       Returns ``true`` if the connection was negotiated with the
@@ -854,7 +861,8 @@ policy settings from a file.
 
      Also allowed: "AES-256", "AES-128",
      "AES-256/CCM", "AES-128/CCM", "AES-256/CCM(8)", "AES-128/CCM(8)",
-     "Camellia-256/GCM", "Camellia-128/GCM", "ARIA-256/GCM", "ARIA-128/GCM"
+     "Camellia-256/GCM", "Camellia-128/GCM", "ARIA-256/GCM", "ARIA-128/GCM",
+     "Camellia-256", "Camellia-128"
 
      Also allowed (though currently experimental): "AES-128/OCB(12)",
      "AES-256/OCB(12)"
@@ -862,7 +870,7 @@ policy settings from a file.
      In versions up to 2.8.0, the CBC and CCM ciphersuites "AES-256",
      "AES-128", "AES-256/CCM" and "AES-128/CCM" were enabled by default.
 
-     Also allowed (although **not recommended**): "3DES"
+     Also allowed (although **not recommended**): "SEED", "3DES"
 
      .. note::
 
@@ -876,7 +884,7 @@ policy settings from a file.
 
      .. note::
 
-        All CBC ciphersuites are deprecated and will be removed in a future release.
+        SEED and 3DES are deprecated and will be removed in a future release.
 
  .. cpp:function:: std::vector<std::string> allowed_macs() const
 
@@ -916,7 +924,7 @@ policy settings from a file.
         the benefit of post quantum security) so if CECPQ1 is being disabled for
         traffic overhead reasons, DH should also be avoided.
 
-     Also allowed: "RSA", "ECDHE_PSK", "DHE_PSK", "PSK"
+     Also allowed: "RSA", "SRP_SHA", "ECDHE_PSK", "DHE_PSK", "PSK"
 
      .. note::
 
@@ -928,7 +936,7 @@ policy settings from a file.
 
      .. note::
 
-        In order to enable RSA or PSK ciphersuites one must also enable
+        In order to enable RSA, SRP, or PSK ciphersuites one must also enable
         authentication method "IMPLICIT", see :cpp:func:`allowed_signature_methods`.
 
  .. cpp:function:: std::vector<std::string> allowed_signature_hashes() const
@@ -950,11 +958,19 @@ policy settings from a file.
 
      Default: "ECDSA", "RSA"
 
-     Also allowed (disabled by default): "IMPLICIT"
+     Also allowed (disabled by default): "DSA", "IMPLICIT", "ANONYMOUS"
 
      "IMPLICIT" enables ciphersuites which are authenticated not by a signature
      but through a side-effect of the key exchange. In particular this setting
-     is required to enable PSK and static RSA ciphersuites.
+     is required to enable PSK, SRP, and static RSA ciphersuites.
+
+     "ANONYMOUS" allows purely anonymous DH/ECDH key exchanges. **Enabling this
+     is not recommended**
+
+     .. note::
+
+        Both DSA authentication and anonymous DH ciphersuites are deprecated,
+        and will be removed in a future release.
 
  .. cpp:function:: std::vector<Group_Params> key_exchange_groups() const
 
@@ -1116,7 +1132,7 @@ policy settings from a file.
 
  .. cpp:function:: bool hide_unknown_users() const
 
-     The PSK suites work using an identifier along with a
+     The SRP and PSK suites work using an identifier along with a
      shared secret. If this function returns true, when an identifier
      that the server does not recognize is provided by a client, a
      random shared secret will be generated in such a way that a
diff --git a/doc/api_ref/x509.rst b/doc/api_ref/x509.rst
index a6c62a207..cbf3d531e 100644
--- a/doc/api_ref/x509.rst
+++ b/doc/api_ref/x509.rst
@@ -317,7 +317,7 @@ store would be one that looked up the certificates in a SQL database,
 or by contacting a CGI script running on a HTTP server. There are
 currently three mechanisms for looking up a certificate, and one for
 retrieving CRLs. By default, most of these mechanisms will return an
-empty ``std::optional`` of ``X509_Certificate``. This storage mechanism
+empty ``std::shared_ptr`` of ``X509_Certificate``. This storage mechanism
 is *only* queried when doing certificate validation: it allows you to
 distribute only the root key with an application, and let some online
 method handle getting all the other certificates that are needed to
@@ -334,24 +334,15 @@ mandatory to implement.
 
 Finally, there is a method for finding a CRL, called ``find_crl_for``,
 that takes an ``X509_Certificate`` object, and returns a
-``std::optional`` of ``X509_CRL``. The ``std::optional`` return
-type makes it easy to return no CRLs by returning ``nullopt``
+``std::shared_ptr`` of ``X509_CRL``. The ``std::shared_ptr`` return
+type makes it easy to return no CRLs by returning ``nullptr``
 (eg, if the certificate store doesn't support retrieving CRLs).
 Implementing the function is optional, and by default will return
-``nullopt``.
+``nullptr``.
 
 Certificate stores are used in the :doc:`tls` module to store a
 list of trusted certificate authorities.
 
-.. note::
-
-   In the 2.x library, the certificate store interface relied on
-   ``shared_ptr<X509_Certificate>`` to avoid copies. However since
-   2.4.0, the ``X509_Certificate`` was internally shared, and thus the
-   outer ``shared_ptr`` was just a cause of needless runtime overhead
-   and API complexity. Starting in version 3.0, the certificate store
-   interface is defined in terms of plain ``X509_Certificate``.
-
 In Memory Certificate Store
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -378,25 +369,17 @@ later.
 
      Add a certificate to the store
 
- .. cpp:function:: void add_crl(const X509_CRL& crl)
-
-     Add a certificate revocation list (CRL) to the store.
+ .. cpp:function:: void add_certificate(std::shared_ptr<const X509_Certificate> cert)
 
-System Certificate Stores
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+     Add a certificate already in a shared_ptr to the store
 
-An interface to use the system provided certificate stores is available for
-Unix, macOS and Windows systems, ``System_Certificate_Store``
+ .. cpp:function:: void add_crl(const X509_CRL& crl)
 
-Flatfile Certificate Stores
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+     Add a certificate revocation list (CRL) to the store.
 
-``Flatfile_Certificate_Store`` is an implementation of certificate store that
-reads certificates as files from a directory. This is also used as the
-implementation of the Unix/Linux system certificate store.
+ .. cpp:function:: void add_crl(std::shared_ptr<const X509_CRL> crl)
 
-The constructor takes a path to the directory to read, along with an optional
-boolean indicating if non-CA certificates should be ignored.
+     Add a certificate revocation list (CRL) to the store as a shared_ptr
 
 SQL-backed Certificate Stores
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -427,7 +410,8 @@ certificates.
 
      Returns the private key for "cert" or an empty shared_ptr if none was found
 
- .. cpp:function:: std::vector<X509_Certificate> find_certs_for_key(const Private_Key& key) const
+ .. cpp:function:: std::vector<std::shared_ptr<const X509_Certificate>> \
+    find_certs_for_key(const Private_Key& key) const
 
      Returns all certificates for private key ``key``
 
@@ -481,7 +465,7 @@ set of functions in ``x509path.h`` named ``x509_path_validate``:
    Usage_Type usage = Usage_Type::UNSPECIFIED, \
    std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), \
    std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), \
-   const std::vector<std::optional<OCSP::Response>>& ocsp_resp = std::vector<std::optional<OCSP::Response>>())
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = std::vector<std::shared_ptr<const OCSP::Response>>())
 
    The last five parameters are optional. ``hostname`` specifies a hostname which is
    matched against the subject DN in ``end_cert`` according to RFC 6125.
@@ -854,7 +838,7 @@ for certificate status information.
 
   .. cpp:function:: Certificate_Status_Code check_signature( \
                     const std::vector<Certificate_Store*>& trust_roots, \
-                    const std::vector<X509_Certificate>& cert_path = const std::vector<X509_Certificate>()) const
+                    const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path = const std::vector<std::shared<const X509_Certificate>>()) const
 
      Find the issuing certificate of the OCSP response, and check the signature.
 
diff --git a/doc/building.rst b/doc/building.rst
index 7e54479a7..93652f266 100644
--- a/doc/building.rst
+++ b/doc/building.rst
@@ -232,11 +232,8 @@ For Android
 ---------------------
 
 Modern versions of Android NDK use Clang and support C++17. Simply
-configure using the appropriate NDK compiler and ``ar`` (``ar`` only
-needed if building the static library). Here we build for Aarch64
-targeting Android API 28::
+configure using the appropriate NDK compiler::
 
-  $ export AR=/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar
   $ export CXX=/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang++
   $ ./configure.py --os=android --cc=clang --cpu=arm64
 
diff --git a/doc/deprecated.rst b/doc/deprecated.rst
index 0ac159692..0d16e5f9a 100644
--- a/doc/deprecated.rst
+++ b/doc/deprecated.rst
@@ -34,12 +34,18 @@ in a future major release:
 - All CBC mode ciphersuites. This includes all available 3DES and SEED
   ciphersuites. This implies also removing Encrypt-then-MAC extension.
 
-- All ciphersuites using DH key exchange (DHE-RSA, DHE-PSK)
+- All ciphersuites using DH key exchange (DHE-DSS, DHE-RSA, DHE-PSK, anon DH)
 
 - Support for renegotiation in TLS v1.2
 
 - All ciphersuites using static RSA key exchange
 
+- SRP ciphersuites. This is implied by the removal of CBC mode, since
+  all available SRP ciphersuites use CBC. To avoid use of obsolete
+  ciphers, it would be better to instead perform a standard TLS
+  negotiation, then a PAKE authentication within (and bound to) the
+  TLS channel.
+
 - OCB ciphersuites using 128-bit keys
 
 Deprecated Functionality
diff --git a/news.rst b/news.rst
index ea4793d60..5e73ff4b5 100644
--- a/news.rst
+++ b/news.rst
@@ -16,16 +16,12 @@ Version 3.0.0, Not Yet Released
   DESX, XTEA, PBKDF1, MCEIES, CBC-MAC and Tiger (GH #2434)
 
 * Remove several deprecated features in TLS including DSA ciphersuites (GH #2505),
-  anonymous ciphersuites (GH #2497), SRP ciphersuites (GH #2506),
-  SEED ciphersuites (GH #2509), Camellia CBC ciphersuites (GH #2509)
+  anonymous ciphersuites (GH #2497)
 
 * Resolve an issue in the modular square root function which could cause
   a near-infinite loop if used with a composite modulus of a certain form
   where finding a quadratic non-residue is hard. (GH #2478 #2476)
 
-* Remove use of ``shared_ptr`` from certificate store API as since
-  2.4.0 ``X509_Certificate`` is internally a ``shared_ptr``. (GH #2484)
-
 * Add new ``X509_DN::DER_encode`` function. (GH #2472)
 
 * Re-enable support for CLMUL instruction on Visual C++, which was accidentally
diff --git a/src/bogo_shim/bogo_shim.cpp b/src/bogo_shim/bogo_shim.cpp
index 350623854..c62bc8e67 100644
--- a/src/bogo_shim/bogo_shim.cpp
+++ b/src/bogo_shim/bogo_shim.cpp
@@ -1009,7 +1009,8 @@ class Shim_Policy final : public Botan::TLS::Policy
          return true;
          }
 
-      std::vector<uint16_t> ciphersuite_list(Botan::TLS::Protocol_Version version) const override;
+      std::vector<uint16_t> ciphersuite_list(Botan::TLS::Protocol_Version version,
+                                             bool have_srp) const override;
 
       size_t dtls_default_mtu() const override
          {
@@ -1043,7 +1044,8 @@ class Shim_Policy final : public Botan::TLS::Policy
       size_t m_sessions;
    };
 
-std::vector<uint16_t> Shim_Policy::ciphersuite_list(Botan::TLS::Protocol_Version version) const
+std::vector<uint16_t> Shim_Policy::ciphersuite_list(Botan::TLS::Protocol_Version version,
+                                                    bool have_srp) const
    {
    std::vector<uint16_t> ciphersuite_codes;
 
@@ -1078,6 +1080,10 @@ std::vector<uint16_t> Shim_Policy::ciphersuite_list(Botan::TLS::Protocol_Version
          if(suite.valid() == false)
             continue;
 
+         // Are we doing SRP?
+         if(!have_srp && suite.kex_method() == Botan::TLS::Kex_Algo::SRP_SHA)
+            continue;
+
          if(cipher_limit != "")
             {
             if(cipher_limit == "DEFAULT:!AES")
@@ -1318,7 +1324,7 @@ class Shim_Callbacks final : public Botan::TLS::Callbacks
          }
 
       void tls_verify_cert_chain(const std::vector<Botan::X509_Certificate>& /*cert_chain*/,
-                                 const std::vector<std::optional<Botan::OCSP::Response>>& /*ocsp_responses*/,
+                                 const std::vector<std::shared_ptr<const Botan::OCSP::Response>>& /*ocsp_responses*/,
                                  const std::vector<Botan::Certificate_Store*>& /*trusted_roots*/,
                                  Botan::Usage_Type /*usage*/,
                                  const std::string& /*hostname*/,
diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp
index eee97a4c0..3ef7195dd 100644
--- a/src/cli/tls_client.cpp
+++ b/src/cli/tls_client.cpp
@@ -308,7 +308,7 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks
 
       void tls_verify_cert_chain(
          const std::vector<Botan::X509_Certificate>& cert_chain,
-         const std::vector<std::optional<Botan::OCSP::Response>>& ocsp,
+         const std::vector<std::shared_ptr<const Botan::OCSP::Response>>& ocsp,
          const std::vector<Botan::Certificate_Store*>& trusted_roots,
          Botan::Usage_Type usage,
          const std::string& hostname,
diff --git a/src/cli/tls_helpers.h b/src/cli/tls_helpers.h
index f23a70798..653a106e0 100644
--- a/src/cli/tls_helpers.h
+++ b/src/cli/tls_helpers.h
@@ -182,7 +182,7 @@ class TLS_All_Policy final : public Botan::TLS::Policy
 
       std::vector<std::string> allowed_key_exchange_methods() const override
          {
-         return { "ECDHE_PSK", "DHE_PSK", "PSK", "CECPQ1", "ECDH", "DH", "RSA" };
+         return { "SRP_SHA", "ECDHE_PSK", "DHE_PSK", "PSK", "CECPQ1", "ECDH", "DH", "RSA" };
          }
 
       std::vector<std::string> allowed_signature_methods() const override
diff --git a/src/cli/tls_utils.cpp b/src/cli/tls_utils.cpp
index 698c625e1..b7340c404 100644
--- a/src/cli/tls_utils.cpp
+++ b/src/cli/tls_utils.cpp
@@ -67,6 +67,7 @@ class TLS_Ciphersuites final : public Command
          {
          const std::string policy_type = get_arg("policy");
          const Botan::TLS::Protocol_Version version(tls_version_from_str(get_arg("version")));
+         const bool with_srp = false; // fixme
 
          auto policy = load_tls_policy(policy_type);
 
@@ -76,7 +77,7 @@ class TLS_Ciphersuites final : public Command
             return;
             }
 
-         for(uint16_t suite_id : policy->ciphersuite_list(version))
+         for(uint16_t suite_id : policy->ciphersuite_list(version, with_srp))
             {
             const Botan::TLS::Ciphersuite suite(Botan::TLS::Ciphersuite::by_id(suite_id));
             output() << suite.to_string() << "\n";
diff --git a/src/cli/x509.cpp b/src/cli/x509.cpp
index 64e66366e..f5691b8d5 100644
--- a/src/cli/x509.cpp
+++ b/src/cli/x509.cpp
@@ -67,9 +67,9 @@ class Trust_Root_Info final : public Command
                      output() << "# " << dn << "\n";
 
                   if(flag_set("display"))
-                     output() << cert.to_string() << "\n";
+                     output() << cert->to_string() << "\n";
 
-                  output() << cert.PEM_encode() << "\n";
+                  output() << cert->PEM_encode() << "\n";
                   }
                }
 
diff --git a/src/fuzzer/tls_client.cpp b/src/fuzzer/tls_client.cpp
index 2adc6b350..c8e5839f4 100644
--- a/src/fuzzer/tls_client.cpp
+++ b/src/fuzzer/tls_client.cpp
@@ -21,7 +21,8 @@ class Fuzzer_TLS_Client_Creds : public Botan::Credentials_Manager
 class Fuzzer_TLS_Policy : public Botan::TLS::Policy
    {
    public:
-      std::vector<uint16_t> ciphersuite_list(Botan::TLS::Protocol_Version version) const override
+      std::vector<uint16_t> ciphersuite_list(Botan::TLS::Protocol_Version version,
+                                             bool have_srp) const override
          {
          std::vector<uint16_t> ciphersuites;
 
@@ -30,6 +31,10 @@ class Fuzzer_TLS_Policy : public Botan::TLS::Policy
             if(suite.valid() == false)
                continue;
 
+            // Are we doing SRP?
+            if(!have_srp && suite.kex_method() == Botan::TLS::Kex_Algo::SRP_SHA)
+               continue;
+
             if(!version.supports_aead_modes())
                {
                // Are we doing AEAD in a non-AEAD version?
@@ -73,7 +78,7 @@ class Fuzzer_TLS_Client_Callbacks : public Botan::TLS::Callbacks
 
       void tls_verify_cert_chain(
          const std::vector<Botan::X509_Certificate>& cert_chain,
-         const std::vector<std::optional<Botan::OCSP::Response>>& ocsp_responses,
+         const std::vector<std::shared_ptr<const Botan::OCSP::Response>>& ocsp_responses,
          const std::vector<Botan::Certificate_Store*>& trusted_roots,
          Botan::Usage_Type usage,
          const std::string& hostname,
diff --git a/src/fuzzer/tls_server.cpp b/src/fuzzer/tls_server.cpp
index f251a9df1..9df6151a7 100644
--- a/src/fuzzer/tls_server.cpp
+++ b/src/fuzzer/tls_server.cpp
@@ -112,7 +112,8 @@ class Fuzzer_TLS_Server_Creds : public Botan::Credentials_Manager
 class Fuzzer_TLS_Policy : public Botan::TLS::Policy
    {
    public:
-      std::vector<uint16_t> ciphersuite_list(Botan::TLS::Protocol_Version version) const override
+      std::vector<uint16_t> ciphersuite_list(Botan::TLS::Protocol_Version version,
+                                             bool have_srp) const override
          {
          std::vector<uint16_t> ciphersuites;
 
@@ -121,6 +122,10 @@ class Fuzzer_TLS_Policy : public Botan::TLS::Policy
             if(suite.valid() == false)
                continue;
 
+            // Are we doing SRP?
+            if(!have_srp && suite.kex_method() == Botan::TLS::Kex_Algo::SRP_SHA)
+               continue;
+
             if(!version.supports_aead_modes())
                {
                // Are we doing AEAD in a non-AEAD version?
@@ -172,7 +177,7 @@ class Fuzzer_TLS_Server_Callbacks : public Botan::TLS::Callbacks
 
       void tls_verify_cert_chain(
          const std::vector<Botan::X509_Certificate>& cert_chain,
-         const std::vector<std::optional<Botan::OCSP::Response>>& ocsp_responses,
+         const std::vector<std::shared_ptr<const Botan::OCSP::Response>>& ocsp_responses,
          const std::vector<Botan::Certificate_Store*>& trusted_roots,
          Botan::Usage_Type usage,
          const std::string& hostname,
diff --git a/src/lib/tls/asio/asio_stream.h b/src/lib/tls/asio/asio_stream.h
index bc2d47cbf..f1ffa67f2 100644
--- a/src/lib/tls/asio/asio_stream.h
+++ b/src/lib/tls/asio/asio_stream.h
@@ -621,7 +621,7 @@ class Stream
 
             void tls_verify_cert_chain(
                const std::vector<X509_Certificate>& cert_chain,
-               const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
+               const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses,
                const std::vector<Certificate_Store*>& trusted_roots,
                Usage_Type usage,
                const std::string& hostname,
@@ -666,14 +666,6 @@ class Stream
       //! @brief Mark bytes in the send buffer as consumed, removing them from the buffer
       void consume_send_buffer(std::size_t bytesConsumed) { m_send_buffer.consume(bytesConsumed); }
 
-      // This is a helper construct to allow mocking the native_handle in test code. It is activated by explicitly
-      // specifying a (mocked) channel type template parameter when constructing the stream and does not attempt to
-      // instantiate the native_handle.
-      // Note: once we have C++17 we can achieve this much more elegantly using constexpr if.
-      template<class T = ChannelT>
-      typename std::enable_if<!std::is_same<Channel, T>::value>::type
-      setup_native_handle(Connection_Side, boost::system::error_code&) {}
-
       /**
        * @brief Create the native handle.
        *
@@ -683,34 +675,39 @@ class Stream
        * @param side The desired connection side (client or server)
        * @param ec Set to indicate what error occurred, if any.
        */
-      template<class T = ChannelT>
-      typename std::enable_if<std::is_same<Channel, T>::value>::type
-      setup_native_handle(Connection_Side side, boost::system::error_code& ec)
+      void setup_native_handle(Connection_Side side, boost::system::error_code& ec)
          {
-         try_with_error_code([&]
+         BOTAN_UNUSED(side);  // workaround: GCC 9 produces a warning claiming side is unused
+
+         // Do not attempt to instantiate the native_handle when a custom (mocked) channel type template parameter has
+         // been specified. This allows mocking the native_handle in test code.
+         if constexpr(std::is_same<ChannelT, Channel>::value)
             {
-            if(side == CLIENT)
-               {
-               m_native_handle = std::unique_ptr<Client>(
-                  new Client(m_core,
-                             m_context.m_session_manager,
-                             m_context.m_credentials_manager,
-                             m_context.m_policy,
-                             m_context.m_rng,
-                             m_context.m_server_info,
-                             Protocol_Version::latest_tls_version()));
-               }
-            else
+            try_with_error_code([&]
                {
-               m_native_handle = std::unique_ptr<Server>(
-                  new Server(m_core,
-                             m_context.m_session_manager,
-                             m_context.m_credentials_manager,
-                             m_context.m_policy,
-                             m_context.m_rng,
-                             false /* no DTLS */));
-               }
-            }, ec);
+               if(side == CLIENT)
+                  {
+                  m_native_handle = std::unique_ptr<Client>(
+                     new Client(m_core,
+                                m_context.m_session_manager,
+                                m_context.m_credentials_manager,
+                                m_context.m_policy,
+                                m_context.m_rng,
+                                m_context.m_server_info,
+                                Protocol_Version::latest_tls_version()));
+                  }
+               else
+                  {
+                  m_native_handle = std::unique_ptr<Server>(
+                     new Server(m_core,
+                                m_context.m_session_manager,
+                                m_context.m_credentials_manager,
+                                m_context.m_policy,
+                                m_context.m_rng,
+                                false /* no DTLS */));
+                  }
+               }, ec);
+            }
          }
 
       /** @brief Synchronously write encrypted data from the send buffer to the next layer.
diff --git a/src/lib/tls/credentials_manager.cpp b/src/lib/tls/credentials_manager.cpp
index aca751d00..0c5ae9718 100644
--- a/src/lib/tls/credentials_manager.cpp
+++ b/src/lib/tls/credentials_manager.cpp
@@ -30,6 +30,36 @@ SymmetricKey Credentials_Manager::psk(const std::string&,
    throw Internal_Error("No PSK set for identity " + identity);
    }
 
+bool Credentials_Manager::attempt_srp(const std::string&,
+                                      const std::string&)
+   {
+   return false;
+   }
+
+std::string Credentials_Manager::srp_identifier(const std::string&,
+                                                const std::string&)
+   {
+   return "";
+   }
+
+std::string Credentials_Manager::srp_password(const std::string&,
+                                              const std::string&,
+                                              const std::string&)
+   {
+   return "";
+   }
+
+bool Credentials_Manager::srp_verifier(const std::string&,
+                                       const std::string&,
+                                       const std::string&,
+                                       std::string&,
+                                       BigInt&,
+                                       std::vector<uint8_t>&,
+                                       bool)
+   {
+   return false;
+   }
+
 std::vector<X509_Certificate> Credentials_Manager::find_cert_chain(
    const std::vector<std::string>& key_types,
    const std::vector<X509_DN>&,
diff --git a/src/lib/tls/credentials_manager.h b/src/lib/tls/credentials_manager.h
index d036a1524..627894a87 100644
--- a/src/lib/tls/credentials_manager.h
+++ b/src/lib/tls/credentials_manager.h
@@ -118,6 +118,48 @@ class BOTAN_PUBLIC_API(2,0) Credentials_Manager
                                            const std::string& type,
                                            const std::string& context);
 
+      /**
+      * @param type specifies the type of operation occurring
+      * @param context specifies a context relative to type.
+      * @return true if we should attempt SRP authentication
+      */
+      virtual bool attempt_srp(const std::string& type,
+                               const std::string& context);
+
+      /**
+      * @param type specifies the type of operation occurring
+      * @param context specifies a context relative to type.
+      * @return identifier for client-side SRP auth, if available
+                for this type/context. Should return empty string
+                if password auth not desired/available.
+      */
+      virtual std::string srp_identifier(const std::string& type,
+                                         const std::string& context);
+
+      /**
+      * @param type specifies the type of operation occurring
+      * @param context specifies a context relative to type.
+      * @param identifier specifies what identifier we want the
+      *        password for. This will be a value previously returned
+      *        by srp_identifier.
+      * @return password for client-side SRP auth, if available
+                for this identifier/type/context.
+      */
+      virtual std::string srp_password(const std::string& type,
+                                       const std::string& context,
+                                       const std::string& identifier);
+
+      /**
+      * Retrieve SRP verifier parameters
+      */
+      virtual bool srp_verifier(const std::string& type,
+                                const std::string& context,
+                                const std::string& identifier,
+                                std::string& group_name,
+                                BigInt& verifier,
+                                std::vector<uint8_t>& salt,
+                                bool generate_fake_on_unknown);
+
       /**
       * @param type specifies the type of operation occurring
       * @param context specifies a context relative to type.
diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp
index 3eee06e69..149f3f0d4 100644
--- a/src/lib/tls/msg_client_hello.cpp
+++ b/src/lib/tls/msg_client_hello.cpp
@@ -89,7 +89,7 @@ Client_Hello::Client_Hello(Handshake_IO& io,
                            const std::vector<std::string>& next_protocols) :
    m_version(client_settings.protocol_version()),
    m_random(make_hello_random(rng, policy)),
-   m_suites(policy.ciphersuite_list(m_version)),
+   m_suites(policy.ciphersuite_list(m_version, !client_settings.srp_identifier().empty())),
    m_comp_methods(1)
    {
    if(!policy.acceptable_protocol_version(m_version))
@@ -125,6 +125,15 @@ Client_Hello::Client_Hello(Handshake_IO& io,
    if(m_version.is_datagram_protocol())
       m_extensions.add(new SRTP_Protection_Profiles(policy.srtp_profiles()));
 
+#if defined(BOTAN_HAS_SRP6)
+   m_extensions.add(new SRP_Identifier(client_settings.srp_identifier()));
+#else
+   if(!client_settings.srp_identifier().empty())
+      {
+      throw Invalid_State("Attempting to initiate SRP session but TLS-SRP support disabled");
+      }
+#endif
+
    std::unique_ptr<Supported_Groups> supported_groups(new Supported_Groups(policy.key_exchange_groups()));
 
    if(supported_groups->ec_groups().size() > 0)
@@ -156,7 +165,7 @@ Client_Hello::Client_Hello(Handshake_IO& io,
    m_version(session.version()),
    m_session_id(session.session_id()),
    m_random(make_hello_random(rng, policy)),
-   m_suites(policy.ciphersuite_list(m_version)),
+   m_suites(policy.ciphersuite_list(m_version, (session.srp_identifier() != ""))),
    m_comp_methods(1)
    {
    if(!policy.acceptable_protocol_version(m_version))
@@ -192,6 +201,15 @@ Client_Hello::Client_Hello(Handshake_IO& io,
    if(session.supports_encrypt_then_mac())
       m_extensions.add(new Encrypt_then_MAC);
 
+#if defined(BOTAN_HAS_SRP6)
+   m_extensions.add(new SRP_Identifier(session.srp_identifier()));
+#else
+   if(!session.srp_identifier().empty())
+      {
+      throw Invalid_State("Attempting to resume SRP session but TLS-SRP support disabled");
+      }
+#endif
+
    if(m_version.supports_negotiable_signature_algorithms())
       m_extensions.add(new Signature_Algorithms(policy.allowed_signature_schemes()));
 
@@ -362,6 +380,15 @@ std::string Client_Hello::sni_hostname() const
    return "";
    }
 
+#if defined(BOTAN_HAS_SRP6)
+std::string Client_Hello::srp_identifier() const
+   {
+   if(SRP_Identifier* srp = m_extensions.get<SRP_Identifier>())
+      return srp->identifier();
+   return "";
+   }
+#endif
+
 bool Client_Hello::secure_renegotiation() const
    {
    return m_extensions.has<Renegotiation_Extension>();
diff --git a/src/lib/tls/msg_client_kex.cpp b/src/lib/tls/msg_client_kex.cpp
index beeede31f..39266962b 100644
--- a/src/lib/tls/msg_client_kex.cpp
+++ b/src/lib/tls/msg_client_kex.cpp
@@ -23,6 +23,10 @@
   #include <botan/cecpq1.h>
 #endif
 
+#if defined(BOTAN_HAS_SRP6)
+  #include <botan/srp6.h>
+#endif
+
 namespace Botan {
 
 namespace TLS {
@@ -142,6 +146,36 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io,
 
          append_tls_length_value(m_key_material, ecdh_result.second, 1);
          }
+#if defined(BOTAN_HAS_SRP6)
+      else if(kex_algo == Kex_Algo::SRP_SHA)
+         {
+         const BigInt N = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
+         const BigInt g = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
+         std::vector<uint8_t> salt = reader.get_range<uint8_t>(1, 1, 255);
+         const BigInt B = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
+
+         const std::string srp_group = srp6_group_identifier(N, g);
+
+         const std::string srp_identifier =
+            creds.srp_identifier("tls-client", hostname);
+
+         const std::string srp_password =
+            creds.srp_password("tls-client", hostname, srp_identifier);
+
+         std::pair<BigInt, SymmetricKey> srp_vals =
+            srp6_client_agree(srp_identifier,
+                              srp_password,
+                              srp_group,
+                              "SHA-1",
+                              salt,
+                              B,
+                              rng);
+
+         append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2);
+         m_pre_master = srp_vals.second.bits_of();
+         }
+#endif
+
 #if defined(BOTAN_HAS_CECPQ1)
       else if(kex_algo == Kex_Algo::CECPQ1)
          {
@@ -279,6 +313,14 @@ Client_Key_Exchange::Client_Key_Exchange(const std::vector<uint8_t>& contents,
          append_tls_length_value(m_pre_master, zeros, 2);
          append_tls_length_value(m_pre_master, psk.bits_of(), 2);
          }
+#if defined(BOTAN_HAS_SRP6)
+      else if(kex_algo == Kex_Algo::SRP_SHA)
+         {
+         SRP6_Server_Session& srp = state.server_kex()->server_srp_params();
+
+         m_pre_master = srp.step2(BigInt::decode(reader.get_range<uint8_t>(2, 0, 65535))).bits_of();
+         }
+#endif
 #if defined(BOTAN_HAS_CECPQ1)
       else if(kex_algo == Kex_Algo::CECPQ1)
          {
diff --git a/src/lib/tls/msg_server_kex.cpp b/src/lib/tls/msg_server_kex.cpp
index 35bd94d1b..cefb88904 100644
--- a/src/lib/tls/msg_server_kex.cpp
+++ b/src/lib/tls/msg_server_kex.cpp
@@ -26,6 +26,10 @@
   #include <botan/cecpq1.h>
 #endif
 
+#if defined(BOTAN_HAS_SRP6)
+  #include <botan/srp6.h>
+#endif
+
 namespace Botan {
 
 namespace TLS {
@@ -133,6 +137,37 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io,
 
       append_tls_length_value(m_params, ecdh_public_val, 1);
       }
+#if defined(BOTAN_HAS_SRP6)
+   else if(kex_algo == Kex_Algo::SRP_SHA)
+      {
+      const std::string srp_identifier = state.client_hello()->srp_identifier();
+
+      std::string group_id;
+      BigInt v;
+      std::vector<uint8_t> salt;
+
+      const bool found = creds.srp_verifier("tls-server", hostname,
+                                            srp_identifier,
+                                            group_id, v, salt,
+                                            policy.hide_unknown_users());
+
+      if(!found)
+         throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY,
+                             "Unknown SRP user " + srp_identifier);
+
+      m_srp_params.reset(new SRP6_Server_Session);
+
+      BigInt B = m_srp_params->step1(v, group_id,
+                                     "SHA-1", rng);
+
+      DL_Group group(group_id);
+
+      append_tls_length_value(m_params, BigInt::encode(group.get_p()), 2);
+      append_tls_length_value(m_params, BigInt::encode(group.get_g()), 2);
+      append_tls_length_value(m_params, salt, 1);
+      append_tls_length_value(m_params, BigInt::encode(B), 2);
+      }
+#endif
 #if defined(BOTAN_HAS_CECPQ1)
    else if(kex_algo == Kex_Algo::CECPQ1)
       {
@@ -204,6 +239,15 @@ Server_Key_Exchange::Server_Key_Exchange(const std::vector<uint8_t>& buf,
       reader.get_uint16_t(); // curve id
       reader.get_range<uint8_t>(1, 1, 255); // public key
       }
+   else if(kex_algo == Kex_Algo::SRP_SHA)
+      {
+      // 2 bigints (N,g) then salt, then server B
+
+      reader.get_range<uint8_t>(2, 1, 65535);
+      reader.get_range<uint8_t>(2, 1, 65535);
+      reader.get_range<uint8_t>(1, 1, 255);
+      reader.get_range<uint8_t>(2, 1, 65535);
+      }
    else if(kex_algo == Kex_Algo::CECPQ1)
       {
       // u16 blob
diff --git a/src/lib/tls/tls_algos.cpp b/src/lib/tls/tls_algos.cpp
index cdd6cc1b9..5c383807b 100644
--- a/src/lib/tls/tls_algos.cpp
+++ b/src/lib/tls/tls_algos.cpp
@@ -38,6 +38,8 @@ std::string kex_method_to_string(Kex_Algo method)
          return "ECDH";
       case Kex_Algo::CECPQ1:
          return "CECPQ1";
+      case Kex_Algo::SRP_SHA:
+         return "SRP_SHA";
       case Kex_Algo::PSK:
          return "PSK";
       case Kex_Algo::DHE_PSK:
@@ -63,6 +65,9 @@ Kex_Algo kex_method_from_string(const std::string& str)
    if(str == "CECPQ1")
       return Kex_Algo::CECPQ1;
 
+   if(str == "SRP_SHA")
+      return Kex_Algo::SRP_SHA;
+
    if(str == "PSK")
       return Kex_Algo::PSK;
 
diff --git a/src/lib/tls/tls_algos.h b/src/lib/tls/tls_algos.h
index 6f99574ce..0d3a02304 100644
--- a/src/lib/tls/tls_algos.h
+++ b/src/lib/tls/tls_algos.h
@@ -20,30 +20,35 @@ namespace TLS {
 enum class Cipher_Algo {
    CHACHA20_POLY1305,
 
+   AES_128_CBC_HMAC_SHA1 = 100,
+   AES_128_CBC_HMAC_SHA256,
+   AES_128_CCM,
+   AES_128_CCM_8,
    AES_128_GCM,
-   AES_256_GCM,
-
    AES_128_OCB,
+
+   AES_256_CBC_HMAC_SHA1 = 200,
+   AES_256_CBC_HMAC_SHA256,
+   AES_256_CBC_HMAC_SHA384,
+   AES_256_CCM,
+   AES_256_CCM_8,
+   AES_256_GCM,
    AES_256_OCB,
 
+   CAMELLIA_128_CBC_HMAC_SHA1 = 300,
+   CAMELLIA_128_CBC_HMAC_SHA256,
    CAMELLIA_128_GCM,
+
+   CAMELLIA_256_CBC_HMAC_SHA1 = 400,
+   CAMELLIA_256_CBC_HMAC_SHA256,
+   CAMELLIA_256_CBC_HMAC_SHA384,
    CAMELLIA_256_GCM,
 
-   ARIA_128_GCM,
+   ARIA_128_GCM = 500,
    ARIA_256_GCM,
 
-   AES_128_CCM,
-   AES_256_CCM,
-   AES_128_CCM_8,
-   AES_256_CCM_8,
-
-   AES_128_CBC_HMAC_SHA1,
-   AES_128_CBC_HMAC_SHA256,
-   AES_256_CBC_HMAC_SHA1,
-   AES_256_CBC_HMAC_SHA256,
-   AES_256_CBC_HMAC_SHA384,
-
-   DES_EDE_CBC_HMAC_SHA1,
+   DES_EDE_CBC_HMAC_SHA1 = 1000,
+   SEED_CBC_HMAC_SHA1,
 };
 
 enum class KDF_Algo {
@@ -136,6 +141,7 @@ enum class Kex_Algo {
    DH,
    ECDH,
    CECPQ1,
+   SRP_SHA,
    PSK,
    DHE_PSK,
    ECDHE_PSK,
diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp
index 4b43359eb..0dd758b75 100644
--- a/src/lib/tls/tls_callbacks.cpp
+++ b/src/lib/tls/tls_callbacks.cpp
@@ -52,7 +52,7 @@ std::string TLS::Callbacks::tls_decode_group_param(Group_Params group_param)
 
 void TLS::Callbacks::tls_verify_cert_chain(
    const std::vector<X509_Certificate>& cert_chain,
-   const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses,
    const std::vector<Certificate_Store*>& trusted_roots,
    Usage_Type usage,
    const std::string& hostname,
diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h
index 5c81e2f93..795663e22 100644
--- a/src/lib/tls/tls_callbacks.h
+++ b/src/lib/tls/tls_callbacks.h
@@ -13,7 +13,7 @@
 #include <botan/tls_session.h>
 #include <botan/tls_alert.h>
 #include <botan/pubkey.h>
-#include <optional>
+#include <functional>
 
 namespace Botan {
 
@@ -128,7 +128,7 @@ class BOTAN_PUBLIC_API(2,0) Callbacks
        */
        virtual void tls_verify_cert_chain(
           const std::vector<X509_Certificate>& cert_chain,
-          const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
+          const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses,
           const std::vector<Certificate_Store*>& trusted_roots,
           Usage_Type usage,
           const std::string& hostname,
diff --git a/src/lib/tls/tls_ciphersuite.cpp b/src/lib/tls/tls_ciphersuite.cpp
index 3e54bcb89..738be110b 100644
--- a/src/lib/tls/tls_ciphersuite.cpp
+++ b/src/lib/tls/tls_ciphersuite.cpp
@@ -199,7 +199,13 @@ bool Ciphersuite::is_usable() const
          return false;
       }
 
-   if(kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK)
+   if(kex_method() == Kex_Algo::SRP_SHA)
+      {
+#if !defined(BOTAN_HAS_SRP6)
+      return false;
+#endif
+      }
+   else if(kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK)
       {
 #if !defined(BOTAN_HAS_ECDH)
       return false;
diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp
index 117dfcabe..091e649a9 100644
--- a/src/lib/tls/tls_client.cpp
+++ b/src/lib/tls/tls_client.cpp
@@ -75,8 +75,11 @@ Client::Client(Callbacks& callbacks,
    m_creds(creds),
    m_info(info)
    {
+   const std::string srp_identifier = m_creds.srp_identifier("tls-client", m_info.hostname());
+
    Handshake_State& state = create_handshake_state(offer_version);
-   send_client_hello(state, false, offer_version, next_protocols);
+   send_client_hello(state, false, offer_version,
+                     srp_identifier, next_protocols);
    }
 
 Handshake_State* Client::new_handshake_state(Handshake_IO* io)
@@ -110,6 +113,7 @@ void Client::initiate_handshake(Handshake_State& state,
 void Client::send_client_hello(Handshake_State& state_base,
                                bool force_full_renegotiation,
                                Protocol_Version version,
+                               const std::string& srp_identifier,
                                const std::vector<std::string>& next_protocols)
    {
    Client_Handshake_State& state = dynamic_cast<Client_Handshake_State&>(state_base);
@@ -136,24 +140,27 @@ void Client::send_client_hello(Handshake_State& state_base,
 
          if(policy().acceptable_ciphersuite(session_info->ciphersuite()) && session_version_ok)
             {
-            state.client_hello(
-               new Client_Hello(state.handshake_io(),
-                                state.hash(),
-                                policy(),
-                                callbacks(),
-                                rng(),
-                                secure_renegotiation_data_for_client_hello(),
-                                *session_info,
-                                next_protocols));
-
-            state.resumed_session = std::move(session_info);
+            if(srp_identifier == "" || session_info->srp_identifier() == srp_identifier)
+               {
+               state.client_hello(
+                  new Client_Hello(state.handshake_io(),
+                                   state.hash(),
+                                   policy(),
+                                   callbacks(),
+                                   rng(),
+                                   secure_renegotiation_data_for_client_hello(),
+                                   *session_info,
+                                   next_protocols));
+
+               state.resumed_session = std::move(session_info);
+               }
             }
          }
       }
 
    if(!state.client_hello()) // not resuming
       {
-      Client_Hello::Settings client_settings(version, m_info.hostname());
+      Client_Hello::Settings client_settings(version, m_info.hostname(), srp_identifier);
       state.client_hello(new Client_Hello(
          state.handshake_io(),
          state.hash(),
@@ -571,11 +578,11 @@ void Client::process_handshake_msg(const Handshake_State* active_state,
             {
             auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname());
 
-            std::vector<std::optional<OCSP::Response>> ocsp;
+            std::vector<std::shared_ptr<const OCSP::Response>> ocsp;
             if(state.server_cert_status() != nullptr)
                {
                try {
-                  ocsp.push_back(OCSP::Response(state.server_cert_status()->response()));
+                   ocsp.push_back(std::make_shared<OCSP::Response>(state.server_cert_status()->response()));
                }
                catch(Decoding_Error&)
                   {
@@ -702,6 +709,7 @@ void Client::process_handshake_msg(const Handshake_State* active_state,
          get_peer_cert_chain(state),
          session_ticket,
          m_info,
+         "",
          state.server_hello()->srtp_profile()
          );
 
diff --git a/src/lib/tls/tls_client.h b/src/lib/tls/tls_client.h
index 8528491ce..7440e59ef 100644
--- a/src/lib/tls/tls_client.h
+++ b/src/lib/tls/tls_client.h
@@ -75,6 +75,7 @@ class BOTAN_PUBLIC_API(2,0) Client final : public Channel
       void send_client_hello(Handshake_State& state,
                              bool force_full_renegotiation,
                              Protocol_Version version,
+                             const std::string& srp_identifier = "",
                              const std::vector<std::string>& next_protocols = {});
 
       void process_handshake_msg(const Handshake_State* active_state,
diff --git a/src/lib/tls/tls_extensions.cpp b/src/lib/tls/tls_extensions.cpp
index ce067d7c0..631868703 100644
--- a/src/lib/tls/tls_extensions.cpp
+++ b/src/lib/tls/tls_extensions.cpp
@@ -24,6 +24,11 @@ Extension* make_extension(TLS_Data_Reader& reader, uint16_t code, uint16_t size,
       case TLSEXT_SERVER_NAME_INDICATION:
          return new Server_Name_Indicator(reader, size);
 
+#if defined(BOTAN_HAS_SRP6)
+      case TLSEXT_SRP_IDENTIFIER:
+         return new SRP_Identifier(reader, size);
+#endif
+
       case TLSEXT_SUPPORTED_GROUPS:
          return new Supported_Groups(reader, size);
 
@@ -208,6 +213,27 @@ std::vector<uint8_t> Server_Name_Indicator::serialize(Connection_Side /*whoami*/
    return buf;
    }
 
+#if defined(BOTAN_HAS_SRP6)
+
+SRP_Identifier::SRP_Identifier(TLS_Data_Reader& reader,
+                               uint16_t extension_size) : m_srp_identifier(reader.get_string(1, 1, 255))
+   {
+   if(m_srp_identifier.size() + 1 != extension_size)
+      throw Decoding_Error("Bad encoding for SRP identifier extension");
+   }
+
+std::vector<uint8_t> SRP_Identifier::serialize(Connection_Side /*whoami*/) const
+   {
+   std::vector<uint8_t> buf;
+
+   const uint8_t* srp_bytes = cast_char_ptr_to_uint8(m_srp_identifier.data());
+   append_tls_length_value(buf, srp_bytes, m_srp_identifier.size(), 1);
+
+   return buf;
+   }
+
+#endif
+
 Renegotiation_Extension::Renegotiation_Extension(TLS_Data_Reader& reader,
                                                  uint16_t extension_size) : m_reneg_data(reader.get_range<uint8_t>(1, 0, 255))
    {
diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h
index fefa8af77..a426c8e56 100644
--- a/src/lib/tls/tls_extensions.h
+++ b/src/lib/tls/tls_extensions.h
@@ -36,6 +36,7 @@ enum Handshake_Extension_Type {
    TLSEXT_CERTIFICATE_TYPES      = 9,
    TLSEXT_SUPPORTED_GROUPS       = 10,
    TLSEXT_EC_POINT_FORMATS       = 11,
+   TLSEXT_SRP_IDENTIFIER         = 12,
    TLSEXT_SIGNATURE_ALGORITHMS   = 13,
    TLSEXT_USE_SRTP               = 14,
    TLSEXT_ALPN                   = 16,
@@ -100,6 +101,34 @@ class BOTAN_UNSTABLE_API Server_Name_Indicator final : public Extension
       std::string m_sni_host_name;
    };
 
+#if defined(BOTAN_HAS_SRP6)
+/**
+* SRP identifier extension (RFC 5054)
+*/
+class BOTAN_UNSTABLE_API SRP_Identifier final : public Extension
+   {
+   public:
+      static Handshake_Extension_Type static_type()
+         { return TLSEXT_SRP_IDENTIFIER; }
+
+      Handshake_Extension_Type type() const override { return static_type(); }
+
+      explicit SRP_Identifier(const std::string& identifier) :
+         m_srp_identifier(identifier) {}
+
+      SRP_Identifier(TLS_Data_Reader& reader,
+                     uint16_t extension_size);
+
+      std::string identifier() const { return m_srp_identifier; }
+
+      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
+
+      bool empty() const override { return m_srp_identifier.empty(); }
+   private:
+      std::string m_srp_identifier;
+   };
+#endif
+
 /**
 * Renegotiation Indication Extension (RFC 5746)
 */
diff --git a/src/lib/tls/tls_handshake_state.cpp b/src/lib/tls/tls_handshake_state.cpp
index ee54000f7..7c1264511 100644
--- a/src/lib/tls/tls_handshake_state.cpp
+++ b/src/lib/tls/tls_handshake_state.cpp
@@ -359,6 +359,18 @@ Handshake_State::get_next_handshake_msg()
    return m_handshake_io->get_next_record(expecting_ccs);
    }
 
+std::string Handshake_State::srp_identifier() const
+   {
+#if defined(BOTAN_HAS_SRP6)
+   // Authenticated via the successful key exchange
+   if(ciphersuite().valid() && ciphersuite().kex_method() == Kex_Algo::SRP_SHA)
+      return client_hello()->srp_identifier();
+#endif
+
+   return "";
+   }
+
+
 std::vector<uint8_t> Handshake_State::session_ticket() const
    {
    if(new_session_ticket() && !new_session_ticket()->ticket().empty())
diff --git a/src/lib/tls/tls_handshake_state.h b/src/lib/tls/tls_handshake_state.h
index 0238ebd2b..3321a6210 100644
--- a/src/lib/tls/tls_handshake_state.h
+++ b/src/lib/tls/tls_handshake_state.h
@@ -93,6 +93,8 @@ class Handshake_State
                            bool for_client_auth,
                            const Policy& policy) const;
 
+      std::string srp_identifier() const;
+
       KDF* protocol_specific_prf() const;
 
       Protocol_Version version() const { return m_version; }
diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h
index 5de15f0a2..fc95a1c02 100644
--- a/src/lib/tls/tls_messages.h
+++ b/src/lib/tls/tls_messages.h
@@ -25,6 +25,10 @@
   #include <botan/cecpq1.h>
 #endif
 
+#if defined(BOTAN_HAS_SRP6)
+  #include <botan/srp6.h>
+#endif
+
 namespace Botan {
 
 class Public_Key;
@@ -70,16 +74,20 @@ class BOTAN_UNSTABLE_API Client_Hello final : public Handshake_Message
          {
          public:
             Settings(const Protocol_Version version,
-                     const std::string& hostname = "") :
+                     const std::string& hostname = "",
+                     const std::string& srp_identifier = "") :
                m_new_session_version(version),
-               m_hostname(hostname) {}
+               m_hostname(hostname),
+               m_srp_identifier(srp_identifier) {}
 
             const Protocol_Version protocol_version() const { return m_new_session_version; }
             const std::string& hostname() const { return m_hostname; }
+            const std::string& srp_identifier() const { return m_srp_identifier; }
 
          private:
             const Protocol_Version m_new_session_version;
             const std::string m_hostname;
+            const std::string m_srp_identifier;
          };
 
       Handshake_Type type() const override { return CLIENT_HELLO; }
@@ -110,6 +118,10 @@ class BOTAN_UNSTABLE_API Client_Hello final : public Handshake_Message
 
       std::string sni_hostname() const;
 
+#if defined(BOTAN_HAS_SRP6)
+      std::string srp_identifier() const;
+#endif
+
       bool secure_renegotiation() const;
 
       std::vector<uint8_t> renegotiation_info() const;
@@ -531,6 +543,15 @@ class BOTAN_UNSTABLE_API Server_Key_Exchange final : public Handshake_Message
       // Only valid for certain kex types
       const Private_Key& server_kex_key() const;
 
+#if defined(BOTAN_HAS_SRP6)
+      // Only valid for SRP negotiation
+      SRP6_Server_Session& server_srp_params() const
+         {
+         BOTAN_ASSERT_NONNULL(m_srp_params);
+         return *m_srp_params;
+         }
+#endif
+
 #if defined(BOTAN_HAS_CECPQ1)
       // Only valid for CECPQ1 negotiation
       const CECPQ1_key& cecpq1_key() const
@@ -556,6 +577,10 @@ class BOTAN_UNSTABLE_API Server_Key_Exchange final : public Handshake_Message
    private:
       std::vector<uint8_t> serialize() const override;
 
+#if defined(BOTAN_HAS_SRP6)
+      std::unique_ptr<SRP6_Server_Session> m_srp_params;
+#endif
+
 #if defined(BOTAN_HAS_CECPQ1)
       std::unique_ptr<CECPQ1_key> m_cecpq1_key;
 #endif
diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp
index 723ba4350..a63c73101 100644
--- a/src/lib/tls/tls_policy.cpp
+++ b/src/lib/tls/tls_policy.cpp
@@ -57,6 +57,9 @@ std::vector<std::string> Policy::allowed_ciphers() const
       //"ARIA-128/GCM",
       //"AES-256",
       //"AES-128",
+      //"Camellia-256",
+      //"Camellia-128",
+      //"SEED",
       //"3DES",
       };
    }
@@ -89,6 +92,7 @@ std::vector<std::string> Policy::allowed_macs() const
 std::vector<std::string> Policy::allowed_key_exchange_methods() const
    {
    return {
+      //"SRP_SHA",
       //"ECDHE_PSK",
       //"DHE_PSK",
       //"PSK",
@@ -424,7 +428,8 @@ class Ciphersuite_Preference_Ordering final
 
 }
 
-std::vector<uint16_t> Policy::ciphersuite_list(Protocol_Version version) const
+std::vector<uint16_t> Policy::ciphersuite_list(Protocol_Version version,
+                                               bool have_srp) const
    {
    const std::vector<std::string> ciphers = allowed_ciphers();
    const std::vector<std::string> macs = allowed_macs();
@@ -447,6 +452,10 @@ std::vector<uint16_t> Policy::ciphersuite_list(Protocol_Version version) const
       if(!this->acceptable_ciphersuite(suite))
          continue;
 
+      // Are we doing SRP?
+      if(!have_srp && suite.kex_method() == Kex_Algo::SRP_SHA)
+         continue;
+
       if(!value_exists(kex, suite.kex_algo()))
          continue; // unsupported key exchange
 
diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h
index 209e814c2..c0f618e0f 100644
--- a/src/lib/tls/tls_policy.h
+++ b/src/lib/tls/tls_policy.h
@@ -205,7 +205,7 @@ class BOTAN_PUBLIC_API(2,0) Policy
       virtual void check_peer_key_acceptable(const Public_Key& public_key) const;
 
       /**
-      * If this function returns false, unknown PSK identifiers
+      * If this function returns false, unknown SRP/PSK identifiers
       * will be rejected with an unknown_psk_identifier alert as soon
       * as the non-existence is identified. Otherwise, a false
       * identifier value will be used and the protocol allowed to
@@ -295,7 +295,8 @@ class BOTAN_PUBLIC_API(2,0) Policy
       /**
       * Return allowed ciphersuites, in order of preference
       */
-      virtual std::vector<uint16_t> ciphersuite_list(Protocol_Version version) const;
+      virtual std::vector<uint16_t> ciphersuite_list(Protocol_Version version,
+                                                     bool have_srp) const;
 
       /**
       * @return the default MTU for DTLS
diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp
index c62053857..3fd4565fd 100644
--- a/src/lib/tls/tls_server.cpp
+++ b/src/lib/tls/tls_server.cpp
@@ -104,6 +104,15 @@ bool check_for_resume(Session& session_info,
                     session_info.ciphersuite_code()))
       return false;
 
+#if defined(BOTAN_HAS_SRP6)
+   // client sent a different SRP identity
+   if(client_hello->srp_identifier() != "")
+      {
+      if(client_hello->srp_identifier() != session_info.srp_identifier())
+         return false;
+      }
+#endif
+
    // client sent a different SNI hostname
    if(client_hello->sni_hostname() != "")
       {
@@ -149,12 +158,14 @@ bool check_for_resume(Session& session_info,
 uint16_t choose_ciphersuite(
    const Policy& policy,
    Protocol_Version version,
+   Credentials_Manager& creds,
    const std::map<std::string, std::vector<X509_Certificate>>& cert_chains,
    const Client_Hello& client_hello)
    {
    const bool our_choice = policy.server_uses_own_ciphersuite_preferences();
+   const bool have_srp = creds.attempt_srp("tls-server", client_hello.sni_hostname());
    const std::vector<uint16_t> client_suites = client_hello.ciphersuites();
-   const std::vector<uint16_t> server_suites = policy.ciphersuite_list(version);
+   const std::vector<uint16_t> server_suites = policy.ciphersuite_list(version, have_srp);
 
    if(server_suites.empty())
       throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
@@ -237,6 +248,20 @@ uint16_t choose_ciphersuite(
             }
          }
 
+#if defined(BOTAN_HAS_SRP6)
+      /*
+      The client may offer SRP cipher suites in the hello message but
+      omit the SRP extension.  If the server would like to select an
+      SRP cipher suite in this case, the server SHOULD return a fatal
+      "unknown_psk_identity" alert immediately after processing the
+      client hello message.
+       - RFC 5054 section 2.5.1.2
+      */
+      if(suite.kex_method() == Kex_Algo::SRP_SHA && client_hello.srp_identifier() == "")
+         throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY,
+                             "Client wanted SRP but did not send username");
+#endif
+
       return suite_id;
       }
 
@@ -661,6 +686,7 @@ void Server::process_finished_msg(Server_Handshake_State& pending_state,
          get_peer_cert_chain(pending_state),
          std::vector<uint8_t>(),
          Server_Information(pending_state.client_hello()->sni_hostname()),
+         pending_state.srp_identifier(),
          pending_state.server_hello()->srtp_profile());
 
       if(save_session(session_info))
@@ -845,7 +871,7 @@ void Server::session_create(Server_Handshake_State& pending_state,
       }
 
    const uint16_t ciphersuite = choose_ciphersuite(policy(), pending_state.version(),
-                                                   cert_chains,
+                                                   m_creds, cert_chains,
                                                    *pending_state.client_hello());
 
    Server_Hello::Settings srv_settings(
diff --git a/src/lib/tls/tls_session.cpp b/src/lib/tls/tls_session.cpp
index de118f778..bd817687c 100644
--- a/src/lib/tls/tls_session.cpp
+++ b/src/lib/tls/tls_session.cpp
@@ -29,6 +29,7 @@ Session::Session(const std::vector<uint8_t>& session_identifier,
                  const std::vector<X509_Certificate>& certs,
                  const std::vector<uint8_t>& ticket,
                  const Server_Information& server_info,
+                 const std::string& srp_identifier,
                  uint16_t srtp_profile) :
    m_start_time(std::chrono::system_clock::now()),
    m_identifier(session_identifier),
@@ -41,7 +42,8 @@ Session::Session(const std::vector<uint8_t>& session_identifier,
    m_extended_master_secret(extended_master_secret),
    m_encrypt_then_mac(encrypt_then_mac),
    m_peer_certs(certs),
-   m_server_info(server_info)
+   m_server_info(server_info),
+   m_srp_identifier(srp_identifier)
    {
    }
 
@@ -122,6 +124,8 @@ Session::Session(const uint8_t ber[], size_t ber_len)
                                       server_service.value(),
                                       static_cast<uint16_t>(server_port));
 
+   m_srp_identifier = srp_identifier_str.value();
+
    if(!peer_cert_bits.empty())
       {
       DataSource_Memory certs(peer_cert_bits.data(), peer_cert_bits.size());
@@ -156,7 +160,7 @@ secure_vector<uint8_t> Session::DER_encode() const
          .encode(ASN1_String(m_server_info.hostname(), UTF8_STRING))
          .encode(ASN1_String(m_server_info.service(), UTF8_STRING))
          .encode(static_cast<size_t>(m_server_info.port()))
-         .encode(ASN1_String("", UTF8_STRING)) // old srp identifier
+         .encode(ASN1_String(m_srp_identifier, UTF8_STRING))
          .encode(static_cast<size_t>(m_srtp_profile))
       .end_cons()
    .get_contents();
diff --git a/src/lib/tls/tls_session.h b/src/lib/tls/tls_session.h
index 5cb1f44be..5a75e6a32 100644
--- a/src/lib/tls/tls_session.h
+++ b/src/lib/tls/tls_session.h
@@ -54,6 +54,7 @@ class BOTAN_PUBLIC_API(2,0) Session final
               const std::vector<X509_Certificate>& peer_certs,
               const std::vector<uint8_t>& session_ticket,
               const Server_Information& server_info,
+              const std::string& srp_identifier,
               uint16_t srtp_profile);
 
       /**
@@ -132,6 +133,11 @@ class BOTAN_PUBLIC_API(2,0) Session final
       */
       Connection_Side side() const { return m_connection_side; }
 
+      /**
+      * Get the SRP identity (if sent by the client in the initial handshake)
+      */
+      const std::string& srp_identifier() const { return m_srp_identifier; }
+
       /**
       * Get the saved master secret
       */
@@ -194,6 +200,7 @@ class BOTAN_PUBLIC_API(2,0) Session final
 
       std::vector<X509_Certificate> m_peer_certs;
       Server_Information m_server_info; // optional
+      std::string m_srp_identifier; // optional
    };
 
 }
diff --git a/src/lib/tls/tls_suite_info.cpp b/src/lib/tls/tls_suite_info.cpp
index 0f3e0527d..4c49f72ad 100644
--- a/src/lib/tls/tls_suite_info.cpp
+++ b/src/lib/tls/tls_suite_info.cpp
@@ -3,7 +3,7 @@
 *
 * This file was automatically generated from the IANA assignments
 * (tls-parameters.txt sha256 6412d7a966151d409d463681e5427e706cd9066f13d34ca7a89f8cc2f7dff4b2)
-* by ./src/scripts/tls_suite_info.py on 2020-11-23
+* by ./src/scripts/tls_suite_info.py on 2020-11-17
 *
 * Botan is released under the Simplified BSD License (see license.txt)
 */
@@ -25,14 +25,20 @@ const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites()
       Ciphersuite(0x0039, "DHE_RSA_WITH_AES_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0x003C, "RSA_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
       Ciphersuite(0x003D, "RSA_WITH_AES_256_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x0041, "RSA_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x0045, "DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0x0067, "DHE_RSA_WITH_AES_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
       Ciphersuite(0x006B, "DHE_RSA_WITH_AES_256_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x0084, "RSA_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x0088, "DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0x008B, "PSK_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::PSK, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0x008C, "PSK_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0x008D, "PSK_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0x008F, "DHE_PSK_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0x0090, "DHE_PSK_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0x0091, "DHE_PSK_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x0096, "RSA_WITH_SEED_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x009A, "DHE_RSA_WITH_SEED_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0x009C, "RSA_WITH_AES_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0x009D, "RSA_WITH_AES_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0x009E, "DHE_RSA_WITH_AES_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4),
@@ -45,6 +51,10 @@ const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites()
       Ciphersuite(0x00AF, "PSK_WITH_AES_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE),
       Ciphersuite(0x00B2, "DHE_PSK_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
       Ciphersuite(0x00B3, "DHE_PSK_WITH_AES_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x00BA, "RSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x00BE, "DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x00C0, "RSA_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0x00C4, "DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
       Ciphersuite(0x16B7, "CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::RSA, Kex_Algo::CECPQ1, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12),
       Ciphersuite(0x16B8, "CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::ECDSA, Kex_Algo::CECPQ1, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12),
       Ciphersuite(0x16B9, "CECPQ1_RSA_WITH_AES_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::CECPQ1, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4),
@@ -55,6 +65,12 @@ const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites()
       Ciphersuite(0xC012, "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::RSA, Kex_Algo::ECDH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0xC013, "ECDHE_RSA_WITH_AES_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0xC014, "ECDHE_RSA_WITH_AES_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC01A, "SRP_SHA_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::SRP_SHA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC01B, "SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::RSA, Kex_Algo::SRP_SHA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC01D, "SRP_SHA_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::SRP_SHA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC01E, "SRP_SHA_RSA_WITH_AES_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::SRP_SHA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC020, "SRP_SHA_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::SRP_SHA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC021, "SRP_SHA_RSA_WITH_AES_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::SRP_SHA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE),
       Ciphersuite(0xC023, "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
       Ciphersuite(0xC024, "ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE),
       Ciphersuite(0xC027, "ECDHE_RSA_WITH_AES_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
@@ -80,6 +96,10 @@ const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites()
       Ciphersuite(0xC06B, "PSK_WITH_ARIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0xC06C, "DHE_PSK_WITH_ARIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0xC06D, "DHE_PSK_WITH_ARIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4),
+      Ciphersuite(0xC072, "ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC073, "ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC076, "ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC077, "ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE),
       Ciphersuite(0xC07A, "RSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0xC07B, "RSA_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0xC07C, "DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::DH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4),
@@ -92,6 +112,12 @@ const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites()
       Ciphersuite(0xC08F, "PSK_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0xC090, "DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0xC091, "DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4),
+      Ciphersuite(0xC094, "PSK_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC095, "PSK_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC096, "DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC097, "DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC09A, "ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE),
+      Ciphersuite(0xC09B, "ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE),
       Ciphersuite(0xC09C, "RSA_WITH_AES_128_CCM", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0xC09D, "RSA_WITH_AES_256_CCM", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4),
       Ciphersuite(0xC09E, "DHE_RSA_WITH_AES_128_CCM", Auth_Method::RSA, Kex_Algo::DH, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4),
diff --git a/src/lib/x509/certstor.cpp b/src/lib/x509/certstor.cpp
index 9bec24f64..a066f208d 100644
--- a/src/lib/x509/certstor.cpp
+++ b/src/lib/x509/certstor.cpp
@@ -16,29 +16,38 @@ namespace Botan {
 
 Certificate_Store::~Certificate_Store() {}
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store::find_cert(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const
    {
    const auto certs = find_all_certs(subject_dn, key_id);
 
    if(certs.empty())
       {
-      return std::nullopt;
+      return nullptr;  // certificate not found
       }
 
    // `count` might be greater than 1, but we'll just select the first match
    return certs.front();
    }
 
-std::optional<X509_CRL> Certificate_Store::find_crl_for(const X509_Certificate&) const
+std::shared_ptr<const X509_CRL> Certificate_Store::find_crl_for(const X509_Certificate&) const
    {
-   return std::nullopt;
+   return {};
    }
 
 void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert)
    {
    for(const auto& c : m_certs)
-      if(c == cert)
+      if(*c == cert)
+         return;
+
+   m_certs.push_back(std::make_shared<const X509_Certificate>(cert));
+   }
+
+void Certificate_Store_In_Memory::add_certificate(std::shared_ptr<const X509_Certificate> cert)
+   {
+   for(const auto& c : m_certs)
+      if(*c == *cert)
          return;
 
    m_certs.push_back(cert);
@@ -48,11 +57,11 @@ std::vector<X509_DN> Certificate_Store_In_Memory::all_subjects() const
    {
    std::vector<X509_DN> subjects;
    for(const auto& cert : m_certs)
-      subjects.push_back(cert.subject_dn());
+      subjects.push_back(cert->subject_dn());
    return subjects;
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn,
                                        const std::vector<uint8_t>& key_id) const
    {
@@ -61,43 +70,43 @@ Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn,
       // Only compare key ids if set in both call and in the cert
       if(key_id.size())
          {
-         std::vector<uint8_t> skid = cert.subject_key_id();
+         std::vector<uint8_t> skid = cert->subject_key_id();
 
          if(skid.size() && skid != key_id) // no match
             continue;
          }
 
-      if(cert.subject_dn() == subject_dn)
+      if(cert->subject_dn() == subject_dn)
          return cert;
       }
 
-   return std::nullopt;
+   return nullptr;
    }
 
-std::vector<X509_Certificate> Certificate_Store_In_Memory::find_all_certs(
+std::vector<std::shared_ptr<const X509_Certificate>> Certificate_Store_In_Memory::find_all_certs(
       const X509_DN& subject_dn,
       const std::vector<uint8_t>& key_id) const
    {
-   std::vector<X509_Certificate> matches;
+   std::vector<std::shared_ptr<const X509_Certificate>> matches;
 
    for(const auto& cert : m_certs)
       {
       if(key_id.size())
          {
-         std::vector<uint8_t> skid = cert.subject_key_id();
+         std::vector<uint8_t> skid = cert->subject_key_id();
 
          if(skid.size() && skid != key_id) // no match
             continue;
          }
 
-      if(cert.subject_dn() == subject_dn)
+      if(cert->subject_dn() == subject_dn)
          matches.push_back(cert);
       }
 
    return matches;
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store_In_Memory::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
    {
    if(key_hash.size() != 20)
@@ -106,15 +115,15 @@ Certificate_Store_In_Memory::find_cert_by_pubkey_sha1(const std::vector<uint8_t>
    std::unique_ptr<HashFunction> hash(HashFunction::create("SHA-1"));
 
    for(const auto& cert : m_certs){
-      hash->update(cert.subject_public_key_bitstring());
+      hash->update(cert->subject_public_key_bitstring());
       if(key_hash == hash->final_stdvec()) //final_stdvec also clears the hash to initial state
          return cert;
    }
 
-   return std::nullopt;
+   return nullptr;
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const
    {
    if(subject_hash.size() != 32)
@@ -123,24 +132,30 @@ Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256(const std::vecto
    std::unique_ptr<HashFunction> hash(HashFunction::create("SHA-256"));
 
    for(const auto& cert : m_certs){
-      hash->update(cert.raw_subject_dn());
+      hash->update(cert->raw_subject_dn());
       if(subject_hash == hash->final_stdvec()) //final_stdvec also clears the hash to initial state
          return cert;
    }
 
-   return std::nullopt;
+   return nullptr;
    }
 
 void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl)
    {
-   X509_DN crl_issuer = crl.issuer_dn();
+   std::shared_ptr<const X509_CRL> crl_s = std::make_shared<const X509_CRL>(crl);
+   return add_crl(crl_s);
+   }
+
+void Certificate_Store_In_Memory::add_crl(std::shared_ptr<const X509_CRL> crl)
+   {
+   X509_DN crl_issuer = crl->issuer_dn();
 
    for(auto& c : m_crls)
       {
       // Found an update of a previously existing one; replace it
-      if(c.issuer_dn() == crl_issuer)
+      if(c->issuer_dn() == crl_issuer)
          {
-         if(c.this_update() <= crl.this_update())
+         if(c->this_update() <= crl->this_update())
             c = crl;
          return;
          }
@@ -150,7 +165,7 @@ void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl)
    m_crls.push_back(crl);
    }
 
-std::optional<X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const
+std::shared_ptr<const X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const
    {
    const std::vector<uint8_t>& key_id = subject.authority_key_id();
 
@@ -159,13 +174,13 @@ std::optional<X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Cer
       // Only compare key ids if set in both call and in the CRL
       if(key_id.size())
          {
-         std::vector<uint8_t> akid = c.authority_key_id();
+         std::vector<uint8_t> akid = c->authority_key_id();
 
          if(akid.size() && akid != key_id) // no match
             continue;
          }
 
-      if(c.issuer_dn() == subject.issuer_dn())
+      if(c->issuer_dn() == subject.issuer_dn())
          return c;
       }
 
@@ -199,8 +214,7 @@ Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir)
             {
             try
                {
-               X509_Certificate cert(src);
-               m_certs.push_back(cert);
+               m_certs.push_back(std::make_shared<X509_Certificate>(src));
                }
             catch(std::exception&)
                {
diff --git a/src/lib/x509/certstor.h b/src/lib/x509/certstor.h
index 0752e908f..6901589d2 100644
--- a/src/lib/x509/certstor.h
+++ b/src/lib/x509/certstor.h
@@ -10,7 +10,6 @@
 
 #include <botan/x509cert.h>
 #include <botan/x509_crl.h>
-#include <optional>
 
 namespace Botan {
 
@@ -26,18 +25,18 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Store
       * Find a certificate by Subject DN and (optionally) key identifier
       * @param subject_dn the subject's distinguished name
       * @param key_id an optional key id
-      * @return a matching certificate or nullopt otherwise
+      * @return a matching certificate or nullptr otherwise
       * If more than one certificate in the certificate store matches, then
       * a single value is selected arbitrarily.
       */
-      virtual std::optional<X509_Certificate>
+      virtual std::shared_ptr<const X509_Certificate>
          find_cert(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const;
 
       /**
       * Find all certificates with a given Subject DN.
       * Subject DN and even the key identifier might not be unique.
       */
-      virtual std::vector<X509_Certificate> find_all_certs(
+      virtual std::vector<std::shared_ptr<const X509_Certificate>> find_all_certs(
          const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const = 0;
 
 
@@ -45,26 +44,26 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Store
       * Find a certificate by searching for one with a matching SHA-1 hash of
       * public key. Used for OCSP.
       * @param key_hash SHA-1 hash of the subject's public key
-      * @return a matching certificate or nullopt otherwise
+      * @return a matching certificate or nullptr otherwise
       */
-      virtual std::optional<X509_Certificate>
+      virtual std::shared_ptr<const X509_Certificate>
          find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const = 0;
 
       /**
       * Find a certificate by searching for one with a matching SHA-256 hash of
       * raw subject name. Used for OCSP.
       * @param subject_hash SHA-256 hash of the subject's raw name
-      * @return a matching certificate or nullopt otherwise
+      * @return a matching certificate or nullptr otherwise
       */
-      virtual std::optional<X509_Certificate>
+      virtual std::shared_ptr<const X509_Certificate>
          find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const = 0;
 
       /**
       * Finds a CRL for the given certificate
       * @param subject the subject certificate
-      * @return the CRL for subject or nullopt otherwise
+      * @return the CRL for subject or nullptr otherwise
       */
-      virtual std::optional<X509_CRL> find_crl_for(const X509_Certificate& subject) const;
+      virtual std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const;
 
       /**
       * @return whether the certificate is known
@@ -72,7 +71,7 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Store
       */
       bool certificate_known(const X509_Certificate& cert) const
          {
-         return find_cert(cert.subject_dn(), cert.subject_key_id()).has_value();
+         return find_cert(cert.subject_dn(), cert.subject_key_id()) != nullptr;
          }
 
       // remove this (used by TLS::Server)
@@ -107,12 +106,24 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_Memory final : public Certifica
       */
       void add_certificate(const X509_Certificate& cert);
 
+      /**
+      * Add a certificate already in a shared_ptr to the store.
+      * @param cert certificate to be added
+      */
+      void add_certificate(std::shared_ptr<const X509_Certificate> cert);
+
       /**
       * Add a certificate revocation list (CRL) to the store.
       * @param crl CRL to be added
       */
       void add_crl(const X509_CRL& crl);
 
+      /**
+      * Add a certificate revocation list (CRL) to the store as a shared_ptr
+      * @param crl CRL to be added
+      */
+      void add_crl(std::shared_ptr<const X509_CRL> crl);
+
       /**
       * @return DNs for all certificates managed by the store
       */
@@ -122,7 +133,7 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_Memory final : public Certifica
       * Find a certificate by Subject DN and (optionally) key identifier
       * @return the first certificate that matches
       */
-      std::optional<X509_Certificate> find_cert(
+      std::shared_ptr<const X509_Certificate> find_cert(
          const X509_DN& subject_dn,
          const std::vector<uint8_t>& key_id) const override;
 
@@ -130,23 +141,23 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_Memory final : public Certifica
       * Find all certificates with a given Subject DN.
       * Subject DN and even the key identifier might not be unique.
       */
-      std::vector<X509_Certificate> find_all_certs(
+      std::vector<std::shared_ptr<const X509_Certificate>> find_all_certs(
          const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
          find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
          find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const override;
 
       /**
       * Finds a CRL for the given certificate
       */
-      std::optional<X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
    private:
       // TODO: Add indexing on the DN and key id to avoid linear search
-      std::vector<X509_Certificate> m_certs;
-      std::vector<X509_CRL> m_crls;
+      std::vector<std::shared_ptr<const X509_Certificate>> m_certs;
+      std::vector<std::shared_ptr<const X509_CRL>> m_crls;
    };
 
 }
diff --git a/src/lib/x509/certstor_flatfile/certstor_flatfile.cpp b/src/lib/x509/certstor_flatfile/certstor_flatfile.cpp
index 74837cd1e..9804759b9 100644
--- a/src/lib/x509/certstor_flatfile/certstor_flatfile.cpp
+++ b/src/lib/x509/certstor_flatfile/certstor_flatfile.cpp
@@ -49,7 +49,7 @@ Flatfile_Certificate_Store::Flatfile_Certificate_Store(const std::string& file,
 
    for(const std::vector<uint8_t>& der : decode_all_certificates(file_stream))
       {
-      X509_Certificate cert(der);
+      std::shared_ptr<const X509_Certificate> cert = std::make_shared<const X509_Certificate>(der.data(), der.size());
 
       /*
       * Various weird or misconfigured system roots include intermediate certificates,
@@ -57,16 +57,16 @@ Flatfile_Certificate_Store::Flatfile_Certificate_Store(const std::string& file,
       * Previously this code would error on such cases as an obvious misconfiguration,
       * but we cannot fix the trust store. So instead just ignore any such certificate.
       */
-      if(cert.is_self_signed() && cert.is_CA_cert())
+      if(cert->is_self_signed() && cert->is_CA_cert())
          {
-         m_all_subjects.push_back(cert.subject_dn());
-         m_dn_to_cert[cert.subject_dn()].push_back(cert);
-         m_pubkey_sha1_to_cert.emplace(cert.subject_public_key_bitstring_sha1(), cert);
-         m_subject_dn_sha256_to_cert.emplace(cert.raw_subject_dn_sha256(), cert);
+         m_all_subjects.push_back(cert->subject_dn());
+         m_dn_to_cert[cert->subject_dn()].push_back(cert);
+         m_pubkey_sha1_to_cert.emplace(cert->subject_public_key_bitstring_sha1(), cert);
+         m_subject_dn_sha256_to_cert.emplace(cert->raw_subject_dn_sha256(), cert);
          }
       else if(!ignore_non_ca)
          {
-         throw Invalid_Argument("Flatfile_Certificate_Store received non CA cert " + cert.subject_dn().to_string());
+         throw Invalid_Argument("Flatfile_Certificate_Store received non CA cert " + cert->subject_dn().to_string());
          }
       }
 
@@ -81,18 +81,18 @@ std::vector<X509_DN> Flatfile_Certificate_Store::all_subjects() const
    return m_all_subjects;
    }
 
-std::vector<X509_Certificate> Flatfile_Certificate_Store::find_all_certs(
+std::vector<std::shared_ptr<const X509_Certificate>> Flatfile_Certificate_Store::find_all_certs(
          const X509_DN& subject_dn,
          const std::vector<uint8_t>& key_id) const
    {
-   std::vector<X509_Certificate> found_certs;
+   std::vector<std::shared_ptr<const X509_Certificate>> found_certs;
    try
       {
       const auto certs = m_dn_to_cert.at(subject_dn);
 
       for(auto cert : certs)
          {
-         if(key_id.empty() || key_id == cert.subject_key_id())
+         if(key_id.empty() || key_id == cert->subject_key_id())
             {
             found_certs.push_back(cert);
             }
@@ -106,7 +106,7 @@ std::vector<X509_Certificate> Flatfile_Certificate_Store::find_all_certs(
    return found_certs;
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Flatfile_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
    {
    if(key_hash.size() != 20)
@@ -121,10 +121,10 @@ Flatfile_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector<uint8_t>&
       return found_cert->second;
       }
 
-   return std::nullopt;
+   return nullptr;
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const
    {
    if(subject_hash.size() != 32)
@@ -137,10 +137,10 @@ Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector
       return found_cert->second;
       }
 
-   return std::nullopt;
+   return nullptr;
    }
 
-std::optional<X509_CRL> Flatfile_Certificate_Store::find_crl_for(const X509_Certificate& subject) const
+std::shared_ptr<const X509_CRL> Flatfile_Certificate_Store::find_crl_for(const X509_Certificate& subject) const
    {
    BOTAN_UNUSED(subject);
    return {};
diff --git a/src/lib/x509/certstor_flatfile/certstor_flatfile.h b/src/lib/x509/certstor_flatfile/certstor_flatfile.h
index fba14382a..1608aaa11 100644
--- a/src/lib/x509/certstor_flatfile/certstor_flatfile.h
+++ b/src/lib/x509/certstor_flatfile/certstor_flatfile.h
@@ -46,7 +46,7 @@ class BOTAN_PUBLIC_API(2, 11) Flatfile_Certificate_Store final : public Certific
       * Find all certificates with a given Subject DN.
       * Subject DN and even the key identifier might not be unique.
       */
-      std::vector<X509_Certificate> find_all_certs(
+      std::vector<std::shared_ptr<const X509_Certificate>> find_all_certs(
                const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
       /**
@@ -54,23 +54,23 @@ class BOTAN_PUBLIC_API(2, 11) Flatfile_Certificate_Store final : public Certific
       * public key.
       * @return a matching certificate or nullptr otherwise
       */
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
       find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
       find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const override;
 
       /**
        * Fetching CRLs is not supported by this certificate store. This will
        * always return an empty list.
        */
-      std::optional<X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
 
    private:
       std::vector<X509_DN> m_all_subjects;
-      std::map<X509_DN, std::vector<X509_Certificate>> m_dn_to_cert;
-      std::map<std::vector<uint8_t>, std::optional<X509_Certificate>> m_pubkey_sha1_to_cert;
-      std::map<std::vector<uint8_t>, std::optional<X509_Certificate>> m_subject_dn_sha256_to_cert;
+      std::map<X509_DN, std::vector<std::shared_ptr<const X509_Certificate>>> m_dn_to_cert;
+      std::map<std::vector<uint8_t>, std::shared_ptr<const X509_Certificate>> m_pubkey_sha1_to_cert;
+      std::map<std::vector<uint8_t>, std::shared_ptr<const X509_Certificate>> m_subject_dn_sha256_to_cert;
    };
 }
 
diff --git a/src/lib/x509/certstor_sql/certstor_sql.cpp b/src/lib/x509/certstor_sql/certstor_sql.cpp
index deab7abdd..ab4b8e64a 100644
--- a/src/lib/x509/certstor_sql/certstor_sql.cpp
+++ b/src/lib/x509/certstor_sql/certstor_sql.cpp
@@ -44,7 +44,7 @@ Certificate_Store_In_SQL::Certificate_Store_In_SQL(std::shared_ptr<SQL_Database>
    }
 
 // Certificate handling
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store_In_SQL::find_cert(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const
    {
    std::shared_ptr<SQL_Database::Statement> stmt;
@@ -67,16 +67,16 @@ Certificate_Store_In_SQL::find_cert(const X509_DN& subject_dn, const std::vector
    while(stmt->step())
       {
       auto blob = stmt->get_blob(0);
-      return X509_Certificate(blob.first, blob.second);
+      return std::make_shared<X509_Certificate>(std::vector<uint8_t>(blob.first, blob.first + blob.second));
       }
 
-   return std::optional<X509_Certificate>();
+   return std::shared_ptr<const X509_Certificate>();
    }
 
-std::vector<X509_Certificate>
+std::vector<std::shared_ptr<const X509_Certificate>>
 Certificate_Store_In_SQL::find_all_certs(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const
    {
-   std::vector<X509_Certificate> certs;
+   std::vector<std::shared_ptr<const X509_Certificate>> certs;
 
    std::shared_ptr<SQL_Database::Statement> stmt;
 
@@ -95,29 +95,30 @@ Certificate_Store_In_SQL::find_all_certs(const X509_DN& subject_dn, const std::v
       stmt->bind(2, key_id);
       }
 
-   std::optional<X509_Certificate> cert;
+   std::shared_ptr<const X509_Certificate> cert;
    while(stmt->step())
       {
       auto blob = stmt->get_blob(0);
-      certs.push_back(X509_Certificate(blob.first, blob.second));
+      certs.push_back(std::make_shared<X509_Certificate>(
+            std::vector<uint8_t>(blob.first,blob.first + blob.second)));
       }
 
    return certs;
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store_In_SQL::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& /*key_hash*/) const
    {
    throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_pubkey_sha1");
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store_In_SQL::find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& /*subject_hash*/) const
    {
    throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_raw_subject_dn_sha256");
    }
 
-std::optional<X509_CRL>
+std::shared_ptr<const X509_CRL>
 Certificate_Store_In_SQL::find_crl_for(const X509_Certificate& subject) const
    {
    auto all_crls = generate_crls();
@@ -125,10 +126,10 @@ Certificate_Store_In_SQL::find_crl_for(const X509_Certificate& subject) const
    for(auto crl: all_crls)
       {
       if(!crl.get_revoked().empty() && crl.issuer_dn() == subject.issuer_dn())
-         return crl;
+         return std::shared_ptr<X509_CRL>(new X509_CRL(crl));
       }
 
-   return std::optional<X509_CRL>();
+   return std::shared_ptr<X509_CRL>();
    }
 
 std::vector<X509_DN> Certificate_Store_In_SQL::all_subjects() const
@@ -208,7 +209,7 @@ std::shared_ptr<const Private_Key> Certificate_Store_In_SQL::find_key(const X509
    return key;
    }
 
-std::vector<X509_Certificate>
+std::vector<std::shared_ptr<const X509_Certificate>>
 Certificate_Store_In_SQL::find_certs_for_key(const Private_Key& key) const
    {
    auto fpr = key.fingerprint_private("SHA-256");
@@ -216,11 +217,12 @@ Certificate_Store_In_SQL::find_certs_for_key(const Private_Key& key) const
 
    stmt->bind(1,fpr);
 
-   std::vector<X509_Certificate> certs;
+   std::vector<std::shared_ptr<const X509_Certificate>> certs;
    while(stmt->step())
       {
       auto blob = stmt->get_blob(0);
-      certs.push_back(X509_Certificate(blob.first, blob.second));
+      certs.push_back(std::make_shared<X509_Certificate>(
+            std::vector<uint8_t>(blob.first,blob.first + blob.second)));
       }
 
    return certs;
diff --git a/src/lib/x509/certstor_sql/certstor_sql.h b/src/lib/x509/certstor_sql/certstor_sql.h
index 05bb2c561..fd80eb191 100644
--- a/src/lib/x509/certstor_sql/certstor_sql.h
+++ b/src/lib/x509/certstor_sql/certstor_sql.h
@@ -40,20 +40,20 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_SQL : public Certificate_Store
       /**
       * Returns the first certificate with matching subject DN and optional key ID.
       */
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
          find_cert(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
       /*
       * Find all certificates with a given Subject DN.
       * Subject DN and even the key identifier might not be unique.
       */
-      std::vector<X509_Certificate> find_all_certs(
+      std::vector<std::shared_ptr<const X509_Certificate>> find_all_certs(
          const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
          find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
          find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const override;
 
       /**
@@ -77,7 +77,7 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_SQL : public Certificate_Store
       std::shared_ptr<const Private_Key> find_key(const X509_Certificate&) const;
 
       /// Returns all certificates for private key "key".
-      std::vector<X509_Certificate>
+      std::vector<std::shared_ptr<const X509_Certificate>>
          find_certs_for_key(const Private_Key& key) const;
 
       /**
@@ -104,7 +104,7 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_SQL : public Certificate_Store
       /**
       * Generates a CRL for all certificates issued by the given issuer.
       */
-      std::optional<X509_CRL>
+      std::shared_ptr<const X509_CRL>
          find_crl_for(const X509_Certificate& issuer) const override;
 
    private:
diff --git a/src/lib/x509/certstor_system/certstor_system.cpp b/src/lib/x509/certstor_system/certstor_system.cpp
index 234979cab..0fca1a975 100644
--- a/src/lib/x509/certstor_system/certstor_system.cpp
+++ b/src/lib/x509/certstor_system/certstor_system.cpp
@@ -31,32 +31,32 @@ System_Certificate_Store::System_Certificate_Store()
 #endif
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 System_Certificate_Store::find_cert(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const
    {
    return m_system_store->find_cert(subject_dn, key_id);
    }
 
-std::vector<X509_Certificate>
+std::vector<std::shared_ptr<const X509_Certificate>>
 System_Certificate_Store::find_all_certs(const X509_DN& subject_dn,
                                          const std::vector<uint8_t>& key_id) const
    {
    return m_system_store->find_all_certs(subject_dn, key_id);
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 System_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
    {
    return m_system_store->find_cert_by_pubkey_sha1(key_hash);
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 System_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const
    {
    return m_system_store->find_cert_by_raw_subject_dn_sha256(subject_hash);
    }
 
-std::optional<X509_CRL>
+std::shared_ptr<const X509_CRL>
 System_Certificate_Store::find_crl_for(const X509_Certificate& subject) const
    {
    return m_system_store->find_crl_for(subject);
diff --git a/src/lib/x509/certstor_system/certstor_system.h b/src/lib/x509/certstor_system/certstor_system.h
index a2be72738..3a0fc6153 100644
--- a/src/lib/x509/certstor_system/certstor_system.h
+++ b/src/lib/x509/certstor_system/certstor_system.h
@@ -17,19 +17,19 @@ class BOTAN_PUBLIC_API(2,11) System_Certificate_Store final : public Certificate
 
       System_Certificate_Store();
 
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
          find_cert(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
-      std::vector<X509_Certificate>
+      std::vector<std::shared_ptr<const X509_Certificate>>
          find_all_certs(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
          find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
          find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const override;
 
-      std::optional<X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
 
       std::vector<X509_DN> all_subjects() const override;
 
diff --git a/src/lib/x509/certstor_system_macos/certstor_macos.cpp b/src/lib/x509/certstor_system_macos/certstor_macos.cpp
index 662ebd0ab..12a907b2b 100644
--- a/src/lib/x509/certstor_system_macos/certstor_macos.cpp
+++ b/src/lib/x509/certstor_system_macos/certstor_macos.cpp
@@ -209,16 +209,13 @@ class Certificate_Store_MacOS_Impl
 
             void addParameter(CFStringRef key, std::vector<uint8_t> value)
                {
-               // TODO C++17: std::vector::emplace_back will return the reference
-               //             to the inserted object straight away.
-               m_data_store.emplace_back(std::move(value));
-               const auto& data = m_data_store.back();
-
-               m_data_refs.emplace_back(CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
-                                        data.data(),
-                                        data.size(),
-                                        kCFAllocatorNull));
-               const auto& data_ref = m_data_refs.back();
+               const auto& data = m_data_store.emplace_back(std::move(value));
+
+               const auto& data_ref = m_data_refs.emplace_back(
+                                         CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
+                                               data.data(),
+                                               data.size(),
+                                               kCFAllocatorNull));
                check_notnull(data_ref, "create CFDataRef of search object failed");
 
                addParameter(key, data_ref.get());
@@ -291,27 +288,24 @@ class Certificate_Store_MacOS_Impl
          check_notnull(m_keychains, "initialize keychain array");
          }
 
-      std::optional<X509_Certificate> findOne(Query query) const
+      std::shared_ptr<const X509_Certificate> findOne(Query query) const
          {
          query.addParameter(kSecMatchLimit, kSecMatchLimitOne);
 
          scoped_CFType<CFTypeRef> result(nullptr);
          search(std::move(query), &result.get());
 
-         if(result)
-            return readCertificate(result.get());
-         else
-            return std::nullopt;
+         return (result) ? readCertificate(result.get()) : nullptr;
          }
 
-      std::vector<X509_Certificate> findAll(Query query) const
+      std::vector<std::shared_ptr<const X509_Certificate>> findAll(Query query) const
          {
          query.addParameter(kSecMatchLimit, kSecMatchLimitAll);
 
          scoped_CFType<CFArrayRef> result(nullptr);
          search(std::move(query), (CFTypeRef*)&result.get());
 
-         std::vector<X509_Certificate> output;
+         std::vector<std::shared_ptr<const X509_Certificate>> output;
 
          if(result)
             {
@@ -347,7 +341,7 @@ class Certificate_Store_MacOS_Impl
       /**
        * Convert a CFTypeRef object into a Botan::X509_Certificate
        */
-      X509_Certificate readCertificate(CFTypeRef object) const
+      std::shared_ptr<const X509_Certificate> readCertificate(CFTypeRef object) const
          {
          if(!object || CFGetTypeID(object) != SecCertificateGetTypeID())
             {
@@ -363,7 +357,7 @@ class Certificate_Store_MacOS_Impl
          const auto length = CFDataGetLength(derData.get());
 
          DataSource_Memory ds(data, length);
-         return X509_Certificate(ds);
+         return std::make_shared<Botan::X509_Certificate>(ds);
          }
 
       CFArrayRef keychains() const { return m_keychains.get(); }
@@ -401,7 +395,7 @@ std::vector<X509_DN> Certificate_Store_MacOS::all_subjects() const
    std::vector<X509_DN> output;
    std::transform(certificates.cbegin(), certificates.cend(),
                   std::back_inserter(output),
-                  [](const std::optional<X509_Certificate> cert)
+                  [](const std::shared_ptr<const X509_Certificate> cert)
       {
       return cert->subject_dn();
       });
@@ -409,7 +403,7 @@ std::vector<X509_DN> Certificate_Store_MacOS::all_subjects() const
    return output;
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store_MacOS::find_cert(const X509_DN& subject_dn,
                                    const std::vector<uint8_t>& key_id) const
    {
@@ -424,7 +418,7 @@ Certificate_Store_MacOS::find_cert(const X509_DN& subject_dn,
    return m_impl->findOne(std::move(query));
    }
 
-std::vector<X509_Certificate> Certificate_Store_MacOS::find_all_certs(
+std::vector<std::shared_ptr<const X509_Certificate>> Certificate_Store_MacOS::find_all_certs(
          const X509_DN& subject_dn,
          const std::vector<uint8_t>& key_id) const
    {
@@ -439,7 +433,7 @@ std::vector<X509_Certificate> Certificate_Store_MacOS::find_all_certs(
    return m_impl->findAll(std::move(query));
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store_MacOS::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
    {
    if(key_hash.size() != 20)
@@ -453,14 +447,14 @@ Certificate_Store_MacOS::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& ke
    return m_impl->findOne(std::move(query));
    }
 
-std::optional<X509_Certificate>
+std::shared_ptr<const X509_Certificate>
 Certificate_Store_MacOS::find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const
    {
    BOTAN_UNUSED(subject_hash);
    throw Not_Implemented("Certificate_Store_MacOS::find_cert_by_raw_subject_dn_sha256");
    }
 
-std::optional<X509_CRL> Certificate_Store_MacOS::find_crl_for(const X509_Certificate& subject) const
+std::shared_ptr<const X509_CRL> Certificate_Store_MacOS::find_crl_for(const X509_Certificate& subject) const
    {
    BOTAN_UNUSED(subject);
    return {};
diff --git a/src/lib/x509/certstor_system_macos/certstor_macos.h b/src/lib/x509/certstor_system_macos/certstor_macos.h
index 3c983dc2e..e7416e631 100644
--- a/src/lib/x509/certstor_system_macos/certstor_macos.h
+++ b/src/lib/x509/certstor_system_macos/certstor_macos.h
@@ -41,7 +41,7 @@ class BOTAN_PUBLIC_API(2, 10) Certificate_Store_MacOS final : public Certificate
       * Find a certificate by Subject DN and (optionally) key identifier
       * @return the first certificate that matches
       */
-      std::optional<X509_Certificate> find_cert(
+      std::shared_ptr<const X509_Certificate> find_cert(
          const X509_DN& subject_dn,
          const std::vector<uint8_t>& key_id) const override;
 
@@ -49,7 +49,7 @@ class BOTAN_PUBLIC_API(2, 10) Certificate_Store_MacOS final : public Certificate
       * Find all certificates with a given Subject DN.
       * Subject DN and even the key identifier might not be unique.
       */
-      std::vector<X509_Certificate> find_all_certs(
+      std::vector<std::shared_ptr<const X509_Certificate>> find_all_certs(
                const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
       /**
@@ -57,20 +57,20 @@ class BOTAN_PUBLIC_API(2, 10) Certificate_Store_MacOS final : public Certificate
       * public key.
       * @return a matching certificate or nullptr otherwise
       */
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
       find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
       /**
        * @throws Botan::Not_Implemented
        */
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
       find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const override;
 
       /**
        * Fetching CRLs is not supported by the keychain on macOS. This will
        * always return an empty list.
        */
-      std::optional<X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
 
    private:
       std::shared_ptr<Certificate_Store_MacOS_Impl> m_impl;
diff --git a/src/lib/x509/certstor_system_windows/certstor_windows.cpp b/src/lib/x509/certstor_system_windows/certstor_windows.cpp
index d112047db..ba202b48c 100644
--- a/src/lib/x509/certstor_system_windows/certstor_windows.cpp
+++ b/src/lib/x509/certstor_system_windows/certstor_windows.cpp
@@ -23,6 +23,8 @@
 namespace Botan {
 namespace {
 
+using Cert_Pointer = std::shared_ptr<const Botan::X509_Certificate>;
+using Cert_Vector = std::vector<Cert_Pointer>;
 const std::array<const char*, 2> cert_store_names{"Root", "CA"};
 
 /**
@@ -117,12 +119,11 @@ HCERTSTORE open_cert_store(const char* cert_store_name)
    return store;
    }
 
-std::vector<X509_Certificate> search_cert_stores(
-   const _CRYPTOAPI_BLOB& blob, const DWORD& find_type,
-   std::function<bool (const std::vector<X509_Certificate>& certs, const X509_Certificate& cert)> filter,
-   bool return_on_first_found)
+Cert_Vector search_cert_stores(const _CRYPTOAPI_BLOB& blob, const DWORD& find_type,
+                               std::function<bool(const Cert_Vector& certs, Cert_Pointer cert)> filter,
+                               bool return_on_first_found)
    {
-   std::vector<X509_Certificate> certs;
+   Cert_Vector certs;
    for(const auto store_name : cert_store_names)
       {
       Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
@@ -132,7 +133,7 @@ std::vector<X509_Certificate> search_cert_stores(
                                    WINCRYPT_UNUSED_PARAM, find_type,
                                    &blob, cert_context.get())))
          {
-         X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
+         auto cert = std::make_shared<X509_Certificate>(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
          if(filter(certs, cert))
             {
             if(return_on_first_found)
@@ -147,15 +148,15 @@ std::vector<X509_Certificate> search_cert_stores(
    return certs;
    }
 
-bool already_contains_certificate(const std::vector<X509_Certificate>& certs, X509_Certificate cert)
+bool already_contains_certificate(const Cert_Vector& certs, Cert_Pointer cert)
    {
-   return std::any_of(certs.begin(), certs.end(), [&](const X509_Certificate& c)
+   return std::any_of(certs.begin(), certs.end(), [&](std::shared_ptr<const Botan::X509_Certificate> c)
       {
-      return c == cert;
+      return *c == *cert;
       });
    }
 
-std::vector<X509_Certificate> find_cert_by_dn_and_key_id(const Botan::X509_DN& subject_dn,
+Cert_Vector find_cert_by_dn_and_key_id(const Botan::X509_DN& subject_dn,
                                        const std::vector<uint8_t>& key_id,
                                        bool return_on_first_found)
    {
@@ -178,9 +179,9 @@ std::vector<X509_Certificate> find_cert_by_dn_and_key_id(const Botan::X509_DN& s
       blob.pbData = const_cast<BYTE*>(key_id.data());
       }
 
-   auto filter = [&](const std::vector<X509_Certificate>& certs, const X509_Certificate& cert)
+   auto filter = [&](const Cert_Vector& certs, Cert_Pointer cert)
       {
-      return !already_contains_certificate(certs, cert) && (key_id.empty() || cert.subject_dn() == subject_dn);
+      return !already_contains_certificate(certs, cert) && (key_id.empty() || cert->subject_dn() == subject_dn);
       };
 
    return search_cert_stores(blob, find_type, filter, return_on_first_found);
@@ -209,26 +210,21 @@ std::vector<X509_DN> Certificate_Store_Windows::all_subjects() const
    return subject_dns;
    }
 
-std::optional<X509_Certificate>
-Certificate_Store_Windows::find_cert(const Botan::X509_DN& subject_dn,
-                                     const std::vector<uint8_t>& key_id) const
+Cert_Pointer Certificate_Store_Windows::find_cert(const Botan::X509_DN& subject_dn,
+      const std::vector<uint8_t>& key_id) const
    {
    const auto certs = find_cert_by_dn_and_key_id(subject_dn, key_id, true);
-   if(certs.empty())
-      return std::nullopt;
-   else
-      return certs.front();
+   return certs.empty() ? nullptr : certs.front();
    }
 
-std::vector<X509_Certificate> Certificate_Store_Windows::find_all_certs(
+Cert_Vector Certificate_Store_Windows::find_all_certs(
    const X509_DN& subject_dn,
    const std::vector<uint8_t>& key_id) const
    {
    return find_cert_by_dn_and_key_id(subject_dn, key_id, false);
    }
 
-std::optional<X509_Certificate>
-Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
+Cert_Pointer Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
    {
    if(key_hash.size() != 20)
       {
@@ -239,27 +235,23 @@ Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector<uint8_t>&
    blob.cbData = static_cast<DWORD>(key_hash.size());
    blob.pbData = const_cast<BYTE*>(key_hash.data());
 
-   auto filter = [&](const std::vector<X509_Certificate>&, const X509_Certificate&) { return true; };
+   auto filter = [](const Cert_Vector&, Cert_Pointer) { return true; };
 
    const auto certs = search_cert_stores(blob, CERT_FIND_KEY_IDENTIFIER, filter, true);
-   if(certs.empty())
-      return std::nullopt;
-   else
-      return certs.front();
+   return certs.empty() ? nullptr : certs.front();
    }
 
-std::optional<X509_Certificate>
-Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256(
+Cert_Pointer Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256(
    const std::vector<uint8_t>& subject_hash) const
    {
    BOTAN_UNUSED(subject_hash);
    throw Not_Implemented("Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256");
    }
 
-std::optional<X509_CRL> Certificate_Store_Windows::find_crl_for(const X509_Certificate& subject) const
+std::shared_ptr<const X509_CRL> Certificate_Store_Windows::find_crl_for(const X509_Certificate& subject) const
    {
    // TODO: this could be implemented by using the CertFindCRLInStore function
    BOTAN_UNUSED(subject);
-   return std::nullopt;
+   return {};
    }
 }
diff --git a/src/lib/x509/certstor_system_windows/certstor_windows.h b/src/lib/x509/certstor_system_windows/certstor_windows.h
index 890920ac9..f47e718c8 100644
--- a/src/lib/x509/certstor_system_windows/certstor_windows.h
+++ b/src/lib/x509/certstor_system_windows/certstor_windows.h
@@ -34,7 +34,7 @@ class BOTAN_PUBLIC_API(2, 11) Certificate_Store_Windows final : public Certifica
       * Find a certificate by Subject DN and (optionally) key identifier
       * @return the first certificate that matches
       */
-      std::optional<X509_Certificate> find_cert(
+      std::shared_ptr<const X509_Certificate> find_cert(
          const X509_DN& subject_dn,
          const std::vector<uint8_t>& key_id) const override;
 
@@ -42,7 +42,7 @@ class BOTAN_PUBLIC_API(2, 11) Certificate_Store_Windows final : public Certifica
       * Find all certificates with a given Subject DN.
       * Subject DN and even the key identifier might not be unique.
       */
-      std::vector<X509_Certificate> find_all_certs(
+      std::vector<std::shared_ptr<const X509_Certificate>> find_all_certs(
                const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
       /**
@@ -50,20 +50,20 @@ class BOTAN_PUBLIC_API(2, 11) Certificate_Store_Windows final : public Certifica
       * public key.
       * @return a matching certificate or nullptr otherwise
       */
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
       find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
       /**
        * @throws Botan::Not_Implemented
        */
-      std::optional<X509_Certificate>
+      std::shared_ptr<const X509_Certificate>
       find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const override;
 
       /**
        * Not Yet Implemented
        * @return nullptr;
        */
-      std::optional<X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
    };
 }
 
diff --git a/src/lib/x509/ocsp.cpp b/src/lib/x509/ocsp.cpp
index 69d216ad0..f4d934526 100644
--- a/src/lib/x509/ocsp.cpp
+++ b/src/lib/x509/ocsp.cpp
@@ -186,12 +186,12 @@ Certificate_Status_Code Response::verify_signature(const X509_Certificate& issue
    }
 
 Certificate_Status_Code Response::check_signature(const std::vector<Certificate_Store*>& trusted_roots,
-                                                  const std::vector<X509_Certificate>& ee_cert_path) const
+                                                  const std::vector<std::shared_ptr<const X509_Certificate>>& ee_cert_path) const
    {
    if (m_responses.empty())
       return m_dummy_response_status;
 
-   std::optional<X509_Certificate> signing_cert;
+   std::shared_ptr<const X509_Certificate> signing_cert;
 
    for(size_t i = 0; i != trusted_roots.size(); ++i)
       {
@@ -223,13 +223,13 @@ Certificate_Status_Code Response::check_signature(const std::vector<Certificate_
       for(size_t i = 1; i < ee_cert_path.size(); ++i)
          {
          // Check all CA certificates in the (assumed validated) EE cert path
-         if(!m_signer_name.empty() && ee_cert_path[i].subject_dn() == m_signer_name)
+         if(!m_signer_name.empty() && ee_cert_path[i]->subject_dn() == m_signer_name)
             {
             signing_cert = ee_cert_path[i];
             break;
             }
 
-         if(m_key_hash.size() > 0 && ee_cert_path[i].subject_public_key_bitstring_sha1() == m_key_hash)
+         if(m_key_hash.size() > 0 && ee_cert_path[i]->subject_public_key_bitstring_sha1() == m_key_hash)
             {
             signing_cert = ee_cert_path[i];
             break;
@@ -244,13 +244,13 @@ Certificate_Status_Code Response::check_signature(const std::vector<Certificate_
          // Check all CA certificates in the (assumed validated) EE cert path
          if(!m_signer_name.empty() && m_certs[i].subject_dn() == m_signer_name)
             {
-            signing_cert = m_certs[i];
+            signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]);
             break;
             }
 
          if(m_key_hash.size() > 0 && m_certs[i].subject_public_key_bitstring_sha1() == m_key_hash)
             {
-            signing_cert = m_certs[i];
+            signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]);
             break;
             }
          }
diff --git a/src/lib/x509/ocsp.h b/src/lib/x509/ocsp.h
index 139bd6c77..552245644 100644
--- a/src/lib/x509/ocsp.h
+++ b/src/lib/x509/ocsp.h
@@ -168,7 +168,7 @@ class BOTAN_PUBLIC_API(2,0) Response final
       * some cases.
       */
       Certificate_Status_Code check_signature(const std::vector<Certificate_Store*>& trust_roots,
-                                              const std::vector<X509_Certificate>& cert_path = {}) const;
+                                              const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path = {}) const;
 
       /**
       * Verify that issuer's key signed this response
diff --git a/src/lib/x509/pkix_types.h b/src/lib/x509/pkix_types.h
index 64c746308..221c67c25 100644
--- a/src/lib/x509/pkix_types.h
+++ b/src/lib/x509/pkix_types.h
@@ -384,7 +384,7 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Extension
       * @param pos Position of subject certificate in cert_path
       */
       virtual void validate(const X509_Certificate& subject, const X509_Certificate& issuer,
-            const std::vector<X509_Certificate>& cert_path,
+            const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
             std::vector<std::set<Certificate_Status_Code>>& cert_status,
             size_t pos);
 
diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp
index e000b2f11..18fcaea44 100644
--- a/src/lib/x509/x509_ext.cpp
+++ b/src/lib/x509/x509_ext.cpp
@@ -110,7 +110,7 @@ Extensions::create_extn_obj(const OID& oid,
 * Validate the extension (the default implementation is a NOP)
 */
 void Certificate_Extension::validate(const X509_Certificate&, const X509_Certificate&,
-      const std::vector<X509_Certificate>&,
+      const std::vector<std::shared_ptr<const X509_Certificate>>&,
       std::vector<std::set<Certificate_Status_Code>>&,
       size_t)
    {
@@ -555,7 +555,7 @@ void Name_Constraints::decode_inner(const std::vector<uint8_t>& in)
    }
 
 void Name_Constraints::validate(const X509_Certificate& subject, const X509_Certificate& issuer,
-      const std::vector<X509_Certificate>& cert_path,
+      const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
       std::vector<std::set<Certificate_Status_Code>>& cert_status,
       size_t pos)
    {
@@ -580,7 +580,7 @@ void Name_Constraints::validate(const X509_Certificate& subject, const X509_Cert
 
          for(auto c: m_name_constraints.permitted())
             {
-            switch(c.base().matches(cert_path.at(j)))
+            switch(c.base().matches(*cert_path.at(j)))
                {
                case GeneralName::MatchResult::NotFound:
                case GeneralName::MatchResult::All:
@@ -597,7 +597,7 @@ void Name_Constraints::validate(const X509_Certificate& subject, const X509_Cert
 
          for(auto c: m_name_constraints.excluded())
             {
-            switch(c.base().matches(cert_path.at(j)))
+            switch(c.base().matches(*cert_path.at(j)))
                {
                case GeneralName::MatchResult::All:
                case GeneralName::MatchResult::Some:
@@ -687,7 +687,7 @@ void Certificate_Policies::decode_inner(const std::vector<uint8_t>& in)
 void Certificate_Policies::validate(
    const X509_Certificate& /*subject*/,
    const X509_Certificate& /*issuer*/,
-   const std::vector<X509_Certificate>& /*cert_path*/,
+   const std::vector<std::shared_ptr<const X509_Certificate>>& /*cert_path*/,
    std::vector<std::set<Certificate_Status_Code>>& cert_status,
    size_t pos)
    {
diff --git a/src/lib/x509/x509_ext.h b/src/lib/x509/x509_ext.h
index 58fd0b35a..bdb8ebd20 100644
--- a/src/lib/x509/x509_ext.h
+++ b/src/lib/x509/x509_ext.h
@@ -229,7 +229,7 @@ class BOTAN_PUBLIC_API(2,0) Name_Constraints final : public Certificate_Extensio
       Name_Constraints(const NameConstraints &nc) : m_name_constraints(nc) {}
 
       void validate(const X509_Certificate& subject, const X509_Certificate& issuer,
-            const std::vector<X509_Certificate>& cert_path,
+            const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
             std::vector<std::set<Certificate_Status_Code>>& cert_status,
             size_t pos) override;
 
@@ -267,7 +267,7 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Policies final : public Certificate_Exte
       OID oid_of() const override { return static_oid(); }
 
       void validate(const X509_Certificate& subject, const X509_Certificate& issuer,
-            const std::vector<X509_Certificate>& cert_path,
+            const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
             std::vector<std::set<Certificate_Status_Code>>& cert_status,
             size_t pos) override;
    private:
@@ -481,7 +481,7 @@ class BOTAN_PUBLIC_API(2,4) Unknown_Extension final : public Certificate_Extensi
       bool is_critical_extension() const { return m_critical; }
 
       void validate(const X509_Certificate&, const X509_Certificate&,
-            const std::vector<X509_Certificate>&,
+            const std::vector<std::shared_ptr<const X509_Certificate>>&,
             std::vector<std::set<Certificate_Status_Code>>& cert_status,
             size_t pos) override
          {
diff --git a/src/lib/x509/x509path.cpp b/src/lib/x509/x509path.cpp
index 840e8f3bf..b5cdc27c2 100644
--- a/src/lib/x509/x509path.cpp
+++ b/src/lib/x509/x509path.cpp
@@ -29,7 +29,7 @@ namespace Botan {
 * PKIX path validation
 */
 CertificatePathStatusCodes
-PKIX::check_chain(const std::vector<X509_Certificate>& cert_path,
+PKIX::check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
                   std::chrono::system_clock::time_point ref_time,
                   const std::string& hostname,
                   Usage_Type usage,
@@ -45,14 +45,14 @@ PKIX::check_chain(const std::vector<X509_Certificate>& cert_path,
 
    CertificatePathStatusCodes cert_status(cert_path.size());
 
-   if(!hostname.empty() && !cert_path[0].matches_dns_name(hostname))
+   if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname))
       cert_status[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH);
 
-   if(!cert_path[0].allowed_usage(usage))
+   if(!cert_path[0]->allowed_usage(usage))
       cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE);
 
-   if(cert_path[0].is_CA_cert() == false &&
-      cert_path[0].has_constraints(KEY_CERT_SIGN))
+   if(cert_path[0]->is_CA_cert() == false &&
+      cert_path[0]->has_constraints(KEY_CERT_SIGN))
       {
       /*
       "If the keyCertSign bit is asserted, then the cA bit in the
@@ -71,9 +71,9 @@ PKIX::check_chain(const std::vector<X509_Certificate>& cert_path,
 
       const bool at_self_signed_root = (i == cert_path.size() - 1);
 
-      const std::optional<X509_Certificate>& subject = cert_path[i];
+      const std::shared_ptr<const X509_Certificate>& subject = cert_path[i];
 
-      const std::optional<X509_Certificate>& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)];
+      const std::shared_ptr<const X509_Certificate>& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)];
 
       if(at_self_signed_root && (issuer->is_self_signed() == false))
          {
@@ -179,7 +179,7 @@ PKIX::check_chain(const std::vector<X509_Certificate>& cert_path,
    for(size_t i = cert_path.size() - 1; i > 0 ; --i)
       {
       std::set<Certificate_Status_Code>& status = cert_status.at(i);
-      const std::optional<X509_Certificate>& subject = cert_path[i];
+      const std::shared_ptr<const X509_Certificate>& subject = cert_path[i];
 
       /*
       * If the certificate was not self-issued, verify that max_path_length is
@@ -211,8 +211,8 @@ PKIX::check_chain(const std::vector<X509_Certificate>& cert_path,
    }
 
 CertificatePathStatusCodes
-PKIX::check_ocsp(const std::vector<X509_Certificate>& cert_path,
-                 const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
+PKIX::check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+                 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses,
                  const std::vector<Certificate_Store*>& trusted_certstores,
                  std::chrono::system_clock::time_point ref_time,
                  std::chrono::seconds max_ocsp_age)
@@ -226,10 +226,10 @@ PKIX::check_ocsp(const std::vector<X509_Certificate>& cert_path,
       {
       std::set<Certificate_Status_Code>& status = cert_status.at(i);
 
-      std::optional<X509_Certificate> subject = cert_path.at(i);
-      std::optional<X509_Certificate> ca = cert_path.at(i+1);
+      std::shared_ptr<const X509_Certificate> subject = cert_path.at(i);
+      std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1);
 
-      if(i < ocsp_responses.size() && (ocsp_responses.at(i) != std::nullopt)
+      if(i < ocsp_responses.size() && (ocsp_responses.at(i) != nullptr)
             && (ocsp_responses.at(i)->status() == OCSP::Response_Status_Code::Successful))
          {
          try
@@ -262,8 +262,8 @@ PKIX::check_ocsp(const std::vector<X509_Certificate>& cert_path,
    }
 
 CertificatePathStatusCodes
-PKIX::check_crl(const std::vector<X509_Certificate>& cert_path,
-                const std::vector<std::optional<X509_CRL>>& crls,
+PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+                const std::vector<std::shared_ptr<const X509_CRL>>& crls,
                 std::chrono::system_clock::time_point ref_time)
    {
    if(cert_path.empty())
@@ -276,10 +276,10 @@ PKIX::check_crl(const std::vector<X509_Certificate>& cert_path,
       {
       std::set<Certificate_Status_Code>& status = cert_status.at(i);
 
-      if(i < crls.size() && crls[i].has_value())
+      if(i < crls.size() && crls.at(i))
          {
-         std::optional<X509_Certificate> subject = cert_path.at(i);
-         std::optional<X509_Certificate> ca = cert_path.at(i+1);
+         std::shared_ptr<const X509_Certificate> subject = cert_path.at(i);
+         std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1);
 
          if(!ca->allowed_usage(CRL_SIGN))
             status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER);
@@ -332,7 +332,7 @@ PKIX::check_crl(const std::vector<X509_Certificate>& cert_path,
    }
 
 CertificatePathStatusCodes
-PKIX::check_crl(const std::vector<X509_Certificate>& cert_path,
+PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
                 const std::vector<Certificate_Store*>& certstores,
                 std::chrono::system_clock::time_point ref_time)
    {
@@ -342,13 +342,14 @@ PKIX::check_crl(const std::vector<X509_Certificate>& cert_path,
    if(certstores.empty())
       throw Invalid_Argument("PKIX::check_crl certstores empty");
 
-   std::vector<std::optional<X509_CRL>> crls(cert_path.size());
+   std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size());
 
    for(size_t i = 0; i != cert_path.size(); ++i)
       {
+      BOTAN_ASSERT_NONNULL(cert_path[i]);
       for(size_t c = 0; c != certstores.size(); ++c)
          {
-         crls[i] = certstores[c]->find_crl_for(cert_path[i]);
+         crls[i] = certstores[c]->find_crl_for(*cert_path[i]);
          if(crls[i])
             break;
          }
@@ -360,7 +361,7 @@ PKIX::check_crl(const std::vector<X509_Certificate>& cert_path,
 #if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)
 
 CertificatePathStatusCodes
-PKIX::check_ocsp_online(const std::vector<X509_Certificate>& cert_path,
+PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
                         const std::vector<Certificate_Store*>& trusted_certstores,
                         std::chrono::system_clock::time_point ref_time,
                         std::chrono::milliseconds timeout,
@@ -370,7 +371,7 @@ PKIX::check_ocsp_online(const std::vector<X509_Certificate>& cert_path,
    if(cert_path.empty())
       throw Invalid_Argument("PKIX::check_ocsp_online cert_path empty");
 
-   std::vector<std::future<std::optional<OCSP::Response>>> ocsp_response_futures;
+   std::vector<std::future<std::shared_ptr<const OCSP::Response>>> ocsp_response_futures;
 
    size_t to_ocsp = 1;
 
@@ -381,18 +382,18 @@ PKIX::check_ocsp_online(const std::vector<X509_Certificate>& cert_path,
 
    for(size_t i = 0; i < to_ocsp; ++i)
       {
-      const std::optional<X509_Certificate>& subject = cert_path.at(i);
-      const std::optional<X509_Certificate>& issuer = cert_path.at(i+1);
+      const std::shared_ptr<const X509_Certificate>& subject = cert_path.at(i);
+      const std::shared_ptr<const X509_Certificate>& issuer = cert_path.at(i+1);
 
       if(subject->ocsp_responder() == "")
          {
-         ocsp_response_futures.emplace_back(std::async(std::launch::deferred, [&]() -> std::optional<OCSP::Response> {
-                  return OCSP::Response(Certificate_Status_Code::OCSP_NO_REVOCATION_URL);
+         ocsp_response_futures.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr<const OCSP::Response> {
+                  return std::make_shared<const OCSP::Response>(Certificate_Status_Code::OCSP_NO_REVOCATION_URL);
                   }));
          }
       else
          {
-         ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]() -> std::optional<OCSP::Response> {
+         ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const OCSP::Response> {
                OCSP::Request req(*issuer, BigInt::decode(subject->serial_number()));
 
                HTTP::Response http;
@@ -409,15 +410,15 @@ PKIX::check_ocsp_online(const std::vector<X509_Certificate>& cert_path,
                   // log e.what() ?
                   }
                if (http.status_code() != 200)
-                  return OCSP::Response(Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE);
+                  return std::make_shared<const OCSP::Response>(Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE);
                // Check the MIME type?
 
-               return OCSP::Response(http.body());
+               return std::make_shared<const OCSP::Response>(http.body());
                }));
          }
       }
 
-   std::vector<std::optional<OCSP::Response>> ocsp_responses;
+   std::vector<std::shared_ptr<const OCSP::Response>> ocsp_responses;
 
    for(size_t i = 0; i < ocsp_response_futures.size(); ++i)
       {
@@ -428,7 +429,7 @@ PKIX::check_ocsp_online(const std::vector<X509_Certificate>& cert_path,
    }
 
 CertificatePathStatusCodes
-PKIX::check_crl_online(const std::vector<X509_Certificate>& cert_path,
+PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
                        const std::vector<Certificate_Store*>& certstores,
                        Certificate_Store_In_Memory* crl_store,
                        std::chrono::system_clock::time_point ref_time,
@@ -439,16 +440,16 @@ PKIX::check_crl_online(const std::vector<X509_Certificate>& cert_path,
    if(certstores.empty())
       throw Invalid_Argument("PKIX::check_crl_online certstores empty");
 
-   std::vector<std::future<std::optional<X509_CRL>>> future_crls;
-   std::vector<std::optional<X509_CRL>> crls(cert_path.size());
+   std::vector<std::future<std::shared_ptr<const X509_CRL>>> future_crls;
+   std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size());
 
    for(size_t i = 0; i != cert_path.size(); ++i)
       {
-      const std::optional<X509_Certificate>& cert = cert_path.at(i);
+      const std::shared_ptr<const X509_Certificate>& cert = cert_path.at(i);
       for(size_t c = 0; c != certstores.size(); ++c)
          {
          crls[i] = certstores[c]->find_crl_for(*cert);
-         if(crls[i].has_value())
+         if(crls[i])
             break;
          }
 
@@ -461,24 +462,24 @@ PKIX::check_crl_online(const std::vector<X509_Certificate>& cert_path,
          We already have a CRL, so just insert this empty one to hold a place in the vector
          so that indexes match up
          */
-         future_crls.emplace_back(std::future<std::optional<X509_CRL>>());
+         future_crls.emplace_back(std::future<std::shared_ptr<const X509_CRL>>());
          }
       else if(cert->crl_distribution_point() == "")
          {
          // Avoid creating a thread for this case
-         future_crls.emplace_back(std::async(std::launch::deferred, [&]() -> std::optional<X509_CRL> {
+         future_crls.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr<const X509_CRL> {
                throw Not_Implemented("No CRL distribution point for this certificate");
                }));
          }
       else
          {
-         future_crls.emplace_back(std::async(std::launch::async, [&]() -> std::optional<X509_CRL> {
+         future_crls.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const X509_CRL> {
                auto http = HTTP::GET_sync(cert->crl_distribution_point(),
                                           /*redirects*/ 1, timeout);
 
                http.throw_unless_ok();
                // check the mime type?
-               return X509_CRL(http.body());
+               return std::make_shared<const X509_CRL>(http.body());
                }));
          }
       }
@@ -508,8 +509,8 @@ PKIX::check_crl_online(const std::vector<X509_Certificate>& cert_path,
          if(crl_status[i].count(Certificate_Status_Code::VALID_CRL_CHECKED))
             {
             // better be non-null, we supposedly validated it
-            BOTAN_ASSERT_NOMSG(crls[i].has_value());
-            crl_store->add_crl(*crls[i]);
+            BOTAN_ASSERT_NONNULL(crls[i]);
+            crl_store->add_crl(crls[i]);
             }
          }
       }
@@ -520,12 +521,12 @@ PKIX::check_crl_online(const std::vector<X509_Certificate>& cert_path,
 #endif
 
 Certificate_Status_Code
-PKIX::build_certificate_path(std::vector<X509_Certificate>& cert_path,
+PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
                              const std::vector<Certificate_Store*>& trusted_certstores,
-                             const X509_Certificate& end_entity,
-                             const std::vector<X509_Certificate>& end_entity_extra)
+                             const std::shared_ptr<const X509_Certificate>& end_entity,
+                             const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra)
    {
-   if(end_entity.is_self_signed())
+   if(end_entity->is_self_signed())
       {
       return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST;
       }
@@ -539,7 +540,7 @@ PKIX::build_certificate_path(std::vector<X509_Certificate>& cert_path,
    std::set<std::string> certs_seen;
 
    cert_path.push_back(end_entity);
-   certs_seen.insert(end_entity.fingerprint("SHA-256"));
+   certs_seen.insert(end_entity->fingerprint("SHA-256"));
 
    Certificate_Store_In_Memory ee_extras;
    for(size_t i = 0; i != end_entity_extra.size(); ++i)
@@ -548,11 +549,11 @@ PKIX::build_certificate_path(std::vector<X509_Certificate>& cert_path,
    // iterate until we reach a root or cannot find the issuer
    for(;;)
       {
-      const X509_Certificate& last = cert_path.back();
+      const X509_Certificate& last = *cert_path.back();
       const X509_DN issuer_dn = last.issuer_dn();
       const std::vector<uint8_t> auth_key_id = last.authority_key_id();
 
-      std::optional<X509_Certificate> issuer;
+      std::shared_ptr<const X509_Certificate> issuer;
       bool trusted_issuer = false;
 
       for(Certificate_Store* store : trusted_certstores)
@@ -582,7 +583,7 @@ PKIX::build_certificate_path(std::vector<X509_Certificate>& cert_path,
          }
 
       certs_seen.insert(fprint);
-      cert_path.push_back(*issuer);
+      cert_path.push_back(issuer);
 
       if(issuer->is_self_signed())
          {
@@ -604,7 +605,7 @@ PKIX::build_certificate_path(std::vector<X509_Certificate>& cert_path,
 namespace
 {
 // <certificate, trusted?>
-using cert_maybe_trusted = std::pair<std::optional<X509_Certificate>,bool>;
+using cert_maybe_trusted = std::pair<std::shared_ptr<const X509_Certificate>,bool>;
 }
 
 /**
@@ -625,10 +626,10 @@ using cert_maybe_trusted = std::pair<std::optional<X509_Certificate>,bool>;
  *
  */
 Certificate_Status_Code
-PKIX::build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& cert_paths_out,
+PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const X509_Certificate>>>& cert_paths_out,
                                   const std::vector<Certificate_Store*>& trusted_certstores,
-                                  const std::optional<X509_Certificate>& end_entity,
-                                  const std::vector<X509_Certificate>& end_entity_extra)
+                                  const std::shared_ptr<const X509_Certificate>& end_entity,
+                                  const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra)
    {
    if(!cert_paths_out.empty())
       {
@@ -661,26 +662,26 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& ce
 
    // new certs are added and removed from the path during the DFS
    // it is copied into cert_paths_out when we encounter a trusted root
-   std::vector<X509_Certificate> path_so_far;
+   std::vector<std::shared_ptr<const X509_Certificate>> path_so_far;
 
    // todo can we assume that the end certificate is not trusted?
    std::vector<cert_maybe_trusted> stack = { {end_entity, false} };
 
    while(!stack.empty())
       {
-      std::optional<X509_Certificate> last = stack.back().first;
       // found a deletion marker that guides the DFS, backtracing
-      if(last == std::nullopt)
+      if(stack.back().first == nullptr)
          {
          stack.pop_back();
-         std::string fprint = path_so_far.back().fingerprint("SHA-256");
+         std::string fprint = path_so_far.back()->fingerprint("SHA-256");
          certs_seen.erase(fprint);
          path_so_far.pop_back();
          }
       // process next cert on the path
       else
          {
-         const bool trusted = stack.back().second;
+         std::shared_ptr<const X509_Certificate> last = stack.back().first;
+         bool trusted = stack.back().second;
          stack.pop_back();
 
          // certificate already seen?
@@ -699,7 +700,7 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& ce
             if(trusted)
                {
                cert_paths_out.push_back(path_so_far);
-               cert_paths_out.back().push_back(*last);
+               cert_paths_out.back().push_back(last);
 
                continue;
                }
@@ -715,7 +716,7 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& ce
          const std::vector<uint8_t> auth_key_id = last->authority_key_id();
 
          // search for trusted issuers
-         std::vector<X509_Certificate> trusted_issuers;
+         std::vector<std::shared_ptr<const X509_Certificate>> trusted_issuers;
          for(Certificate_Store* store : trusted_certstores)
             {
             auto new_issuers = store->find_all_certs(issuer_dn, auth_key_id);
@@ -723,7 +724,7 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& ce
             }
 
          // search the supplemental certs
-         std::vector<X509_Certificate> misc_issuers =
+         std::vector<std::shared_ptr<const X509_Certificate>> misc_issuers =
             ee_extras.find_all_certs(issuer_dn, auth_key_id);
 
          // if we could not find any issuers, the current path ends here
@@ -734,11 +735,11 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& ce
             }
 
          // push the latest certificate onto the path_so_far
-         path_so_far.push_back(*last);
+         path_so_far.push_back(last);
          certs_seen.emplace(fprint);
 
          // push a deletion marker on the stack for backtracing later
-         stack.push_back({std::optional<X509_Certificate>(), false});
+         stack.push_back({std::shared_ptr<const X509_Certificate>(nullptr),false});
 
          for(const auto& trusted_cert : trusted_issuers)
             {
@@ -850,21 +851,21 @@ Path_Validation_Result x509_path_validate(
    Usage_Type usage,
    std::chrono::system_clock::time_point ref_time,
    std::chrono::milliseconds ocsp_timeout,
-   const std::vector<std::optional<OCSP::Response>>& ocsp_resp)
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
    {
    if(end_certs.empty())
       {
       throw Invalid_Argument("x509_path_validate called with no subjects");
       }
 
-   X509_Certificate end_entity = end_certs[0];
-   std::vector<X509_Certificate> end_entity_extra;
+   std::shared_ptr<const X509_Certificate> end_entity(std::make_shared<const X509_Certificate>(end_certs[0]));
+   std::vector<std::shared_ptr<const X509_Certificate>> end_entity_extra;
    for(size_t i = 1; i < end_certs.size(); ++i)
       {
-      end_entity_extra.push_back(end_certs[i]);
+      end_entity_extra.push_back(std::make_shared<const X509_Certificate>(end_certs[i]));
       }
 
-   std::vector<std::vector<X509_Certificate>> cert_paths;
+   std::vector<std::vector<std::shared_ptr<const X509_Certificate>>> cert_paths;
    Certificate_Status_Code path_building_result = PKIX::build_all_certificate_paths(cert_paths, trusted_roots, end_entity, end_entity_extra);
 
    // If we cannot successfully build a chain to a trusted self-signed root, stop now
@@ -929,7 +930,7 @@ Path_Validation_Result x509_path_validate(
    Usage_Type usage,
    std::chrono::system_clock::time_point when,
    std::chrono::milliseconds ocsp_timeout,
-   const std::vector<std::optional<OCSP::Response>>& ocsp_resp)
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
    {
    std::vector<X509_Certificate> certs;
    certs.push_back(end_cert);
@@ -944,7 +945,7 @@ Path_Validation_Result x509_path_validate(
    Usage_Type usage,
    std::chrono::system_clock::time_point when,
    std::chrono::milliseconds ocsp_timeout,
-   const std::vector<std::optional<OCSP::Response>>& ocsp_resp)
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
    {
    std::vector<Certificate_Store*> trusted_roots;
    trusted_roots.push_back(const_cast<Certificate_Store*>(&store));
@@ -960,7 +961,7 @@ Path_Validation_Result x509_path_validate(
    Usage_Type usage,
    std::chrono::system_clock::time_point when,
    std::chrono::milliseconds ocsp_timeout,
-   const std::vector<std::optional<OCSP::Response>>& ocsp_resp)
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
    {
    std::vector<X509_Certificate> certs;
    certs.push_back(end_cert);
@@ -1011,7 +1012,7 @@ CertificatePathStatusCodes find_warnings(const CertificatePathStatusCodes& all_s
 }
 
 Path_Validation_Result::Path_Validation_Result(CertificatePathStatusCodes status,
-                                               std::vector<X509_Certificate>&& cert_chain) :
+                                               std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain) :
    m_all_status(status),
    m_warnings(find_warnings(m_all_status)),
    m_cert_path(cert_chain),
@@ -1026,14 +1027,14 @@ const X509_Certificate& Path_Validation_Result::trust_root() const
    if(result() != Certificate_Status_Code::VERIFIED)
       throw Invalid_State("Path_Validation_Result::trust_root meaningless with invalid status");
 
-   return m_cert_path[m_cert_path.size()-1];
+   return *m_cert_path[m_cert_path.size()-1];
    }
 
 std::set<std::string> Path_Validation_Result::trusted_hashes() const
    {
    std::set<std::string> hashes;
    for(size_t i = 0; i != m_cert_path.size(); ++i)
-      hashes.insert(m_cert_path[i].hash_used_for_signature());
+      hashes.insert(m_cert_path[i]->hash_used_for_signature());
    return hashes;
    }
 
diff --git a/src/lib/x509/x509path.h b/src/lib/x509/x509path.h
index 9aee14973..c8575fd32 100644
--- a/src/lib/x509/x509path.h
+++ b/src/lib/x509/x509path.h
@@ -143,7 +143,7 @@ class BOTAN_PUBLIC_API(2,0) Path_Validation_Result final
       * @return the full path from subject to trust root
       * This path may be empty
       */
-      const std::vector<X509_Certificate>& cert_path() const { return m_cert_path; }
+      const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path() const { return m_cert_path; }
 
       /**
       * @return true iff the validation was successful
@@ -193,7 +193,7 @@ class BOTAN_PUBLIC_API(2,0) Path_Validation_Result final
       * @param cert_chain the certificate chain that was validated
       */
       Path_Validation_Result(CertificatePathStatusCodes status,
-                             std::vector<X509_Certificate>&& cert_chain);
+                             std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain);
 
       /**
       * Create a Path_Validation_Result
@@ -204,7 +204,7 @@ class BOTAN_PUBLIC_API(2,0) Path_Validation_Result final
    private:
       CertificatePathStatusCodes m_all_status;
       CertificatePathStatusCodes m_warnings;
-      std::vector<X509_Certificate> m_cert_path;
+      std::vector<std::shared_ptr<const X509_Certificate>> m_cert_path;
       Certificate_Status_Code m_overall;
    };
 
@@ -231,7 +231,7 @@ Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate(
    Usage_Type usage = Usage_Type::UNSPECIFIED,
    std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(),
    std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0),
-   const std::vector<std::optional<OCSP::Response>>& ocsp_resp = {});
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {});
 
 /**
 * PKIX Path Validation
@@ -253,7 +253,7 @@ Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate(
    Usage_Type usage = Usage_Type::UNSPECIFIED,
    std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(),
    std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0),
-   const std::vector<std::optional<OCSP::Response>>& ocsp_resp = {});
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {});
 
 /**
 * PKIX Path Validation
@@ -275,7 +275,7 @@ Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate(
    Usage_Type usage = Usage_Type::UNSPECIFIED,
    std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(),
    std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0),
-   const std::vector<std::optional<OCSP::Response>>& ocsp_resp = {});
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {});
 
 /**
 * PKIX Path Validation
@@ -297,7 +297,7 @@ Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate(
    Usage_Type usage = Usage_Type::UNSPECIFIED,
    std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(),
    std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0),
-   const std::vector<std::optional<OCSP::Response>>& ocsp_resp = {});
+   const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {});
 
 
 /**
@@ -309,10 +309,10 @@ Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate(
 namespace PKIX {
 
 Certificate_Status_Code
-build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& cert_paths,
+build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const X509_Certificate>>>& cert_paths,
                             const std::vector<Certificate_Store*>& trusted_certstores,
-                            const std::optional<X509_Certificate>& end_entity,
-                            const std::vector<X509_Certificate>& end_entity_extra);
+                            const std::shared_ptr<const X509_Certificate>& end_entity,
+                            const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra);
 
 
 /**
@@ -324,10 +324,10 @@ build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& cert_pat
 * @return result of the path building operation (OK or error)
 */
 Certificate_Status_Code
-BOTAN_PUBLIC_API(2,0) build_certificate_path(std::vector<X509_Certificate>& cert_path_out,
+BOTAN_PUBLIC_API(2,0) build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path_out,
                                  const std::vector<Certificate_Store*>& trusted_certstores,
-                                 const X509_Certificate& end_entity,
-                                 const std::vector<X509_Certificate>& end_entity_extra);
+                                 const std::shared_ptr<const X509_Certificate>& end_entity,
+                                 const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra);
 
 /**
 * Check the certificate chain, but not any revocation data
@@ -347,7 +347,7 @@ BOTAN_PUBLIC_API(2,0) build_certificate_path(std::vector<X509_Certificate>& cert
 * then the result for that certificate is successful. If all results are
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2,0) check_chain(const std::vector<X509_Certificate>& cert_path,
+BOTAN_PUBLIC_API(2,0) check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
                       std::chrono::system_clock::time_point ref_time,
                       const std::string& hostname,
                       Usage_Type usage,
@@ -366,8 +366,8 @@ BOTAN_PUBLIC_API(2,0) check_chain(const std::vector<X509_Certificate>& cert_path
 * @return revocation status
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2, 0) check_ocsp(const std::vector<X509_Certificate>& cert_path,
-                                  const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
+BOTAN_PUBLIC_API(2, 0) check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+                                  const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses,
                                   const std::vector<Certificate_Store*>& certstores,
                                   std::chrono::system_clock::time_point ref_time,
                                   std::chrono::seconds max_ocsp_age = std::chrono::seconds::zero());
@@ -382,9 +382,9 @@ BOTAN_PUBLIC_API(2, 0) check_ocsp(const std::vector<X509_Certificate>& cert_path
 * @return revocation status
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<X509_Certificate>& cert_path,
-                                const std::vector<std::optional<X509_CRL>>& crls,
-                                std::chrono::system_clock::time_point ref_time);
+BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+                    const std::vector<std::shared_ptr<const X509_CRL>>& crls,
+                    std::chrono::system_clock::time_point ref_time);
 
 /**
 * Check CRLs for revocation information
@@ -395,7 +395,7 @@ BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<X509_Certificate>& cert_path,
 * @return revocation status
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<X509_Certificate>& cert_path,
+BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
                     const std::vector<Certificate_Store*>& certstores,
                     std::chrono::system_clock::time_point ref_time);
 
@@ -418,7 +418,7 @@ BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<X509_Certificate>& cert_path,
 * @return revocation status
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2, 0) check_ocsp_online(const std::vector<X509_Certificate>& cert_path,
+BOTAN_PUBLIC_API(2, 0) check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
       const std::vector<Certificate_Store*>& trusted_certstores,
       std::chrono::system_clock::time_point ref_time,
       std::chrono::milliseconds timeout,
@@ -440,7 +440,7 @@ BOTAN_PUBLIC_API(2, 0) check_ocsp_online(const std::vector<X509_Certificate>& ce
 * @return revocation status
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2,0) check_crl_online(const std::vector<X509_Certificate>& cert_path,
+BOTAN_PUBLIC_API(2,0) check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
                            const std::vector<Certificate_Store*>& trusted_certstores,
                            Certificate_Store_In_Memory* certstore_to_recv_crls,
                            std::chrono::system_clock::time_point ref_time,
diff --git a/src/scripts/ci/setup_gh_actions.sh b/src/scripts/ci/setup_gh_actions.sh
index 636b7ead1..43007bd79 100755
--- a/src/scripts/ci/setup_gh_actions.sh
+++ b/src/scripts/ci/setup_gh_actions.sh
@@ -56,7 +56,7 @@ if type -p "apt-get"; then
     elif [ "$TARGET" = "coverage" ]; then
         sudo apt-get -qq install g++-8 softhsm2 libtspi-dev lcov python-coverage libboost-all-dev gdb
         pip install --user codecov
-        echo "$HOME/.local/bin" >> "$GITHUB_PATH"
+        echo "$HOME/.local/bin" >> $GITHUB_PATH
 
         git clone --depth 1 --branch runner-changes https://github.com/randombit/boringssl.git
 
@@ -64,7 +64,7 @@ if type -p "apt-get"; then
         sudo chmod g+w /var/lib/softhsm/tokens
 
         softhsm2-util --init-token --free --label test --pin 123456 --so-pin 12345678
-        echo "PKCS11_LIB=/usr/lib/softhsm/libsofthsm2.so" >> "$GITHUB_ENV"
+        echo "PKCS11_LIB=/usr/lib/softhsm/libsofthsm2.so" >> $GITHUB_ENV
 
     elif [ "$TARGET" = "docs" ]; then
         sudo apt-get -qq install doxygen python-docutils python3-sphinx
diff --git a/src/scripts/ci/travis.yml b/src/scripts/ci/travis.yml
index 1337cc95c..46736d0ff 100644
--- a/src/scripts/ci/travis.yml
+++ b/src/scripts/ci/travis.yml
@@ -10,11 +10,6 @@ jobs:
       env:
        - TARGET="shared"
 
-    - name: Linux arm64 (GCC)
-      arch: arm64
-      env:
-       - TARGET="shared"
-
 install:
   - ./src/scripts/ci/setup_travis.sh
 
diff --git a/src/scripts/ci_build.py b/src/scripts/ci_build.py
index f6010c389..03ef0f97c 100755
--- a/src/scripts/ci_build.py
+++ b/src/scripts/ci_build.py
@@ -74,6 +74,12 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin,
     test_prefix = []
     test_cmd = [os.path.join(root_dir, 'botan-test')]
 
+    essential_tests = ['block', 'aead', 'hash', 'stream', 'mac', 'modes', 'kdf',
+                       'hmac_drbg', 'hmac_drbg_unit', 'tls',
+                       'rsa_sign', 'rsa_verify', 'dh_kat',
+                       'ecc_randomized', 'ecdh_kat', 'ecdsa_sign', 'curve25519_scalar',
+                       'cpuid', 'simd_32', 'os_utils', 'util', 'util_dates']
+
     install_prefix = os.path.join(tempfile.gettempdir(), 'botan-install')
 
     flags = ['--prefix=%s' % (install_prefix),
@@ -112,21 +118,13 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin,
         flags += ['--with-coverage-info', '--with-debug-info', '--test-mode']
 
     if target == 'valgrind':
-        flags += ['--with-valgrind']
+        # valgrind in 16.04 has a bug with rdrand handling
+        flags += ['--with-valgrind', '--disable-rdrand']
         test_prefix = ['valgrind', '--error-exitcode=9', '-v', '--leak-check=full', '--show-reachable=yes']
         # valgrind is single threaded anyway
         test_cmd += ['--test-threads=1']
         # valgrind is slow
-        slow_tests = [
-            'cryptobox', 'dh_invalid', 'dh_kat', 'dh_keygen',
-            'dl_group_gen', 'dlies', 'dsa_param', 'ecc_basemul',
-            'ecdsa_verify_wycheproof', 'mce_keygen', 'passhash9',
-            'rsa_encrypt', 'rsa_pss', 'rsa_pss_raw', 'scrypt',
-            'srp6_kat', 'x509_path_bsi', 'xmss_keygen', 'xmss_sign',
-            'pbkdf', 'argon2', 'bcrypt', 'bcrypt_pbkdf', 'compression',
-            'ed25519_sign', 'elgamal_keygen', 'x509_path_rsa_pss']
-
-        test_cmd += ['--skip-tests=%s' % (','.join(slow_tests))]
+        test_cmd += essential_tests
 
     if target == 'fuzzers':
         flags += ['--unsafe-fuzzer-mode']
@@ -197,6 +195,9 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin,
             test_cmd = [os.path.join(root_dir, 'botan-test.exe')] + test_cmd[1:]
             test_prefix = ['wine']
         else:
+            # Build everything but restrict what is run
+            test_cmd += essential_tests
+
             if target == 'cross-arm32':
                 flags += ['--cpu=armv7']
                 cc_bin = 'arm-linux-gnueabihf-g++'
diff --git a/src/scripts/tls_suite_info.py b/src/scripts/tls_suite_info.py
index 77a6b6bed..3e3c40307 100755
--- a/src/scripts/tls_suite_info.py
+++ b/src/scripts/tls_suite_info.py
@@ -176,6 +176,11 @@ def process_command_line(args):
     parser.add_option('--without-cecpq1', action='store_false', dest='with_cecpq1',
                       help='disable CECPQ1 suites')
 
+    parser.add_option('--with-srp-aead', action='store_true', default=False,
+                      help='add SRP AEAD suites')
+    parser.add_option('--without-srp-aead', action='store_false', dest='with_srp_aead',
+                      help='disable SRP AEAD suites')
+
     parser.add_option('--save-download', action='store_true', default=False,
                       help='save downloaded tls-parameters.txt to cwd')
 
@@ -189,12 +194,11 @@ def main(args = None):
     if args is None:
         args = sys.argv
 
-    weak_crypto = ['EXPORT', 'RC2', 'IDEA', 'RC4', '_DES_', 'WITH_NULL', 'GOST', '_anon_']
+    weak_crypto = ['EXPORT', 'RC2', 'IDEA', 'RC4', '_DES_', 'WITH_NULL', 'GOST', '_anon_', '_DSS_']
     static_dh = ['ECDH_ECDSA', 'ECDH_RSA', 'DH_DSS', 'DH_RSA'] # not supported
-    removed_algos = ['_DSS_', 'SRP_', 'SEED', 'CAMELLIA_128_CBC', 'CAMELLIA_256_CBC']
     protocol_goop = ['SCSV', 'KRB5']
     maybe_someday = ['RSA_PSK', 'ECCPWD']
-    not_supported = weak_crypto + static_dh + protocol_goop + maybe_someday + removed_algos
+    not_supported = weak_crypto + static_dh + protocol_goop + maybe_someday
 
     (options, args) = process_command_line(args)
 
@@ -265,6 +269,19 @@ def main(args = None):
         define_custom_ciphersuite('CECPQ1_ECDSA_WITH_AES_256_OCB_SHA256', 'FFCD')
         #define_custom_ciphersuite('CECPQ1_PSK_WITH_AES_256_OCB_SHA256', 'FFCE')
 
+    if options.with_srp_aead:
+        # SRP using GCM or OCB - Botan extension
+        define_custom_ciphersuite('SRP_SHA_WITH_AES_256_GCM_SHA384', 'FFA0')
+        define_custom_ciphersuite('SRP_SHA_RSA_WITH_AES_256_GCM_SHA384', 'FFA1')
+        define_custom_ciphersuite('SRP_SHA_DSS_WITH_AES_256_GCM_SHA384', 'FFA2')
+        define_custom_ciphersuite('SRP_SHA_ECDSA_WITH_AES_256_GCM_SHA384', 'FFA3')
+
+        if options.with_ocb:
+            define_custom_ciphersuite('SRP_SHA_WITH_AES_256_OCB_SHA256', 'FFA4')
+            define_custom_ciphersuite('SRP_SHA_RSA_WITH_AES_256_OCB_SHA256', 'FFA5')
+            define_custom_ciphersuite('SRP_SHA_DSS_WITH_AES_256_OCB_SHA256', 'FFA6')
+            define_custom_ciphersuite('SRP_SHA_ECDSA_WITH_AES_256_OCB_SHA256', 'FFA7')
+
     suite_info = ''
 
     def header():


Test patch:
diff --git a/src/tests/test_certstor.cpp b/src/tests/test_certstor.cpp
index 681b323ca..6359944f1 100644
--- a/src/tests/test_certstor.cpp
+++ b/src/tests/test_certstor.cpp
@@ -88,8 +88,8 @@ Test::Result test_certstor_sqlite3_insert_find_remove_test(const std::vector<Cer
                }
             else
                {
-               const bool found = std::any_of(rev_certs.begin(), rev_certs.end(),
-                                              [&](const Botan::X509_Certificate& c) { return c.fingerprint() == cert.fingerprint(); });
+               const bool found = std::any_of(rev_certs.begin(),
+               rev_certs.end(), [&](std::shared_ptr<const Botan::X509_Certificate> c) { return c->fingerprint() == cert.fingerprint(); });
 
                result.test_eq("Got wrong/no certificate", found, true);
                }
@@ -247,7 +247,7 @@ Test::Result test_certstor_sqlite3_find_all_certs_test(const std::vector<Certifi
             std::stringstream a_ss;
             a_ss << a.certificate.subject_dn();
             std::stringstream res_ss;
-            res_ss << res_vec.at(0).subject_dn();
+            res_ss << res_vec.at(0)->subject_dn();
             result.test_eq("Check subject " + a_ss.str(), a_ss.str(), res_ss.str());
             }
          }
@@ -271,10 +271,10 @@ Test::Result test_certstor_sqlite3_find_all_certs_test(const std::vector<Certifi
          std::stringstream cert_ss;
          cert_ss << same_dn_1.subject_dn();
          std::stringstream res_ss;
-         res_ss << res_vec.at(0).subject_dn();
+         res_ss << res_vec.at(0)->subject_dn();
          result.test_eq("Check subject " + cert_ss.str(), cert_ss.str(), res_ss.str());
          res_ss.str("");
-         res_ss << res_vec.at(1).subject_dn();
+         res_ss << res_vec.at(1)->subject_dn();
          result.test_eq("Check subject " + cert_ss.str(), cert_ss.str(), res_ss.str());
          }
       }
@@ -349,8 +349,8 @@ Test::Result test_certstor_load_allcert()
       Botan::X509_Certificate root_cert(Test::data_dir() + "/x509/x509test/root.pem");
       Botan::X509_Certificate valid_cert(Test::data_dir() + "/x509/x509test/ValidCert.pem");
       std::vector<uint8_t> key_id;
-      result.confirm("Root cert found", store.find_cert(root_cert.subject_dn(), key_id) != std::nullopt);
-      result.confirm("ValidCert found", store.find_cert(valid_cert.subject_dn(), key_id) != std::nullopt);
+      result.confirm("Root cert found", store.find_cert(root_cert.subject_dn(), key_id) != nullptr);
+      result.confirm("ValidCert found", store.find_cert(valid_cert.subject_dn(), key_id) != nullptr);
       return result;
       }
    catch(std::exception& e)
diff --git a/src/tests/test_certstor_flatfile.cpp b/src/tests/test_certstor_flatfile.cpp
index 3c8177653..213c6d390 100644
--- a/src/tests/test_certstor_flatfile.cpp
+++ b/src/tests/test_certstor_flatfile.cpp
@@ -61,7 +61,7 @@ Test::Result find_certificate_by_pubkey_sha1()
       auto cert = certstore.find_cert_by_pubkey_sha1(get_key_id());
       result.end_timer();
 
-      if(result.test_not_nullopt("found certificate", cert))
+      if(result.test_not_null("found certificate", cert.get()))
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_int_eq("exactly one CN", cns.size(), 1);
@@ -95,7 +95,7 @@ Test::Result find_cert_by_subject_dn()
       auto cert = certstore.find_cert(dn, std::vector<uint8_t>());
       result.end_timer();
 
-      if(result.test_not_nullopt("found certificate", cert))
+      if(result.test_not_null("found certificate", cert.get()))
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_int_eq("exactly one CN", cns.size(), 1);
@@ -124,7 +124,7 @@ Test::Result find_cert_by_utf8_subject_dn()
 
       result.end_timer();
 
-      if(result.test_not_nullopt("found certificate", cert))
+      if(result.test_not_null("found certificate", cert.get()))
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
@@ -152,7 +152,7 @@ Test::Result find_cert_by_subject_dn_and_key_id()
       auto cert = certstore.find_cert(dn, get_key_id());
       result.end_timer();
 
-      if(result.test_not_nullopt("found certificate", cert))
+      if(result.test_not_null("found certificate", cert.get()))
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_int_eq("exactly one CN", cns.size(), 1);
@@ -183,7 +183,7 @@ Test::Result find_certs_by_subject_dn_and_key_id()
       if(result.confirm("result not empty", !certs.empty()) &&
             result.test_eq("exactly one certificate", certs.size(), 1))
          {
-         auto cns = certs.front().subject_dn().get_attribute("CN");
+         auto cns = certs.front()->subject_dn().get_attribute("CN");
          result.test_int_eq("exactly one CN", cns.size(), 1);
          result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
diff --git a/src/tests/test_certstor_system.cpp b/src/tests/test_certstor_system.cpp
index b0cd80b03..ff254f11e 100644
--- a/src/tests/test_certstor_system.cpp
+++ b/src/tests/test_certstor_system.cpp
@@ -29,7 +29,7 @@ Test::Result find_certificate_by_pubkey_sha1(Botan::Certificate_Store& certstore
       auto cert = certstore.find_cert_by_pubkey_sha1(get_key_id());
       result.end_timer();
 
-      if(result.test_not_nullopt("found certificate", cert))
+      if(result.test_not_null("found certificate", cert.get()))
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
@@ -61,7 +61,7 @@ Test::Result find_cert_by_subject_dn(Botan::Certificate_Store& certstore)
       auto cert = certstore.find_cert(dn, std::vector<uint8_t>());
       result.end_timer();
 
-      if(result.test_not_nullopt("found certificate", cert))
+      if(result.test_not_null("found certificate", cert.get()))
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
@@ -94,7 +94,7 @@ Test::Result find_cert_by_utf8_subject_dn(Botan::Certificate_Store& certstore)
       auto cert = certstore.find_cert(dn, std::vector<uint8_t>());
       result.end_timer();
 
-      if(result.test_not_nullopt("found certificate", cert))
+      if(result.test_not_null("found certificate", cert.get()))
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
@@ -122,7 +122,7 @@ Test::Result find_cert_by_subject_dn_and_key_id(Botan::Certificate_Store& certst
       auto cert = certstore.find_cert(dn, get_key_id());
       result.end_timer();
 
-      if(result.test_not_nullopt("found certificate", cert))
+      if(result.test_not_null("found certificate", cert.get()))
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
@@ -152,7 +152,7 @@ Test::Result find_certs_by_subject_dn_and_key_id(Botan::Certificate_Store& certs
       if(result.confirm("result not empty", !certs.empty()) &&
             result.test_eq("exactly one certificate", certs.size(), 1))
          {
-         auto cns = certs.front().subject_dn().get_attribute("CN");
+         auto cns = certs.front()->subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
          result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
@@ -189,7 +189,7 @@ Test::Result find_all_certs_by_subject_dn(Botan::Certificate_Store& certstore)
 
       if(result.confirm("result not empty", !certs.empty()))
          {
-         auto cns = certs.front().subject_dn().get_attribute("CN");
+         auto cns = certs.front()->subject_dn().get_attribute("CN");
          result.test_gte("at least one CN", cns.size(), size_t(1));
          result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
@@ -279,9 +279,9 @@ Test::Result certificate_matching_with_dn_normalization(Botan::Certificate_Store
       result.end_timer();
 
       if(result.confirm("find_all_certs did find the skewed DN", !certs.empty()) &&
-         result.confirm("find_cert did find the skewed DN", cert.has_value()))
+            result.confirm("find_cert did find the skewed DN", cert != nullptr))
          {
-         result.test_eq("it is the correct cert", certs.front().subject_dn().get_first_attribute("CN"), "DST Root CA X3");
+         result.test_eq("it is the correct cert", certs.front()->subject_dn().get_first_attribute("CN"), "DST Root CA X3");
          result.test_eq("it is the correct cert", cert->subject_dn().get_first_attribute("CN"), "DST Root CA X3");
          }
       }
diff --git a/src/tests/test_compression.cpp b/src/tests/test_compression.cpp
index 7f503d538..fdc2ddd35 100644
--- a/src/tests/test_compression.cpp
+++ b/src/tests/test_compression.cpp
@@ -66,8 +66,6 @@ class Compression_Tests final : public Test
                {
                Test::Result result(algo + " compression");
 
-               result.start_timer();
-
                std::unique_ptr<Botan::Compression_Algorithm> c(Botan::make_compressor(algo));
                std::unique_ptr<Botan::Decompression_Algorithm> d(Botan::make_decompressor(algo));
 
@@ -110,8 +108,6 @@ class Compression_Tests final : public Test
                result.test_lt("Zeros compresses much better than text", c1_z / 8, c1_t);
                result.test_lt("Text compresses much better than random", c1_t / 2, c1_r);
 
-               result.end_timer();
-
                results.emplace_back(result);
                }
             catch(std::exception& e)
diff --git a/src/tests/test_ocsp.cpp b/src/tests/test_ocsp.cpp
index 5d6c98b47..443f79aba 100644
--- a/src/tests/test_ocsp.cpp
+++ b/src/tests/test_ocsp.cpp
@@ -21,14 +21,14 @@ namespace Botan_Tests {
 class OCSP_Tests final : public Test
    {
    private:
-      Botan::X509_Certificate load_test_X509_cert(const std::string& path)
+      std::shared_ptr<const Botan::X509_Certificate> load_test_X509_cert(const std::string& path)
          {
-         return Botan::X509_Certificate(Test::data_file(path));
+         return std::make_shared<const Botan::X509_Certificate>(Test::data_file(path));
          }
 
-      Botan::OCSP::Response load_test_OCSP_resp(const std::string& path)
+      std::shared_ptr<const Botan::OCSP::Response> load_test_OCSP_resp(const std::string& path)
          {
-         return Botan::OCSP::Response(Test::read_binary_data_file(path));
+         return std::make_shared<const Botan::OCSP::Response>(Test::read_binary_data_file(path));
          }
 
       Test::Result test_response_parsing()
@@ -131,13 +131,13 @@ class OCSP_Tests final : public Test
          {
          Test::Result result("OCSP request check with next_update w/o max_age");
 
-         auto ee = load_test_X509_cert("x509/ocsp/randombit.pem");
-         auto ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
-         auto trust_root = load_test_X509_cert("x509/ocsp/geotrust.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("x509/ocsp/randombit.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
+         std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("x509/ocsp/geotrust.pem");
 
-         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
+         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
 
-         auto ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
+         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
 
          Botan::Certificate_Store_In_Memory certstore;
          certstore.add_certificate(trust_root);
@@ -169,13 +169,13 @@ class OCSP_Tests final : public Test
          {
          Test::Result result("OCSP request check with next_update with max_age");
 
-         auto ee = load_test_X509_cert("x509/ocsp/randombit.pem");
-         auto ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
-         auto trust_root = load_test_X509_cert("x509/ocsp/geotrust.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("x509/ocsp/randombit.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
+         std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("x509/ocsp/geotrust.pem");
 
-         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
+         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
 
-         auto ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
+         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
 
          Botan::Certificate_Store_In_Memory certstore;
          certstore.add_certificate(trust_root);
@@ -210,13 +210,13 @@ class OCSP_Tests final : public Test
          {
          Test::Result result("OCSP request check w/o next_update with max_age");
 
-         auto ee = load_test_X509_cert("x509/ocsp/patrickschmidt.pem");
-         auto ca = load_test_X509_cert("x509/ocsp/bdrive_encryption.pem");
-         auto trust_root = load_test_X509_cert("x509/ocsp/bdrive_root.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("x509/ocsp/patrickschmidt.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("x509/ocsp/bdrive_encryption.pem");
+         std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("x509/ocsp/bdrive_root.pem");
 
-         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
+         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
 
-         auto ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
+         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
 
          Botan::Certificate_Store_In_Memory certstore;
          certstore.add_certificate(trust_root);
@@ -249,13 +249,13 @@ class OCSP_Tests final : public Test
          {
          Test::Result result("OCSP request check w/o next_update w/o max_age");
 
-         auto ee = load_test_X509_cert("x509/ocsp/patrickschmidt.pem");
-         auto ca = load_test_X509_cert("x509/ocsp/bdrive_encryption.pem");
-         auto trust_root = load_test_X509_cert("x509/ocsp/bdrive_root.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("x509/ocsp/patrickschmidt.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("x509/ocsp/bdrive_encryption.pem");
+         std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("x509/ocsp/bdrive_root.pem");
 
-         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
+         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
 
-         auto ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
+         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
 
          Botan::Certificate_Store_In_Memory certstore;
          certstore.add_certificate(trust_root);
@@ -285,13 +285,14 @@ class OCSP_Tests final : public Test
          {
          Test::Result result("OCSP request softfail check");
 
-         auto ee = load_test_X509_cert("x509/ocsp/randombit.pem");
-         auto ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
-         auto trust_root = load_test_X509_cert("x509/ocsp/geotrust.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("x509/ocsp/randombit.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
+         std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("x509/ocsp/geotrust.pem");
 
-         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
+         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
 
-         Botan::OCSP::Response ocsp(Botan::Certificate_Status_Code::OCSP_NO_REVOCATION_URL);
+         std::shared_ptr<const Botan::OCSP::Response> ocsp =
+            std::make_shared<const Botan::OCSP::Response>(Botan::Certificate_Status_Code::OCSP_NO_REVOCATION_URL);
 
          Botan::Certificate_Store_In_Memory certstore;
          certstore.add_certificate(trust_root);
@@ -317,10 +318,10 @@ class OCSP_Tests final : public Test
          Test::Result result("OCSP online check");
 
          // Expired end-entity certificate:
-         auto ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
-         auto trust_root = load_test_X509_cert("x509/ocsp/identrust.pem");
+         std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
+         std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("x509/ocsp/identrust.pem");
 
-         const std::vector<Botan::X509_Certificate> cert_path = { ca, trust_root };
+         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ca, trust_root };
 
          Botan::Certificate_Store_In_Memory certstore;
          certstore.add_certificate(trust_root);
diff --git a/src/tests/test_tls.cpp b/src/tests/test_tls.cpp
index 69cbf2095..454388d0a 100644
--- a/src/tests/test_tls.cpp
+++ b/src/tests/test_tls.cpp
@@ -50,6 +50,7 @@ class TLS_Session_Tests final : public Test
                                      std::vector<Botan::X509_Certificate>(),
                                      std::vector<uint8_t>(),
                                      Botan::TLS::Server_Information("server"),
+                                     "SRP username",
                                      0x0000);
 
          const std::string pem = session.PEM_encode();
@@ -72,6 +73,7 @@ class TLS_Session_Tests final : public Test
                         ctext2.data(), 12, expected_hdr.data(), 12);
 
          Botan::TLS::Session dsession = Botan::TLS::Session::decrypt(ctext1.data(), ctext1.size(), key);
+         result.test_eq("Decrypted session access works", dsession.srp_identifier(), "SRP username");
 
          Fixed_Output_RNG frng1("00112233445566778899AABBCCDDEEFF802802802802802802802802");
          const std::vector<uint8_t> ctextf1 = session.encrypt(key, frng1);
@@ -464,6 +466,7 @@ class Test_TLS_Algo_Strings : public Test
             Botan::TLS::Kex_Algo::DH,
             Botan::TLS::Kex_Algo::ECDH,
             Botan::TLS::Kex_Algo::CECPQ1,
+            Botan::TLS::Kex_Algo::SRP_SHA,
             Botan::TLS::Kex_Algo::PSK,
             Botan::TLS::Kex_Algo::DHE_PSK,
             Botan::TLS::Kex_Algo::ECDHE_PSK
diff --git a/src/tests/test_tls_stream_integration.cpp b/src/tests/test_tls_stream_integration.cpp
index 084d2c08a..f11f134f3 100644
--- a/src/tests/test_tls_stream_integration.cpp
+++ b/src/tests/test_tls_stream_integration.cpp
@@ -292,7 +292,7 @@ class Client : public Side
    {
       static void accept_all(
          const std::vector<Botan::X509_Certificate>&,
-         const std::vector<std::optional<Botan::OCSP::Response>>&,
+         const std::vector<std::shared_ptr<const Botan::OCSP::Response>>&,
          const std::vector<Botan::Certificate_Store*>&, Botan::Usage_Type,
          const std::string&, const Botan::TLS::Policy&) {}
 
diff --git a/src/tests/test_x509_path.cpp b/src/tests/test_x509_path.cpp
index bd113a6f4..0b07231e1 100644
--- a/src/tests/test_x509_path.cpp
+++ b/src/tests/test_x509_path.cpp
@@ -412,41 +412,38 @@ std::vector<Test::Result> PSS_Path_Validation_Tests::run()
          continue;
          }
 
-      std::optional<Botan::X509_CRL> crl;
-      std::optional<Botan::X509_Certificate> end;
-      std::optional<Botan::X509_Certificate> root;
+      std::shared_ptr<Botan::X509_CRL> crl;
+      std::shared_ptr<Botan::X509_Certificate> end;
+      std::shared_ptr<Botan::X509_Certificate> root;
       Botan::Certificate_Store_In_Memory store;
-      std::optional<Botan::PKCS10_Request> csr;
-
-      auto validation_time = Botan::calendar_point(
-         std::atoi((validation_times_iter++)->second.c_str()),
-         0, 0, 0, 0, 0).to_std_timepoint();
-
+      std::shared_ptr<Botan::PKCS10_Request> csr;
+      auto validation_time = Botan::calendar_point(std::atoi((validation_times_iter++)->second.c_str()), 0, 0, 0, 0,
+                             0).to_std_timepoint();
       for(auto const& file : all_files)
          {
          if(file.find("end.crt") != std::string::npos)
             {
-            end = Botan::X509_Certificate(file);
+            end.reset(new Botan::X509_Certificate(file));
             }
          else if(file.find("root.crt") != std::string::npos)
             {
-            root = Botan::X509_Certificate(file);
+            root.reset(new Botan::X509_Certificate(file));
             store.add_certificate(*root);
             }
          else if(file.find(".crl") != std::string::npos)
             {
-            crl = Botan::X509_CRL(file);
+            crl.reset(new Botan::X509_CRL(file));
             }
          else if(file.find(".csr") != std::string::npos)
             {
-            csr = Botan::PKCS10_Request(file);
+            csr.reset(new Botan::PKCS10_Request(file));
             }
          }
 
       if(end && crl && root)    // CRL tests
          {
-         const std::vector<Botan::X509_Certificate> cert_path = { *end, *root };
-         const std::vector<std::optional<Botan::X509_CRL>> crls = { crl };
+         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { end, root };
+         const std::vector<std::shared_ptr<const Botan::X509_CRL>> crls = { crl };
          auto crl_status = Botan::PKIX::check_crl(cert_path, crls,
                            validation_time);   // alternatively we could just call crl.check_signature( root_pubkey )
 
@@ -826,9 +823,9 @@ class Path_Validation_With_OCSP_Tests final : public Test
          return Botan::X509_Certificate(Test::data_file(path));
          }
 
-      std::optional<Botan::OCSP::Response> load_test_OCSP_resp(const std::string& path)
+      std::shared_ptr<const Botan::OCSP::Response> load_test_OCSP_resp(const std::string& path)
          {
-         return Botan::OCSP::Response(Test::read_binary_data_file(path));
+         return std::make_shared<const Botan::OCSP::Response>(Test::read_binary_data_file(path));
          }
 
       Test::Result validate_with_ocsp_with_next_update_without_max_age()
@@ -845,7 +842,7 @@ class Path_Validation_With_OCSP_Tests final : public Test
 
          const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::optional<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
+         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
 
          auto check_path = [&](const std::chrono::system_clock::time_point valid_time,
                                const Botan::Certificate_Status_Code expected)
@@ -885,7 +882,7 @@ class Path_Validation_With_OCSP_Tests final : public Test
 
          const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         auto ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
+         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
 
          auto check_path = [&](const std::chrono::system_clock::time_point valid_time,
                                const Botan::Certificate_Status_Code expected)
@@ -925,7 +922,7 @@ class Path_Validation_With_OCSP_Tests final : public Test
 
          const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         auto ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
+         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
 
          auto check_path = [&](const std::chrono::system_clock::time_point valid_time,
                                const Botan::Certificate_Status_Code expected)
@@ -964,7 +961,7 @@ class Path_Validation_With_OCSP_Tests final : public Test
 
          const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         auto ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
+         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
 
          auto check_path = [&](const std::chrono::system_clock::time_point valid_time,
                                const Botan::Certificate_Status_Code expected)
@@ -1071,7 +1068,8 @@ class XMSS_Path_Validation_Tests final : public Test
       Botan::Path_Validation_Restrictions restrictions;
       auto self_signed = Botan::X509_Certificate(Test::data_dir() + "/x509/xmss/" + file);
 
-      auto cert_path = std::vector<Botan::X509_Certificate>{self_signed};
+      auto cert_path = std::vector<std::shared_ptr<const Botan::X509_Certificate>>{
+				            std::make_shared<const Botan::X509_Certificate>(self_signed)};
       auto valid_time = Botan::calendar_point(2019, 10, 8, 4, 45, 0).to_std_timepoint();
 
       auto status = Botan::PKIX::overall_status(Botan::PKIX::check_chain(cert_path, valid_time,
diff --git a/src/tests/tests.h b/src/tests/tests.h
index 159c61400..694779ac5 100644
--- a/src/tests/tests.h
+++ b/src/tests/tests.h
@@ -21,7 +21,6 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
-#include <optional>
 
 namespace Botan {
 
@@ -272,15 +271,6 @@ class Test
                   return test_success(what + " was not null");
                }
 
-            template<typename T>
-            bool test_not_nullopt(const std::string& what, std::optional<T> val)
-               {
-               if(val == std::nullopt)
-                  return test_failure(what + " was nullopt");
-               else
-                  return test_success(what + " was not nullopt");
-               }
-
             bool test_eq(const std::string& what, const char* produced, const char* expected);
 
             bool test_is_nonempty(const std::string& what_is_it, const std::string& to_examine);
diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp
index 9b2322e2a..8ecd305e9 100644
--- a/src/tests/unit_tls.cpp
+++ b/src/tests/unit_tls.cpp
@@ -28,6 +28,10 @@
    #include <botan/x509_ca.h>
    #include <botan/x509self.h>
 
+   #if defined(BOTAN_HAS_SRP6)
+      #include <botan/srp6.h>
+   #endif
+
    #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
       #include <botan/tls_session_manager_sqlite.h>
    #endif
@@ -233,6 +237,88 @@ create_creds(Botan::RandomNumberGenerator& rng,
    return cmt;
    }
 
+#if defined(BOTAN_HAS_SRP6)
+Botan::Credentials_Manager*
+create_srp6_creds(Botan::RandomNumberGenerator& rng)
+   {
+   class Credentials_Manager_SRP6 : public Botan::Credentials_Manager
+      {
+      public:
+         Credentials_Manager_SRP6(Botan::RandomNumberGenerator& rng)
+            {
+            m_group_id = "modp/srp/1024";
+            m_username = "srp6_username";
+            m_password = "srp6_password";
+            m_salt.resize(16);
+            rng.randomize(m_salt.data(), m_salt.size());
+
+            m_verifier = Botan::generate_srp6_verifier(m_username,
+                                                       m_password,
+                                                       m_salt,
+                                                       m_group_id,
+                                                       "SHA-1");
+            }
+
+         bool attempt_srp(const std::string& /*type*/,
+                          const std::string& /*context*/) override
+            {
+            return true;
+            }
+
+         std::string srp_identifier(const std::string& /*type*/,
+                                    const std::string& /*context*/) override
+            {
+            return m_username;
+            }
+
+         std::string srp_password(const std::string& /*type*/,
+                                  const std::string& /*context*/,
+                                  const std::string& identifier) override
+            {
+            if(identifier == m_username)
+               return m_password;
+            return "";
+            }
+
+         bool srp_verifier(const std::string& /*type*/,
+                           const std::string& /*context*/,
+                           const std::string& identifier,
+                           std::string& group_name,
+                           Botan::BigInt& verifier,
+                           std::vector<uint8_t>& salt,
+                           bool generate_fake_on_unknown) override
+            {
+            // FIXME test generate_fake_on_unknown behavior
+            if(identifier == m_username)
+               {
+               group_name = m_group_id;
+               verifier = m_verifier;
+               salt = m_salt;
+               return true;
+               }
+            else if(generate_fake_on_unknown)
+               {
+               group_name = m_group_id;
+               verifier = m_verifier + 1;
+               salt = m_salt;
+               return true;
+               }
+            else
+               return false;
+            }
+
+         std::string m_username;
+         std::string m_password;
+         std::vector<uint8_t> m_salt;
+         std::string m_group_id;
+         Botan::BigInt m_verifier;
+      };
+
+   return new Credentials_Manager_SRP6(rng);
+   }
+#endif
+
+
 class TLS_Handshake_Test final
    {
    public:
@@ -697,7 +783,7 @@ class TLS_Unit_Tests final : public Test
          policy.set("allow_dtls10", "true");
          policy.set("allow_dtls12", "true");
 
-         if(kex_policy.find("RSA") != std::string::npos)
+         if(kex_policy.find("RSA") != std::string::npos || kex_policy.find("SRP") != std::string::npos)
             {
             policy.set("signature_methods", "IMPLICIT");
             }
@@ -800,17 +886,33 @@ class TLS_Unit_Tests final : public Test
             test_all_versions("AES-128 RSA", results, *client_ses, *server_ses, *creds, "RSA", "AES-128", "SHA-256 SHA-1", etm_setting);
             test_all_versions("AES-128 ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "AES-128", "SHA-256 SHA-1", etm_setting);
 
+#if defined(BOTAN_HAS_CAMELLIA) && defined(BOTAN_HAS_TLS_CBC)
+            test_all_versions("Camellia-128 RSA", results, *client_ses, *server_ses,
+                              *creds, "RSA", "Camellia-128", "SHA-256 SHA-1", etm_setting);
+            test_all_versions("Camellia-256 RSA SHA-2", results, *client_ses, *server_ses,
+                              *creds, "RSA", "Camellia-256", "SHA-256 SHA-384 SHA-1", etm_setting);
+#endif
+
 #if defined(BOTAN_HAS_DES)
             test_all_versions("3DES RSA", results, *client_ses, *server_ses, *creds, "RSA", "3DES", "SHA-1", etm_setting);
             test_all_versions("3DES ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "3DES", "SHA-1", etm_setting);
 #endif
 
+#if defined(BOTAN_HAS_SEED)
+            test_all_versions("SEED RSA", results, *client_ses, *server_ses, *creds, "RSA", "SEED", "SHA-1", etm_setting);
+#endif
+
             server_ses->remove_all();
             }
          client_ses->remove_all();
 
          test_modern_versions("AES-128 DH", results, *client_ses, *server_ses, *creds, "DH", "AES-128", "SHA-256");
 
+#if defined(BOTAN_HAS_SRP6)
+         std::unique_ptr<Botan::Credentials_Manager> srp6_creds(create_srp6_creds(rng));
+         test_all_versions("SRP6 AES", results, *client_ses, *server_ses, *srp6_creds, "SRP_SHA", "AES-128", "SHA-1", "false");
+#endif
+
 #endif
 
          Botan::TLS::Strict_Policy strict_policy;
@@ -837,12 +939,15 @@ class TLS_Unit_Tests final : public Test
 
          client_ses->remove_all();
 
+#if defined(BOTAN_HAS_CAMELLIA) && defined(BOTAN_HAS_TLS_CBC)
+         test_modern_versions("Camellia-256 SHA-2", results, *client_ses, *server_ses, *creds, "RSA", "Camellia-256", "SHA-384 SHA-256");
+#endif
 #if defined(BOTAN_HAS_CAMELLIA) && defined(BOTAN_HAS_AEAD_GCM)
          test_modern_versions("Camellia-128/GCM ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "Camellia-128/GCM", "AEAD");
 #endif
 
 #if defined(BOTAN_HAS_ARIA)
-         test_modern_versions("ARIA/GCM ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "ARIA-128/GCM", "AEAD");
+         test_modern_versions("ARIA ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "ARIA-128/GCM", "AEAD");
 #endif
 
 #if defined(BOTAN_HAS_CECPQ1)