From b48d95d7c169cc6defb2e5605d181ab2cc5a2143 Mon Sep 17 00:00:00 2001
From: turbocool3r <turbocooler@cocaine.ninja>
Date: Mon, 8 May 2023 23:16:51 +0300
Subject: [PATCH] Add custom error types support to the Decode and DecodeValue
 traits.

---
 Cargo.lock                                |  6 +--
 Cargo.toml                                |  4 ++
 crmf/src/pop.rs                           |  2 +
 der/derive/src/choice.rs                  |  2 +
 der/derive/src/enumerated.rs              |  2 +
 der/derive/src/sequence.rs                |  2 +
 der/src/asn1/any.rs                       | 58 +++++++++++++----------
 der/src/asn1/bit_string.rs                |  6 +++
 der/src/asn1/bmp_string.rs                |  2 +
 der/src/asn1/boolean.rs                   |  2 +
 der/src/asn1/context_specific.rs          | 39 ++++++++-------
 der/src/asn1/generalized_time.rs          | 16 +++++--
 der/src/asn1/integer/int.rs               | 12 +++--
 der/src/asn1/integer/uint.rs              | 10 +++-
 der/src/asn1/internal_macros.rs           |  8 ++--
 der/src/asn1/null.rs                      |  4 ++
 der/src/asn1/octet_string.rs              | 32 ++++++++-----
 der/src/asn1/oid.rs                       |  2 +
 der/src/asn1/optional.rs                  | 16 ++++---
 der/src/asn1/real.rs                      |  6 ++-
 der/src/asn1/sequence.rs                  |  5 +-
 der/src/asn1/sequence_of.rs               | 38 ++++++++-------
 der/src/asn1/set_of.rs                    | 58 ++++++++++++-----------
 der/src/asn1/utc_time.rs                  |  2 +
 der/src/asn1/utf8_string.rs               |  2 +
 der/src/bytes_owned.rs                    |  2 +
 der/src/bytes_ref.rs                      |  2 +
 der/src/decode.rs                         | 42 ++++++++++------
 der/src/document.rs                       | 58 +++++++++++++----------
 der/src/header.rs                         |  4 +-
 der/src/length.rs                         |  4 ++
 der/src/lib.rs                            |  2 +
 der/src/reader.rs                         | 42 +++++++++-------
 der/src/reader/slice.rs                   | 20 ++++----
 der/src/str_owned.rs                      |  6 ++-
 der/src/str_ref.rs                        |  4 +-
 der/src/tag.rs                            |  2 +
 gss-api/src/lib.rs                        |  2 +
 pkcs1/src/params.rs                       |  5 ++
 pkcs1/src/private_key.rs                  |  4 ++
 pkcs1/src/private_key/other_prime_info.rs |  2 +
 pkcs1/src/public_key.rs                   |  1 +
 pkcs1/src/version.rs                      |  1 +
 pkcs12/src/safe_bag.rs                    |  2 +
 pkcs5/src/lib.rs                          |  2 +
 pkcs5/src/pbes1.rs                        |  4 ++
 pkcs5/src/pbes2.rs                        |  4 ++
 pkcs5/src/pbes2/kdf.rs                    |  5 ++
 pkcs5/src/pbes2/kdf/salt.rs               |  2 +
 pkcs8/src/encrypted_private_key_info.rs   |  2 +
 pkcs8/src/private_key_info.rs             |  2 +
 pkcs8/src/version.rs                      |  2 +
 sec1/src/parameters.rs                    |  2 +
 sec1/src/private_key.rs                   |  2 +
 spki/src/algorithm.rs                     | 11 +++--
 spki/src/spki.rs                          | 30 ++++++------
 x509-cert/src/certificate.rs              | 16 ++++---
 x509-cert/src/macros.rs                   |  2 +
 x509-cert/src/serial_number.rs            |  2 +
 x509-cert/tests/certificate.rs            |  4 ++
 60 files changed, 410 insertions(+), 223 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index f5af32085..4dc40c19c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -562,8 +562,7 @@ dependencies = [
 [[package]]
 name = "ecdsa"
 version = "0.17.0-pre.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7e045ee5c360512162782f3d4cb07d2f4ce8c4ef9bf7c77ec16d1cf60b3d5ca"
+source = "git+https://github.com/turbocool3r/signatures?branch=custom-errors#d9d394ad7a87de8943a0eb39b85f316149ebb025"
 dependencies = [
  "der",
  "digest 0.11.0-pre.8",
@@ -1272,8 +1271,7 @@ checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca"
 [[package]]
 name = "rfc6979"
 version = "0.5.0-pre.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "045972f2f66b9467a2f6834b7fd0f9b23ca214b4a8700b880c36edb726e96da6"
+source = "git+https://github.com/turbocool3r/signatures?branch=custom-errors#d9d394ad7a87de8943a0eb39b85f316149ebb025"
 dependencies = [
  "hmac 0.13.0-pre.3",
  "subtle",
diff --git a/Cargo.toml b/Cargo.toml
index c2497b7e4..ca136aa55 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -64,3 +64,7 @@ x509-ocsp         = { path = "./x509-ocsp" }
 p256 = { git = "https://github.com/RustCrypto/elliptic-curves.git" }
 # Pending a release of 0.11.0-pre.2
 whirlpool = { git = "https://github.com/RustCrypto/hashes.git" }
+
+# https://github.com/RustCrypto/formats/pull/1055
+# https://github.com/RustCrypto/signatures/pull/809
+ecdsa = { git = "https://github.com/turbocool3r/signatures", branch = "custom-errors" }
diff --git a/crmf/src/pop.rs b/crmf/src/pop.rs
index dbb56ac3b..e2aa88bf7 100644
--- a/crmf/src/pop.rs
+++ b/crmf/src/pop.rs
@@ -231,6 +231,8 @@ impl<'a> ::der::Choice<'a> for EncKeyWithIdChoice<'a> {
     }
 }
 impl<'a> ::der::Decode<'a> for EncKeyWithIdChoice<'a> {
+    type Error = ::der::Error;
+
     fn decode<R: ::der::Reader<'a>>(reader: &mut R) -> ::der::Result<Self> {
         let t = reader.peek_tag()?;
         if t == <Utf8StringRef<'a> as ::der::FixedTag>::TAG {
diff --git a/der/derive/src/choice.rs b/der/derive/src/choice.rs
index fb2ff0c91..707ca9c8e 100644
--- a/der/derive/src/choice.rs
+++ b/der/derive/src/choice.rs
@@ -96,6 +96,8 @@ impl DeriveChoice {
             }
 
             impl<#lifetime> ::der::Decode<#lifetime> for #ident<#lt_params> {
+                type Error = ::der::Error;
+
                 fn decode<R: ::der::Reader<#lifetime>>(reader: &mut R) -> ::der::Result<Self> {
                     use der::Reader as _;
                     match reader.peek_tag()? {
diff --git a/der/derive/src/enumerated.rs b/der/derive/src/enumerated.rs
index ecf863557..303014140 100644
--- a/der/derive/src/enumerated.rs
+++ b/der/derive/src/enumerated.rs
@@ -117,6 +117,8 @@ impl DeriveEnumerated {
 
         quote! {
             impl<#default_lifetime> ::der::DecodeValue<#default_lifetime> for #ident {
+                type Error = ::der::Error;
+
                 fn decode_value<R: ::der::Reader<#default_lifetime>>(
                     reader: &mut R,
                     header: ::der::Header
diff --git a/der/derive/src/sequence.rs b/der/derive/src/sequence.rs
index 26fc59f7c..81ca3d729 100644
--- a/der/derive/src/sequence.rs
+++ b/der/derive/src/sequence.rs
@@ -86,6 +86,8 @@ impl DeriveSequence {
 
         quote! {
             impl #impl_generics ::der::DecodeValue<#lifetime> for #ident #ty_generics #where_clause {
+                type Error = ::der::Error;
+
                 fn decode_value<R: ::der::Reader<#lifetime>>(
                     reader: &mut R,
                     header: ::der::Header,
diff --git a/der/src/asn1/any.rs b/der/src/asn1/any.rs
index 2682b56ef..1ed9286c0 100644
--- a/der/src/asn1/any.rs
+++ b/der/src/asn1/any.rs
@@ -4,7 +4,7 @@
 
 use crate::{
     BytesRef, Choice, Decode, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, Header, Length,
-    Reader, Result, SliceReader, Tag, Tagged, ValueOrd, Writer,
+    Reader, SliceReader, Tag, Tagged, ValueOrd, Writer,
 };
 use core::cmp::Ordering;
 
@@ -40,7 +40,7 @@ impl<'a> AnyRef<'a> {
     };
 
     /// Create a new [`AnyRef`] from the provided [`Tag`] and DER bytes.
-    pub fn new(tag: Tag, bytes: &'a [u8]) -> Result<Self> {
+    pub fn new(tag: Tag, bytes: &'a [u8]) -> Result<Self, Error> {
         let value = BytesRef::new(bytes).map_err(|_| ErrorKind::Length { tag })?;
         Ok(Self { tag, value })
     }
@@ -56,12 +56,12 @@ impl<'a> AnyRef<'a> {
     }
 
     /// Attempt to decode this [`AnyRef`] type into the inner value.
-    pub fn decode_as<T>(self) -> Result<T>
+    pub fn decode_as<T>(self) -> Result<T, <T as DecodeValue<'a>>::Error>
     where
         T: Choice<'a> + DecodeValue<'a>,
     {
         if !T::can_decode(self.tag) {
-            return Err(self.tag.unexpected_error(None));
+            return Err(self.tag.unexpected_error(None).into());
         }
 
         let header = Header {
@@ -71,7 +71,7 @@ impl<'a> AnyRef<'a> {
 
         let mut decoder = SliceReader::new(self.value())?;
         let result = T::decode_value(&mut decoder, header)?;
-        decoder.finish(result)
+        Ok(decoder.finish(result)?)
     }
 
     /// Is this value an ASN.1 `NULL` value?
@@ -81,14 +81,15 @@ impl<'a> AnyRef<'a> {
 
     /// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new
     /// nested reader and calling the provided argument with it.
-    pub fn sequence<F, T>(self, f: F) -> Result<T>
+    pub fn sequence<F, T, E>(self, f: F) -> Result<T, E>
     where
-        F: FnOnce(&mut SliceReader<'a>) -> Result<T>,
+        F: FnOnce(&mut SliceReader<'a>) -> Result<T, E>,
+        E: From<Error>,
     {
         self.tag.assert_eq(Tag::Sequence)?;
         let mut reader = SliceReader::new(self.value.as_slice())?;
         let result = f(&mut reader)?;
-        reader.finish(result)
+        Ok(reader.finish(result)?)
     }
 }
 
@@ -99,14 +100,18 @@ impl<'a> Choice<'a> for AnyRef<'a> {
 }
 
 impl<'a> Decode<'a> for AnyRef<'a> {
-    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<AnyRef<'a>> {
+    type Error = Error;
+
+    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<AnyRef<'a>, Error> {
         let header = Header::decode(reader)?;
         Self::decode_value(reader, header)
     }
 }
 
 impl<'a> DecodeValue<'a> for AnyRef<'a> {
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+    type Error = Error;
+
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Error> {
         Ok(Self {
             tag: header.tag,
             value: BytesRef::decode_value(reader, header)?,
@@ -115,11 +120,11 @@ impl<'a> DecodeValue<'a> for AnyRef<'a> {
 }
 
 impl EncodeValue for AnyRef<'_> {
-    fn value_len(&self) -> Result<Length> {
+    fn value_len(&self) -> Result<Length, Error> {
         Ok(self.value.len())
     }
 
-    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
         writer.write(self.value())
     }
 }
@@ -131,7 +136,7 @@ impl Tagged for AnyRef<'_> {
 }
 
 impl ValueOrd for AnyRef<'_> {
-    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+    fn value_cmp(&self, other: &Self) -> Result<Ordering, Error> {
         self.value.der_cmp(&other.value)
     }
 }
@@ -145,7 +150,7 @@ impl<'a> From<AnyRef<'a>> for BytesRef<'a> {
 impl<'a> TryFrom<&'a [u8]> for AnyRef<'a> {
     type Error = Error;
 
-    fn try_from(bytes: &'a [u8]) -> Result<AnyRef<'a>> {
+    fn try_from(bytes: &'a [u8]) -> Result<AnyRef<'a>, Error> {
         AnyRef::from_der(bytes)
     }
 }
@@ -175,7 +180,7 @@ mod allocating {
 
     impl Any {
         /// Create a new [`Any`] from the provided [`Tag`] and DER bytes.
-        pub fn new(tag: Tag, bytes: impl Into<Box<[u8]>>) -> Result<Self> {
+        pub fn new(tag: Tag, bytes: impl Into<Box<[u8]>>) -> Result<Self, Error> {
             let value = BytesOwned::new(bytes)?;
 
             // Ensure the tag and value are a valid `AnyRef`.
@@ -189,7 +194,7 @@ mod allocating {
         }
 
         /// Attempt to decode this [`Any`] type into the inner value.
-        pub fn decode_as<'a, T>(&'a self) -> Result<T>
+        pub fn decode_as<'a, T>(&'a self) -> Result<T, <T as DecodeValue<'a>>::Error>
         where
             T: Choice<'a> + DecodeValue<'a>,
         {
@@ -197,7 +202,7 @@ mod allocating {
         }
 
         /// Encode the provided type as an [`Any`] value.
-        pub fn encode_from<T>(msg: &T) -> Result<Self>
+        pub fn encode_from<T>(msg: &T) -> Result<Self, Error>
         where
             T: Tagged + EncodeValue,
         {
@@ -211,9 +216,10 @@ mod allocating {
 
         /// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new
         /// nested reader and calling the provided argument with it.
-        pub fn sequence<'a, F, T>(&'a self, f: F) -> Result<T>
+        pub fn sequence<'a, F, T, E>(&'a self, f: F) -> Result<T, E>
         where
-            F: FnOnce(&mut SliceReader<'a>) -> Result<T>,
+            F: FnOnce(&mut SliceReader<'a>) -> Result<T, E>,
+            E: From<Error>,
         {
             AnyRef::from(self).sequence(f)
         }
@@ -234,25 +240,29 @@ mod allocating {
     }
 
     impl<'a> Decode<'a> for Any {
-        fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
+        type Error = Error;
+
+        fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self, Error> {
             let header = Header::decode(reader)?;
             Self::decode_value(reader, header)
         }
     }
 
     impl<'a> DecodeValue<'a> for Any {
-        fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+        type Error = Error;
+
+        fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Error> {
             let value = reader.read_vec(header.length)?;
             Self::new(header.tag, value)
         }
     }
 
     impl EncodeValue for Any {
-        fn value_len(&self) -> Result<Length> {
+        fn value_len(&self) -> Result<Length, Error> {
             Ok(self.value.len())
         }
 
-        fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+        fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
             writer.write(self.value.as_slice())
         }
     }
@@ -271,7 +281,7 @@ mod allocating {
     }
 
     impl ValueOrd for Any {
-        fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+        fn value_cmp(&self, other: &Self) -> Result<Ordering, Error> {
             self.value.der_cmp(&other.value)
         }
     }
diff --git a/der/src/asn1/bit_string.rs b/der/src/asn1/bit_string.rs
index cd9f6d3fd..c30a06042 100644
--- a/der/src/asn1/bit_string.rs
+++ b/der/src/asn1/bit_string.rs
@@ -120,6 +120,8 @@ impl<'a> BitStringRef<'a> {
 impl_any_conversions!(BitStringRef<'a>, 'a);
 
 impl<'a> DecodeValue<'a> for BitStringRef<'a> {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         let header = Header {
             tag: header.tag,
@@ -309,6 +311,8 @@ mod allocating {
     impl_any_conversions!(BitString);
 
     impl<'a> DecodeValue<'a> for BitString {
+        type Error = Error;
+
         fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
             let inner_len = (header.length - Length::ONE)?;
             let unused_bits = reader.read_byte()?;
@@ -442,6 +446,8 @@ where
     T::Type: From<bool>,
     T::Type: core::ops::Shl<usize, Output = T::Type>,
 {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         let position = reader.position();
         let bits = BitStringRef::decode_value(reader, header)?;
diff --git a/der/src/asn1/bmp_string.rs b/der/src/asn1/bmp_string.rs
index ad5e1a2d1..fa42d1ae4 100644
--- a/der/src/asn1/bmp_string.rs
+++ b/der/src/asn1/bmp_string.rs
@@ -90,6 +90,8 @@ impl AsRef<[u8]> for BmpString {
 }
 
 impl<'a> DecodeValue<'a> for BmpString {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         Self::from_ucs2(reader.read_vec(header.length)?)
     }
diff --git a/der/src/asn1/boolean.rs b/der/src/asn1/boolean.rs
index e99ad44b6..3bbc03341 100644
--- a/der/src/asn1/boolean.rs
+++ b/der/src/asn1/boolean.rs
@@ -15,6 +15,8 @@ const TRUE_OCTET: u8 = 0b11111111;
 const FALSE_OCTET: u8 = 0b00000000;
 
 impl<'a> DecodeValue<'a> for bool {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         if header.length != Length::ONE {
             return Err(reader.error(ErrorKind::Length { tag: Self::TAG }));
diff --git a/der/src/asn1/context_specific.rs b/der/src/asn1/context_specific.rs
index 09031f0d4..6867029da 100644
--- a/der/src/asn1/context_specific.rs
+++ b/der/src/asn1/context_specific.rs
@@ -2,7 +2,7 @@
 
 use crate::{
     asn1::AnyRef, Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error,
-    Header, Length, Reader, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer,
+    Header, Length, Reader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer,
 };
 use core::cmp::Ordering;
 
@@ -42,7 +42,7 @@ impl<T> ContextSpecific<T> {
     pub fn decode_explicit<'a, R: Reader<'a>>(
         reader: &mut R,
         tag_number: TagNumber,
-    ) -> Result<Option<Self>>
+    ) -> Result<Option<Self>, T::Error>
     where
         T: Decode<'a>,
     {
@@ -58,16 +58,16 @@ impl<T> ContextSpecific<T> {
     pub fn decode_implicit<'a, R: Reader<'a>>(
         reader: &mut R,
         tag_number: TagNumber,
-    ) -> Result<Option<Self>>
+    ) -> Result<Option<Self>, T::Error>
     where
         T: DecodeValue<'a> + Tagged,
     {
-        Self::decode_with(reader, tag_number, |reader| {
+        Self::decode_with::<_, _, T::Error>(reader, tag_number, |reader| {
             let header = Header::decode(reader)?;
             let value = T::decode_value(reader, header)?;
 
             if header.tag.is_constructed() != value.tag().is_constructed() {
-                return Err(header.tag.non_canonical_error());
+                return Err(header.tag.non_canonical_error().into());
             }
 
             Ok(Self {
@@ -80,13 +80,14 @@ impl<T> ContextSpecific<T> {
 
     /// Attempt to decode a context-specific field with the given
     /// helper callback.
-    fn decode_with<'a, F, R: Reader<'a>>(
+    fn decode_with<'a, F, R: Reader<'a>, E>(
         reader: &mut R,
         tag_number: TagNumber,
         f: F,
-    ) -> Result<Option<Self>>
+    ) -> Result<Option<Self>, E>
     where
-        F: FnOnce(&mut R) -> Result<Self>,
+        F: FnOnce(&mut R) -> Result<Self, E>,
+        E: From<Error>,
     {
         while let Some(octet) = reader.peek_byte() {
             let tag = Tag::try_from(octet)?;
@@ -117,7 +118,9 @@ impl<'a, T> Decode<'a> for ContextSpecific<T>
 where
     T: Decode<'a>,
 {
-    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
+    type Error = T::Error;
+
+    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self, Self::Error> {
         let header = Header::decode(reader)?;
 
         match header.tag {
@@ -129,7 +132,7 @@ where
                 tag_mode: TagMode::default(),
                 value: reader.read_nested(header.length, |reader| T::decode(reader))?,
             }),
-            tag => Err(tag.unexpected_error(None)),
+            tag => Err(tag.unexpected_error(None).into()),
         }
     }
 }
@@ -138,14 +141,14 @@ impl<T> EncodeValue for ContextSpecific<T>
 where
     T: EncodeValue + Tagged,
 {
-    fn value_len(&self) -> Result<Length> {
+    fn value_len(&self) -> Result<Length, Error> {
         match self.tag_mode {
             TagMode::Explicit => self.value.encoded_len(),
             TagMode::Implicit => self.value.value_len(),
         }
     }
 
-    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
         match self.tag_mode {
             TagMode::Explicit => self.value.encode(writer),
             TagMode::Implicit => self.value.encode_value(writer),
@@ -174,9 +177,9 @@ impl<'a, T> TryFrom<AnyRef<'a>> for ContextSpecific<T>
 where
     T: Decode<'a>,
 {
-    type Error = Error;
+    type Error = T::Error;
 
-    fn try_from(any: AnyRef<'a>) -> Result<ContextSpecific<T>> {
+    fn try_from(any: AnyRef<'a>) -> Result<ContextSpecific<T>, Self::Error> {
         match any.tag() {
             Tag::ContextSpecific {
                 number,
@@ -186,7 +189,7 @@ where
                 tag_mode: TagMode::default(),
                 value: T::from_der(any.value())?,
             }),
-            tag => Err(tag.unexpected_error(None)),
+            tag => Err(tag.unexpected_error(None).into()),
         }
     }
 }
@@ -195,7 +198,7 @@ impl<T> ValueOrd for ContextSpecific<T>
 where
     T: EncodeValue + ValueOrd + Tagged,
 {
-    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+    fn value_cmp(&self, other: &Self) -> Result<Ordering, Error> {
         match self.tag_mode {
             TagMode::Explicit => self.der_cmp(other),
             TagMode::Implicit => self.value_cmp(other),
@@ -235,11 +238,11 @@ impl<'a, T> EncodeValue for ContextSpecificRef<'a, T>
 where
     T: EncodeValue + Tagged,
 {
-    fn value_len(&self) -> Result<Length> {
+    fn value_len(&self) -> Result<Length, Error> {
         self.encoder().value_len()
     }
 
-    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
         self.encoder().encode_value(writer)
     }
 }
diff --git a/der/src/asn1/generalized_time.rs b/der/src/asn1/generalized_time.rs
index e2b509008..7c77d26bf 100644
--- a/der/src/asn1/generalized_time.rs
+++ b/der/src/asn1/generalized_time.rs
@@ -4,15 +4,13 @@
 use crate::{
     datetime::{self, DateTime},
     ord::OrdIsValueOrd,
-    DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer,
+    DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag,
+    Writer,
 };
 use core::time::Duration;
 
 #[cfg(feature = "std")]
-use {
-    crate::{asn1::AnyRef, Error},
-    std::time::SystemTime,
-};
+use {crate::asn1::AnyRef, std::time::SystemTime};
 
 #[cfg(feature = "time")]
 use time::PrimitiveDateTime;
@@ -77,6 +75,8 @@ impl GeneralizedTime {
 impl_any_conversions!(GeneralizedTime);
 
 impl<'a> DecodeValue<'a> for GeneralizedTime {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         if Self::LENGTH != usize::try_from(header.length)? {
             return Err(Self::TAG.value_error());
@@ -166,6 +166,8 @@ impl From<&DateTime> for GeneralizedTime {
 }
 
 impl<'a> DecodeValue<'a> for DateTime {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         Ok(GeneralizedTime::decode_value(reader, header)?.into())
     }
@@ -189,6 +191,8 @@ impl OrdIsValueOrd for DateTime {}
 
 #[cfg(feature = "std")]
 impl<'a> DecodeValue<'a> for SystemTime {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         Ok(GeneralizedTime::decode_value(reader, header)?.into())
     }
@@ -256,6 +260,8 @@ impl OrdIsValueOrd for SystemTime {}
 
 #[cfg(feature = "time")]
 impl<'a> DecodeValue<'a> for PrimitiveDateTime {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         GeneralizedTime::decode_value(reader, header)?.try_into()
     }
diff --git a/der/src/asn1/integer/int.rs b/der/src/asn1/integer/int.rs
index ccec93fe4..4e7755160 100644
--- a/der/src/asn1/integer/int.rs
+++ b/der/src/asn1/integer/int.rs
@@ -14,7 +14,9 @@ macro_rules! impl_encoding_traits {
     ($($int:ty => $uint:ty),+) => {
         $(
             impl<'a> DecodeValue<'a> for $int {
-                fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+                type Error = $crate::Error;
+
+                fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> $crate::Result<Self> {
                     let mut buf = [0u8; Self::BITS as usize / 8];
                     let max_length = u32::from(header.length) as usize;
 
@@ -122,6 +124,8 @@ impl<'a> IntRef<'a> {
 impl_any_conversions!(IntRef<'a>, 'a);
 
 impl<'a> DecodeValue<'a> for IntRef<'a> {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         let bytes = BytesRef::decode_value(reader, header)?;
         validate_canonical(bytes.as_slice())?;
@@ -167,8 +171,8 @@ mod allocating {
         asn1::Uint,
         ord::OrdIsValueOrd,
         referenced::{OwnedToRef, RefToOwned},
-        BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result,
-        Tag, Writer,
+        BytesOwned, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader,
+        Result, Tag, Writer,
     };
     use alloc::vec::Vec;
 
@@ -214,6 +218,8 @@ mod allocating {
     impl_any_conversions!(Int);
 
     impl<'a> DecodeValue<'a> for Int {
+        type Error = Error;
+
         fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
             let bytes = BytesOwned::decode_value(reader, header)?;
             validate_canonical(bytes.as_slice())?;
diff --git a/der/src/asn1/integer/uint.rs b/der/src/asn1/integer/uint.rs
index a9bb966b0..0c65f25f8 100644
--- a/der/src/asn1/integer/uint.rs
+++ b/der/src/asn1/integer/uint.rs
@@ -14,6 +14,8 @@ macro_rules! impl_encoding_traits {
     ($($uint:ty),+) => {
         $(
             impl<'a> DecodeValue<'a> for $uint {
+                type Error = $crate::Error;
+
                 fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
                     // Integers always encodes as a signed value, unsigned gets a leading 0x00 that
                     // needs to be stripped off. We need to provide room for it.
@@ -114,6 +116,8 @@ impl<'a> UintRef<'a> {
 impl_any_conversions!(UintRef<'a>, 'a);
 
 impl<'a> DecodeValue<'a> for UintRef<'a> {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         let bytes = BytesRef::decode_value(reader, header)?.as_slice();
         let result = Self::new(decode_to_slice(bytes)?)?;
@@ -160,8 +164,8 @@ mod allocating {
     use crate::{
         ord::OrdIsValueOrd,
         referenced::{OwnedToRef, RefToOwned},
-        BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result,
-        Tag, Writer,
+        BytesOwned, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader,
+        Result, Tag, Writer,
     };
 
     /// Unsigned arbitrary precision ASN.1 `INTEGER` type.
@@ -206,6 +210,8 @@ mod allocating {
     impl_any_conversions!(Uint);
 
     impl<'a> DecodeValue<'a> for Uint {
+        type Error = Error;
+
         fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
             let bytes = BytesOwned::decode_value(reader, header)?;
             let result = Self::new(decode_to_slice(bytes.as_slice())?)?;
diff --git a/der/src/asn1/internal_macros.rs b/der/src/asn1/internal_macros.rs
index 10ad99d23..1872c73c4 100644
--- a/der/src/asn1/internal_macros.rs
+++ b/der/src/asn1/internal_macros.rs
@@ -6,7 +6,7 @@ macro_rules! impl_any_conversions {
         impl<'__der: $($li),*, $($li),*> TryFrom<$crate::AnyRef<'__der>> for $type {
             type Error = $crate::Error;
 
-            fn try_from(any: $crate::AnyRef<'__der>) -> Result<$type> {
+            fn try_from(any: $crate::AnyRef<'__der>) -> $crate::Result<$type> {
                 any.decode_as()
             }
         }
@@ -15,7 +15,7 @@ macro_rules! impl_any_conversions {
         impl<'__der: $($li),*, $($li),*> TryFrom<&'__der $crate::Any> for $type {
             type Error = $crate::Error;
 
-            fn try_from(any: &'__der $crate::Any) -> Result<$type> {
+            fn try_from(any: &'__der $crate::Any) -> $crate::Result<$type> {
                 any.decode_as()
             }
         }
@@ -48,7 +48,9 @@ macro_rules! impl_string_type {
             }
 
             impl<'__der: $($li),*, $($li),*> DecodeValue<'__der> for $type {
-                fn decode_value<R: Reader<'__der>>(reader: &mut R, header: Header) -> Result<Self> {
+                type Error = $crate::Error;
+
+                fn decode_value<R: Reader<'__der>>(reader: &mut R, header: Header) -> $crate::Result<Self> {
                     Self::new(BytesRef::decode_value(reader, header)?.as_slice())
                 }
             }
diff --git a/der/src/asn1/null.rs b/der/src/asn1/null.rs
index 43847218c..be66e02cf 100644
--- a/der/src/asn1/null.rs
+++ b/der/src/asn1/null.rs
@@ -12,6 +12,8 @@ pub struct Null;
 impl_any_conversions!(Null);
 
 impl<'a> DecodeValue<'a> for Null {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         if header.length.is_zero() {
             Ok(Null)
@@ -58,6 +60,8 @@ impl<'a> From<()> for AnyRef<'a> {
 }
 
 impl<'a> DecodeValue<'a> for () {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         Null::decode_value(reader, header)?;
         Ok(())
diff --git a/der/src/asn1/octet_string.rs b/der/src/asn1/octet_string.rs
index 12a1e0e4d..3a0a87a2d 100644
--- a/der/src/asn1/octet_string.rs
+++ b/der/src/asn1/octet_string.rs
@@ -1,8 +1,8 @@
 //! ASN.1 `OCTET STRING` support.
 
 use crate::{
-    asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, Decode, DecodeValue, EncodeValue, ErrorKind,
-    FixedTag, Header, Length, Reader, Result, Tag, Writer,
+    asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, Decode, DecodeValue, EncodeValue, Error, ErrorKind,
+    FixedTag, Header, Length, Reader, Tag, Writer,
 };
 
 /// ASN.1 `OCTET STRING` type: borrowed form.
@@ -18,7 +18,7 @@ pub struct OctetStringRef<'a> {
 
 impl<'a> OctetStringRef<'a> {
     /// Create a new ASN.1 `OCTET STRING` from a byte slice.
-    pub fn new(slice: &'a [u8]) -> Result<Self> {
+    pub fn new(slice: &'a [u8]) -> Result<Self, Error> {
         BytesRef::new(slice)
             .map(|inner| Self { inner })
             .map_err(|_| ErrorKind::Length { tag: Self::TAG }.into())
@@ -40,7 +40,7 @@ impl<'a> OctetStringRef<'a> {
     }
 
     /// Parse `T` from this `OCTET STRING`'s contents.
-    pub fn decode_into<T: Decode<'a>>(&self) -> Result<T> {
+    pub fn decode_into<T: Decode<'a>>(&self) -> Result<T, T::Error> {
         Decode::from_der(self.as_bytes())
     }
 }
@@ -54,18 +54,20 @@ impl AsRef<[u8]> for OctetStringRef<'_> {
 }
 
 impl<'a> DecodeValue<'a> for OctetStringRef<'a> {
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+    type Error = Error;
+
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Error> {
         let inner = BytesRef::decode_value(reader, header)?;
         Ok(Self { inner })
     }
 }
 
 impl EncodeValue for OctetStringRef<'_> {
-    fn value_len(&self) -> Result<Length> {
+    fn value_len(&self) -> Result<Length, Error> {
         self.inner.value_len()
     }
 
-    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
         self.inner.encode_value(writer)
     }
 }
@@ -117,7 +119,7 @@ mod allocating {
 
     impl OctetString {
         /// Create a new ASN.1 `OCTET STRING`.
-        pub fn new(bytes: impl Into<Vec<u8>>) -> Result<Self> {
+        pub fn new(bytes: impl Into<Vec<u8>>) -> Result<Self, Error> {
             let inner = bytes.into();
 
             // Ensure the bytes parse successfully as an `OctetStringRef`
@@ -156,17 +158,19 @@ mod allocating {
     }
 
     impl<'a> DecodeValue<'a> for OctetString {
-        fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+        type Error = Error;
+
+        fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Error> {
             Self::new(reader.read_vec(header.length)?)
         }
     }
 
     impl EncodeValue for OctetString {
-        fn value_len(&self) -> Result<Length> {
+        fn value_len(&self) -> Result<Length, Error> {
             self.inner.len().try_into()
         }
 
-        fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+        fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
             writer.write(&self.inner)
         }
     }
@@ -217,10 +221,14 @@ mod allocating {
 #[cfg(feature = "bytes")]
 mod bytes {
     use super::OctetString;
-    use crate::{DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer};
+    use crate::{
+        DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, Writer,
+    };
     use bytes::Bytes;
 
     impl<'a> DecodeValue<'a> for Bytes {
+        type Error = Error;
+
         fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
             OctetString::decode_value(reader, header).map(|octet_string| octet_string.inner.into())
         }
diff --git a/der/src/asn1/oid.rs b/der/src/asn1/oid.rs
index a0329a879..fc72ac178 100644
--- a/der/src/asn1/oid.rs
+++ b/der/src/asn1/oid.rs
@@ -10,6 +10,8 @@ use const_oid::ObjectIdentifier;
 use super::Any;
 
 impl<'a> DecodeValue<'a> for ObjectIdentifier {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         let mut buf = [0u8; ObjectIdentifier::MAX_SIZE];
         let slice = buf
diff --git a/der/src/asn1/optional.rs b/der/src/asn1/optional.rs
index ecda4f8ec..26e24d683 100644
--- a/der/src/asn1/optional.rs
+++ b/der/src/asn1/optional.rs
@@ -1,13 +1,15 @@
 //! ASN.1 `OPTIONAL` as mapped to Rust's `Option` type
 
-use crate::{Choice, Decode, DerOrd, Encode, Length, Reader, Result, Tag, Writer};
+use crate::{Choice, Decode, DerOrd, Encode, Error, Length, Reader, Tag, Writer};
 use core::cmp::Ordering;
 
 impl<'a, T> Decode<'a> for Option<T>
 where
     T: Choice<'a>, // NOTE: all `Decode + Tagged` types receive a blanket `Choice` impl
 {
-    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Option<T>> {
+    type Error = T::Error;
+
+    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Option<T>, Self::Error> {
         if let Some(byte) = reader.peek_byte() {
             if T::can_decode(Tag::try_from(byte)?) {
                 return T::decode(reader).map(Some);
@@ -22,7 +24,7 @@ impl<T> DerOrd for Option<T>
 where
     T: DerOrd,
 {
-    fn der_cmp(&self, other: &Self) -> Result<Ordering> {
+    fn der_cmp(&self, other: &Self) -> Result<Ordering, Error> {
         match self {
             Some(a) => match other {
                 Some(b) => a.der_cmp(b),
@@ -37,11 +39,11 @@ impl<T> Encode for Option<T>
 where
     T: Encode,
 {
-    fn encoded_len(&self) -> Result<Length> {
+    fn encoded_len(&self) -> Result<Length, Error> {
         (&self).encoded_len()
     }
 
-    fn encode(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
         (&self).encode(writer)
     }
 }
@@ -50,14 +52,14 @@ impl<T> Encode for &Option<T>
 where
     T: Encode,
 {
-    fn encoded_len(&self) -> Result<Length> {
+    fn encoded_len(&self) -> Result<Length, Error> {
         match self {
             Some(encodable) => encodable.encoded_len(),
             None => Ok(0u8.into()),
         }
     }
 
-    fn encode(&self, encoder: &mut impl Writer) -> Result<()> {
+    fn encode(&self, encoder: &mut impl Writer) -> Result<(), Error> {
         match self {
             Some(encodable) => encodable.encode(encoder),
             None => Ok(()),
diff --git a/der/src/asn1/real.rs b/der/src/asn1/real.rs
index 7239dadfe..99a95527e 100644
--- a/der/src/asn1/real.rs
+++ b/der/src/asn1/real.rs
@@ -8,13 +8,15 @@
 )]
 
 use crate::{
-    BytesRef, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, StrRef, Tag,
-    Writer,
+    BytesRef, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, StrRef,
+    Tag, Writer,
 };
 
 use super::integer::uint::strip_leading_zeroes;
 
 impl<'a> DecodeValue<'a> for f64 {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         let bytes = BytesRef::decode_value(reader, header)?.as_slice();
 
diff --git a/der/src/asn1/sequence.rs b/der/src/asn1/sequence.rs
index ad4a5d52e..6c217424e 100644
--- a/der/src/asn1/sequence.rs
+++ b/der/src/asn1/sequence.rs
@@ -2,7 +2,8 @@
 //! `SEQUENCE`s to Rust structs.
 
 use crate::{
-    BytesRef, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer,
+    BytesRef, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag,
+    Writer,
 };
 
 #[cfg(feature = "alloc")]
@@ -33,6 +34,8 @@ pub struct SequenceRef<'a> {
 }
 
 impl<'a> DecodeValue<'a> for SequenceRef<'a> {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         Ok(Self {
             body: BytesRef::decode_value(reader, header)?,
diff --git a/der/src/asn1/sequence_of.rs b/der/src/asn1/sequence_of.rs
index 0f493fa7e..d32d66ef9 100644
--- a/der/src/asn1/sequence_of.rs
+++ b/der/src/asn1/sequence_of.rs
@@ -1,8 +1,8 @@
 //! ASN.1 `SEQUENCE OF` support.
 
 use crate::{
-    arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag,
-    Header, Length, Reader, Result, Tag, ValueOrd, Writer,
+    arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, Error,
+    FixedTag, Header, Length, Reader, Tag, ValueOrd, Writer,
 };
 use core::cmp::Ordering;
 
@@ -29,7 +29,7 @@ impl<T, const N: usize> SequenceOf<T, N> {
     }
 
     /// Add an element to this [`SequenceOf`].
-    pub fn add(&mut self, element: T) -> Result<()> {
+    pub fn add(&mut self, element: T) -> Result<(), Error> {
         self.inner.push(element)
     }
 
@@ -66,7 +66,9 @@ impl<'a, T, const N: usize> DecodeValue<'a> for SequenceOf<T, N>
 where
     T: Decode<'a>,
 {
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+    type Error = T::Error;
+
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
         reader.read_nested(header.length, |reader| {
             let mut sequence_of = Self::new();
 
@@ -83,12 +85,12 @@ impl<T, const N: usize> EncodeValue for SequenceOf<T, N>
 where
     T: Encode,
 {
-    fn value_len(&self) -> Result<Length> {
+    fn value_len(&self) -> Result<Length, Error> {
         self.iter()
             .try_fold(Length::ZERO, |len, elem| len + elem.encoded_len()?)
     }
 
-    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
         for elem in self.iter() {
             elem.encode(writer)?;
         }
@@ -105,7 +107,7 @@ impl<T, const N: usize> ValueOrd for SequenceOf<T, N>
 where
     T: DerOrd,
 {
-    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+    fn value_cmp(&self, other: &Self) -> Result<Ordering, Error> {
         iter_cmp(self.iter(), other.iter())
     }
 }
@@ -131,7 +133,9 @@ impl<'a, T, const N: usize> DecodeValue<'a> for [T; N]
 where
     T: Decode<'a>,
 {
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+    type Error = T::Error;
+
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
         let sequence_of = SequenceOf::<T, N>::decode_value(reader, header)?;
 
         // TODO(tarcieri): use `[T; N]::try_map` instead of `expect` when stable
@@ -141,7 +145,7 @@ where
                 .into_array()
                 .map(|elem| elem.expect("arrayvec length mismatch")))
         } else {
-            Err(Self::TAG.length_error())
+            Err(Self::TAG.length_error().into())
         }
     }
 }
@@ -150,12 +154,12 @@ impl<T, const N: usize> EncodeValue for [T; N]
 where
     T: Encode,
 {
-    fn value_len(&self) -> Result<Length> {
+    fn value_len(&self) -> Result<Length, Error> {
         self.iter()
             .try_fold(Length::ZERO, |len, elem| len + elem.encoded_len()?)
     }
 
-    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
         for elem in self {
             elem.encode(writer)?;
         }
@@ -172,7 +176,7 @@ impl<T, const N: usize> ValueOrd for [T; N]
 where
     T: DerOrd,
 {
-    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+    fn value_cmp(&self, other: &Self) -> Result<Ordering, Error> {
         iter_cmp(self.iter(), other.iter())
     }
 }
@@ -182,7 +186,9 @@ impl<'a, T> DecodeValue<'a> for Vec<T>
 where
     T: Decode<'a>,
 {
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+    type Error = T::Error;
+
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
         reader.read_nested(header.length, |reader| {
             let mut sequence_of = Self::new();
 
@@ -200,12 +206,12 @@ impl<T> EncodeValue for Vec<T>
 where
     T: Encode,
 {
-    fn value_len(&self) -> Result<Length> {
+    fn value_len(&self) -> Result<Length, Error> {
         self.iter()
             .try_fold(Length::ZERO, |len, elem| len + elem.encoded_len()?)
     }
 
-    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
         for elem in self {
             elem.encode(writer)?;
         }
@@ -224,7 +230,7 @@ impl<T> ValueOrd for Vec<T>
 where
     T: DerOrd,
 {
-    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+    fn value_cmp(&self, other: &Self) -> Result<Ordering, Error> {
         iter_cmp(self.iter(), other.iter())
     }
 }
diff --git a/der/src/asn1/set_of.rs b/der/src/asn1/set_of.rs
index c28ff4dde..636d04ba2 100644
--- a/der/src/asn1/set_of.rs
+++ b/der/src/asn1/set_of.rs
@@ -12,7 +12,7 @@
 
 use crate::{
     arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, Error,
-    ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer,
+    ErrorKind, FixedTag, Header, Length, Reader, Tag, ValueOrd, Writer,
 };
 use core::cmp::Ordering;
 
@@ -49,12 +49,12 @@ where
     /// Items MUST be added in lexicographical order according to the
     /// [`DerOrd`] impl on `T`.
     #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")]
-    pub fn add(&mut self, new_elem: T) -> Result<()> {
+    pub fn add(&mut self, new_elem: T) -> Result<(), Error> {
         self.insert_ordered(new_elem)
     }
 
     /// Insert an item into this [`SetOf`].
-    pub fn insert(&mut self, item: T) -> Result<()> {
+    pub fn insert(&mut self, item: T) -> Result<(), Error> {
         self.inner.push(item)?;
         der_sort(self.inner.as_mut())
     }
@@ -63,7 +63,7 @@ where
     ///
     /// Items MUST be added in lexicographical order according to the
     /// [`DerOrd`] impl on `T`.
-    pub fn insert_ordered(&mut self, item: T) -> Result<()> {
+    pub fn insert_ordered(&mut self, item: T) -> Result<(), Error> {
         // Ensure set elements are lexicographically ordered
         if let Some(last) = self.inner.last() {
             check_der_ordering(last, &item)?;
@@ -108,7 +108,9 @@ impl<'a, T, const N: usize> DecodeValue<'a> for SetOf<T, N>
 where
     T: Decode<'a> + DerOrd,
 {
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+    type Error = T::Error;
+
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
         reader.read_nested(header.length, |reader| {
             let mut result = Self::new();
 
@@ -127,12 +129,12 @@ impl<'a, T, const N: usize> EncodeValue for SetOf<T, N>
 where
     T: 'a + Decode<'a> + Encode + DerOrd,
 {
-    fn value_len(&self) -> Result<Length> {
+    fn value_len(&self) -> Result<Length, Error> {
         self.iter()
             .try_fold(Length::ZERO, |len, elem| len + elem.encoded_len()?)
     }
 
-    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
         for elem in self.iter() {
             elem.encode(writer)?;
         }
@@ -154,7 +156,7 @@ where
 {
     type Error = Error;
 
-    fn try_from(mut arr: [T; N]) -> Result<SetOf<T, N>> {
+    fn try_from(mut arr: [T; N]) -> Result<SetOf<T, N>, Error> {
         der_sort(&mut arr)?;
 
         let mut result = SetOf::new();
@@ -171,7 +173,7 @@ impl<T, const N: usize> ValueOrd for SetOf<T, N>
 where
     T: DerOrd,
 {
-    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+    fn value_cmp(&self, other: &Self) -> Result<Ordering, Error> {
         iter_cmp(self.iter(), other.iter())
     }
 }
@@ -232,7 +234,7 @@ where
     /// Note: this is an inherent method instead of an impl of the
     /// [`FromIterator`] trait in order to be fallible.
     #[allow(clippy::should_implement_trait)]
-    pub fn from_iter<I>(iter: I) -> Result<Self>
+    pub fn from_iter<I>(iter: I) -> Result<Self, Error>
     where
         I: IntoIterator<Item = T>,
     {
@@ -244,7 +246,7 @@ where
     /// Items MUST be added in lexicographical order according to the
     /// [`DerOrd`] impl on `T`.
     #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")]
-    pub fn add(&mut self, item: T) -> Result<()> {
+    pub fn add(&mut self, item: T) -> Result<(), Error> {
         self.insert_ordered(item)
     }
 
@@ -252,7 +254,7 @@ where
     ///
     /// Note: this is an inherent method instead of an impl of the
     /// [`Extend`] trait in order to be fallible.
-    pub fn extend<I>(&mut self, iter: I) -> Result<()>
+    pub fn extend<I>(&mut self, iter: I) -> Result<(), Error>
     where
         I: IntoIterator<Item = T>,
     {
@@ -261,7 +263,7 @@ where
     }
 
     /// Insert an item into this [`SetOfVec`]. Must be unique.
-    pub fn insert(&mut self, item: T) -> Result<()> {
+    pub fn insert(&mut self, item: T) -> Result<(), Error> {
         self.inner.push(item);
         der_sort(&mut self.inner)
     }
@@ -270,7 +272,7 @@ where
     ///
     /// Items MUST be added in lexicographical order according to the
     /// [`DerOrd`] impl on `T`.
-    pub fn insert_ordered(&mut self, item: T) -> Result<()> {
+    pub fn insert_ordered(&mut self, item: T) -> Result<(), Error> {
         // Ensure set elements are lexicographically ordered
         if let Some(last) = self.inner.last() {
             check_der_ordering(last, &item)?;
@@ -326,7 +328,9 @@ impl<'a, T> DecodeValue<'a> for SetOfVec<T>
 where
     T: Decode<'a> + DerOrd,
 {
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+    type Error = T::Error;
+
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
         reader.read_nested(header.length, |reader| {
             let mut inner = Vec::new();
 
@@ -346,12 +350,12 @@ impl<'a, T> EncodeValue for SetOfVec<T>
 where
     T: 'a + Decode<'a> + Encode + DerOrd,
 {
-    fn value_len(&self) -> Result<Length> {
+    fn value_len(&self) -> Result<Length, Error> {
         self.iter()
             .try_fold(Length::ZERO, |len, elem| len + elem.encoded_len()?)
     }
 
-    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
         for elem in self.iter() {
             elem.encode(writer)?;
         }
@@ -385,7 +389,8 @@ where
 {
     type Error = Error;
 
-    fn try_from(mut vec: Vec<T>) -> Result<SetOfVec<T>> {
+    fn try_from(mut vec: Vec<T>) -> Result<SetOfVec<T>, Error> {
+        // TODO(tarcieri): use `[T]::sort_by` here?
         der_sort(vec.as_mut_slice())?;
         Ok(SetOfVec { inner: vec })
     }
@@ -398,7 +403,7 @@ where
 {
     type Error = Error;
 
-    fn try_from(arr: [T; N]) -> Result<SetOfVec<T>> {
+    fn try_from(arr: [T; N]) -> Result<SetOfVec<T>, Error> {
         Vec::from(arr).try_into()
     }
 }
@@ -408,7 +413,7 @@ impl<T> ValueOrd for SetOfVec<T>
 where
     T: DerOrd,
 {
-    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+    fn value_cmp(&self, other: &Self) -> Result<Ordering, Error> {
         iter_cmp(self.iter(), other.iter())
     }
 }
@@ -421,11 +426,8 @@ where
     T: DerOrd + arbitrary::Arbitrary<'a>,
 {
     fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
-        Self::try_from(
-            u.arbitrary_iter()?
-                .collect::<std::result::Result<Vec<_>, _>>()?,
-        )
-        .map_err(|_| arbitrary::Error::IncorrectFormat)
+        Self::try_from(u.arbitrary_iter()?.collect::<Result<Vec<_>, _>>()?)
+            .map_err(|_| arbitrary::Error::IncorrectFormat)
     }
 
     fn size_hint(_depth: usize) -> (usize, Option<usize>) {
@@ -434,7 +436,7 @@ where
 }
 
 /// Ensure set elements are lexicographically ordered using [`DerOrd`].
-fn check_der_ordering<T: DerOrd>(a: &T, b: &T) -> Result<()> {
+fn check_der_ordering<T: DerOrd>(a: &T, b: &T) -> Result<(), Error> {
     match a.der_cmp(b)? {
         Ordering::Less => Ok(()),
         Ordering::Equal => Err(ErrorKind::SetDuplicate.into()),
@@ -452,7 +454,7 @@ fn check_der_ordering<T: DerOrd>(a: &T, b: &T) -> Result<()> {
 /// to support heapless `no_std` targets as well as to enable bubbling up
 /// sorting errors.
 #[allow(clippy::arithmetic_side_effects)]
-fn der_sort<T: DerOrd>(slice: &mut [T]) -> Result<()> {
+fn der_sort<T: DerOrd>(slice: &mut [T]) -> Result<(), Error> {
     for i in 0..slice.len() {
         let mut j = i;
 
@@ -473,7 +475,7 @@ fn der_sort<T: DerOrd>(slice: &mut [T]) -> Result<()> {
 
 /// Validate the elements of a `SET OF`, ensuring that they are all in order
 /// and that there are no duplicates.
-fn validate<T: DerOrd>(slice: &[T]) -> Result<()> {
+fn validate<T: DerOrd>(slice: &[T]) -> Result<(), Error> {
     if let Some(len) = slice.len().checked_sub(1) {
         for i in 0..len {
             let j = i.checked_add(1).ok_or(ErrorKind::Overflow)?;
diff --git a/der/src/asn1/utc_time.rs b/der/src/asn1/utc_time.rs
index f19d8f66c..74e8f0322 100644
--- a/der/src/asn1/utc_time.rs
+++ b/der/src/asn1/utc_time.rs
@@ -82,6 +82,8 @@ impl UtcTime {
 impl_any_conversions!(UtcTime);
 
 impl<'a> DecodeValue<'a> for UtcTime {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         if Self::LENGTH != usize::try_from(header.length)? {
             return Err(Self::TAG.value_error());
diff --git a/der/src/asn1/utf8_string.rs b/der/src/asn1/utf8_string.rs
index 0ba570acb..9ffdc2044 100644
--- a/der/src/asn1/utf8_string.rs
+++ b/der/src/asn1/utf8_string.rs
@@ -116,6 +116,8 @@ impl<'a> TryFrom<AnyRef<'a>> for String {
 
 #[cfg(feature = "alloc")]
 impl<'a> DecodeValue<'a> for String {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         Ok(String::from_utf8(reader.read_vec(header.length)?)?)
     }
diff --git a/der/src/bytes_owned.rs b/der/src/bytes_owned.rs
index b5e928e3b..38f5855f0 100644
--- a/der/src/bytes_owned.rs
+++ b/der/src/bytes_owned.rs
@@ -53,6 +53,8 @@ impl AsRef<[u8]> for BytesOwned {
 }
 
 impl<'a> DecodeValue<'a> for BytesOwned {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         reader.read_vec(header.length).and_then(Self::new)
     }
diff --git a/der/src/bytes_ref.rs b/der/src/bytes_ref.rs
index 2cee4076e..ca40e3156 100644
--- a/der/src/bytes_ref.rs
+++ b/der/src/bytes_ref.rs
@@ -58,6 +58,8 @@ impl AsRef<[u8]> for BytesRef<'_> {
 }
 
 impl<'a> DecodeValue<'a> for BytesRef<'a> {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         reader.read_slice(header.length).and_then(Self::new)
     }
diff --git a/der/src/decode.rs b/der/src/decode.rs
index fe53341b3..ccb487f52 100644
--- a/der/src/decode.rs
+++ b/der/src/decode.rs
@@ -1,6 +1,6 @@
 //! Trait definition for [`Decode`].
 
-use crate::{FixedTag, Header, Reader, Result, SliceReader};
+use crate::{Error, FixedTag, Header, Reader, SliceReader};
 use core::marker::PhantomData;
 
 #[cfg(feature = "pem")]
@@ -16,23 +16,28 @@ use alloc::boxed::Box;
 ///
 /// This trait provides the core abstraction upon which all decoding operations
 /// are based.
-pub trait Decode<'a>: Sized {
+pub trait Decode<'a>: Sized + 'a {
+    /// Type returned in the event of a decoding error.
+    type Error: From<Error> + 'static;
+
     /// Attempt to decode this message using the provided decoder.
-    fn decode<R: Reader<'a>>(decoder: &mut R) -> Result<Self>;
+    fn decode<R: Reader<'a>>(decoder: &mut R) -> Result<Self, Self::Error>;
 
     /// Parse `Self` from the provided DER-encoded byte slice.
-    fn from_der(bytes: &'a [u8]) -> Result<Self> {
+    fn from_der(bytes: &'a [u8]) -> Result<Self, Self::Error> {
         let mut reader = SliceReader::new(bytes)?;
         let result = Self::decode(&mut reader)?;
-        reader.finish(result)
+        Ok(reader.finish(result)?)
     }
 }
 
 impl<'a, T> Decode<'a> for T
 where
-    T: DecodeValue<'a> + FixedTag,
+    T: DecodeValue<'a> + FixedTag + 'a,
 {
-    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<T> {
+    type Error = <T as DecodeValue<'a>>::Error;
+
+    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<T, <T as DecodeValue<'a>>::Error> {
         let header = Header::decode(reader)?;
         header.tag.assert_eq(T::TAG)?;
         T::decode_value(reader, header)
@@ -43,9 +48,11 @@ where
 /// implementations on structs with phantom fields.
 impl<'a, T> Decode<'a> for PhantomData<T>
 where
-    T: ?Sized,
+    T: ?Sized + 'a,
 {
-    fn decode<R: Reader<'a>>(_reader: &mut R) -> Result<PhantomData<T>> {
+    type Error = Error;
+
+    fn decode<R: Reader<'a>>(_reader: &mut R) -> Result<PhantomData<T>, Error> {
         Ok(PhantomData)
     }
 }
@@ -69,14 +76,14 @@ impl<T> DecodeOwned for T where T: for<'a> Decode<'a> {}
 #[cfg(feature = "pem")]
 pub trait DecodePem: DecodeOwned + PemLabel {
     /// Try to decode this type from PEM.
-    fn from_pem(pem: impl AsRef<[u8]>) -> Result<Self>;
+    fn from_pem(pem: impl AsRef<[u8]>) -> Result<Self, <Self as Decode<'static>>::Error>;
 }
 
 #[cfg(feature = "pem")]
-impl<T: DecodeOwned + PemLabel> DecodePem for T {
-    fn from_pem(pem: impl AsRef<[u8]>) -> Result<Self> {
+impl<T: DecodeOwned<Error = Error> + PemLabel> DecodePem for T {
+    fn from_pem(pem: impl AsRef<[u8]>) -> Result<T, Error> {
         let mut reader = PemReader::new(pem.as_ref())?;
-        Self::validate_pem_label(reader.type_label())?;
+        Self::validate_pem_label(reader.type_label()).map_err(Error::from)?;
         T::decode(&mut reader)
     }
 }
@@ -84,8 +91,11 @@ impl<T: DecodeOwned + PemLabel> DecodePem for T {
 /// Decode the value part of a Tag-Length-Value encoded field, sans the [`Tag`]
 /// and [`Length`].
 pub trait DecodeValue<'a>: Sized {
+    /// Type returned in the event of a decoding error.
+    type Error: From<Error> + 'static;
+
     /// Attempt to decode this message using the provided [`Reader`].
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self>;
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error>;
 }
 
 #[cfg(feature = "alloc")]
@@ -93,7 +103,9 @@ impl<'a, T> DecodeValue<'a> for Box<T>
 where
     T: DecodeValue<'a>,
 {
-    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+    type Error = T::Error;
+
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
         Ok(Box::new(T::decode_value(reader, header)?))
     }
 }
diff --git a/der/src/document.rs b/der/src/document.rs
index 78355a67a..716083584 100644
--- a/der/src/document.rs
+++ b/der/src/document.rs
@@ -1,6 +1,6 @@
 //! ASN.1 DER-encoded documents stored on the heap.
 
-use crate::{Decode, Encode, Error, FixedTag, Length, Reader, Result, SliceReader, Tag, Writer};
+use crate::{Decode, Encode, Error, FixedTag, Length, Reader, SliceReader, Tag, Writer};
 use alloc::vec::Vec;
 use core::fmt::{self, Debug};
 
@@ -65,13 +65,13 @@ impl Document {
 
     /// Try to decode the inner ASN.1 DER message contained in this
     /// [`Document`] as the given type.
-    pub fn decode_msg<'a, T: Decode<'a>>(&'a self) -> Result<T> {
+    pub fn decode_msg<'a, T: Decode<'a>>(&'a self) -> Result<T, T::Error> {
         T::from_der(self.as_bytes())
     }
 
     /// Encode the provided type as ASN.1 DER, storing the resulting encoded DER
     /// as a [`Document`].
-    pub fn encode_msg<T: Encode>(msg: &T) -> Result<Self> {
+    pub fn encode_msg<T: Encode>(msg: &T) -> Result<Self, Error> {
         msg.to_der()?.try_into()
     }
 
@@ -79,7 +79,7 @@ impl Document {
     ///
     /// Returns the PEM label and decoded [`Document`] on success.
     #[cfg(feature = "pem")]
-    pub fn from_pem(pem: &str) -> Result<(&str, Self)> {
+    pub fn from_pem(pem: &str) -> Result<(&str, Self), Error> {
         let (label, der_bytes) = pem::decode_vec(pem.as_bytes())?;
         Ok((label, der_bytes.try_into()?))
     }
@@ -87,25 +87,29 @@ impl Document {
     /// Encode ASN.1 DER document as a PEM string with encapsulation boundaries
     /// containing the provided PEM type `label` (e.g. `CERTIFICATE`).
     #[cfg(feature = "pem")]
-    pub fn to_pem(&self, label: &'static str, line_ending: pem::LineEnding) -> Result<String> {
+    pub fn to_pem(
+        &self,
+        label: &'static str,
+        line_ending: pem::LineEnding,
+    ) -> Result<String, Error> {
         Ok(pem::encode_string(label, line_ending, self.as_bytes())?)
     }
 
     /// Read ASN.1 DER document from a file.
     #[cfg(feature = "std")]
-    pub fn read_der_file(path: impl AsRef<Path>) -> Result<Self> {
+    pub fn read_der_file(path: impl AsRef<Path>) -> Result<Self, Error> {
         fs::read(path)?.try_into()
     }
 
     /// Write ASN.1 DER document to a file.
     #[cfg(feature = "std")]
-    pub fn write_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
+    pub fn write_der_file(&self, path: impl AsRef<Path>) -> Result<(), Error> {
         Ok(fs::write(path, self.as_bytes())?)
     }
 
     /// Read PEM-encoded ASN.1 DER document from a file.
     #[cfg(all(feature = "pem", feature = "std"))]
-    pub fn read_pem_file(path: impl AsRef<Path>) -> Result<(String, Self)> {
+    pub fn read_pem_file(path: impl AsRef<Path>) -> Result<(String, Self), Error> {
         Self::from_pem(&fs::read_to_string(path)?).map(|(label, doc)| (label.to_owned(), doc))
     }
 
@@ -116,7 +120,7 @@ impl Document {
         path: impl AsRef<Path>,
         label: &'static str,
         line_ending: pem::LineEnding,
-    ) -> Result<()> {
+    ) -> Result<(), Error> {
         let pem = self.to_pem(label, line_ending)?;
         Ok(fs::write(path, pem.as_bytes())?)
     }
@@ -141,7 +145,9 @@ impl Debug for Document {
 }
 
 impl<'a> Decode<'a> for Document {
-    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Document> {
+    type Error = Error;
+
+    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Document, Error> {
         let header = reader.peek_header()?;
         let length = (header.encoded_len()? + header.length)?;
         let bytes = reader.read_slice(length)?;
@@ -154,11 +160,11 @@ impl<'a> Decode<'a> for Document {
 }
 
 impl Encode for Document {
-    fn encoded_len(&self) -> Result<Length> {
+    fn encoded_len(&self) -> Result<Length, Error> {
         Ok(self.len())
     }
 
-    fn encode(&self, writer: &mut impl Writer) -> Result<()> {
+    fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
         writer.write(self.as_bytes())
     }
 }
@@ -170,7 +176,7 @@ impl FixedTag for Document {
 impl TryFrom<&[u8]> for Document {
     type Error = Error;
 
-    fn try_from(der_bytes: &[u8]) -> Result<Self> {
+    fn try_from(der_bytes: &[u8]) -> Result<Self, Error> {
         Self::from_der(der_bytes)
     }
 }
@@ -178,7 +184,7 @@ impl TryFrom<&[u8]> for Document {
 impl TryFrom<Vec<u8>> for Document {
     type Error = Error;
 
-    fn try_from(der_bytes: Vec<u8>) -> Result<Self> {
+    fn try_from(der_bytes: Vec<u8>) -> Result<Self, Error> {
         let mut decoder = SliceReader::new(&der_bytes)?;
         decode_sequence(&mut decoder)?;
         decoder.finish(())?;
@@ -218,18 +224,18 @@ impl SecretDocument {
     }
 
     /// Try to decode the inner ASN.1 DER message as the given type.
-    pub fn decode_msg<'a, T: Decode<'a>>(&'a self) -> Result<T> {
+    pub fn decode_msg<'a, T: Decode<'a>>(&'a self) -> Result<T, T::Error> {
         self.0.decode_msg()
     }
 
     /// Encode the provided type as ASN.1 DER.
-    pub fn encode_msg<T: Encode>(msg: &T) -> Result<Self> {
+    pub fn encode_msg<T: Encode>(msg: &T) -> Result<Self, Error> {
         Document::encode_msg(msg).map(Self)
     }
 
     /// Decode ASN.1 DER document from PEM.
     #[cfg(feature = "pem")]
-    pub fn from_pem(pem: &str) -> Result<(&str, Self)> {
+    pub fn from_pem(pem: &str) -> Result<(&str, Self), Error> {
         Document::from_pem(pem).map(|(label, doc)| (label, Self(doc)))
     }
 
@@ -239,25 +245,25 @@ impl SecretDocument {
         &self,
         label: &'static str,
         line_ending: pem::LineEnding,
-    ) -> Result<Zeroizing<String>> {
+    ) -> Result<Zeroizing<String>, Error> {
         self.0.to_pem(label, line_ending).map(Zeroizing::new)
     }
 
     /// Read ASN.1 DER document from a file.
     #[cfg(feature = "std")]
-    pub fn read_der_file(path: impl AsRef<Path>) -> Result<Self> {
+    pub fn read_der_file(path: impl AsRef<Path>) -> Result<Self, Error> {
         Document::read_der_file(path).map(Self)
     }
 
     /// Write ASN.1 DER document to a file.
     #[cfg(feature = "std")]
-    pub fn write_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
+    pub fn write_der_file(&self, path: impl AsRef<Path>) -> Result<(), Error> {
         write_secret_file(path, self.as_bytes())
     }
 
     /// Read PEM-encoded ASN.1 DER document from a file.
     #[cfg(all(feature = "pem", feature = "std"))]
-    pub fn read_pem_file(path: impl AsRef<Path>) -> Result<(String, Self)> {
+    pub fn read_pem_file(path: impl AsRef<Path>) -> Result<(String, Self), Error> {
         Document::read_pem_file(path).map(|(label, doc)| (label, Self(doc)))
     }
 
@@ -268,7 +274,7 @@ impl SecretDocument {
         path: impl AsRef<Path>,
         label: &'static str,
         line_ending: pem::LineEnding,
-    ) -> Result<()> {
+    ) -> Result<(), Error> {
         write_secret_file(path, self.to_pem(label, line_ending)?.as_bytes())
     }
 }
@@ -297,7 +303,7 @@ impl From<Document> for SecretDocument {
 impl TryFrom<&[u8]> for SecretDocument {
     type Error = Error;
 
-    fn try_from(der_bytes: &[u8]) -> Result<Self> {
+    fn try_from(der_bytes: &[u8]) -> Result<Self, Error> {
         Document::try_from(der_bytes).map(Self)
     }
 }
@@ -306,7 +312,7 @@ impl TryFrom<&[u8]> for SecretDocument {
 impl TryFrom<Vec<u8>> for SecretDocument {
     type Error = Error;
 
-    fn try_from(der_bytes: Vec<u8>) -> Result<Self> {
+    fn try_from(der_bytes: Vec<u8>) -> Result<Self, Error> {
         Document::try_from(der_bytes).map(Self)
     }
 }
@@ -316,7 +322,7 @@ impl ZeroizeOnDrop for SecretDocument {}
 
 /// Attempt to decode a ASN.1 `SEQUENCE` from the given decoder, returning the
 /// entire sequence including the header.
-fn decode_sequence<'a>(decoder: &mut SliceReader<'a>) -> Result<&'a [u8]> {
+fn decode_sequence<'a>(decoder: &mut SliceReader<'a>) -> Result<&'a [u8], Error> {
     let header = decoder.peek_header()?;
     header.tag.assert_eq(Tag::Sequence)?;
 
@@ -327,7 +333,7 @@ fn decode_sequence<'a>(decoder: &mut SliceReader<'a>) -> Result<&'a [u8]> {
 /// Write a file containing secret data to the filesystem, restricting the
 /// file permissions so it's only readable by the owner
 #[cfg(all(unix, feature = "std", feature = "zeroize"))]
-fn write_secret_file(path: impl AsRef<Path>, data: &[u8]) -> Result<()> {
+fn write_secret_file(path: impl AsRef<Path>, data: &[u8]) -> Result<(), Error> {
     use std::{io::Write, os::unix::fs::OpenOptionsExt};
 
     /// File permissions for secret data
diff --git a/der/src/header.rs b/der/src/header.rs
index ad303810c..c3d5ded7b 100644
--- a/der/src/header.rs
+++ b/der/src/header.rs
@@ -1,6 +1,6 @@
 //! ASN.1 DER headers.
 
-use crate::{Decode, DerOrd, Encode, ErrorKind, Length, Reader, Result, Tag, Writer};
+use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Tag, Writer};
 use core::cmp::Ordering;
 
 /// ASN.1 DER headers: tag + length component of TLV-encoded values
@@ -24,6 +24,8 @@ impl Header {
 }
 
 impl<'a> Decode<'a> for Header {
+    type Error = Error;
+
     fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Header> {
         let tag = Tag::decode(reader)?;
 
diff --git a/der/src/length.rs b/der/src/length.rs
index 1f0b816ae..7ffdfc0cc 100644
--- a/der/src/length.rs
+++ b/der/src/length.rs
@@ -207,6 +207,8 @@ impl TryFrom<Length> for usize {
 }
 
 impl<'a> Decode<'a> for Length {
+    type Error = Error;
+
     fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Length> {
         match reader.read_byte()? {
             // Note: per X.690 Section 8.1.3.6.1 the byte 0x80 encodes indefinite
@@ -356,6 +358,8 @@ impl IndefiniteLength {
 }
 
 impl<'a> Decode<'a> for IndefiniteLength {
+    type Error = Error;
+
     fn decode<R: Reader<'a>>(reader: &mut R) -> Result<IndefiniteLength> {
         if reader.peek_byte() == Some(INDEFINITE_LENGTH_OCTET) {
             // Consume the byte we already peeked at.
diff --git a/der/src/lib.rs b/der/src/lib.rs
index 7ea99d849..d20ff18b0 100644
--- a/der/src/lib.rs
+++ b/der/src/lib.rs
@@ -110,6 +110,8 @@
 //! }
 //!
 //! impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> {
+//!     type Error = der::Error;
+//!
 //!     fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
 //!        // The `der::Decoder::Decode` method can be used to decode any
 //!        // type which impls the `Decode` trait, which is impl'd for
diff --git a/der/src/reader.rs b/der/src/reader.rs
index ef538f1b4..10576be29 100644
--- a/der/src/reader.rs
+++ b/der/src/reader.rs
@@ -9,7 +9,7 @@ pub(crate) use nested::NestedReader;
 
 use crate::{
     asn1::ContextSpecific, Decode, DecodeValue, Encode, EncodingRules, Error, ErrorKind, FixedTag,
-    Header, Length, Result, Tag, TagMode, TagNumber,
+    Header, Length, Tag, TagMode, TagNumber,
 };
 
 #[cfg(feature = "alloc")]
@@ -30,7 +30,7 @@ pub trait Reader<'r>: Sized {
     /// the data at the current position in the decoder.
     ///
     /// Does not modify the decoder's state.
-    fn peek_header(&self) -> Result<Header>;
+    fn peek_header(&self) -> Result<Header, Error>;
 
     /// Get the position within the buffer.
     fn position(&self) -> Length;
@@ -42,13 +42,17 @@ pub trait Reader<'r>: Sized {
     /// - `Ok(slice)` on success
     /// - `Err(ErrorKind::Incomplete)` if there is not enough data
     /// - `Err(ErrorKind::Reader)` if the reader can't borrow from the input
-    fn read_slice(&mut self, len: Length) -> Result<&'r [u8]>;
+    fn read_slice(&mut self, len: Length) -> Result<&'r [u8], Error>;
 
     /// Attempt to decode an ASN.1 `CONTEXT-SPECIFIC` field with the
     /// provided [`TagNumber`].
-    fn context_specific<T>(&mut self, tag_number: TagNumber, tag_mode: TagMode) -> Result<Option<T>>
+    fn context_specific<T>(
+        &mut self,
+        tag_number: TagNumber,
+        tag_mode: TagMode,
+    ) -> Result<Option<T>, T::Error>
     where
-        T: DecodeValue<'r> + FixedTag,
+        T: DecodeValue<'r> + FixedTag + 'r,
     {
         Ok(match tag_mode {
             TagMode::Explicit => ContextSpecific::<T>::decode_explicit(self, tag_number)?,
@@ -58,8 +62,8 @@ pub trait Reader<'r>: Sized {
     }
 
     /// Decode a value which impls the [`Decode`] trait.
-    fn decode<T: Decode<'r>>(&mut self) -> Result<T> {
-        T::decode(self).map_err(|e| e.nested(self.position()))
+    fn decode<T: Decode<'r>>(&mut self) -> Result<T, T::Error> {
+        T::decode(self)
     }
 
     /// Return an error with the given [`ErrorKind`], annotating it with
@@ -70,7 +74,7 @@ pub trait Reader<'r>: Sized {
 
     /// Finish decoding, returning the given value if there is no
     /// remaining data, or an error otherwise
-    fn finish<T>(self, value: T) -> Result<T> {
+    fn finish<T>(self, value: T) -> Result<T, Error> {
         if !self.is_finished() {
             Err(ErrorKind::TrailingData {
                 decoded: self.position(),
@@ -100,7 +104,7 @@ pub trait Reader<'r>: Sized {
     /// [`Tag`] value.
     ///
     /// Does not modify the decoder's state.
-    fn peek_tag(&self) -> Result<Tag> {
+    fn peek_tag(&self) -> Result<Tag, Error> {
         match self.peek_byte() {
             Some(byte) => byte.try_into(),
             None => Err(Error::incomplete(self.input_len())),
@@ -108,7 +112,7 @@ pub trait Reader<'r>: Sized {
     }
 
     /// Read a single byte.
-    fn read_byte(&mut self) -> Result<u8> {
+    fn read_byte(&mut self) -> Result<u8, Error> {
         let mut buf = [0];
         self.read_into(&mut buf)?;
         Ok(buf[0])
@@ -120,25 +124,26 @@ pub trait Reader<'r>: Sized {
     /// # Returns
     /// - `Ok(slice)` if there is sufficient data
     /// - `Err(ErrorKind::Incomplete)` if there is not enough data
-    fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
+    fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8], Error> {
         let input = self.read_slice(buf.len().try_into()?)?;
         buf.copy_from_slice(input);
         Ok(buf)
     }
 
     /// Read nested data of the given length.
-    fn read_nested<'n, T, F>(&'n mut self, len: Length, f: F) -> Result<T>
+    fn read_nested<'n, T, F, E>(&'n mut self, len: Length, f: F) -> Result<T, E>
     where
-        F: FnOnce(&mut NestedReader<'n, Self>) -> Result<T>,
+        F: FnOnce(&mut NestedReader<'n, Self>) -> Result<T, E>,
+        E: From<Error>,
     {
         let mut reader = NestedReader::new(self, len)?;
         let ret = f(&mut reader)?;
-        reader.finish(ret)
+        Ok(reader.finish(ret)?)
     }
 
     /// Read a byte vector of the given length.
     #[cfg(feature = "alloc")]
-    fn read_vec(&mut self, len: Length) -> Result<Vec<u8>> {
+    fn read_vec(&mut self, len: Length) -> Result<Vec<u8>, Error> {
         let mut bytes = vec![0u8; usize::try_from(len)?];
         self.read_into(&mut bytes)?;
         Ok(bytes)
@@ -152,9 +157,10 @@ pub trait Reader<'r>: Sized {
 
     /// Read an ASN.1 `SEQUENCE`, creating a nested [`Reader`] for the body and
     /// calling the provided closure with it.
-    fn sequence<'n, F, T>(&'n mut self, f: F) -> Result<T>
+    fn sequence<'n, F, T, E>(&'n mut self, f: F) -> Result<T, E>
     where
-        F: FnOnce(&mut NestedReader<'n, Self>) -> Result<T>,
+        F: FnOnce(&mut NestedReader<'n, Self>) -> Result<T, E>,
+        E: From<Error>,
     {
         let header = Header::decode(self)?;
         header.tag.assert_eq(Tag::Sequence)?;
@@ -162,7 +168,7 @@ pub trait Reader<'r>: Sized {
     }
 
     /// Obtain a slice of bytes contain a complete TLV production suitable for parsing later.
-    fn tlv_bytes(&mut self) -> Result<&'r [u8]> {
+    fn tlv_bytes(&mut self) -> Result<&'r [u8], Error> {
         let header = self.peek_header()?;
         let header_len = header.encoded_len()?;
         self.read_slice((header_len + header.length)?)
diff --git a/der/src/reader/slice.rs b/der/src/reader/slice.rs
index 40d5682fb..30345daf5 100644
--- a/der/src/reader/slice.rs
+++ b/der/src/reader/slice.rs
@@ -1,8 +1,6 @@
 //! Slice reader.
 
-use crate::{
-    BytesRef, Decode, EncodingRules, Error, ErrorKind, Header, Length, Reader, Result, Tag,
-};
+use crate::{BytesRef, Decode, EncodingRules, Error, ErrorKind, Header, Length, Reader, Tag};
 
 /// [`Reader`] which consumes an input byte slice.
 #[derive(Clone, Debug)]
@@ -22,7 +20,7 @@ pub struct SliceReader<'a> {
 
 impl<'a> SliceReader<'a> {
     /// Create a new slice reader for the given byte slice.
-    pub fn new(bytes: &'a [u8]) -> Result<Self> {
+    pub fn new(bytes: &'a [u8]) -> Result<Self, Error> {
         Ok(Self {
             bytes: BytesRef::new(bytes)?,
             encoding_rules: EncodingRules::default(),
@@ -50,7 +48,7 @@ impl<'a> SliceReader<'a> {
 
     /// Obtain the remaining bytes in this slice reader from the current cursor
     /// position.
-    fn remaining(&self) -> Result<&'a [u8]> {
+    fn remaining(&self) -> Result<&'a [u8], Error> {
         if self.is_failed() {
             Err(ErrorKind::Failed.at(self.position))
         } else {
@@ -77,7 +75,7 @@ impl<'a> Reader<'a> for SliceReader<'a> {
             .and_then(|bytes| bytes.first().cloned())
     }
 
-    fn peek_header(&self) -> Result<Header> {
+    fn peek_header(&self) -> Result<Header, Error> {
         Header::decode(&mut self.clone())
     }
 
@@ -85,7 +83,7 @@ impl<'a> Reader<'a> for SliceReader<'a> {
         self.position
     }
 
-    fn read_slice(&mut self, len: Length) -> Result<&'a [u8]> {
+    fn read_slice(&mut self, len: Length) -> Result<&'a [u8], Error> {
         if self.is_failed() {
             return Err(self.error(ErrorKind::Failed));
         }
@@ -102,14 +100,14 @@ impl<'a> Reader<'a> for SliceReader<'a> {
         }
     }
 
-    fn decode<T: Decode<'a>>(&mut self) -> Result<T> {
+    fn decode<T: Decode<'a>>(&mut self) -> Result<T, T::Error> {
         if self.is_failed() {
-            return Err(self.error(ErrorKind::Failed));
+            return Err(self.error(ErrorKind::Failed).into());
         }
 
         T::decode(self).map_err(|e| {
             self.failed = true;
-            e.nested(self.position)
+            e
         })
     }
 
@@ -118,7 +116,7 @@ impl<'a> Reader<'a> for SliceReader<'a> {
         kind.at(self.position)
     }
 
-    fn finish<T>(self, value: T) -> Result<T> {
+    fn finish<T>(self, value: T) -> Result<T, Error> {
         if self.is_failed() {
             Err(ErrorKind::Failed.at(self.position))
         } else if !self.is_finished() {
diff --git a/der/src/str_owned.rs b/der/src/str_owned.rs
index 20bfea5bd..0bf9e72ff 100644
--- a/der/src/str_owned.rs
+++ b/der/src/str_owned.rs
@@ -2,8 +2,8 @@
 //! library-level length limitation i.e. `Length::max()`.
 
 use crate::{
-    referenced::OwnedToRef, BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result,
-    StrRef, Writer,
+    referenced::OwnedToRef, BytesRef, DecodeValue, EncodeValue, Error, Header, Length, Reader,
+    Result, StrRef, Writer,
 };
 use alloc::string::String;
 use core::str;
@@ -69,6 +69,8 @@ impl AsRef<[u8]> for StrOwned {
 }
 
 impl<'a> DecodeValue<'a> for StrOwned {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         Self::from_bytes(BytesRef::decode_value(reader, header)?.as_slice())
     }
diff --git a/der/src/str_ref.rs b/der/src/str_ref.rs
index 899c7506b..d327606cd 100644
--- a/der/src/str_ref.rs
+++ b/der/src/str_ref.rs
@@ -1,7 +1,7 @@
 //! Common handling for types backed by `str` slices with enforcement of a
 //! library-level length limitation i.e. `Length::max()`.
 
-use crate::{BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result, Writer};
+use crate::{BytesRef, DecodeValue, EncodeValue, Error, Header, Length, Reader, Result, Writer};
 use core::str;
 
 /// String slice newtype which respects the [`Length::max`] limit.
@@ -63,6 +63,8 @@ impl AsRef<[u8]> for StrRef<'_> {
 }
 
 impl<'a> DecodeValue<'a> for StrRef<'a> {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         Self::from_bytes(BytesRef::decode_value(reader, header)?.as_slice())
     }
diff --git a/der/src/tag.rs b/der/src/tag.rs
index 848168999..4ece7cbad 100644
--- a/der/src/tag.rs
+++ b/der/src/tag.rs
@@ -315,6 +315,8 @@ impl From<&Tag> for u8 {
 }
 
 impl<'a> Decode<'a> for Tag {
+    type Error = Error;
+
     fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
         reader.read_byte().and_then(Self::try_from)
     }
diff --git a/gss-api/src/lib.rs b/gss-api/src/lib.rs
index 8c925ec68..59316485d 100644
--- a/gss-api/src/lib.rs
+++ b/gss-api/src/lib.rs
@@ -62,6 +62,8 @@ impl<'a> FixedTag for InitialContextToken<'a> {
 }
 
 impl<'a> DecodeValue<'a> for InitialContextToken<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, _header: der::Header) -> der::Result<Self> {
         Ok(Self {
             this_mech: reader.decode()?,
diff --git a/pkcs1/src/params.rs b/pkcs1/src/params.rs
index 74a1ee486..52ce89642 100644
--- a/pkcs1/src/params.rs
+++ b/pkcs1/src/params.rs
@@ -37,6 +37,8 @@ impl Default for TrailerField {
 }
 
 impl<'a> DecodeValue<'a> for TrailerField {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
         match u8::decode_value(decoder, header)? {
             1 => Ok(TrailerField::BC),
@@ -178,6 +180,8 @@ impl<'a> Default for RsaPssParams<'a> {
 }
 
 impl<'a> DecodeValue<'a> for RsaPssParams<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
         reader.read_nested(header.length, |reader| {
             Ok(Self {
@@ -342,6 +346,7 @@ impl<'a> Default for RsaOaepParams<'a> {
 }
 
 impl<'a> DecodeValue<'a> for RsaOaepParams<'a> {
+    type Error = der::Error;
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
         reader.read_nested(header.length, |reader| {
             Ok(Self {
diff --git a/pkcs1/src/private_key.rs b/pkcs1/src/private_key.rs
index b913c4764..d7a7bb554 100644
--- a/pkcs1/src/private_key.rs
+++ b/pkcs1/src/private_key.rs
@@ -93,6 +93,8 @@ impl<'a> RsaPrivateKey<'a> {
 }
 
 impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
         reader.read_nested(header.length, |reader| {
             let version = Version::decode(reader)?;
@@ -215,6 +217,8 @@ pub struct OtherPrimeInfos<'a> {
 
 #[cfg(not(feature = "alloc"))]
 impl<'a> DecodeValue<'a> for OtherPrimeInfos<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
         // Placeholder decoder that always returns an error.
         // Uses `Tag::Integer` to signal an unsupported version.
diff --git a/pkcs1/src/private_key/other_prime_info.rs b/pkcs1/src/private_key/other_prime_info.rs
index 35194a590..b2a613572 100644
--- a/pkcs1/src/private_key/other_prime_info.rs
+++ b/pkcs1/src/private_key/other_prime_info.rs
@@ -30,6 +30,8 @@ pub struct OtherPrimeInfo<'a> {
 }
 
 impl<'a> DecodeValue<'a> for OtherPrimeInfo<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
         reader.read_nested(header.length, |reader| {
             Ok(Self {
diff --git a/pkcs1/src/public_key.rs b/pkcs1/src/public_key.rs
index 3281744cb..f8bc06932 100644
--- a/pkcs1/src/public_key.rs
+++ b/pkcs1/src/public_key.rs
@@ -34,6 +34,7 @@ pub struct RsaPublicKey<'a> {
 }
 
 impl<'a> DecodeValue<'a> for RsaPublicKey<'a> {
+    type Error = der::Error;
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
         reader.read_nested(header.length, |reader| {
             Ok(Self {
diff --git a/pkcs1/src/version.rs b/pkcs1/src/version.rs
index 2fdb19884..f880253f2 100644
--- a/pkcs1/src/version.rs
+++ b/pkcs1/src/version.rs
@@ -52,6 +52,7 @@ impl TryFrom<u8> for Version {
 }
 
 impl<'a> Decode<'a> for Version {
+    type Error = der::Error;
     fn decode<R: Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
         Version::try_from(u8::decode(decoder)?).map_err(|_| Self::TAG.value_error())
     }
diff --git a/pkcs12/src/safe_bag.rs b/pkcs12/src/safe_bag.rs
index 0e5fd02a3..04c5a0cb5 100644
--- a/pkcs12/src/safe_bag.rs
+++ b/pkcs12/src/safe_bag.rs
@@ -37,6 +37,8 @@ pub struct SafeBag {
 }
 
 impl<'a> ::der::DecodeValue<'a> for SafeBag {
+    type Error = ::der::Error;
+
     fn decode_value<R: ::der::Reader<'a>>(
         reader: &mut R,
         header: ::der::Header,
diff --git a/pkcs5/src/lib.rs b/pkcs5/src/lib.rs
index 550cd0d5e..6d883c027 100644
--- a/pkcs5/src/lib.rs
+++ b/pkcs5/src/lib.rs
@@ -144,6 +144,8 @@ impl EncryptionScheme {
 }
 
 impl<'a> DecodeValue<'a> for EncryptionScheme {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(decoder: &mut R, header: Header) -> der::Result<Self> {
         AlgorithmIdentifierRef::decode_value(decoder, header)?.try_into()
     }
diff --git a/pkcs5/src/pbes1.rs b/pkcs5/src/pbes1.rs
index 217154795..025e2a53d 100644
--- a/pkcs5/src/pbes1.rs
+++ b/pkcs5/src/pbes1.rs
@@ -67,6 +67,8 @@ impl Algorithm {
 }
 
 impl<'a> DecodeValue<'a> for Algorithm {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
         AlgorithmIdentifierRef::decode_value(reader, header)?.try_into()
     }
@@ -125,6 +127,8 @@ pub struct Parameters {
 }
 
 impl<'a> DecodeValue<'a> for Parameters {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
         AnyRef::decode_value(reader, header)?.try_into()
     }
diff --git a/pkcs5/src/pbes2.rs b/pkcs5/src/pbes2.rs
index 50483dd5e..a84ff3005 100644
--- a/pkcs5/src/pbes2.rs
+++ b/pkcs5/src/pbes2.rs
@@ -262,6 +262,8 @@ impl Parameters {
 }
 
 impl<'a> DecodeValue<'a> for Parameters {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
         AnyRef::decode_value(reader, header)?.try_into()
     }
@@ -370,6 +372,8 @@ impl EncryptionScheme {
 }
 
 impl<'a> Decode<'a> for EncryptionScheme {
+    type Error = der::Error;
+
     fn decode<R: Reader<'a>>(reader: &mut R) -> der::Result<Self> {
         AlgorithmIdentifierRef::decode(reader).and_then(TryInto::try_into)
     }
diff --git a/pkcs5/src/pbes2/kdf.rs b/pkcs5/src/pbes2/kdf.rs
index 29965e78c..b5e55563f 100644
--- a/pkcs5/src/pbes2/kdf.rs
+++ b/pkcs5/src/pbes2/kdf.rs
@@ -104,6 +104,8 @@ impl Kdf {
 }
 
 impl<'a> DecodeValue<'a> for Kdf {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
         AlgorithmIdentifierRef::decode_value(reader, header)?.try_into()
     }
@@ -222,6 +224,7 @@ impl Pbkdf2Params {
 }
 
 impl<'a> DecodeValue<'a> for Pbkdf2Params {
+    type Error = der::Error;
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
         AnyRef::decode_value(reader, header)?.try_into()
     }
@@ -419,6 +422,8 @@ impl ScryptParams {
 }
 
 impl<'a> DecodeValue<'a> for ScryptParams {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
         AnyRef::decode_value(reader, header)?.try_into()
     }
diff --git a/pkcs5/src/pbes2/kdf/salt.rs b/pkcs5/src/pbes2/kdf/salt.rs
index 75c5a0758..59e961594 100644
--- a/pkcs5/src/pbes2/kdf/salt.rs
+++ b/pkcs5/src/pbes2/kdf/salt.rs
@@ -56,6 +56,8 @@ impl AsRef<[u8]> for Salt {
 }
 
 impl<'a> DecodeValue<'a> for Salt {
+    type Error = Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         let length = usize::try_from(header.length)?;
 
diff --git a/pkcs8/src/encrypted_private_key_info.rs b/pkcs8/src/encrypted_private_key_info.rs
index e081c8e11..12fafdf21 100644
--- a/pkcs8/src/encrypted_private_key_info.rs
+++ b/pkcs8/src/encrypted_private_key_info.rs
@@ -97,6 +97,8 @@ impl<'a> EncryptedPrivateKeyInfo<'a> {
 }
 
 impl<'a> DecodeValue<'a> for EncryptedPrivateKeyInfo<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(
         reader: &mut R,
         header: Header,
diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs
index ec4c6ec04..b3550d619 100644
--- a/pkcs8/src/private_key_info.rs
+++ b/pkcs8/src/private_key_info.rs
@@ -171,6 +171,8 @@ impl<'a> PrivateKeyInfo<'a> {
 }
 
 impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(
         reader: &mut R,
         header: Header,
diff --git a/pkcs8/src/version.rs b/pkcs8/src/version.rs
index 0ca80bc48..d5a3c5747 100644
--- a/pkcs8/src/version.rs
+++ b/pkcs8/src/version.rs
@@ -26,6 +26,8 @@ impl Version {
 }
 
 impl<'a> Decode<'a> for Version {
+    type Error = der::Error;
+
     fn decode<R: Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
         Version::try_from(u8::decode(decoder)?).map_err(|_| Self::TAG.value_error())
     }
diff --git a/sec1/src/parameters.rs b/sec1/src/parameters.rs
index 20458e6e9..7f77653b1 100644
--- a/sec1/src/parameters.rs
+++ b/sec1/src/parameters.rs
@@ -28,6 +28,8 @@ pub enum EcParameters {
 }
 
 impl<'a> DecodeValue<'a> for EcParameters {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(decoder: &mut R, header: Header) -> der::Result<Self> {
         ObjectIdentifier::decode_value(decoder, header).map(Self::NamedCurve)
     }
diff --git a/sec1/src/private_key.rs b/sec1/src/private_key.rs
index 531579936..dacb808f6 100644
--- a/sec1/src/private_key.rs
+++ b/sec1/src/private_key.rs
@@ -95,6 +95,8 @@ impl<'a> EcPrivateKey<'a> {
 }
 
 impl<'a> DecodeValue<'a> for EcPrivateKey<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
         reader.read_nested(header.length, |reader| {
             if u8::decode(reader)? != VERSION {
diff --git a/spki/src/algorithm.rs b/spki/src/algorithm.rs
index 5f4b5e8c2..a49c21df0 100644
--- a/spki/src/algorithm.rs
+++ b/spki/src/algorithm.rs
@@ -33,8 +33,10 @@ pub struct AlgorithmIdentifier<Params> {
 
 impl<'a, Params> DecodeValue<'a> for AlgorithmIdentifier<Params>
 where
-    Params: Choice<'a>,
+    Params: Choice<'a, Error = der::Error>,
 {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
         reader.read_nested(header.length, |reader| {
             Ok(Self {
@@ -60,11 +62,14 @@ where
     }
 }
 
-impl<'a, Params> Sequence<'a> for AlgorithmIdentifier<Params> where Params: Choice<'a> + Encode {}
+impl<'a, Params> Sequence<'a> for AlgorithmIdentifier<Params> where
+    Params: Choice<'a, Error = der::Error> + Encode
+{
+}
 
 impl<'a, Params> TryFrom<&'a [u8]> for AlgorithmIdentifier<Params>
 where
-    Params: Choice<'a> + Encode,
+    Params: Choice<'a, Error = der::Error> + Encode,
 {
     type Error = Error;
 
diff --git a/spki/src/spki.rs b/spki/src/spki.rs
index 192b726a3..b2972a62e 100644
--- a/spki/src/spki.rs
+++ b/spki/src/spki.rs
@@ -51,10 +51,10 @@ pub struct SubjectPublicKeyInfo<Params, Key> {
 
 impl<'a, Params, Key> SubjectPublicKeyInfo<Params, Key>
 where
-    Params: Choice<'a> + Encode,
+    Params: Choice<'a, Error = der::Error> + 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,
+    Key: Decode<'a, Error = der::Error> + Encode + FixedTag,
 {
     /// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] and
     /// encode it as a Base64 string.
@@ -84,9 +84,11 @@ where
 
 impl<'a: 'k, 'k, Params, Key: 'k> DecodeValue<'a> for SubjectPublicKeyInfo<Params, Key>
 where
-    Params: Choice<'a> + Encode,
-    Key: Decode<'a>,
+    Params: Choice<'a, Error = der::Error> + Encode,
+    Key: Decode<'a, Error = der::Error>,
 {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
         reader.read_nested(header.length, |reader| {
             Ok(Self {
@@ -99,7 +101,7 @@ where
 
 impl<'a, Params, Key> EncodeValue for SubjectPublicKeyInfo<Params, Key>
 where
-    Params: Choice<'a> + Encode,
+    Params: Choice<'a, Error = der::Error> + Encode,
     Key: Encode,
 {
     fn value_len(&self) -> der::Result<Length> {
@@ -115,15 +117,15 @@ where
 
 impl<'a, Params, Key> Sequence<'a> for SubjectPublicKeyInfo<Params, Key>
 where
-    Params: Choice<'a> + Encode,
-    Key: Decode<'a> + Encode + FixedTag,
+    Params: Choice<'a, Error = der::Error> + Encode,
+    Key: Decode<'a, Error = der::Error> + Encode + FixedTag,
 {
 }
 
 impl<'a, Params, Key> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<Params, Key>
 where
-    Params: Choice<'a> + Encode,
-    Key: Decode<'a> + Encode + FixedTag,
+    Params: Choice<'a, Error = der::Error> + Encode,
+    Key: Decode<'a, Error = der::Error> + Encode + FixedTag,
 {
     type Error = Error;
 
@@ -134,7 +136,7 @@ where
 
 impl<'a, Params, Key> ValueOrd for SubjectPublicKeyInfo<Params, Key>
 where
-    Params: Choice<'a> + DerOrd + Encode,
+    Params: Choice<'a, Error = der::Error> + DerOrd + Encode,
     Key: ValueOrd,
 {
     fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
@@ -148,8 +150,8 @@ where
 #[cfg(feature = "alloc")]
 impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<SubjectPublicKeyInfo<Params, Key>> for Document
 where
-    Params: Choice<'a> + Encode,
-    Key: Decode<'a> + Encode + FixedTag,
+    Params: Choice<'a, Error = der::Error> + Encode,
+    Key: Decode<'a, Error = der::Error> + Encode + FixedTag,
     BitStringRef<'a>: From<&'k Key>,
 {
     type Error = Error;
@@ -162,8 +164,8 @@ where
 #[cfg(feature = "alloc")]
 impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<&SubjectPublicKeyInfo<Params, Key>> for Document
 where
-    Params: Choice<'a> + Encode,
-    Key: Decode<'a> + Encode + FixedTag,
+    Params: Choice<'a, Error = der::Error> + Encode,
+    Key: Decode<'a, Error = der::Error> + Encode + FixedTag,
     BitStringRef<'a>: From<&'k Key>,
 {
     type Error = Error;
diff --git a/x509-cert/src/certificate.rs b/x509-cert/src/certificate.rs
index c5a105dbb..4152c7f01 100644
--- a/x509-cert/src/certificate.rs
+++ b/x509-cert/src/certificate.rs
@@ -5,7 +5,7 @@ use alloc::vec::Vec;
 use const_oid::AssociatedOid;
 use core::{cmp::Ordering, fmt::Debug};
 use der::asn1::BitString;
-use der::{Decode, Enumerated, Error, ErrorKind, Sequence, Tag, ValueOrd};
+use der::{Decode, Enumerated, ErrorKind, Sequence, Tag, ValueOrd};
 use spki::{AlgorithmIdentifierOwned, SubjectPublicKeyInfoOwned};
 
 #[cfg(feature = "pem")]
@@ -116,7 +116,7 @@ pub type TbsCertificate = TbsCertificateInner<Rfc5280>;
 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct TbsCertificateInner<P: Profile = Rfc5280> {
+pub struct TbsCertificateInner<P: Profile + 'static = Rfc5280> {
     /// The certificate version
     ///
     /// Note that this value defaults to Version 1 per the RFC. However,
@@ -149,12 +149,14 @@ impl<P: Profile> TbsCertificateInner<P> {
     /// Returns an error if multiple of these extensions is present. Returns
     /// `Ok(None)` if the extension is not present. Returns a decoding error
     /// if decoding failed. Otherwise returns the extension.
-    pub fn get<'a, T: Decode<'a> + AssociatedOid>(&'a self) -> Result<Option<(bool, T)>, Error> {
+    pub fn get<'a, T: Decode<'a> + AssociatedOid>(
+        &'a self,
+    ) -> Result<Option<(bool, T)>, <T as Decode<'a>>::Error> {
         let mut iter = self.filter::<T>().peekable();
         match iter.next() {
             None => Ok(None),
             Some(item) => match iter.peek() {
-                Some(..) => Err(ErrorKind::Failed.into()),
+                Some(..) => Err(der::Error::from(ErrorKind::Failed).into()),
                 None => Ok(Some(item?)),
             },
         }
@@ -165,7 +167,7 @@ impl<P: Profile> TbsCertificateInner<P> {
     /// Returns a filtered iterator over all the extensions with the OID.
     pub fn filter<'a, T: Decode<'a> + AssociatedOid>(
         &'a self,
-    ) -> impl 'a + Iterator<Item = Result<(bool, T), Error>> {
+    ) -> impl 'a + Iterator<Item = Result<(bool, T), <T as Decode<'a>>::Error>> {
         self.extensions
             .as_deref()
             .unwrap_or(&[])
@@ -194,7 +196,7 @@ pub type Certificate = CertificateInner<Rfc5280>;
 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct CertificateInner<P: Profile = Rfc5280> {
+pub struct CertificateInner<P: Profile + 'static = Rfc5280> {
     pub tbs_certificate: TbsCertificateInner<P>,
     pub signature_algorithm: AlgorithmIdentifierOwned,
     pub signature: BitString,
@@ -223,7 +225,7 @@ impl<P: Profile> CertificateInner<P> {
     /// Parse a chain of pem-encoded certificates from a slice.
     ///
     /// Returns the list of certificates.
-    pub fn load_pem_chain(mut input: &[u8]) -> Result<Vec<Self>, Error> {
+    pub fn load_pem_chain(mut input: &[u8]) -> Result<Vec<Self>, der::Error> {
         fn find_boundary<T>(haystack: &[T], needle: &[T]) -> Option<usize>
         where
             for<'a> &'a [T]: PartialEq,
diff --git a/x509-cert/src/macros.rs b/x509-cert/src/macros.rs
index 0333ef7b9..c9f5153d8 100644
--- a/x509-cert/src/macros.rs
+++ b/x509-cert/src/macros.rs
@@ -49,6 +49,8 @@ macro_rules! impl_newtype {
         }
 
         impl<'a> ::der::DecodeValue<'a> for $newtype {
+            type Error = ::der::Error;
+
             fn decode_value<R: ::der::Reader<'a>>(
                 decoder: &mut R,
                 header: ::der::Header,
diff --git a/x509-cert/src/serial_number.rs b/x509-cert/src/serial_number.rs
index bd0d93947..50d2090f7 100644
--- a/x509-cert/src/serial_number.rs
+++ b/x509-cert/src/serial_number.rs
@@ -130,6 +130,8 @@ impl<P: Profile> EncodeValue for SerialNumber<P> {
 }
 
 impl<'a, P: Profile> DecodeValue<'a> for SerialNumber<P> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
         let inner = Int::decode_value(reader, header)?;
         let serial = Self {
diff --git a/x509-cert/tests/certificate.rs b/x509-cert/tests/certificate.rs
index d4859c2e3..8ce118017 100644
--- a/x509-cert/tests/certificate.rs
+++ b/x509-cert/tests/certificate.rs
@@ -38,6 +38,8 @@ pub struct DeferDecodeCertificate<'a> {
 }
 
 impl<'a> DecodeValue<'a> for DeferDecodeCertificate<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(
         reader: &mut R,
         header: Header,
@@ -81,6 +83,8 @@ pub struct DeferDecodeTbsCertificate<'a> {
 }
 
 impl<'a> DecodeValue<'a> for DeferDecodeTbsCertificate<'a> {
+    type Error = der::Error;
+
     fn decode_value<R: Reader<'a>>(
         reader: &mut R,
         header: Header,
