Repository: randombit/botan
Pull request #3220 (2023-01-24 23:46:39)

Remove various uses of raw pointers in the public API
GH #3216

While some of these are changing the return types of non-deprecated functions, I think this is mostly OK; it's easy enough to use either variant as (for example) `std::unique_ptr<Public_Key> key(cert.subject_public_key())` and if it doesn't work at least the compiler gives a hint what is wrong (couldn't convert unique_ptr to raw ptr) vs the function just vanishing.




Patch:
diff --git a/doc/dev_ref/oids.rst b/doc/dev_ref/oids.rst
index 4a534c6a6..6c7d2aed0 100644
--- a/doc/dev_ref/oids.rst
+++ b/doc/dev_ref/oids.rst
@@ -14,17 +14,7 @@ Values currently assigned are::
   -- { publicKey 4 } previously used as private X25519
   -- { publicKey 5 } previously used for XMSS draft 6
   gost-3410-with-sha256 OBJECT IDENTIFIER ::= { publicKey 6 1 }
-
   kyber       OBJECT IDENTIFIER ::= { publicKey 7 }
-  kyber-90s   OBJECT IDENTIFIER ::= { publicKey 11 }
-
-  kyber-512      OBJECT IDENTIFIER ::= { kyber 1 }
-  kyber-768      OBJECT IDENTIFIER ::= { kyber 2 }
-  kyber-1024     OBJECT IDENTIFIER ::= { kyber 3 }
-  kyber-512-90s  OBJECT IDENTIFIER ::= { kyber-90s 1 }
-  kyber-768-90s  OBJECT IDENTIFIER ::= { kyber-90s 2 }
-  kyber-1024-90s OBJECT IDENTIFIER ::= { kyber-90s 3 }
-
   xmss        OBJECT IDENTIFIER ::= { publicKey 8 }
 
   -- The current dilithium implementation is compatible with the reference
diff --git a/doc/migration_guide.rst b/doc/migration_guide.rst
index 95b86e7ac..e5e5245c8 100644
--- a/doc/migration_guide.rst
+++ b/doc/migration_guide.rst
@@ -148,3 +148,14 @@ regressions due to creating and processing very small buffers.
 Previously the library accepted "SHA-160" and "SHA1" alternative names
 for "SHA-1". This is no longer the case, you must use "SHA-1". Botan
 2.x also recognizes "SHA-1".
+
+X509::load_key
+-------------------
+
+Previously these functions returned a raw pointer. They now return
+a std::unique_ptr
+
+PKCS11_Request::subject_public_key and X509_Certificate::subject_public_key
+-----------------------------------------------------------------------------
+
+These functions now return a unique_ptr
diff --git a/src/build-data/oids.txt b/src/build-data/oids.txt
index e547e11b7..e048e6e1d 100644
--- a/src/build-data/oids.txt
+++ b/src/build-data/oids.txt
@@ -15,13 +15,15 @@
 1.3.101.110 = Curve25519
 1.3.101.112 = Ed25519
 
-# Kyber OIDs are currently in Botan's private arc
-1.3.6.1.4.1.25258.1.7.1 = Kyber-512-r3
-1.3.6.1.4.1.25258.1.7.2 = Kyber-768-r3
-1.3.6.1.4.1.25258.1.7.3 = Kyber-1024-r3
-1.3.6.1.4.1.25258.1.11.1 = Kyber-512-90s-r3
-1.3.6.1.4.1.25258.1.11.2 = Kyber-768-90s-r3
-1.3.6.1.4.1.25258.1.11.3 = Kyber-1024-90s-r3
+# Kyber OIDs are based on the following internet draft
+#   https://www.ietf.org/id/draft-uni-qsckeys-00.html#section-4.1
+# (the list contained some typos that were fixed, best effort)
+1.3.6.1.4.1.2.267.8.2.2 = Kyber-512-r3
+1.3.6.1.4.1.2.267.8.3.3 = Kyber-768-r3
+1.3.6.1.4.1.2.267.8.4.4 = Kyber-1024-r3
+1.3.6.1.4.1.2.267.10.2.2 = Kyber-512-90s-r3
+1.3.6.1.4.1.2.267.10.3.3 = Kyber-768-90s-r3
+1.3.6.1.4.1.2.267.10.4.4 = Kyber-1024-90s-r3
 
 # Dilithium OIDs are currently in Botan's private arc
 1.3.6.1.4.1.25258.1.9.1 = Dilithium-4x4-r3
diff --git a/src/lib/asn1/oid_maps.cpp b/src/lib/asn1/oid_maps.cpp
index 84be22b52..4b5f8aa5f 100644
--- a/src/lib/asn1/oid_maps.cpp
+++ b/src/lib/asn1/oid_maps.cpp
@@ -1,7 +1,7 @@
 /*
 * OID maps
 *
-* This file was automatically generated by src/scripts/oids.py on 2023-01-24
+* This file was automatically generated by src/scripts/oids.py on 2023-01-23
 *
 * All manual edits to this file will be lost. Edit the script
 * then regenerate this source file.
@@ -138,18 +138,18 @@ std::unordered_map<std::string, std::string> OIDS::load_oid2str_map()
       { "1.3.36.3.3.2.8.1.1.9", "brainpool320r1" },
       { "1.3.6.1.4.1.11591.15.1", "OpenPGP.Ed25519" },
       { "1.3.6.1.4.1.11591.4.11", "Scrypt" },
+      { "1.3.6.1.4.1.2.267.10.2.2", "Kyber-512-90s-r3" },
+      { "1.3.6.1.4.1.2.267.10.3.3", "Kyber-768-90s-r3" },
+      { "1.3.6.1.4.1.2.267.10.4.4", "Kyber-1024-90s-r3" },
+      { "1.3.6.1.4.1.2.267.8.2.2", "Kyber-512-r3" },
+      { "1.3.6.1.4.1.2.267.8.3.3", "Kyber-768-r3" },
+      { "1.3.6.1.4.1.2.267.8.4.4", "Kyber-1024-r3" },
       { "1.3.6.1.4.1.25258.1.10.1", "Dilithium-4x4-AES-r3" },
       { "1.3.6.1.4.1.25258.1.10.2", "Dilithium-6x5-AES-r3" },
       { "1.3.6.1.4.1.25258.1.10.3", "Dilithium-8x7-AES-r3" },
-      { "1.3.6.1.4.1.25258.1.11.1", "Kyber-512-90s-r3" },
-      { "1.3.6.1.4.1.25258.1.11.2", "Kyber-768-90s-r3" },
-      { "1.3.6.1.4.1.25258.1.11.3", "Kyber-1024-90s-r3" },
       { "1.3.6.1.4.1.25258.1.3", "McEliece" },
       { "1.3.6.1.4.1.25258.1.5", "XMSS-draft6" },
       { "1.3.6.1.4.1.25258.1.6.1", "GOST-34.10-2012-256/EMSA1(SHA-256)" },
-      { "1.3.6.1.4.1.25258.1.7.1", "Kyber-512-r3" },
-      { "1.3.6.1.4.1.25258.1.7.2", "Kyber-768-r3" },
-      { "1.3.6.1.4.1.25258.1.7.3", "Kyber-1024-r3" },
       { "1.3.6.1.4.1.25258.1.8", "XMSS-draft12" },
       { "1.3.6.1.4.1.25258.1.9.1", "Dilithium-4x4-r3" },
       { "1.3.6.1.4.1.25258.1.9.2", "Dilithium-6x5-r3" },
@@ -372,12 +372,12 @@ std::unordered_map<std::string, OID> OIDS::load_str2oid_map()
       { "KeyWrap.AES-256", OID({2,16,840,1,101,3,4,1,45}) },
       { "KeyWrap.CAST-128", OID({1,2,840,113533,7,66,15}) },
       { "KeyWrap.TripleDES", OID({1,2,840,113549,1,9,16,3,6}) },
-      { "Kyber-1024-90s-r3", OID({1,3,6,1,4,1,25258,1,11,3}) },
-      { "Kyber-1024-r3", OID({1,3,6,1,4,1,25258,1,7,3}) },
-      { "Kyber-512-90s-r3", OID({1,3,6,1,4,1,25258,1,11,1}) },
-      { "Kyber-512-r3", OID({1,3,6,1,4,1,25258,1,7,1}) },
-      { "Kyber-768-90s-r3", OID({1,3,6,1,4,1,25258,1,11,2}) },
-      { "Kyber-768-r3", OID({1,3,6,1,4,1,25258,1,7,2}) },
+      { "Kyber-1024-90s-r3", OID({1,3,6,1,4,1,2,267,10,4,4}) },
+      { "Kyber-1024-r3", OID({1,3,6,1,4,1,2,267,8,4,4}) },
+      { "Kyber-512-90s-r3", OID({1,3,6,1,4,1,2,267,10,2,2}) },
+      { "Kyber-512-r3", OID({1,3,6,1,4,1,2,267,8,2,2}) },
+      { "Kyber-768-90s-r3", OID({1,3,6,1,4,1,2,267,10,3,3}) },
+      { "Kyber-768-r3", OID({1,3,6,1,4,1,2,267,8,3,3}) },
       { "MD5", OID({1,2,840,113549,2,5}) },
       { "MGF1", OID({1,2,840,113549,1,1,8}) },
       { "McEliece", OID({1,3,6,1,4,1,25258,1,3}) },
diff --git a/src/lib/ffi/ffi_cert.cpp b/src/lib/ffi/ffi_cert.cpp
index aeceb9737..d636187dd 100644
--- a/src/lib/ffi/ffi_cert.cpp
+++ b/src/lib/ffi/ffi_cert.cpp
@@ -89,7 +89,7 @@ int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key)
 
 #if defined(BOTAN_HAS_X509_CERTIFICATES)
    return ffi_guard_thunk(__func__, [=]() -> int {
-      std::unique_ptr<Botan::Public_Key> public_key = safe_get(cert).load_subject_public_key();
+      std::unique_ptr<Botan::Public_Key> public_key = safe_get(cert).subject_public_key();
       *key = new botan_pubkey_struct(std::move(public_key));
       return BOTAN_FFI_SUCCESS;
       });
diff --git a/src/lib/pubkey/pkcs8.h b/src/lib/pubkey/pkcs8.h
index a4b2f4ba1..dc96e298c 100644
--- a/src/lib/pubkey/pkcs8.h
+++ b/src/lib/pubkey/pkcs8.h
@@ -1,6 +1,6 @@
 /*
 * PKCS #8
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2023 Jack Lloyd
 *
 * Botan is released under the Simplified BSD License (see license.txt)
 */
@@ -217,117 +217,6 @@ inline std::unique_ptr<Private_Key> copy_key(const Private_Key& key)
    return PKCS8::load_key(source);
    }
 
-// Deprecated functions follow
-
-/**
-* Load an encrypted key from a data source.
-* @param source the data source providing the encoded key
-* @param rng ignored for compatibility
-* @param get_passphrase a function that returns passphrases
-* @return loaded private key object
-*/
-BOTAN_DEPRECATED("Use version that doesn't take an RNG")
-inline Private_Key* load_key(DataSource& source,
-                             RandomNumberGenerator& rng,
-                             std::function<std::string ()> get_passphrase)
-   {
-   BOTAN_UNUSED(rng);
-   return PKCS8::load_key(source, get_passphrase).release();
-   }
-
-/** Load an encrypted key from a data source.
-* @param source the data source providing the encoded key
-* @param rng ignored for compatibility
-* @param pass the passphrase to decrypt the key
-* @return loaded private key object
-*/
-BOTAN_DEPRECATED("Use version that doesn't take an RNG")
-inline Private_Key* load_key(DataSource& source,
-                             RandomNumberGenerator& rng,
-                             const std::string& pass)
-   {
-   BOTAN_UNUSED(rng);
-   return PKCS8::load_key(source, pass).release();
-   }
-
-/** Load an unencrypted key from a data source.
-* @param source the data source providing the encoded key
-* @param rng ignored for compatibility
-* @return loaded private key object
-*/
-BOTAN_DEPRECATED("Use version that doesn't take an RNG")
-inline Private_Key* load_key(DataSource& source,
-                             RandomNumberGenerator& rng)
-   {
-   BOTAN_UNUSED(rng);
-   return PKCS8::load_key(source).release();
-   }
-
-#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
-/**
-* Load an encrypted key from a file.
-* @param filename the path to the file containing the encoded key
-* @param rng ignored for compatibility
-* @param get_passphrase a function that returns passphrases
-* @return loaded private key object
-*/
-BOTAN_DEPRECATED("Use DataSource_Stream and another load_key variant")
-inline Private_Key* load_key(const std::string& filename,
-                             RandomNumberGenerator& rng,
-                             std::function<std::string ()> get_passphrase)
-   {
-   BOTAN_UNUSED(rng);
-   DataSource_Stream in(filename);
-   return PKCS8::load_key(in, get_passphrase).release();
-   }
-
-/** Load an encrypted key from a file.
-* @param filename the path to the file containing the encoded key
-* @param rng ignored for compatibility
-* @param pass the passphrase to decrypt the key
-* @return loaded private key object
-*/
-BOTAN_DEPRECATED("Use DataSource_Stream and another load_key variant")
-inline Private_Key* load_key(const std::string& filename,
-                             RandomNumberGenerator& rng,
-                             const std::string& pass)
-   {
-   BOTAN_UNUSED(rng);
-   DataSource_Stream in(filename);
-   // We need to use bind rather than a lambda capturing `pass` here in order to avoid a Clang 8 bug.
-   // See https://github.com/randombit/botan/issues/2255.
-   return PKCS8::load_key(in, std::bind([](const std::string p) { return p; }, pass)).release();
-   }
-
-/** Load an unencrypted key from a file.
-* @param filename the path to the file containing the encoded key
-* @param rng ignored for compatibility
-* @return loaded private key object
-*/
-BOTAN_DEPRECATED("Use DataSource_Stream and another load_key variant")
-inline Private_Key* load_key(const std::string& filename,
-                             RandomNumberGenerator& rng)
-   {
-   BOTAN_UNUSED(rng);
-   DataSource_Stream in(filename);
-   return PKCS8::load_key(in).release();
-   }
-#endif
-
-/**
-* Copy an existing encoded key object.
-* @param key the key to copy
-* @param rng ignored for compatibility
-* @return new copy of the key
-*/
-BOTAN_DEPRECATED("Use version that doesn't take an RNG")
-inline Private_Key* copy_key(const Private_Key& key,
-                             RandomNumberGenerator& rng)
-   {
-   BOTAN_UNUSED(rng);
-   return PKCS8::copy_key(key).release();
-   }
-
 }
 
 }
diff --git a/src/lib/pubkey/x509_key.cpp b/src/lib/pubkey/x509_key.cpp
index 5952d5ccd..07419a438 100644
--- a/src/lib/pubkey/x509_key.cpp
+++ b/src/lib/pubkey/x509_key.cpp
@@ -26,7 +26,7 @@ std::string PEM_encode(const Public_Key& key)
 /*
 * Extract a public key and return it
 */
-Public_Key* load_key(DataSource& source)
+std::unique_ptr<Public_Key> load_key(DataSource& source)
    {
    try {
       AlgorithmIdentifier alg_id;
@@ -56,7 +56,7 @@ Public_Key* load_key(DataSource& source)
       if(key_bits.empty())
          throw Decoding_Error("X.509 public key decoding");
 
-      return load_public_key(alg_id, key_bits).release();
+      return load_public_key(alg_id, key_bits);
       }
    catch(Decoding_Error& e)
       {
diff --git a/src/lib/pubkey/x509_key.h b/src/lib/pubkey/x509_key.h
index 450f7523f..cd1d59cf7 100644
--- a/src/lib/pubkey/x509_key.h
+++ b/src/lib/pubkey/x509_key.h
@@ -1,6 +1,6 @@
 /*
 * X.509 Public Key
-* (C) 1999-2010 Jack Lloyd
+* (C) 1999-2010,2023 Jack Lloyd
 *
 * Botan is released under the Simplified BSD License (see license.txt)
 */
@@ -42,7 +42,7 @@ BOTAN_PUBLIC_API(2,0) std::string PEM_encode(const Public_Key& key);
 * @param source the source providing the DER or PEM encoded key
 * @return new public key object
 */
-BOTAN_PUBLIC_API(2,0) Public_Key* load_key(DataSource& source);
+BOTAN_PUBLIC_API(3,0) std::unique_ptr<Public_Key> load_key(DataSource& source);
 
 #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
 /**
@@ -50,7 +50,7 @@ BOTAN_PUBLIC_API(2,0) Public_Key* load_key(DataSource& source);
 * @param filename pathname to the file to load
 * @return new public key object
 */
-inline Public_Key* load_key(const std::string& filename)
+inline std::unique_ptr<Public_Key> load_key(const std::string& filename)
    {
    DataSource_Stream source(filename, true);
    return X509::load_key(source);
@@ -62,7 +62,7 @@ inline Public_Key* load_key(const std::string& filename)
 * @param enc the memory region containing the DER or PEM encoded key
 * @return new public key object
 */
-inline Public_Key* load_key(const std::vector<uint8_t>& enc)
+inline std::unique_ptr<Public_Key> load_key(const std::vector<uint8_t>& enc)
    {
    DataSource_Memory source(enc);
    return X509::load_key(source);
@@ -73,7 +73,7 @@ inline Public_Key* load_key(const std::vector<uint8_t>& enc)
 * @param key the public key to copy
 * @return new public key object
 */
-inline Public_Key* copy_key(const Public_Key& key)
+inline std::unique_ptr<Public_Key> copy_key(const Public_Key& key)
    {
    DataSource_Memory source(PEM_encode(key));
    return X509::load_key(source);
diff --git a/src/lib/tls/msg_cert_verify.cpp b/src/lib/tls/msg_cert_verify.cpp
index b808beb2e..ae3d191f5 100644
--- a/src/lib/tls/msg_cert_verify.cpp
+++ b/src/lib/tls/msg_cert_verify.cpp
@@ -211,7 +211,7 @@ bool Certificate_Verify_13::verify(const X509_Certificate& cert,
    if(m_scheme.algorithm_identifier() != cert.subject_public_key_algo())
       { throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Signature algorithm does not match certificate's public key"); }
 
-   const auto key = cert.load_subject_public_key();
+   const auto key = cert.subject_public_key();
    const bool signature_valid =
       callbacks.tls_verify_message(*key,
                                    m_scheme.padding_string(),
diff --git a/src/lib/tls/tls13/msg_certificate_13.cpp b/src/lib/tls/tls13/msg_certificate_13.cpp
index ae793d2e5..4670af457 100644
--- a/src/lib/tls/tls13/msg_certificate_13.cpp
+++ b/src/lib/tls/tls13/msg_certificate_13.cpp
@@ -318,7 +318,7 @@ Certificate_13::Certificate_13(const std::vector<uint8_t>& buf,
    else
       {
       /* validation of provided certificate public key */
-      auto key = m_entries.front().certificate.load_subject_public_key();
+      auto key = m_entries.front().certificate.subject_public_key();
 
       policy.check_peer_key_acceptable(*key);
 
diff --git a/src/lib/x509/pkcs10.cpp b/src/lib/x509/pkcs10.cpp
index 73ec42147..1c8575fd6 100644
--- a/src/lib/x509/pkcs10.cpp
+++ b/src/lib/x509/pkcs10.cpp
@@ -185,7 +185,8 @@ void PKCS10_Request::force_decode()
 
    m_data.reset(data.release());
 
-   if(!this->check_signature(subject_public_key()))
+   auto key = this->subject_public_key();
+   if(!this->check_signature(*key))
       throw Decoding_Error("PKCS #10 request: Bad signature detected");
    }
 
@@ -223,7 +224,7 @@ const std::vector<uint8_t>& PKCS10_Request::raw_public_key() const
 /*
 * Return the public key of the requestor
 */
-Public_Key* PKCS10_Request::subject_public_key() const
+std::unique_ptr<Public_Key> PKCS10_Request::subject_public_key() const
    {
    DataSource_Memory source(raw_public_key());
    return X509::load_key(source);
diff --git a/src/lib/x509/pkcs10.h b/src/lib/x509/pkcs10.h
index 3f3f87357..1687aad19 100644
--- a/src/lib/x509/pkcs10.h
+++ b/src/lib/x509/pkcs10.h
@@ -32,7 +32,7 @@ class BOTAN_PUBLIC_API(2,0) PKCS10_Request final : public X509_Object
       * Get the subject public key.
       * @return subject public key
       */
-      Public_Key* subject_public_key() const;
+      std::unique_ptr<Public_Key> subject_public_key() const;
 
       /**
       * Get the raw DER encoded public key.
diff --git a/src/lib/x509/x509_obj.cpp b/src/lib/x509/x509_obj.cpp
index 021ff4766..78a12e239 100644
--- a/src/lib/x509/x509_obj.cpp
+++ b/src/lib/x509/x509_obj.cpp
@@ -167,14 +167,6 @@ std::string X509_Object::hash_used_for_signature() const
 /*
 * Check the signature on an object
 */
-bool X509_Object::check_signature(const Public_Key* pub_key) const
-   {
-   if(!pub_key)
-      throw Invalid_Argument("No key provided for " + PEM_label() + " signature check");
-   std::unique_ptr<const Public_Key> key(pub_key);
-   return check_signature(*key);
-   }
-
 bool X509_Object::check_signature(const Public_Key& pub_key) const
    {
    const Certificate_Status_Code code = verify_signature(pub_key);
diff --git a/src/lib/x509/x509_obj.h b/src/lib/x509/x509_obj.h
index f121a76fc..45449ba40 100644
--- a/src/lib/x509/x509_obj.h
+++ b/src/lib/x509/x509_obj.h
@@ -80,15 +80,6 @@ class BOTAN_PUBLIC_API(2,0) X509_Object : public ASN1_Object
       */
       bool check_signature(const Public_Key& key) const;
 
-      /**
-      * Check the signature on this data
-      * @param key the public key purportedly used to sign this data
-      *        the object will be deleted after use (this should have
-      *        been a std::unique_ptr<Public_Key>)
-      * @return true if the signature is valid, otherwise false
-      */
-      bool check_signature(const Public_Key* key) const;
-
       /**
       * DER encode an X509_Object
       * See @ref ASN1_Object::encode_into()
diff --git a/src/lib/x509/x509cert.cpp b/src/lib/x509/x509cert.cpp
index 59d419632..1d636e287 100644
--- a/src/lib/x509/x509cert.cpp
+++ b/src/lib/x509/x509cert.cpp
@@ -663,7 +663,7 @@ X509_Certificate::issuer_info(const std::string& req) const
 /*
 * Return the public key in this certificate
 */
-std::unique_ptr<Public_Key> X509_Certificate::load_subject_public_key() const
+std::unique_ptr<Public_Key> X509_Certificate::subject_public_key() const
    {
    try
       {
@@ -671,13 +671,13 @@ std::unique_ptr<Public_Key> X509_Certificate::load_subject_public_key() const
       }
    catch(std::exception& e)
       {
-      throw Decoding_Error("X509_Certificate::load_subject_public_key", e);
+      throw Decoding_Error("X509_Certificate::subject_public_key", e);
       }
    }
 
-Public_Key* X509_Certificate::subject_public_key() const
+std::unique_ptr<Public_Key> X509_Certificate::load_subject_public_key() const
    {
-   return load_subject_public_key().release();
+   return this->subject_public_key();
    }
 
 std::vector<uint8_t> X509_Certificate::raw_issuer_dn_sha256() const
diff --git a/src/lib/x509/x509cert.h b/src/lib/x509/x509cert.h
index 021d82af9..94599d6a0 100644
--- a/src/lib/x509/x509cert.h
+++ b/src/lib/x509/x509cert.h
@@ -38,15 +38,15 @@ class BOTAN_PUBLIC_API(2,0) X509_Certificate : public X509_Object
    {
    public:
       /**
-      * Return a newly allocated copy of the public key associated
-      * with the subject of this certificate. This object is owned
-      * by the caller.
-      *
-      * Prefer load_subject_public_key in new code
+      * Create a public key object associated with the public key bits in this
+      * certificate. If the public key bits was valid for X.509 encoding
+      * purposes but invalid algorithmically (for example, RSA with an even
+      * modulus) that will be detected at this point, and an exception will be
+      * thrown.
       *
-      * @return public key
+      * @return subject public key of this certificate
       */
-      Public_Key* subject_public_key() const;
+      std::unique_ptr<Public_Key> subject_public_key() const;
 
       /**
       * Create a public key object associated with the public key bits in this
@@ -57,6 +57,7 @@ class BOTAN_PUBLIC_API(2,0) X509_Certificate : public X509_Object
       *
       * @return subject public key of this certificate
       */
+      BOTAN_DEPRECATED("Use subject_public_key")
       std::unique_ptr<Public_Key> load_subject_public_key() const;
 
       /**
diff --git a/src/lib/x509/x509path.cpp b/src/lib/x509/x509path.cpp
index 612f86b11..d4cc52a38 100644
--- a/src/lib/x509/x509path.cpp
+++ b/src/lib/x509/x509path.cpp
@@ -367,7 +367,8 @@ PKIX::check_crl(const std::vector<X509_Certificate>& cert_path,
          if(validation_time > crls[i]->next_update())
             status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED);
 
-         if(crls[i]->check_signature(ca.subject_public_key()) == false)
+         auto ca_key = ca.subject_public_key();
+         if(crls[i]->check_signature(*ca_key) == false)
             status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE);
 
          status.insert(Certificate_Status_Code::VALID_CRL_CHECKED);


Test patch:
diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp
index b3c5fd5d1..d741b8889 100644
--- a/src/tests/unit_x509.cpp
+++ b/src/tests/unit_x509.cpp
@@ -483,7 +483,7 @@ Test::Result test_rsa_oaep()
 #if defined(BOTAN_HAS_RSA)
    Botan::X509_Certificate cert(Test::data_file("x509/misc/rsa_oaep.pem"));
 
-   auto public_key = cert.load_subject_public_key();
+   auto public_key = cert.subject_public_key();
    result.test_not_null("Decoding RSA-OAEP worked", public_key.get());
    const auto& pk_info = cert.subject_public_key_algo();