Repository: randombit/botan
Pull request #2484 (2020-11-10 23:24:38)

Remove outer shared_ptr from Certificate in certstore interface
Since 2.4.0 X509_Certificate and X509_CRL have been internally
shared so an other shared_ptr is just overhead and API complexity.
Use std::optional for APIs where the object was optional.


Patch:
diff --git a/src/bogo_shim/bogo_shim.cpp b/src/bogo_shim/bogo_shim.cpp
index 4a043c91d..350623854 100644
--- a/src/bogo_shim/bogo_shim.cpp
+++ b/src/bogo_shim/bogo_shim.cpp
@@ -1318,7 +1318,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::shared_ptr<const Botan::OCSP::Response>>& /*ocsp_responses*/,
+                                 const std::vector<std::optional<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 3ef7195dd..eee97a4c0 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::shared_ptr<const Botan::OCSP::Response>>& ocsp,
+         const std::vector<std::optional<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/x509.cpp b/src/cli/x509.cpp
index f5691b8d5..64e66366e 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 abbd2c72f..2adc6b350 100644
--- a/src/fuzzer/tls_client.cpp
+++ b/src/fuzzer/tls_client.cpp
@@ -73,7 +73,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::shared_ptr<const Botan::OCSP::Response>>& ocsp_responses,
+         const std::vector<std::optional<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 d933153a7..f251a9df1 100644
--- a/src/fuzzer/tls_server.cpp
+++ b/src/fuzzer/tls_server.cpp
@@ -172,7 +172,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::shared_ptr<const Botan::OCSP::Response>>& ocsp_responses,
+         const std::vector<std::optional<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 24286f10d..bc2d47cbf 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::shared_ptr<const OCSP::Response>>& ocsp_responses,
+               const std::vector<std::optional<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.cpp b/src/lib/tls/tls_callbacks.cpp
index 0dd758b75..4b43359eb 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::shared_ptr<const OCSP::Response>>& ocsp_responses,
+   const std::vector<std::optional<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 795663e22..5c81e2f93 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 <functional>
+#include <optional>
 
 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::shared_ptr<const OCSP::Response>>& ocsp_responses,
+          const std::vector<std::optional<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_client.cpp b/src/lib/tls/tls_client.cpp
index 7b668d48a..117dfcabe 100644
--- a/src/lib/tls/tls_client.cpp
+++ b/src/lib/tls/tls_client.cpp
@@ -571,11 +571,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::shared_ptr<const OCSP::Response>> ocsp;
+            std::vector<std::optional<OCSP::Response>> ocsp;
             if(state.server_cert_status() != nullptr)
                {
                try {
-                   ocsp.push_back(std::make_shared<OCSP::Response>(state.server_cert_status()->response()));
+                  ocsp.push_back(OCSP::Response(state.server_cert_status()->response()));
                }
                catch(Decoding_Error&)
                   {
diff --git a/src/lib/x509/certstor.cpp b/src/lib/x509/certstor.cpp
index a066f208d..9bec24f64 100644
--- a/src/lib/x509/certstor.cpp
+++ b/src/lib/x509/certstor.cpp
@@ -16,38 +16,29 @@ namespace Botan {
 
 Certificate_Store::~Certificate_Store() {}
 
-std::shared_ptr<const X509_Certificate>
+std::optional<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 nullptr;  // certificate not found
+      return std::nullopt;
       }
 
    // `count` might be greater than 1, but we'll just select the first match
    return certs.front();
    }
 
-std::shared_ptr<const X509_CRL> Certificate_Store::find_crl_for(const X509_Certificate&) const
+std::optional<X509_CRL> Certificate_Store::find_crl_for(const X509_Certificate&) const
    {
-   return {};
+   return std::nullopt;
    }
 
 void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert)
    {
    for(const auto& c : m_certs)
-      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)
+      if(c == cert)
          return;
 
    m_certs.push_back(cert);
@@ -57,11 +48,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::shared_ptr<const X509_Certificate>
+std::optional<X509_Certificate>
 Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn,
                                        const std::vector<uint8_t>& key_id) const
    {
@@ -70,43 +61,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 nullptr;
+   return std::nullopt;
    }
 
-std::vector<std::shared_ptr<const X509_Certificate>> Certificate_Store_In_Memory::find_all_certs(
+std::vector<X509_Certificate> Certificate_Store_In_Memory::find_all_certs(
       const X509_DN& subject_dn,
       const std::vector<uint8_t>& key_id) const
    {
-   std::vector<std::shared_ptr<const X509_Certificate>> matches;
+   std::vector<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::shared_ptr<const X509_Certificate>
+std::optional<X509_Certificate>
 Certificate_Store_In_Memory::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
    {
    if(key_hash.size() != 20)
@@ -115,15 +106,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 nullptr;
+   return std::nullopt;
    }
 
-std::shared_ptr<const X509_Certificate>
+std::optional<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)
@@ -132,30 +123,24 @@ 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 nullptr;
+   return std::nullopt;
    }
 
 void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl)
    {
-   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();
+   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;
          }
@@ -165,7 +150,7 @@ void Certificate_Store_In_Memory::add_crl(std::shared_ptr<const X509_CRL> crl)
    m_crls.push_back(crl);
    }
 
-std::shared_ptr<const X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const
+std::optional<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();
 
@@ -174,13 +159,13 @@ std::shared_ptr<const X509_CRL> Certificate_Store_In_Memory::find_crl_for(const
       // 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;
       }
 
@@ -214,7 +199,8 @@ Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir)
             {
             try
                {
-               m_certs.push_back(std::make_shared<X509_Certificate>(src));
+               X509_Certificate cert(src);
+               m_certs.push_back(cert);
                }
             catch(std::exception&)
                {
diff --git a/src/lib/x509/certstor.h b/src/lib/x509/certstor.h
index 6901589d2..0752e908f 100644
--- a/src/lib/x509/certstor.h
+++ b/src/lib/x509/certstor.h
@@ -10,6 +10,7 @@
 
 #include <botan/x509cert.h>
 #include <botan/x509_crl.h>
+#include <optional>
 
 namespace Botan {
 
@@ -25,18 +26,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 nullptr otherwise
+      * @return a matching certificate or nullopt otherwise
       * If more than one certificate in the certificate store matches, then
       * a single value is selected arbitrarily.
       */
-      virtual std::shared_ptr<const X509_Certificate>
+      virtual std::optional<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<std::shared_ptr<const X509_Certificate>> find_all_certs(
+      virtual std::vector<X509_Certificate> find_all_certs(
          const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const = 0;
 
 
@@ -44,26 +45,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 nullptr otherwise
+      * @return a matching certificate or nullopt otherwise
       */
-      virtual std::shared_ptr<const X509_Certificate>
+      virtual std::optional<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 nullptr otherwise
+      * @return a matching certificate or nullopt otherwise
       */
-      virtual std::shared_ptr<const X509_Certificate>
+      virtual std::optional<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 nullptr otherwise
+      * @return the CRL for subject or nullopt otherwise
       */
-      virtual std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const;
+      virtual std::optional<X509_CRL> find_crl_for(const X509_Certificate& subject) const;
 
       /**
       * @return whether the certificate is known
@@ -71,7 +72,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()) != nullptr;
+         return find_cert(cert.subject_dn(), cert.subject_key_id()).has_value();
          }
 
       // remove this (used by TLS::Server)
@@ -106,24 +107,12 @@ 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
       */
@@ -133,7 +122,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::shared_ptr<const X509_Certificate> find_cert(
+      std::optional<X509_Certificate> find_cert(
          const X509_DN& subject_dn,
          const std::vector<uint8_t>& key_id) const override;
 
@@ -141,23 +130,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<std::shared_ptr<const X509_Certificate>> find_all_certs(
+      std::vector<X509_Certificate> find_all_certs(
          const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
-      std::shared_ptr<const X509_Certificate>
+      std::optional<X509_Certificate>
          find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
-      std::shared_ptr<const X509_Certificate>
+      std::optional<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::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::optional<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<std::shared_ptr<const X509_Certificate>> m_certs;
-      std::vector<std::shared_ptr<const X509_CRL>> m_crls;
+      std::vector<X509_Certificate> m_certs;
+      std::vector<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 9804759b9..74837cd1e 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))
       {
-      std::shared_ptr<const X509_Certificate> cert = std::make_shared<const X509_Certificate>(der.data(), der.size());
+      X509_Certificate cert(der);
 
       /*
       * 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<std::shared_ptr<const X509_Certificate>> Flatfile_Certificate_Store::find_all_certs(
+std::vector<X509_Certificate> Flatfile_Certificate_Store::find_all_certs(
          const X509_DN& subject_dn,
          const std::vector<uint8_t>& key_id) const
    {
-   std::vector<std::shared_ptr<const X509_Certificate>> found_certs;
+   std::vector<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<std::shared_ptr<const X509_Certificate>> Flatfile_Certificate_Store:
    return found_certs;
    }
 
-std::shared_ptr<const X509_Certificate>
+std::optional<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 nullptr;
+   return std::nullopt;
    }
 
-std::shared_ptr<const X509_Certificate>
+std::optional<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 nullptr;
+   return std::nullopt;
    }
 
-std::shared_ptr<const X509_CRL> Flatfile_Certificate_Store::find_crl_for(const X509_Certificate& subject) const
+std::optional<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 1608aaa11..fba14382a 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<std::shared_ptr<const X509_Certificate>> find_all_certs(
+      std::vector<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::shared_ptr<const X509_Certificate>
+      std::optional<X509_Certificate>
       find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
-      std::shared_ptr<const X509_Certificate>
+      std::optional<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::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::optional<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<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;
+      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;
    };
 }
 
diff --git a/src/lib/x509/certstor_sql/certstor_sql.cpp b/src/lib/x509/certstor_sql/certstor_sql.cpp
index ab4b8e64a..deab7abdd 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::shared_ptr<const X509_Certificate>
+std::optional<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 std::make_shared<X509_Certificate>(std::vector<uint8_t>(blob.first, blob.first + blob.second));
+      return X509_Certificate(blob.first, blob.second);
       }
 
-   return std::shared_ptr<const X509_Certificate>();
+   return std::optional<X509_Certificate>();
    }
 
-std::vector<std::shared_ptr<const X509_Certificate>>
+std::vector<X509_Certificate>
 Certificate_Store_In_SQL::find_all_certs(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const
    {
-   std::vector<std::shared_ptr<const X509_Certificate>> certs;
+   std::vector<X509_Certificate> certs;
 
    std::shared_ptr<SQL_Database::Statement> stmt;
 
@@ -95,30 +95,29 @@ Certificate_Store_In_SQL::find_all_certs(const X509_DN& subject_dn, const std::v
       stmt->bind(2, key_id);
       }
 
-   std::shared_ptr<const X509_Certificate> cert;
+   std::optional<X509_Certificate> cert;
    while(stmt->step())
       {
       auto blob = stmt->get_blob(0);
-      certs.push_back(std::make_shared<X509_Certificate>(
-            std::vector<uint8_t>(blob.first,blob.first + blob.second)));
+      certs.push_back(X509_Certificate(blob.first, blob.second));
       }
 
    return certs;
    }
 
-std::shared_ptr<const X509_Certificate>
+std::optional<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::shared_ptr<const X509_Certificate>
+std::optional<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::shared_ptr<const X509_CRL>
+std::optional<X509_CRL>
 Certificate_Store_In_SQL::find_crl_for(const X509_Certificate& subject) const
    {
    auto all_crls = generate_crls();
@@ -126,10 +125,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 std::shared_ptr<X509_CRL>(new X509_CRL(crl));
+         return crl;
       }
 
-   return std::shared_ptr<X509_CRL>();
+   return std::optional<X509_CRL>();
    }
 
 std::vector<X509_DN> Certificate_Store_In_SQL::all_subjects() const
@@ -209,7 +208,7 @@ std::shared_ptr<const Private_Key> Certificate_Store_In_SQL::find_key(const X509
    return key;
    }
 
-std::vector<std::shared_ptr<const X509_Certificate>>
+std::vector<X509_Certificate>
 Certificate_Store_In_SQL::find_certs_for_key(const Private_Key& key) const
    {
    auto fpr = key.fingerprint_private("SHA-256");
@@ -217,12 +216,11 @@ Certificate_Store_In_SQL::find_certs_for_key(const Private_Key& key) const
 
    stmt->bind(1,fpr);
 
-   std::vector<std::shared_ptr<const X509_Certificate>> certs;
+   std::vector<X509_Certificate> certs;
    while(stmt->step())
       {
       auto blob = stmt->get_blob(0);
-      certs.push_back(std::make_shared<X509_Certificate>(
-            std::vector<uint8_t>(blob.first,blob.first + blob.second)));
+      certs.push_back(X509_Certificate(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 fd80eb191..05bb2c561 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::shared_ptr<const X509_Certificate>
+      std::optional<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<std::shared_ptr<const X509_Certificate>> find_all_certs(
+      std::vector<X509_Certificate> find_all_certs(
          const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
-      std::shared_ptr<const X509_Certificate>
+      std::optional<X509_Certificate>
          find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
-      std::shared_ptr<const X509_Certificate>
+      std::optional<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<std::shared_ptr<const X509_Certificate>>
+      std::vector<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::shared_ptr<const X509_CRL>
+      std::optional<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 0fca1a975..234979cab 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::shared_ptr<const X509_Certificate>
+std::optional<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<std::shared_ptr<const X509_Certificate>>
+std::vector<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::shared_ptr<const X509_Certificate>
+std::optional<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::shared_ptr<const X509_Certificate>
+std::optional<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::shared_ptr<const X509_CRL>
+std::optional<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 3a0fc6153..a2be72738 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::shared_ptr<const X509_Certificate>
+      std::optional<X509_Certificate>
          find_cert(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
-      std::vector<std::shared_ptr<const X509_Certificate>>
+      std::vector<X509_Certificate>
          find_all_certs(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override;
 
-      std::shared_ptr<const X509_Certificate>
+      std::optional<X509_Certificate>
          find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
-      std::shared_ptr<const X509_Certificate>
+      std::optional<X509_Certificate>
          find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const override;
 
-      std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::optional<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 ee66092af..662ebd0ab 100644
--- a/src/lib/x509/certstor_system_macos/certstor_macos.cpp
+++ b/src/lib/x509/certstor_system_macos/certstor_macos.cpp
@@ -291,24 +291,27 @@ class Certificate_Store_MacOS_Impl
          check_notnull(m_keychains, "initialize keychain array");
          }
 
-      std::shared_ptr<const X509_Certificate> findOne(Query query) const
+      std::optional<X509_Certificate> findOne(Query query) const
          {
          query.addParameter(kSecMatchLimit, kSecMatchLimitOne);
 
          scoped_CFType<CFTypeRef> result(nullptr);
          search(std::move(query), &result.get());
 
-         return (result) ? readCertificate(result.get()) : nullptr;
+         if(result)
+            return readCertificate(result.get());
+         else
+            return std::nullopt;
          }
 
-      std::vector<std::shared_ptr<const X509_Certificate>> findAll(Query query) const
+      std::vector<X509_Certificate> findAll(Query query) const
          {
          query.addParameter(kSecMatchLimit, kSecMatchLimitAll);
 
          scoped_CFType<CFArrayRef> result(nullptr);
          search(std::move(query), (CFTypeRef*)&result.get());
 
-         std::vector<std::shared_ptr<const X509_Certificate>> output;
+         std::vector<X509_Certificate> output;
 
          if(result)
             {
@@ -344,7 +347,7 @@ class Certificate_Store_MacOS_Impl
       /**
        * Convert a CFTypeRef object into a Botan::X509_Certificate
        */
-      std::shared_ptr<const X509_Certificate> readCertificate(CFTypeRef object) const
+      X509_Certificate readCertificate(CFTypeRef object) const
          {
          if(!object || CFGetTypeID(object) != SecCertificateGetTypeID())
             {
@@ -360,7 +363,7 @@ class Certificate_Store_MacOS_Impl
          const auto length = CFDataGetLength(derData.get());
 
          DataSource_Memory ds(data, length);
-         return std::make_shared<Botan::X509_Certificate>(ds);
+         return X509_Certificate(ds);
          }
 
       CFArrayRef keychains() const { return m_keychains.get(); }
@@ -398,7 +401,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::shared_ptr<const X509_Certificate> cert)
+                  [](const std::optional<X509_Certificate> cert)
       {
       return cert->subject_dn();
       });
@@ -406,7 +409,7 @@ std::vector<X509_DN> Certificate_Store_MacOS::all_subjects() const
    return output;
    }
 
-std::shared_ptr<const X509_Certificate>
+std::optional<X509_Certificate>
 Certificate_Store_MacOS::find_cert(const X509_DN& subject_dn,
                                    const std::vector<uint8_t>& key_id) const
    {
@@ -421,7 +424,7 @@ Certificate_Store_MacOS::find_cert(const X509_DN& subject_dn,
    return m_impl->findOne(std::move(query));
    }
 
-std::vector<std::shared_ptr<const X509_Certificate>> Certificate_Store_MacOS::find_all_certs(
+std::vector<X509_Certificate> Certificate_Store_MacOS::find_all_certs(
          const X509_DN& subject_dn,
          const std::vector<uint8_t>& key_id) const
    {
@@ -436,7 +439,7 @@ std::vector<std::shared_ptr<const X509_Certificate>> Certificate_Store_MacOS::fi
    return m_impl->findAll(std::move(query));
    }
 
-std::shared_ptr<const X509_Certificate>
+std::optional<X509_Certificate>
 Certificate_Store_MacOS::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
    {
    if(key_hash.size() != 20)
@@ -450,14 +453,14 @@ Certificate_Store_MacOS::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& ke
    return m_impl->findOne(std::move(query));
    }
 
-std::shared_ptr<const X509_Certificate>
+std::optional<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::shared_ptr<const X509_CRL> Certificate_Store_MacOS::find_crl_for(const X509_Certificate& subject) const
+std::optional<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 e7416e631..3c983dc2e 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::shared_ptr<const X509_Certificate> find_cert(
+      std::optional<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<std::shared_ptr<const X509_Certificate>> find_all_certs(
+      std::vector<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::shared_ptr<const X509_Certificate>
+      std::optional<X509_Certificate>
       find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
       /**
        * @throws Botan::Not_Implemented
        */
-      std::shared_ptr<const X509_Certificate>
+      std::optional<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::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::optional<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 ba202b48c..d112047db 100644
--- a/src/lib/x509/certstor_system_windows/certstor_windows.cpp
+++ b/src/lib/x509/certstor_system_windows/certstor_windows.cpp
@@ -23,8 +23,6 @@
 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"};
 
 /**
@@ -119,11 +117,12 @@ HCERTSTORE open_cert_store(const char* cert_store_name)
    return store;
    }
 
-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> 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 certs;
+   std::vector<X509_Certificate> certs;
    for(const auto store_name : cert_store_names)
       {
       Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
@@ -133,7 +132,7 @@ Cert_Vector search_cert_stores(const _CRYPTOAPI_BLOB& blob, const DWORD& find_ty
                                    WINCRYPT_UNUSED_PARAM, find_type,
                                    &blob, cert_context.get())))
          {
-         auto cert = std::make_shared<X509_Certificate>(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
+         X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
          if(filter(certs, cert))
             {
             if(return_on_first_found)
@@ -148,15 +147,15 @@ Cert_Vector search_cert_stores(const _CRYPTOAPI_BLOB& blob, const DWORD& find_ty
    return certs;
    }
 
-bool already_contains_certificate(const Cert_Vector& certs, Cert_Pointer cert)
+bool already_contains_certificate(const std::vector<X509_Certificate>& certs, X509_Certificate cert)
    {
-   return std::any_of(certs.begin(), certs.end(), [&](std::shared_ptr<const Botan::X509_Certificate> c)
+   return std::any_of(certs.begin(), certs.end(), [&](const X509_Certificate& c)
       {
-      return *c == *cert;
+      return c == cert;
       });
    }
 
-Cert_Vector find_cert_by_dn_and_key_id(const Botan::X509_DN& subject_dn,
+std::vector<X509_Certificate> 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)
    {
@@ -179,9 +178,9 @@ Cert_Vector find_cert_by_dn_and_key_id(const Botan::X509_DN& subject_dn,
       blob.pbData = const_cast<BYTE*>(key_id.data());
       }
 
-   auto filter = [&](const Cert_Vector& certs, Cert_Pointer cert)
+   auto filter = [&](const std::vector<X509_Certificate>& certs, const X509_Certificate& 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);
@@ -210,21 +209,26 @@ std::vector<X509_DN> Certificate_Store_Windows::all_subjects() const
    return subject_dns;
    }
 
-Cert_Pointer Certificate_Store_Windows::find_cert(const Botan::X509_DN& subject_dn,
-      const std::vector<uint8_t>& key_id) const
+std::optional<X509_Certificate>
+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);
-   return certs.empty() ? nullptr : certs.front();
+   if(certs.empty())
+      return std::nullopt;
+   else
+      return certs.front();
    }
 
-Cert_Vector Certificate_Store_Windows::find_all_certs(
+std::vector<X509_Certificate> 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);
    }
 
-Cert_Pointer Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
+std::optional<X509_Certificate>
+Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
    {
    if(key_hash.size() != 20)
       {
@@ -235,23 +239,27 @@ Cert_Pointer Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vect
    blob.cbData = static_cast<DWORD>(key_hash.size());
    blob.pbData = const_cast<BYTE*>(key_hash.data());
 
-   auto filter = [](const Cert_Vector&, Cert_Pointer) { return true; };
+   auto filter = [&](const std::vector<X509_Certificate>&, const X509_Certificate&) { return true; };
 
    const auto certs = search_cert_stores(blob, CERT_FIND_KEY_IDENTIFIER, filter, true);
-   return certs.empty() ? nullptr : certs.front();
+   if(certs.empty())
+      return std::nullopt;
+   else
+      return certs.front();
    }
 
-Cert_Pointer Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256(
+std::optional<X509_Certificate>
+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::shared_ptr<const X509_CRL> Certificate_Store_Windows::find_crl_for(const X509_Certificate& subject) const
+std::optional<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 {};
+   return std::nullopt;
    }
 }
diff --git a/src/lib/x509/certstor_system_windows/certstor_windows.h b/src/lib/x509/certstor_system_windows/certstor_windows.h
index f47e718c8..890920ac9 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::shared_ptr<const X509_Certificate> find_cert(
+      std::optional<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<std::shared_ptr<const X509_Certificate>> find_all_certs(
+      std::vector<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::shared_ptr<const X509_Certificate>
+      std::optional<X509_Certificate>
       find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override;
 
       /**
        * @throws Botan::Not_Implemented
        */
-      std::shared_ptr<const X509_Certificate>
+      std::optional<X509_Certificate>
       find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const override;
 
       /**
        * Not Yet Implemented
        * @return nullptr;
        */
-      std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
+      std::optional<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 f4d934526..69d216ad0 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<std::shared_ptr<const X509_Certificate>>& ee_cert_path) const
+                                                  const std::vector<X509_Certificate>& ee_cert_path) const
    {
    if (m_responses.empty())
       return m_dummy_response_status;
 
-   std::shared_ptr<const X509_Certificate> signing_cert;
+   std::optional<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 = std::make_shared<const X509_Certificate>(m_certs[i]);
+            signing_cert = m_certs[i];
             break;
             }
 
          if(m_key_hash.size() > 0 && m_certs[i].subject_public_key_bitstring_sha1() == m_key_hash)
             {
-            signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]);
+            signing_cert = m_certs[i];
             break;
             }
          }
diff --git a/src/lib/x509/ocsp.h b/src/lib/x509/ocsp.h
index 552245644..139bd6c77 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<std::shared_ptr<const X509_Certificate>>& cert_path = {}) const;
+                                              const std::vector<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 221c67c25..64c746308 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<std::shared_ptr<const X509_Certificate>>& cert_path,
+            const std::vector<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 18fcaea44..e000b2f11 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<std::shared_ptr<const X509_Certificate>>&,
+      const std::vector<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<std::shared_ptr<const X509_Certificate>>& cert_path,
+      const std::vector<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<std::shared_ptr<const X509_Certificate>>& /*cert_path*/,
+   const std::vector<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 bdb8ebd20..58fd0b35a 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<std::shared_ptr<const X509_Certificate>>& cert_path,
+            const std::vector<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<std::shared_ptr<const X509_Certificate>>& cert_path,
+            const std::vector<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<std::shared_ptr<const X509_Certificate>>&,
+            const std::vector<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 b5cdc27c2..840e8f3bf 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<std::shared_ptr<const X509_Certificate>>& cert_path,
+PKIX::check_chain(const std::vector<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<std::shared_ptr<const X509_Certificate>>& ce
 
    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<std::shared_ptr<const X509_Certificate>>& ce
 
       const bool at_self_signed_root = (i == cert_path.size() - 1);
 
-      const std::shared_ptr<const X509_Certificate>& subject = cert_path[i];
+      const std::optional<X509_Certificate>& subject = cert_path[i];
 
-      const std::shared_ptr<const X509_Certificate>& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)];
+      const std::optional<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<std::shared_ptr<const X509_Certificate>>& ce
    for(size_t i = cert_path.size() - 1; i > 0 ; --i)
       {
       std::set<Certificate_Status_Code>& status = cert_status.at(i);
-      const std::shared_ptr<const X509_Certificate>& subject = cert_path[i];
+      const std::optional<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<std::shared_ptr<const X509_Certificate>>& ce
    }
 
 CertificatePathStatusCodes
-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,
+PKIX::check_ocsp(const std::vector<X509_Certificate>& cert_path,
+                 const std::vector<std::optional<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<std::shared_ptr<const X509_Certificate>>& cer
       {
       std::set<Certificate_Status_Code>& status = cert_status.at(i);
 
-      std::shared_ptr<const X509_Certificate> subject = cert_path.at(i);
-      std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1);
+      std::optional<X509_Certificate> subject = cert_path.at(i);
+      std::optional<X509_Certificate> ca = cert_path.at(i+1);
 
-      if(i < ocsp_responses.size() && (ocsp_responses.at(i) != nullptr)
+      if(i < ocsp_responses.size() && (ocsp_responses.at(i) != std::nullopt)
             && (ocsp_responses.at(i)->status() == OCSP::Response_Status_Code::Successful))
          {
          try
@@ -262,8 +262,8 @@ PKIX::check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cer
    }
 
 CertificatePathStatusCodes
-PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
-                const std::vector<std::shared_ptr<const X509_CRL>>& crls,
+PKIX::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)
    {
    if(cert_path.empty())
@@ -276,10 +276,10 @@ PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert
       {
       std::set<Certificate_Status_Code>& status = cert_status.at(i);
 
-      if(i < crls.size() && crls.at(i))
+      if(i < crls.size() && crls[i].has_value())
          {
-         std::shared_ptr<const X509_Certificate> subject = cert_path.at(i);
-         std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1);
+         std::optional<X509_Certificate> subject = cert_path.at(i);
+         std::optional<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<std::shared_ptr<const X509_Certificate>>& cert
    }
 
 CertificatePathStatusCodes
-PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+PKIX::check_crl(const std::vector<X509_Certificate>& cert_path,
                 const std::vector<Certificate_Store*>& certstores,
                 std::chrono::system_clock::time_point ref_time)
    {
@@ -342,14 +342,13 @@ PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert
    if(certstores.empty())
       throw Invalid_Argument("PKIX::check_crl certstores empty");
 
-   std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size());
+   std::vector<std::optional<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;
          }
@@ -361,7 +360,7 @@ PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert
 #if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)
 
 CertificatePathStatusCodes
-PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+PKIX::check_ocsp_online(const std::vector<X509_Certificate>& cert_path,
                         const std::vector<Certificate_Store*>& trusted_certstores,
                         std::chrono::system_clock::time_point ref_time,
                         std::chrono::milliseconds timeout,
@@ -371,7 +370,7 @@ PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate
    if(cert_path.empty())
       throw Invalid_Argument("PKIX::check_ocsp_online cert_path empty");
 
-   std::vector<std::future<std::shared_ptr<const OCSP::Response>>> ocsp_response_futures;
+   std::vector<std::future<std::optional<OCSP::Response>>> ocsp_response_futures;
 
    size_t to_ocsp = 1;
 
@@ -382,18 +381,18 @@ PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate
 
    for(size_t i = 0; i < to_ocsp; ++i)
       {
-      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);
+      const std::optional<X509_Certificate>& subject = cert_path.at(i);
+      const std::optional<X509_Certificate>& issuer = cert_path.at(i+1);
 
       if(subject->ocsp_responder() == "")
          {
-         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);
+         ocsp_response_futures.emplace_back(std::async(std::launch::deferred, [&]() -> std::optional<OCSP::Response> {
+                  return OCSP::Response(Certificate_Status_Code::OCSP_NO_REVOCATION_URL);
                   }));
          }
       else
          {
-         ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const OCSP::Response> {
+         ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]() -> std::optional<OCSP::Response> {
                OCSP::Request req(*issuer, BigInt::decode(subject->serial_number()));
 
                HTTP::Response http;
@@ -410,15 +409,15 @@ PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate
                   // log e.what() ?
                   }
                if (http.status_code() != 200)
-                  return std::make_shared<const OCSP::Response>(Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE);
+                  return OCSP::Response(Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE);
                // Check the MIME type?
 
-               return std::make_shared<const OCSP::Response>(http.body());
+               return OCSP::Response(http.body());
                }));
          }
       }
 
-   std::vector<std::shared_ptr<const OCSP::Response>> ocsp_responses;
+   std::vector<std::optional<OCSP::Response>> ocsp_responses;
 
    for(size_t i = 0; i < ocsp_response_futures.size(); ++i)
       {
@@ -429,7 +428,7 @@ PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate
    }
 
 CertificatePathStatusCodes
-PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+PKIX::check_crl_online(const std::vector<X509_Certificate>& cert_path,
                        const std::vector<Certificate_Store*>& certstores,
                        Certificate_Store_In_Memory* crl_store,
                        std::chrono::system_clock::time_point ref_time,
@@ -440,16 +439,16 @@ PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>
    if(certstores.empty())
       throw Invalid_Argument("PKIX::check_crl_online certstores empty");
 
-   std::vector<std::future<std::shared_ptr<const X509_CRL>>> future_crls;
-   std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size());
+   std::vector<std::future<std::optional<X509_CRL>>> future_crls;
+   std::vector<std::optional<X509_CRL>> crls(cert_path.size());
 
    for(size_t i = 0; i != cert_path.size(); ++i)
       {
-      const std::shared_ptr<const X509_Certificate>& cert = cert_path.at(i);
+      const std::optional<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])
+         if(crls[i].has_value())
             break;
          }
 
@@ -462,24 +461,24 @@ PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>
          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::shared_ptr<const X509_CRL>>());
+         future_crls.emplace_back(std::future<std::optional<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::shared_ptr<const X509_CRL> {
+         future_crls.emplace_back(std::async(std::launch::deferred, [&]() -> std::optional<X509_CRL> {
                throw Not_Implemented("No CRL distribution point for this certificate");
                }));
          }
       else
          {
-         future_crls.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const X509_CRL> {
+         future_crls.emplace_back(std::async(std::launch::async, [&]() -> std::optional<X509_CRL> {
                auto http = HTTP::GET_sync(cert->crl_distribution_point(),
                                           /*redirects*/ 1, timeout);
 
                http.throw_unless_ok();
                // check the mime type?
-               return std::make_shared<const X509_CRL>(http.body());
+               return X509_CRL(http.body());
                }));
          }
       }
@@ -509,8 +508,8 @@ PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>
          if(crl_status[i].count(Certificate_Status_Code::VALID_CRL_CHECKED))
             {
             // better be non-null, we supposedly validated it
-            BOTAN_ASSERT_NONNULL(crls[i]);
-            crl_store->add_crl(crls[i]);
+            BOTAN_ASSERT_NOMSG(crls[i].has_value());
+            crl_store->add_crl(*crls[i]);
             }
          }
       }
@@ -521,12 +520,12 @@ PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>
 #endif
 
 Certificate_Status_Code
-PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+PKIX::build_certificate_path(std::vector<X509_Certificate>& cert_path,
                              const std::vector<Certificate_Store*>& trusted_certstores,
-                             const std::shared_ptr<const X509_Certificate>& end_entity,
-                             const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra)
+                             const X509_Certificate& end_entity,
+                             const std::vector<X509_Certificate>& end_entity_extra)
    {
-   if(end_entity->is_self_signed())
+   if(end_entity.is_self_signed())
       {
       return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST;
       }
@@ -540,7 +539,7 @@ PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>
    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)
@@ -549,11 +548,11 @@ PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>
    // 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::shared_ptr<const X509_Certificate> issuer;
+      std::optional<X509_Certificate> issuer;
       bool trusted_issuer = false;
 
       for(Certificate_Store* store : trusted_certstores)
@@ -583,7 +582,7 @@ PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>
          }
 
       certs_seen.insert(fprint);
-      cert_path.push_back(issuer);
+      cert_path.push_back(*issuer);
 
       if(issuer->is_self_signed())
          {
@@ -605,7 +604,7 @@ PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>
 namespace
 {
 // <certificate, trusted?>
-using cert_maybe_trusted = std::pair<std::shared_ptr<const X509_Certificate>,bool>;
+using cert_maybe_trusted = std::pair<std::optional<X509_Certificate>,bool>;
 }
 
 /**
@@ -626,10 +625,10 @@ using cert_maybe_trusted = std::pair<std::shared_ptr<const X509_Certificate>,boo
  *
  */
 Certificate_Status_Code
-PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const X509_Certificate>>>& cert_paths_out,
+PKIX::build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& cert_paths_out,
                                   const std::vector<Certificate_Store*>& trusted_certstores,
-                                  const std::shared_ptr<const X509_Certificate>& end_entity,
-                                  const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra)
+                                  const std::optional<X509_Certificate>& end_entity,
+                                  const std::vector<X509_Certificate>& end_entity_extra)
    {
    if(!cert_paths_out.empty())
       {
@@ -662,26 +661,26 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const
 
    // 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<std::shared_ptr<const X509_Certificate>> path_so_far;
+   std::vector<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(stack.back().first == nullptr)
+      if(last == std::nullopt)
          {
          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
          {
-         std::shared_ptr<const X509_Certificate> last = stack.back().first;
-         bool trusted = stack.back().second;
+         const bool trusted = stack.back().second;
          stack.pop_back();
 
          // certificate already seen?
@@ -700,7 +699,7 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const
             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;
                }
@@ -716,7 +715,7 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const
          const std::vector<uint8_t> auth_key_id = last->authority_key_id();
 
          // search for trusted issuers
-         std::vector<std::shared_ptr<const X509_Certificate>> trusted_issuers;
+         std::vector<X509_Certificate> trusted_issuers;
          for(Certificate_Store* store : trusted_certstores)
             {
             auto new_issuers = store->find_all_certs(issuer_dn, auth_key_id);
@@ -724,7 +723,7 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const
             }
 
          // search the supplemental certs
-         std::vector<std::shared_ptr<const X509_Certificate>> misc_issuers =
+         std::vector<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
@@ -735,11 +734,11 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const
             }
 
          // 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::shared_ptr<const X509_Certificate>(nullptr),false});
+         stack.push_back({std::optional<X509_Certificate>(), false});
 
          for(const auto& trusted_cert : trusted_issuers)
             {
@@ -851,21 +850,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::shared_ptr<const OCSP::Response>>& ocsp_resp)
+   const std::vector<std::optional<OCSP::Response>>& ocsp_resp)
    {
    if(end_certs.empty())
       {
       throw Invalid_Argument("x509_path_validate called with no subjects");
       }
 
-   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;
+   X509_Certificate end_entity = end_certs[0];
+   std::vector<X509_Certificate> end_entity_extra;
    for(size_t i = 1; i < end_certs.size(); ++i)
       {
-      end_entity_extra.push_back(std::make_shared<const X509_Certificate>(end_certs[i]));
+      end_entity_extra.push_back(end_certs[i]);
       }
 
-   std::vector<std::vector<std::shared_ptr<const X509_Certificate>>> cert_paths;
+   std::vector<std::vector<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
@@ -930,7 +929,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::shared_ptr<const OCSP::Response>>& ocsp_resp)
+   const std::vector<std::optional<OCSP::Response>>& ocsp_resp)
    {
    std::vector<X509_Certificate> certs;
    certs.push_back(end_cert);
@@ -945,7 +944,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::shared_ptr<const OCSP::Response>>& ocsp_resp)
+   const std::vector<std::optional<OCSP::Response>>& ocsp_resp)
    {
    std::vector<Certificate_Store*> trusted_roots;
    trusted_roots.push_back(const_cast<Certificate_Store*>(&store));
@@ -961,7 +960,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::shared_ptr<const OCSP::Response>>& ocsp_resp)
+   const std::vector<std::optional<OCSP::Response>>& ocsp_resp)
    {
    std::vector<X509_Certificate> certs;
    certs.push_back(end_cert);
@@ -1012,7 +1011,7 @@ CertificatePathStatusCodes find_warnings(const CertificatePathStatusCodes& all_s
 }
 
 Path_Validation_Result::Path_Validation_Result(CertificatePathStatusCodes status,
-                                               std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain) :
+                                               std::vector<X509_Certificate>&& cert_chain) :
    m_all_status(status),
    m_warnings(find_warnings(m_all_status)),
    m_cert_path(cert_chain),
@@ -1027,14 +1026,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 c8575fd32..9aee14973 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<std::shared_ptr<const X509_Certificate>>& cert_path() const { return m_cert_path; }
+      const std::vector<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<std::shared_ptr<const X509_Certificate>>&& cert_chain);
+                             std::vector<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<std::shared_ptr<const X509_Certificate>> m_cert_path;
+      std::vector<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::shared_ptr<const OCSP::Response>>& ocsp_resp = {});
+   const std::vector<std::optional<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::shared_ptr<const OCSP::Response>>& ocsp_resp = {});
+   const std::vector<std::optional<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::shared_ptr<const OCSP::Response>>& ocsp_resp = {});
+   const std::vector<std::optional<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::shared_ptr<const OCSP::Response>>& ocsp_resp = {});
+   const std::vector<std::optional<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<std::shared_ptr<const X509_Certificate>>>& cert_paths,
+build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& cert_paths,
                             const std::vector<Certificate_Store*>& trusted_certstores,
-                            const std::shared_ptr<const X509_Certificate>& end_entity,
-                            const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra);
+                            const std::optional<X509_Certificate>& end_entity,
+                            const std::vector<X509_Certificate>& end_entity_extra);
 
 
 /**
@@ -324,10 +324,10 @@ build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const X509_C
 * @return result of the path building operation (OK or error)
 */
 Certificate_Status_Code
-BOTAN_PUBLIC_API(2,0) build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path_out,
+BOTAN_PUBLIC_API(2,0) build_certificate_path(std::vector<X509_Certificate>& cert_path_out,
                                  const std::vector<Certificate_Store*>& trusted_certstores,
-                                 const std::shared_ptr<const X509_Certificate>& end_entity,
-                                 const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra);
+                                 const X509_Certificate& end_entity,
+                                 const std::vector<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<std::shared_ptr<const X
 * then the result for that certificate is successful. If all results are
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2,0) check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+BOTAN_PUBLIC_API(2,0) check_chain(const std::vector<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<std::shared_ptr<const X509_C
 * @return revocation status
 */
 CertificatePathStatusCodes
-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,
+BOTAN_PUBLIC_API(2, 0) check_ocsp(const std::vector<X509_Certificate>& cert_path,
+                                  const std::vector<std::optional<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<std::shared_ptr<const X509_C
 * @return revocation status
 */
 CertificatePathStatusCodes
-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);
+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);
 
 /**
 * Check CRLs for revocation information
@@ -395,7 +395,7 @@ BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<std::shared_ptr<const X509_Cer
 * @return revocation status
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<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<std::shared_ptr<const X509_Cer
 * @return revocation status
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2, 0) check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+BOTAN_PUBLIC_API(2, 0) check_ocsp_online(const std::vector<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<std::shared_ptr<const
 * @return revocation status
 */
 CertificatePathStatusCodes
-BOTAN_PUBLIC_API(2,0) check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
+BOTAN_PUBLIC_API(2,0) check_crl_online(const std::vector<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,


Test patch:
diff --git a/src/tests/test_certstor.cpp b/src/tests/test_certstor.cpp
index 6359944f1..681b323ca 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(), [&](std::shared_ptr<const Botan::X509_Certificate> c) { return c->fingerprint() == cert.fingerprint(); });
+               const bool found = std::any_of(rev_certs.begin(), rev_certs.end(),
+                                              [&](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) != nullptr);
-      result.confirm("ValidCert found", store.find_cert(valid_cert.subject_dn(), key_id) != nullptr);
+      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);
       return result;
       }
    catch(std::exception& e)
diff --git a/src/tests/test_certstor_flatfile.cpp b/src/tests/test_certstor_flatfile.cpp
index 213c6d390..3c8177653 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_null("found certificate", cert.get()))
+      if(result.test_not_nullopt("found certificate", cert))
          {
          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_null("found certificate", cert.get()))
+      if(result.test_not_nullopt("found certificate", cert))
          {
          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_null("found certificate", cert.get()))
+      if(result.test_not_nullopt("found certificate", cert))
          {
          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_null("found certificate", cert.get()))
+      if(result.test_not_nullopt("found certificate", cert))
          {
          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 ff254f11e..b0cd80b03 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_null("found certificate", cert.get()))
+      if(result.test_not_nullopt("found certificate", cert))
          {
          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_null("found certificate", cert.get()))
+      if(result.test_not_nullopt("found certificate", cert))
          {
          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_null("found certificate", cert.get()))
+      if(result.test_not_nullopt("found certificate", cert))
          {
          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_null("found certificate", cert.get()))
+      if(result.test_not_nullopt("found certificate", cert))
          {
          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 != nullptr))
+         result.confirm("find_cert did find the skewed DN", cert.has_value()))
          {
-         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_ocsp.cpp b/src/tests/test_ocsp.cpp
index 443f79aba..5d6c98b47 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:
-      std::shared_ptr<const Botan::X509_Certificate> load_test_X509_cert(const std::string& path)
+      Botan::X509_Certificate load_test_X509_cert(const std::string& path)
          {
-         return std::make_shared<const Botan::X509_Certificate>(Test::data_file(path));
+         return Botan::X509_Certificate(Test::data_file(path));
          }
 
-      std::shared_ptr<const Botan::OCSP::Response> load_test_OCSP_resp(const std::string& path)
+      Botan::OCSP::Response load_test_OCSP_resp(const std::string& path)
          {
-         return std::make_shared<const Botan::OCSP::Response>(Test::read_binary_data_file(path));
+         return 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");
 
-         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");
+         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");
 
-         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
+         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
+         auto 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");
 
-         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");
+         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");
 
-         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
+         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
+         auto 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");
 
-         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");
+         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");
 
-         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
+         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
+         auto 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");
 
-         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");
+         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");
 
-         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
+         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
+         auto ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
 
          Botan::Certificate_Store_In_Memory certstore;
          certstore.add_certificate(trust_root);
@@ -285,14 +285,13 @@ class OCSP_Tests final : public Test
          {
          Test::Result result("OCSP request softfail check");
 
-         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");
+         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");
 
-         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
+         const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::shared_ptr<const Botan::OCSP::Response> ocsp =
-            std::make_shared<const Botan::OCSP::Response>(Botan::Certificate_Status_Code::OCSP_NO_REVOCATION_URL);
+         Botan::OCSP::Response ocsp(Botan::Certificate_Status_Code::OCSP_NO_REVOCATION_URL);
 
          Botan::Certificate_Store_In_Memory certstore;
          certstore.add_certificate(trust_root);
@@ -318,10 +317,10 @@ class OCSP_Tests final : public Test
          Test::Result result("OCSP online check");
 
          // Expired end-entity certificate:
-         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");
+         auto ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
+         auto trust_root = load_test_X509_cert("x509/ocsp/identrust.pem");
 
-         const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ca, trust_root };
+         const std::vector<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_stream_integration.cpp b/src/tests/test_tls_stream_integration.cpp
index f11f134f3..084d2c08a 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::shared_ptr<const Botan::OCSP::Response>>&,
+         const std::vector<std::optional<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 0b07231e1..bd113a6f4 100644
--- a/src/tests/test_x509_path.cpp
+++ b/src/tests/test_x509_path.cpp
@@ -412,38 +412,41 @@ std::vector<Test::Result> PSS_Path_Validation_Tests::run()
          continue;
          }
 
-      std::shared_ptr<Botan::X509_CRL> crl;
-      std::shared_ptr<Botan::X509_Certificate> end;
-      std::shared_ptr<Botan::X509_Certificate> root;
+      std::optional<Botan::X509_CRL> crl;
+      std::optional<Botan::X509_Certificate> end;
+      std::optional<Botan::X509_Certificate> root;
       Botan::Certificate_Store_In_Memory store;
-      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();
+      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();
+
       for(auto const& file : all_files)
          {
          if(file.find("end.crt") != std::string::npos)
             {
-            end.reset(new Botan::X509_Certificate(file));
+            end = Botan::X509_Certificate(file);
             }
          else if(file.find("root.crt") != std::string::npos)
             {
-            root.reset(new Botan::X509_Certificate(file));
+            root = Botan::X509_Certificate(file);
             store.add_certificate(*root);
             }
          else if(file.find(".crl") != std::string::npos)
             {
-            crl.reset(new Botan::X509_CRL(file));
+            crl = Botan::X509_CRL(file);
             }
          else if(file.find(".csr") != std::string::npos)
             {
-            csr.reset(new Botan::PKCS10_Request(file));
+            csr = Botan::PKCS10_Request(file);
             }
          }
 
       if(end && crl && root)    // CRL tests
          {
-         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 };
+         const std::vector<Botan::X509_Certificate> cert_path = { *end, *root };
+         const std::vector<std::optional<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 )
 
@@ -823,9 +826,9 @@ class Path_Validation_With_OCSP_Tests final : public Test
          return Botan::X509_Certificate(Test::data_file(path));
          }
 
-      std::shared_ptr<const Botan::OCSP::Response> load_test_OCSP_resp(const std::string& path)
+      std::optional<Botan::OCSP::Response> load_test_OCSP_resp(const std::string& path)
          {
-         return std::make_shared<const Botan::OCSP::Response>(Test::read_binary_data_file(path));
+         return Botan::OCSP::Response(Test::read_binary_data_file(path));
          }
 
       Test::Result validate_with_ocsp_with_next_update_without_max_age()
@@ -842,7 +845,7 @@ class Path_Validation_With_OCSP_Tests final : public Test
 
          const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
+         std::optional<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)
@@ -882,7 +885,7 @@ class Path_Validation_With_OCSP_Tests final : public Test
 
          const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
+         auto 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)
@@ -922,7 +925,7 @@ class Path_Validation_With_OCSP_Tests final : public Test
 
          const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
+         auto 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)
@@ -961,7 +964,7 @@ class Path_Validation_With_OCSP_Tests final : public Test
 
          const std::vector<Botan::X509_Certificate> cert_path = { ee, ca, trust_root };
 
-         std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/patrickschmidt_ocsp.der");
+         auto 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)
@@ -1068,8 +1071,7 @@ 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<std::shared_ptr<const Botan::X509_Certificate>>{
-				            std::make_shared<const Botan::X509_Certificate>(self_signed)};
+      auto cert_path = std::vector<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 694779ac5..159c61400 100644
--- a/src/tests/tests.h
+++ b/src/tests/tests.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
+#include <optional>
 
 namespace Botan {
 
@@ -271,6 +272,15 @@ 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);