Revert^2 "Upgrade spki to 0.7.3" am: 81a66df692 am: c6bdff74a1 am: a14fc500ec

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/spki/+/2881111

Change-Id: Ie41d89259c77776f72ad959ed9f8e922adc867db
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 66cdc9c..a390d72 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "d91ca33448c5a3fa8952651160046a37f6b5eef9"
+    "sha1": "15ea461dc3484d48710deed932e4d3d9052c1f9b"
   },
   "path_in_vcs": "spki"
 }
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index f35a356..7d7b447 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,7 +35,7 @@
     name: "libspki",
     crate_name: "spki",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.6.0",
+    cargo_pkg_version: "0.7.3",
     srcs: ["src/lib.rs"],
     edition: "2021",
     features: ["alloc"],
@@ -46,7 +46,7 @@
     name: "libspki_nostd",
     crate_name: "spki",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.6.0",
+    cargo_pkg_version: "0.7.3",
     srcs: ["src/lib.rs"],
     edition: "2021",
     features: ["alloc"],
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce0f5b7..cf3722d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,55 @@
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## 0.7.3 (2023-11-28)
+### Added
+- public key to `SubjectPublicKeyInfoOwned` helper ([#1269])
+
+[#1269]: https://github.com/RustCrypto/formats/pull/1269
+
+## 0.7.2 (2023-05-04)
+
+### Added
+- `AlgorithmIdentifierWithOid` trait ([#986])
+- `SignatureBitStringEncoding` trait ([#1047])
+
+### Changed
+-  Bump `hex-literal` to v0.4.1 ([#999])
+
+[#986]: https://github.com/RustCrypto/formats/pull/986
+[#999]: https://github.com/RustCrypto/formats/pull/999
+[#1047]: https://github.com/RustCrypto/formats/pull/1047
+
+
+## 0.7.1 (2023-04-04)
+### Added
+- `AssociatedAlgorithmIdentifier` trait ([#962], [#966])
+- `DynAssociatedAlgorithmIdentifier` trait ([#962])
+- `SignatureAlgorithmIdentifier` trait ([#967])
+- `DynSignatureAlgorithmIdentifier` trait ([#967])
+
+### Changed
+- Bump `der` dependency to v0.7.2 ([#979])
+
+[#962]: https://github.com/RustCrypto/formats/pull/962
+[#966]: https://github.com/RustCrypto/formats/pull/966
+[#967]: https://github.com/RustCrypto/formats/pull/967
+[#979]: https://github.com/RustCrypto/formats/pull/979
+
+## 0.7.0 (2023-02-26)
+### Changed
+- Make `AlgorithmIdentifier` generic around `Params` ([#769])
+- Use blanket impls for `Decode*` traits ([#785])
+- Make `SubjectPublicKeyInfo` own the public key ([#790])
+- Rename `to_owned` method ([#835])
+- Bump `der` dependency to v0.7 ([#899])
+
+[#769]: https://github.com/RustCrypto/formats/pull/769
+[#785]: https://github.com/RustCrypto/formats/pull/785
+[#790]: https://github.com/RustCrypto/formats/pull/790
+[#835]: https://github.com/RustCrypto/formats/pull/835
+[#899]: https://github.com/RustCrypto/formats/pull/899
+
 ## 0.6.0 (2022-05-08)
 ### Added
 - `AlgorithmIdentifier::oids()` helper function ([#443])
diff --git a/Cargo.toml b/Cargo.toml
index 20147e1..1c7f305 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,9 +11,9 @@
 
 [package]
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 name = "spki"
-version = "0.6.0"
+version = "0.7.3"
 authors = ["RustCrypto Developers"]
 description = """
 X.509 Subject Public Key Info (RFC5280) describing public keys as well as their
@@ -32,7 +32,6 @@
 ]
 license = "Apache-2.0 OR MIT"
 repository = "https://github.com/RustCrypto/formats/tree/master/spki"
-resolver = "2"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -41,13 +40,18 @@
     "docsrs",
 ]
 
+[dependencies.arbitrary]
+version = "1.2"
+features = ["derive"]
+optional = true
+
 [dependencies.base64ct]
 version = "1"
 optional = true
 default-features = false
 
 [dependencies.der]
-version = "0.6"
+version = "0.7.2"
 features = ["oid"]
 
 [dependencies.sha2]
@@ -56,7 +60,7 @@
 default-features = false
 
 [dev-dependencies.hex-literal]
-version = "0.3"
+version = "0.4"
 
 [dev-dependencies.tempfile]
 version = "3"
@@ -66,6 +70,12 @@
     "base64ct?/alloc",
     "der/alloc",
 ]
+arbitrary = [
+    "std",
+    "dep:arbitrary",
+    "der/arbitrary",
+]
+base64 = ["dep:base64ct"]
 fingerprint = ["sha2"]
 pem = [
     "alloc",
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index bb49bd8..e9e2687 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "spki"
-version = "0.6.0"
+version = "0.7.3"
 description = """
 X.509 Subject Public Key Info (RFC5280) describing public keys as well as their
 associated AlgorithmIdentifiers (i.e. OIDs)
@@ -12,24 +12,28 @@
 keywords = ["crypto", "x509"]
 readme = "README.md"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [dependencies]
-der = { version = "0.6", features = ["oid"], path = "../der" }
+der = { version = "0.7.2", features = ["oid"] }
 
 # Optional dependencies
+arbitrary = { version = "1.2", features = ["derive"], optional = true }
+base64ct = { version = "1", optional = true, default-features = false }
 sha2 = { version = "0.10", optional = true, default-features = false }
-base64ct = { version = "1", path = "../base64ct", optional = true, default-features = false }
 
 [dev-dependencies]
-hex-literal = "0.3"
+hex-literal = "0.4"
 tempfile = "3"
 
 [features]
 alloc = ["base64ct?/alloc", "der/alloc"]
+std = ["der/std", "alloc"]
+
+arbitrary = ["std", "dep:arbitrary", "der/arbitrary"]
+base64 = ["dep:base64ct"]
 fingerprint = ["sha2"]
 pem = ["alloc", "der/pem"]
-std = ["der/std", "alloc"]
 
 [package.metadata.docs.rs]
 all-features = true
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..3294d74
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2021-2023 The RustCrypto Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
index 6ce048a..0fa8081 100644
--- a/METADATA
+++ b/METADATA
@@ -1,20 +1,20 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/spki
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
 name: "spki"
 description: "X.509 Subject Public Key Info types describing public keys as well as their associated AlgorithmIdentifiers (i.e. OIDs)."
 third_party {
-  url {
-    type: HOMEPAGE
-    value: "https://crates.io/crates/spki"
-  }
-  url {
-    type: ARCHIVE
-    value: "https://static.crates.io/crates/spki/spki-0.6.0.crate"
-  }
-  version: "0.6.0"
-  # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
   license_type: NOTICE
   last_upgrade_date {
-    year: 2022
-    month: 9
-    day: 6
+    year: 2023
+    month: 12
+    day: 15
+  }
+  homepage: "https://crates.io/crates/spki"
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/spki/spki-0.7.3.crate"
+    version: "0.7.3"
   }
 }
diff --git a/README.md b/README.md
index caa01cc..4ac8554 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
 
 ## Minimum Supported Rust Version
 
-This crate requires **Rust 1.57** at a minimum.
+This crate requires **Rust 1.65** at a minimum.
 
 We may change the MSRV in the future, but it will be accompanied by a minor
 version bump.
@@ -45,7 +45,7 @@
 [build-image]: https://github.com/RustCrypto/formats/actions/workflows/spki.yml/badge.svg
 [build-link]: https://github.com/RustCrypto/formats/actions/workflows/spki.yml
 [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
-[rustc-image]: https://img.shields.io/badge/rustc-1.57+-blue.svg
+[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg
 [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
 [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats
 
diff --git a/patches/std.diff b/patches/std.diff
index cf6bd2e..7ef1d49 100644
--- a/patches/std.diff
+++ b/patches/std.diff
@@ -1,16 +1,3 @@
-diff --git a/Cargo.toml b/Cargo.toml
-index 13205cb..20147e1 100644
---- a/Cargo.toml
-+++ b/Cargo.toml
-@@ -63,7 +63,7 @@ version = "3"
- 
- [features]
- alloc = [
--    "base64ct/alloc",
-+    "base64ct?/alloc",
-     "der/alloc",
- ]
- fingerprint = ["sha2"]
 diff --git a/src/lib.rs b/src/lib.rs
 index f466756..995f3bd 100644
 --- a/src/lib.rs
@@ -25,16 +12,3 @@
 +
  #[cfg(feature = "alloc")]
  pub use {crate::traits::EncodePublicKey, der::Document};
-diff --git a/Cargo.toml.orig b/Cargo.toml.orig
-index e7138a7..be1a9f6 100644
---- a/Cargo.toml.orig
-+++ b/Cargo.toml.orig
-@@ -26,7 +26,7 @@ hex-literal = "0.3"
- tempfile = "3"
- 
- [features]
--alloc = ["base64ct/alloc", "der/alloc"]
-+alloc = ["base64ct?/alloc", "der/alloc"]
- fingerprint = ["sha2"]
- pem = ["alloc", "der/pem"]
- std = ["der/std", "alloc"]
diff --git a/src/algorithm.rs b/src/algorithm.rs
index 2a8b6c7..5f4b5e8 100644
--- a/src/algorithm.rs
+++ b/src/algorithm.rs
@@ -2,8 +2,14 @@
 
 use crate::{Error, Result};
 use core::cmp::Ordering;
-use der::asn1::{AnyRef, ObjectIdentifier};
-use der::{Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd};
+use der::{
+    asn1::{AnyRef, Choice, ObjectIdentifier},
+    Decode, DecodeValue, DerOrd, Encode, EncodeValue, Header, Length, Reader, Sequence, ValueOrd,
+    Writer,
+};
+
+#[cfg(feature = "alloc")]
+use der::asn1::Any;
 
 /// X.509 `AlgorithmIdentifier` as defined in [RFC 5280 Section 4.1.1.2].
 ///
@@ -14,17 +20,82 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
-pub struct AlgorithmIdentifier<'a> {
+pub struct AlgorithmIdentifier<Params> {
     /// Algorithm OID, i.e. the `algorithm` field in the `AlgorithmIdentifier`
     /// ASN.1 schema.
     pub oid: ObjectIdentifier,
 
     /// Algorithm `parameters`.
-    pub parameters: Option<AnyRef<'a>>,
+    pub parameters: Option<Params>,
 }
 
-impl<'a> AlgorithmIdentifier<'a> {
+impl<'a, Params> DecodeValue<'a> for AlgorithmIdentifier<Params>
+where
+    Params: Choice<'a>,
+{
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
+        reader.read_nested(header.length, |reader| {
+            Ok(Self {
+                oid: reader.decode()?,
+                parameters: reader.decode()?,
+            })
+        })
+    }
+}
+
+impl<Params> EncodeValue for AlgorithmIdentifier<Params>
+where
+    Params: Encode,
+{
+    fn value_len(&self) -> der::Result<Length> {
+        self.oid.encoded_len()? + self.parameters.encoded_len()?
+    }
+
+    fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
+        self.oid.encode(writer)?;
+        self.parameters.encode(writer)?;
+        Ok(())
+    }
+}
+
+impl<'a, Params> Sequence<'a> for AlgorithmIdentifier<Params> where Params: Choice<'a> + Encode {}
+
+impl<'a, Params> TryFrom<&'a [u8]> for AlgorithmIdentifier<Params>
+where
+    Params: Choice<'a> + Encode,
+{
+    type Error = Error;
+
+    fn try_from(bytes: &'a [u8]) -> Result<Self> {
+        Ok(Self::from_der(bytes)?)
+    }
+}
+
+impl<Params> ValueOrd for AlgorithmIdentifier<Params>
+where
+    Params: DerOrd,
+{
+    fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
+        match self.oid.der_cmp(&other.oid)? {
+            Ordering::Equal => self.parameters.der_cmp(&other.parameters),
+            other => Ok(other),
+        }
+    }
+}
+
+/// `AlgorithmIdentifier` reference which has `AnyRef` parameters.
+pub type AlgorithmIdentifierRef<'a> = AlgorithmIdentifier<AnyRef<'a>>;
+
+/// `AlgorithmIdentifier` with `ObjectIdentifier` parameters.
+pub type AlgorithmIdentifierWithOid = AlgorithmIdentifier<ObjectIdentifier>;
+
+/// `AlgorithmIdentifier` reference which has `Any` parameters.
+#[cfg(feature = "alloc")]
+pub type AlgorithmIdentifierOwned = AlgorithmIdentifier<Any>;
+
+impl<Params> AlgorithmIdentifier<Params> {
     /// Assert the `algorithm` OID is an expected value.
     pub fn assert_algorithm_oid(&self, expected_oid: ObjectIdentifier) -> Result<ObjectIdentifier> {
         if self.oid == expected_oid {
@@ -33,7 +104,9 @@
             Err(Error::OidUnknown { oid: expected_oid })
         }
     }
+}
 
+impl<'a> AlgorithmIdentifierRef<'a> {
     /// Assert `parameters` is an OID and has the expected value.
     pub fn assert_parameters_oid(
         &self,
@@ -87,46 +160,35 @@
                 None => None,
                 Some(p) => match p {
                     AnyRef::NULL => None,
-                    _ => Some(p.oid()?),
+                    _ => Some(p.decode_as::<ObjectIdentifier>()?),
                 },
             },
         ))
     }
 }
 
-impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> {
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
-        reader.read_nested(header.length, |reader| {
-            Ok(Self {
-                oid: reader.decode()?,
-                parameters: reader.decode()?,
-            })
-        })
+#[cfg(feature = "alloc")]
+mod allocating {
+    use super::*;
+    use der::referenced::*;
+
+    impl<'a> RefToOwned<'a> for AlgorithmIdentifierRef<'a> {
+        type Owned = AlgorithmIdentifierOwned;
+        fn ref_to_owned(&self) -> Self::Owned {
+            AlgorithmIdentifier {
+                oid: self.oid,
+                parameters: self.parameters.ref_to_owned(),
+            }
+        }
     }
-}
 
-impl<'a> Sequence<'a> for AlgorithmIdentifier<'a> {
-    fn fields<F, T>(&self, f: F) -> der::Result<T>
-    where
-        F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
-    {
-        f(&[&self.oid, &self.parameters])
-    }
-}
-
-impl<'a> TryFrom<&'a [u8]> for AlgorithmIdentifier<'a> {
-    type Error = Error;
-
-    fn try_from(bytes: &'a [u8]) -> Result<Self> {
-        Ok(Self::from_der(bytes)?)
-    }
-}
-
-impl ValueOrd for AlgorithmIdentifier<'_> {
-    fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
-        match self.oid.der_cmp(&other.oid)? {
-            Ordering::Equal => self.parameters.der_cmp(&other.parameters),
-            other => Ok(other),
+    impl OwnedToRef for AlgorithmIdentifierOwned {
+        type Borrowed<'a> = AlgorithmIdentifierRef<'a>;
+        fn owned_to_ref(&self) -> Self::Borrowed<'_> {
+            AlgorithmIdentifier {
+                oid: self.oid,
+                parameters: self.parameters.owned_to_ref(),
+            }
         }
     }
 }
diff --git a/src/fingerprint.rs b/src/fingerprint.rs
index 6a3901f..ba06e62 100644
--- a/src/fingerprint.rs
+++ b/src/fingerprint.rs
@@ -12,7 +12,6 @@
 /// See [RFC7469 § 2.1.1] for more information.
 ///
 /// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1
-#[cfg_attr(docsrs, doc(cfg(feature = "fingerprint")))]
 pub type FingerprintBytes = [u8; SIZE];
 
 /// Writer newtype which accepts DER being serialized on-the-fly and computes a
diff --git a/src/lib.rs b/src/lib.rs
index 995f3bd..a8b7653 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,13 +1,19 @@
 #![no_std]
-#![cfg_attr(docsrs, feature(doc_cfg))]
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
 #![doc = include_str!("../README.md")]
 #![doc(
-    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
-    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
+    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
+    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
 )]
-#![forbid(unsafe_code, clippy::unwrap_used)]
-#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
-
+#![forbid(unsafe_code)]
+#![warn(
+    clippy::mod_module_files,
+    clippy::unwrap_used,
+    missing_docs,
+    rust_2018_idioms,
+    unused_lifetimes,
+    unused_qualifications
+)]
 //! # Usage
 //! The following example demonstrates how to use an OID as the `parameters`
 //! of an [`AlgorithmIdentifier`].
@@ -15,14 +21,14 @@
 //! Borrow the [`ObjectIdentifier`] first then use [`der::AnyRef::from`] or `.into()`:
 //!
 //! ```
-//! use spki::{AlgorithmIdentifier, ObjectIdentifier, der::AnyRef};
+//! use spki::{AlgorithmIdentifier, ObjectIdentifier};
 //!
 //! let alg_oid = "1.2.840.10045.2.1".parse::<ObjectIdentifier>().unwrap();
 //! let params_oid = "1.2.840.10045.3.1.7".parse::<ObjectIdentifier>().unwrap();
 //!
 //! let alg_id = AlgorithmIdentifier {
 //!     oid: alg_oid,
-//!     parameters: Some(AnyRef::from(&params_oid))
+//!     parameters: Some(params_oid)
 //! };
 //! ```
 
@@ -41,10 +47,10 @@
 mod fingerprint;
 
 pub use crate::{
-    algorithm::AlgorithmIdentifier,
+    algorithm::{AlgorithmIdentifier, AlgorithmIdentifierRef, AlgorithmIdentifierWithOid},
     error::{Error, Result},
-    spki::SubjectPublicKeyInfo,
-    traits::DecodePublicKey,
+    spki::{SubjectPublicKeyInfo, SubjectPublicKeyInfoRef},
+    traits::{AssociatedAlgorithmIdentifier, DecodePublicKey, SignatureAlgorithmIdentifier},
 };
 pub use der::{self, asn1::ObjectIdentifier};
 
@@ -53,7 +59,17 @@
 extern crate std;
 
 #[cfg(feature = "alloc")]
-pub use {crate::traits::EncodePublicKey, der::Document};
+pub use {
+    crate::{
+        algorithm::AlgorithmIdentifierOwned,
+        spki::SubjectPublicKeyInfoOwned,
+        traits::{
+            DynAssociatedAlgorithmIdentifier, DynSignatureAlgorithmIdentifier, EncodePublicKey,
+            SignatureBitStringEncoding,
+        },
+    },
+    der::Document,
+};
 
 #[cfg(feature = "fingerprint")]
 pub use crate::fingerprint::FingerprintBytes;
diff --git a/src/spki.rs b/src/spki.rs
index 9058e49..b7e4c92 100644
--- a/src/spki.rs
+++ b/src/spki.rs
@@ -3,24 +3,30 @@
 use crate::{AlgorithmIdentifier, Error, Result};
 use core::cmp::Ordering;
 use der::{
-    asn1::BitStringRef, Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd,
+    asn1::{AnyRef, BitStringRef},
+    Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag, Header, Length, Reader,
+    Sequence, ValueOrd, Writer,
 };
 
 #[cfg(feature = "alloc")]
-use der::Document;
+use der::{
+    asn1::{Any, BitString},
+    Document,
+};
 
 #[cfg(feature = "fingerprint")]
 use crate::{fingerprint, FingerprintBytes};
 
-#[cfg(all(feature = "alloc", feature = "fingerprint"))]
-use {
-    alloc::string::String,
-    base64ct::{Base64, Encoding},
-};
-
 #[cfg(feature = "pem")]
 use der::pem::PemLabel;
 
+/// [`SubjectPublicKeyInfo`] with [`AnyRef`] algorithm parameters, and [`BitStringRef`] params.
+pub type SubjectPublicKeyInfoRef<'a> = SubjectPublicKeyInfo<AnyRef<'a>, BitStringRef<'a>>;
+
+/// [`SubjectPublicKeyInfo`] with [`Any`] algorithm parameters, and [`BitString`] params.
+#[cfg(feature = "alloc")]
+pub type SubjectPublicKeyInfoOwned = SubjectPublicKeyInfo<Any, BitString>;
+
 /// X.509 `SubjectPublicKeyInfo` (SPKI) as defined in [RFC 5280 § 4.1.2.7].
 ///
 /// ASN.1 structure containing an [`AlgorithmIdentifier`] and public key
@@ -33,25 +39,32 @@
 /// ```
 ///
 /// [RFC 5280 § 4.1.2.7]: https://tools.ietf.org/html/rfc5280#section-4.1.2.7
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct SubjectPublicKeyInfo<'a> {
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct SubjectPublicKeyInfo<Params, Key> {
     /// X.509 [`AlgorithmIdentifier`] for the public key type
-    pub algorithm: AlgorithmIdentifier<'a>,
+    pub algorithm: AlgorithmIdentifier<Params>,
 
     /// Public key data
-    pub subject_public_key: &'a [u8],
+    pub subject_public_key: Key,
 }
 
-impl<'a> SubjectPublicKeyInfo<'a> {
+impl<'a, Params, Key> SubjectPublicKeyInfo<Params, Key>
+where
+    Params: Choice<'a> + Encode,
+    // TODO: replace FixedTag with FixedTag<TAG = { Tag::BitString }> once
+    // https://github.com/rust-lang/rust/issues/92827 is fixed
+    Key: Decode<'a> + Encode + FixedTag,
+{
     /// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] and
     /// encode it as a Base64 string.
     ///
     /// See [RFC7469 § 2.1.1] for more information.
     ///
     /// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1
-    #[cfg(all(feature = "fingerprint", feature = "alloc"))]
-    #[cfg_attr(docsrs, doc(cfg(all(feature = "fingerprint", feature = "alloc"))))]
-    pub fn fingerprint_base64(&self) -> Result<String> {
+    #[cfg(all(feature = "fingerprint", feature = "alloc", feature = "base64"))]
+    pub fn fingerprint_base64(&self) -> Result<alloc::string::String> {
+        use base64ct::{Base64, Encoding};
         Ok(Base64::encode_string(&self.fingerprint_bytes()?))
     }
 
@@ -62,42 +75,56 @@
     ///
     /// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1
     #[cfg(feature = "fingerprint")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "fingerprint")))]
     pub fn fingerprint_bytes(&self) -> Result<FingerprintBytes> {
         let mut builder = fingerprint::Builder::new();
         self.encode(&mut builder)?;
         Ok(builder.finish())
     }
-
-    /// Get a [`BitString`] representing the `subject_public_key`
-    fn bitstring(&self) -> der::Result<BitStringRef<'a>> {
-        BitStringRef::from_bytes(self.subject_public_key)
-    }
 }
 
-impl<'a> DecodeValue<'a> for SubjectPublicKeyInfo<'a> {
+impl<'a: 'k, 'k, Params, Key: 'k> DecodeValue<'a> for SubjectPublicKeyInfo<Params, Key>
+where
+    Params: Choice<'a> + Encode,
+    Key: Decode<'a>,
+{
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
         reader.read_nested(header.length, |reader| {
             Ok(Self {
                 algorithm: reader.decode()?,
-                subject_public_key: BitStringRef::decode(reader)?
-                    .as_bytes()
-                    .ok_or_else(|| der::Tag::BitString.value_error())?,
+                subject_public_key: Key::decode(reader)?,
             })
         })
     }
 }
 
-impl<'a> Sequence<'a> for SubjectPublicKeyInfo<'a> {
-    fn fields<F, T>(&self, f: F) -> der::Result<T>
-    where
-        F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
-    {
-        f(&[&self.algorithm, &self.bitstring()?])
+impl<'a, Params, Key> EncodeValue for SubjectPublicKeyInfo<Params, Key>
+where
+    Params: Choice<'a> + Encode,
+    Key: Encode,
+{
+    fn value_len(&self) -> der::Result<Length> {
+        self.algorithm.encoded_len()? + self.subject_public_key.encoded_len()?
+    }
+
+    fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
+        self.algorithm.encode(writer)?;
+        self.subject_public_key.encode(writer)?;
+        Ok(())
     }
 }
 
-impl<'a> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<'a> {
+impl<'a, Params, Key> Sequence<'a> for SubjectPublicKeyInfo<Params, Key>
+where
+    Params: Choice<'a> + Encode,
+    Key: Decode<'a> + Encode + FixedTag,
+{
+}
+
+impl<'a, Params, Key> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<Params, Key>
+where
+    Params: Choice<'a> + Encode,
+    Key: Decode<'a> + Encode + FixedTag,
+{
     type Error = Error;
 
     fn try_from(bytes: &'a [u8]) -> Result<Self> {
@@ -105,37 +132,86 @@
     }
 }
 
-impl ValueOrd for SubjectPublicKeyInfo<'_> {
+impl<'a, Params, Key> ValueOrd for SubjectPublicKeyInfo<Params, Key>
+where
+    Params: Choice<'a> + DerOrd + Encode,
+    Key: ValueOrd,
+{
     fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
         match self.algorithm.der_cmp(&other.algorithm)? {
-            Ordering::Equal => self.bitstring()?.der_cmp(&other.bitstring()?),
+            Ordering::Equal => self.subject_public_key.value_cmp(&other.subject_public_key),
             other => Ok(other),
         }
     }
 }
 
 #[cfg(feature = "alloc")]
-#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
-impl TryFrom<SubjectPublicKeyInfo<'_>> for Document {
+impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<SubjectPublicKeyInfo<Params, Key>> for Document
+where
+    Params: Choice<'a> + Encode,
+    Key: Decode<'a> + Encode + FixedTag,
+    BitStringRef<'a>: From<&'k Key>,
+{
     type Error = Error;
 
-    fn try_from(spki: SubjectPublicKeyInfo<'_>) -> Result<Document> {
+    fn try_from(spki: SubjectPublicKeyInfo<Params, Key>) -> Result<Document> {
         Self::try_from(&spki)
     }
 }
 
 #[cfg(feature = "alloc")]
-#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
-impl TryFrom<&SubjectPublicKeyInfo<'_>> for Document {
+impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<&SubjectPublicKeyInfo<Params, Key>> for Document
+where
+    Params: Choice<'a> + Encode,
+    Key: Decode<'a> + Encode + FixedTag,
+    BitStringRef<'a>: From<&'k Key>,
+{
     type Error = Error;
 
-    fn try_from(spki: &SubjectPublicKeyInfo<'_>) -> Result<Document> {
+    fn try_from(spki: &SubjectPublicKeyInfo<Params, Key>) -> Result<Document> {
         Ok(Self::encode_msg(spki)?)
     }
 }
 
 #[cfg(feature = "pem")]
-#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
-impl PemLabel for SubjectPublicKeyInfo<'_> {
+impl<Params, Key> PemLabel for SubjectPublicKeyInfo<Params, Key> {
     const PEM_LABEL: &'static str = "PUBLIC KEY";
 }
+
+#[cfg(feature = "alloc")]
+mod allocating {
+    use super::*;
+    use crate::EncodePublicKey;
+    use der::referenced::*;
+
+    impl<'a> RefToOwned<'a> for SubjectPublicKeyInfoRef<'a> {
+        type Owned = SubjectPublicKeyInfoOwned;
+        fn ref_to_owned(&self) -> Self::Owned {
+            SubjectPublicKeyInfo {
+                algorithm: self.algorithm.ref_to_owned(),
+                subject_public_key: self.subject_public_key.ref_to_owned(),
+            }
+        }
+    }
+
+    impl OwnedToRef for SubjectPublicKeyInfoOwned {
+        type Borrowed<'a> = SubjectPublicKeyInfoRef<'a>;
+        fn owned_to_ref(&self) -> Self::Borrowed<'_> {
+            SubjectPublicKeyInfo {
+                algorithm: self.algorithm.owned_to_ref(),
+                subject_public_key: self.subject_public_key.owned_to_ref(),
+            }
+        }
+    }
+
+    impl SubjectPublicKeyInfoOwned {
+        /// Create a [`SubjectPublicKeyInfoOwned`] from any object that implements
+        /// [`EncodePublicKey`].
+        pub fn from_key<T>(source: T) -> Result<Self>
+        where
+            T: EncodePublicKey,
+        {
+            Ok(source.to_public_key_der()?.decode_msg::<Self>()?)
+        }
+    }
+}
diff --git a/src/traits.rs b/src/traits.rs
index c16e397..764b02a 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -1,9 +1,13 @@
 //! Traits for encoding/decoding SPKI public keys.
 
-use crate::{Error, Result, SubjectPublicKeyInfo};
+use crate::{AlgorithmIdentifier, Error, Result, SubjectPublicKeyInfoRef};
+use der::{EncodeValue, Tagged};
 
 #[cfg(feature = "alloc")]
-use der::Document;
+use {
+    crate::AlgorithmIdentifierOwned,
+    der::{asn1::BitString, Any, Document},
+};
 
 #[cfg(feature = "pem")]
 use {
@@ -14,15 +18,14 @@
 #[cfg(feature = "std")]
 use std::path::Path;
 
+#[cfg(doc)]
+use crate::SubjectPublicKeyInfo;
+
 /// Parse a public key object from an encoded SPKI document.
-pub trait DecodePublicKey:
-    for<'a> TryFrom<SubjectPublicKeyInfo<'a>, Error = Error> + Sized
-{
+pub trait DecodePublicKey: Sized {
     /// Deserialize object from ASN.1 DER-encoded [`SubjectPublicKeyInfo`]
     /// (binary format).
-    fn from_public_key_der(bytes: &[u8]) -> Result<Self> {
-        Self::try_from(SubjectPublicKeyInfo::try_from(bytes)?)
-    }
+    fn from_public_key_der(bytes: &[u8]) -> Result<Self>;
 
     /// Deserialize PEM-encoded [`SubjectPublicKeyInfo`].
     ///
@@ -32,17 +35,15 @@
     /// -----BEGIN PUBLIC KEY-----
     /// ```
     #[cfg(feature = "pem")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
     fn from_public_key_pem(s: &str) -> Result<Self> {
         let (label, doc) = Document::from_pem(s)?;
-        SubjectPublicKeyInfo::validate_pem_label(label)?;
+        SubjectPublicKeyInfoRef::validate_pem_label(label)?;
         Self::from_public_key_der(doc.as_bytes())
     }
 
     /// Load public key object from an ASN.1 DER-encoded file on the local
     /// filesystem (binary format).
     #[cfg(feature = "std")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
     fn read_public_key_der_file(path: impl AsRef<Path>) -> Result<Self> {
         let doc = Document::read_der_file(path)?;
         Self::from_public_key_der(doc.as_bytes())
@@ -50,45 +51,134 @@
 
     /// Load public key object from a PEM-encoded file on the local filesystem.
     #[cfg(all(feature = "pem", feature = "std"))]
-    #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))]
     fn read_public_key_pem_file(path: impl AsRef<Path>) -> Result<Self> {
         let (label, doc) = Document::read_pem_file(path)?;
-        SubjectPublicKeyInfo::validate_pem_label(&label)?;
+        SubjectPublicKeyInfoRef::validate_pem_label(&label)?;
         Self::from_public_key_der(doc.as_bytes())
     }
 }
 
+impl<T> DecodePublicKey for T
+where
+    T: for<'a> TryFrom<SubjectPublicKeyInfoRef<'a>, Error = Error>,
+{
+    fn from_public_key_der(bytes: &[u8]) -> Result<Self> {
+        Self::try_from(SubjectPublicKeyInfoRef::try_from(bytes)?)
+    }
+}
+
 /// Serialize a public key object to a SPKI-encoded document.
 #[cfg(feature = "alloc")]
-#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
 pub trait EncodePublicKey {
     /// Serialize a [`Document`] containing a SPKI-encoded public key.
     fn to_public_key_der(&self) -> Result<Document>;
 
     /// Serialize this public key as PEM-encoded SPKI with the given [`LineEnding`].
     #[cfg(feature = "pem")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
     fn to_public_key_pem(&self, line_ending: LineEnding) -> Result<String> {
         let doc = self.to_public_key_der()?;
-        Ok(doc.to_pem(SubjectPublicKeyInfo::PEM_LABEL, line_ending)?)
+        Ok(doc.to_pem(SubjectPublicKeyInfoRef::PEM_LABEL, line_ending)?)
     }
 
     /// Write ASN.1 DER-encoded public key to the given path
     #[cfg(feature = "std")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
     fn write_public_key_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
         Ok(self.to_public_key_der()?.write_der_file(path)?)
     }
 
     /// Write ASN.1 DER-encoded public key to the given path
     #[cfg(all(feature = "pem", feature = "std"))]
-    #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))]
     fn write_public_key_pem_file(
         &self,
         path: impl AsRef<Path>,
         line_ending: LineEnding,
     ) -> Result<()> {
         let doc = self.to_public_key_der()?;
-        Ok(doc.write_pem_file(path, SubjectPublicKeyInfo::PEM_LABEL, line_ending)?)
+        Ok(doc.write_pem_file(path, SubjectPublicKeyInfoRef::PEM_LABEL, line_ending)?)
     }
 }
+
+/// Returns `AlgorithmIdentifier` associated with the structure.
+///
+/// This is useful for e.g. keys for digital signature algorithms.
+pub trait AssociatedAlgorithmIdentifier {
+    /// Algorithm parameters.
+    type Params: Tagged + EncodeValue;
+
+    /// `AlgorithmIdentifier` for this structure.
+    const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params>;
+}
+
+/// Returns `AlgorithmIdentifier` associated with the structure.
+///
+/// This is useful for e.g. keys for digital signature algorithms.
+#[cfg(feature = "alloc")]
+pub trait DynAssociatedAlgorithmIdentifier {
+    /// `AlgorithmIdentifier` for this structure.
+    fn algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>;
+}
+
+#[cfg(feature = "alloc")]
+impl<T> DynAssociatedAlgorithmIdentifier for T
+where
+    T: AssociatedAlgorithmIdentifier,
+{
+    fn algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned> {
+        Ok(AlgorithmIdentifierOwned {
+            oid: T::ALGORITHM_IDENTIFIER.oid,
+            parameters: T::ALGORITHM_IDENTIFIER
+                .parameters
+                .as_ref()
+                .map(Any::encode_from)
+                .transpose()?,
+        })
+    }
+}
+
+/// Returns `AlgorithmIdentifier` associated with the signature system.
+///
+/// Unlike AssociatedAlgorithmIdentifier this is intended to be implemented for public and/or
+/// private keys.
+pub trait SignatureAlgorithmIdentifier {
+    /// Algorithm parameters.
+    type Params: Tagged + EncodeValue;
+
+    /// `AlgorithmIdentifier` for the corresponding singature system.
+    const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params>;
+}
+
+/// Returns `AlgorithmIdentifier` associated with the signature system.
+///
+/// Unlike AssociatedAlgorithmIdentifier this is intended to be implemented for public and/or
+/// private keys.
+#[cfg(feature = "alloc")]
+pub trait DynSignatureAlgorithmIdentifier {
+    /// `AlgorithmIdentifier` for the corresponding singature system.
+    fn signature_algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>;
+}
+
+#[cfg(feature = "alloc")]
+impl<T> DynSignatureAlgorithmIdentifier for T
+where
+    T: SignatureAlgorithmIdentifier,
+{
+    fn signature_algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned> {
+        Ok(AlgorithmIdentifierOwned {
+            oid: T::SIGNATURE_ALGORITHM_IDENTIFIER.oid,
+            parameters: T::SIGNATURE_ALGORITHM_IDENTIFIER
+                .parameters
+                .as_ref()
+                .map(Any::encode_from)
+                .transpose()?,
+        })
+    }
+}
+
+/// Returns the `BitString` encoding of the signature.
+///
+/// X.509 and CSR structures require signatures to be BitString encoded.
+#[cfg(feature = "alloc")]
+pub trait SignatureBitStringEncoding {
+    /// `BitString` encoding for this signature.
+    fn to_bitstring(&self) -> der::Result<BitString>;
+}
diff --git a/tests/spki.rs b/tests/spki.rs
index 3d6b19f..f912d48 100644
--- a/tests/spki.rs
+++ b/tests/spki.rs
@@ -1,7 +1,8 @@
 //! `SubjectPublicKeyInfo` tests.
 
+use der::asn1::ObjectIdentifier;
 use hex_literal::hex;
-use spki::SubjectPublicKeyInfo;
+use spki::SubjectPublicKeyInfoRef;
 
 #[cfg(feature = "alloc")]
 use der::Encode;
@@ -34,40 +35,44 @@
 /// The SPKI fingerprint for `ED25519_SPKI_FINGERPRINT` as a Base64 string
 ///
 /// Generated using `cat ed25519-pub.der | openssl dgst -binary -sha256 | base64`
-#[cfg(all(feature = "fingerprint", feature = "alloc"))]
+#[cfg(all(feature = "alloc", feature = "base64", feature = "fingerprint"))]
 const ED25519_SPKI_FINGERPRINT_BASE64: &str = "Vd1MdLDkhTTi9OFzzs61DfjyenrCqomRzHrpFOAwvO0=";
 
 /// The SPKI fingerprint for `ED25519_SPKI_FINGERPRINT` as straight hash bytes
 ///
 /// Generated using `cat ed25519-pub.der | openssl dgst -sha256`
-#[cfg(all(feature = "fingerprint"))]
+#[cfg(feature = "fingerprint")]
 const ED25519_SPKI_FINGERPRINT: &[u8] =
     &hex!("55dd4c74b0e48534e2f4e173ceceb50df8f27a7ac2aa8991cc7ae914e030bced");
 
 #[test]
 fn decode_ec_p256_der() {
-    let spki = SubjectPublicKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap();
+    let spki = SubjectPublicKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap();
 
     assert_eq!(spki.algorithm.oid, "1.2.840.10045.2.1".parse().unwrap());
 
     assert_eq!(
-        spki.algorithm.parameters.unwrap().oid().unwrap(),
+        spki.algorithm
+            .parameters
+            .unwrap()
+            .decode_as::<ObjectIdentifier>()
+            .unwrap(),
         "1.2.840.10045.3.1.7".parse().unwrap()
     );
 
-    assert_eq!(spki.subject_public_key, &hex!("041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F")[..]);
+    assert_eq!(spki.subject_public_key.raw_bytes(), &hex!("041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F")[..]);
 }
 
 #[test]
 #[cfg(feature = "fingerprint")]
 fn decode_ed25519_and_fingerprint_spki() {
     // Repeat the decode test from the pkcs8 crate
-    let spki = SubjectPublicKeyInfo::try_from(ED25519_DER_EXAMPLE).unwrap();
+    let spki = SubjectPublicKeyInfoRef::try_from(ED25519_DER_EXAMPLE).unwrap();
 
     assert_eq!(spki.algorithm.oid, "1.3.101.112".parse().unwrap());
     assert_eq!(spki.algorithm.parameters, None);
     assert_eq!(
-        spki.subject_public_key,
+        spki.subject_public_key.raw_bytes(),
         &hex!("4D29167F3F1912A6F7ADFA293A051A15C05EC67B8F17267B1C5550DCE853BD0D")[..]
     );
 
@@ -79,15 +84,15 @@
 }
 
 #[test]
-#[cfg(all(feature = "fingerprint", feature = "alloc"))]
+#[cfg(all(feature = "alloc", feature = "base64", feature = "fingerprint"))]
 fn decode_ed25519_and_fingerprint_base64() {
     // Repeat the decode test from the pkcs8 crate
-    let spki = SubjectPublicKeyInfo::try_from(ED25519_DER_EXAMPLE).unwrap();
+    let spki = SubjectPublicKeyInfoRef::try_from(ED25519_DER_EXAMPLE).unwrap();
 
     assert_eq!(spki.algorithm.oid, "1.3.101.112".parse().unwrap());
     assert_eq!(spki.algorithm.parameters, None);
     assert_eq!(
-        spki.subject_public_key,
+        spki.subject_public_key.raw_bytes(),
         &hex!("4D29167F3F1912A6F7ADFA293A051A15C05EC67B8F17267B1C5550DCE853BD0D")[..]
     );
 
@@ -100,41 +105,41 @@
 
 #[test]
 fn decode_rsa_2048_der() {
-    let spki = SubjectPublicKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap();
+    let spki = SubjectPublicKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap();
 
     assert_eq!(spki.algorithm.oid, "1.2.840.113549.1.1.1".parse().unwrap());
     assert!(spki.algorithm.parameters.unwrap().is_null());
-    assert_eq!(spki.subject_public_key, &hex!("3082010A0282010100B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F0203010001")[..]);
+    assert_eq!(spki.subject_public_key.raw_bytes(), &hex!("3082010A0282010100B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F0203010001")[..]);
 }
 
 #[test]
 #[cfg(feature = "alloc")]
 fn encode_ec_p256_der() {
-    let pk = SubjectPublicKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap();
-    let pk_encoded = pk.to_vec().unwrap();
+    let pk = SubjectPublicKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap();
+    let pk_encoded = pk.to_der().unwrap();
     assert_eq!(EC_P256_DER_EXAMPLE, pk_encoded.as_slice());
 }
 
 #[test]
 #[cfg(feature = "alloc")]
 fn encode_ed25519_der() {
-    let pk = SubjectPublicKeyInfo::try_from(ED25519_DER_EXAMPLE).unwrap();
-    let pk_encoded = pk.to_vec().unwrap();
+    let pk = SubjectPublicKeyInfoRef::try_from(ED25519_DER_EXAMPLE).unwrap();
+    let pk_encoded = pk.to_der().unwrap();
     assert_eq!(ED25519_DER_EXAMPLE, pk_encoded.as_slice());
 }
 
 #[test]
 #[cfg(feature = "alloc")]
 fn encode_rsa_2048_der() {
-    let pk = SubjectPublicKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap();
-    let pk_encoded = pk.to_vec().unwrap();
+    let pk = SubjectPublicKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap();
+    let pk_encoded = pk.to_der().unwrap();
     assert_eq!(RSA_2048_DER_EXAMPLE, pk_encoded.as_slice());
 }
 
 #[test]
 #[cfg(feature = "pem")]
 fn encode_ec_p256_pem() {
-    let pk = SubjectPublicKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap();
+    let pk = SubjectPublicKeyInfoRef::try_from(EC_P256_DER_EXAMPLE).unwrap();
     let pk_encoded = pk.to_pem(LineEnding::LF).unwrap();
     assert_eq!(EC_P256_PEM_EXAMPLE, pk_encoded);
 }
@@ -142,7 +147,7 @@
 #[test]
 #[cfg(feature = "pem")]
 fn encode_ed25519_pem() {
-    let pk = SubjectPublicKeyInfo::try_from(ED25519_DER_EXAMPLE).unwrap();
+    let pk = SubjectPublicKeyInfoRef::try_from(ED25519_DER_EXAMPLE).unwrap();
     let pk_encoded = pk.to_pem(LineEnding::LF).unwrap();
     assert_eq!(ED25519_PEM_EXAMPLE, pk_encoded);
 }
@@ -150,7 +155,7 @@
 #[test]
 #[cfg(feature = "pem")]
 fn encode_rsa_2048_pem() {
-    let pk = SubjectPublicKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap();
+    let pk = SubjectPublicKeyInfoRef::try_from(RSA_2048_DER_EXAMPLE).unwrap();
     let pk_encoded = pk.to_pem(LineEnding::LF).unwrap();
     assert_eq!(RSA_2048_PEM_EXAMPLE, pk_encoded);
 }
diff --git a/tests/traits.rs b/tests/traits.rs
index 597399e..1114333 100644
--- a/tests/traits.rs
+++ b/tests/traits.rs
@@ -3,7 +3,7 @@
 #![cfg(any(feature = "pem", feature = "std"))]
 
 use der::{Decode, Encode};
-use spki::{DecodePublicKey, Document, EncodePublicKey, Error, Result, SubjectPublicKeyInfo};
+use spki::{DecodePublicKey, Document, EncodePublicKey, Error, Result, SubjectPublicKeyInfoRef};
 
 #[cfg(feature = "pem")]
 use spki::der::pem::LineEnding;
@@ -30,23 +30,17 @@
     }
 }
 
-impl DecodePublicKey for MockKey {
-    fn from_public_key_der(bytes: &[u8]) -> Result<MockKey> {
-        Ok(MockKey(bytes.to_vec()))
-    }
-}
-
 impl EncodePublicKey for MockKey {
     fn to_public_key_der(&self) -> Result<Document> {
         Ok(Document::from_der(self.as_ref())?)
     }
 }
 
-impl TryFrom<SubjectPublicKeyInfo<'_>> for MockKey {
+impl TryFrom<SubjectPublicKeyInfoRef<'_>> for MockKey {
     type Error = Error;
 
-    fn try_from(spki: SubjectPublicKeyInfo<'_>) -> Result<MockKey> {
-        Ok(MockKey(spki.to_vec()?))
+    fn try_from(spki: SubjectPublicKeyInfoRef<'_>) -> Result<MockKey> {
+        Ok(MockKey(spki.to_der()?))
     }
 }