Upgrade x509-cert to 0.2.4 am: d2a24d5102 am: 58583aa0bf am: 106e9e3011

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/x509-cert/+/2877379

Change-Id: I8da3dfd63116b61271f86f00243d008a4ef58e34
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 271baca..ec6a5a4 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "5747b144d21463fe471a2aaa34a5a1bd67b611f2"
+    "sha1": "dc5a611afb6d3aa7b9b9bfae3587f996bb25fdc6"
   },
   "path_in_vcs": "x509-cert"
 }
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 0715dd3..01da6f9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,14 +35,12 @@
     name: "libx509_cert",
     crate_name: "x509_cert",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.1.1",
+    cargo_pkg_version: "0.2.4",
     srcs: ["src/lib.rs"],
     edition: "2021",
-    features: ["alloc"],
     rustlibs: [
         "libconst_oid",
         "libder",
-        "libflagset",
         "libspki",
     ],
 }
@@ -51,14 +49,12 @@
     name: "libx509_cert_nostd",
     crate_name: "x509_cert",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.1.1",
+    cargo_pkg_version: "0.2.4",
     srcs: ["src/lib.rs"],
     edition: "2021",
-    features: ["alloc"],
     rustlibs: [
         "libconst_oid_nostd",
         "libder_nostd",
-        "libflagset_nostd",
         "libspki_nostd",
     ],
     apex_available: [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 83406c9..9922da4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,131 @@
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## 0.2.4 (2023-07-25)
+
+### Added
+- `add_attribute` to `RequestBuilder` ([#1137])
+
+### Changed
+- bump `serde_json` from 1.0.97 to 1.0.99 ([#1122])
+- use the shortest name when looking attr OID ([#1130])
+- bump `serde_json` from 1.0.100 to 1.0.103 ([#1158])
+
+### Fixed
+- RDN string representation ([#1126])
+- `Arbitrary` for certificates ([#1150])
+
+[#1122]: https://github.com/RustCrypto/formats/pull/1122
+[#1126]: https://github.com/RustCrypto/formats/pull/1126
+[#1130]: https://github.com/RustCrypto/formats/pull/1130
+[#1137]: https://github.com/RustCrypto/formats/pull/1137
+[#1150]: https://github.com/RustCrypto/formats/pull/1150
+[#1158]: https://github.com/RustCrypto/formats/pull/1158
+
+## 0.2.3 (2023-05-30)
+
+### Added
+- Added `TryFrom` for `RelativeDistinguishedName` ([#1092])
+- Load a chain of certificates from a slice ([#1081])
+
+[#1092]: https://github.com/RustCrypto/formats/pull/1092
+[#1081]: https://github.com/RustCrypto/formats/pull/1081
+
+## 0.2.2 (2023-05-19)
+
+### Added
+- Certificate builder ([#764])
+- Support for `RandomizedSigner` in builder ([#1007])
+- Provide parsing profiles ([#987])
+- Support for `Time::INFINITY` ([#1024])
+- Conversion from `std::net::IpAddr` ([#1035])
+- `CertReq` builder ([#1034])
+- missing extension implementations ([#1050])
+- notes about `UTCTime` range being 1970-2049 ([#1052])
+- consume the `SignatureBitStringEncoding` trait ([#1048])
+
+### Changed
+- use `ErrorKind::Value` for overlength serial ([#988])
+- Bump `hex-literal` to v0.4.1 ([#999])
+- Builder updates ([#1001])
+- better debug info when `zlint` isn't installed ([#1018])
+- make SKI optional in leaf certificate ([#1028])
+- bump rsa from 0.9.0-pre.2 to 0.9.0 ([#1033])
+- bump rsa from 0.9.1 to 0.9.2 ([#1056])
+
+### Fixed
+- fix `KeyUsage` bit tests ([#993])
+- extraneous PhantomData in `TbsCertificate` ([#1017])
+- CI flakiness ([#1042])
+- usage of ecdsa signer ([#1043])
+
+[#764]: https://github.com/RustCrypto/formats/pull/764
+[#987]: https://github.com/RustCrypto/formats/pull/987
+[#988]: https://github.com/RustCrypto/formats/pull/988
+[#993]: https://github.com/RustCrypto/formats/pull/993
+[#999]: https://github.com/RustCrypto/formats/pull/999
+[#1001]: https://github.com/RustCrypto/formats/pull/1001
+[#1007]: https://github.com/RustCrypto/formats/pull/1007
+[#1017]: https://github.com/RustCrypto/formats/pull/1017
+[#1018]: https://github.com/RustCrypto/formats/pull/1018
+[#1024]: https://github.com/RustCrypto/formats/pull/1024
+[#1028]: https://github.com/RustCrypto/formats/pull/1028
+[#1033]: https://github.com/RustCrypto/formats/pull/1033
+[#1034]: https://github.com/RustCrypto/formats/pull/1034
+[#1035]: https://github.com/RustCrypto/formats/pull/1035
+[#1042]: https://github.com/RustCrypto/formats/pull/1042
+[#1043]: https://github.com/RustCrypto/formats/pull/1043
+[#1048]: https://github.com/RustCrypto/formats/pull/1048
+[#1050]: https://github.com/RustCrypto/formats/pull/1050
+[#1052]: https://github.com/RustCrypto/formats/pull/1052
+[#1056]: https://github.com/RustCrypto/formats/pull/1056
+
+## 0.2.1 (2023-03-26)
+### Added
+- `FromStr` impls for `RdnSequence` (`Name`), `RelativeDistinguishedName`, and
+  `AttributeTypeAndValue` ([#949])
+
+### Changed
+- Deprecate `encode_from_string` functions ([#951])
+
+[#949]: https://github.com/RustCrypto/formats/pull/949
+[#951]: https://github.com/RustCrypto/formats/pull/951
+
+## 0.2.0 (2023-03-18)
+### Added
+- Feature-gated `Arbitrary` impl for `Certificate` ([#761])
+- Allow request to be serialized to PEM ([#819])
+- `Display` impl for `SerialNumber` ([#820])
+- `std` feature implies `const-oid/std` ([#874])
+
+### Changed
+- Serial numbers are formatted as `PrintableString` ([#794])
+- `SerialNumber` is now a specialized object ([#795])
+- MSRV 1.65 ([#805])
+- Make types owned instead of reference-based ([#806], [#841])
+- Bump `der` to v0.7 ([#899])
+- Bump `spki` to v0.7 ([#900])
+
+### Fixed
+- Handling of negative serial numbers ([#823], [#831])
+
+### Removed
+- `alloc` feature: now unconditionally required ([#841])
+
+[#761]: https://github.com/RustCrypto/formats/pull/761
+[#794]: https://github.com/RustCrypto/formats/pull/794
+[#795]: https://github.com/RustCrypto/formats/pull/795
+[#805]: https://github.com/RustCrypto/formats/pull/805
+[#806]: https://github.com/RustCrypto/formats/pull/806
+[#819]: https://github.com/RustCrypto/formats/pull/819
+[#820]: https://github.com/RustCrypto/formats/pull/820
+[#823]: https://github.com/RustCrypto/formats/pull/823
+[#831]: https://github.com/RustCrypto/formats/pull/831
+[#841]: https://github.com/RustCrypto/formats/pull/841
+[#874]: https://github.com/RustCrypto/formats/pull/874
+[#899]: https://github.com/RustCrypto/formats/pull/899
+[#900]: https://github.com/RustCrypto/formats/pull/900
+
 ## 0.1.1 (2022-12-10)
 ### Added
 - Support `TeletexString` in `DirectoryString` ([#692])
diff --git a/Cargo.toml b/Cargo.toml
index 43ad5a1..793721f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,9 +11,9 @@
 
 [package]
 edition = "2021"
-rust-version = "1.56"
+rust-version = "1.65"
 name = "x509-cert"
-version = "0.1.1"
+version = "0.2.4"
 authors = ["RustCrypto Developers"]
 description = """
 Pure Rust implementation of the X.509 Public Key Infrastructure Certificate
@@ -37,37 +37,90 @@
     "docsrs",
 ]
 
+[dependencies.arbitrary]
+version = "1.3"
+features = ["derive"]
+optional = true
+
 [dependencies.const-oid]
-version = "0.9"
+version = "0.9.3"
 features = ["db"]
 
 [dependencies.der]
-version = "0.6"
+version = "0.7.6"
 features = [
-    "derive",
     "alloc",
+    "derive",
     "flagset",
+    "oid",
 ]
 
-[dependencies.flagset]
-version = "0.4.3"
+[dependencies.sha1]
+version = "0.10.0"
+optional = true
+
+[dependencies.signature]
+version = "2.1.0"
+features = ["rand_core"]
+optional = true
 
 [dependencies.spki]
-version = "0.6"
+version = "0.7.2"
+features = ["alloc"]
+
+[dev-dependencies.ecdsa]
+version = "0.16.7"
+features = [
+    "digest",
+    "pem",
+]
 
 [dev-dependencies.hex-literal]
-version = "0.3"
+version = "0.4"
+
+[dev-dependencies.p256]
+version = "0.13.0"
+
+[dev-dependencies.rand]
+version = "0.8.5"
+
+[dev-dependencies.rsa]
+version = "0.9.2"
+features = ["sha2"]
 
 [dev-dependencies.rstest]
-version = "0.12"
+version = "0.17"
+
+[dev-dependencies.sha2]
+version = "0.10"
+features = ["oid"]
+
+[dev-dependencies.tempfile]
+version = "3.5.0"
 
 [features]
-alloc = ["der/alloc"]
+arbitrary = [
+    "dep:arbitrary",
+    "std",
+    "der/arbitrary",
+    "spki/arbitrary",
+]
+builder = [
+    "std",
+    "sha1/default",
+    "signature",
+]
+default = [
+    "pem",
+    "std",
+]
+hazmat = []
 pem = [
-    "alloc",
     "der/pem",
+    "spki/pem",
 ]
 std = [
+    "const-oid/std",
     "der/std",
     "spki/std",
 ]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 723504f..717379f 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "x509-cert"
-version = "0.1.1"
+version = "0.2.4"
 description = """
 Pure Rust implementation of the X.509 Public Key Infrastructure Certificate
 format as described in RFC 5280
@@ -12,26 +12,37 @@
 keywords = ["crypto"]
 readme = "README.md"
 edition = "2021"
-rust-version = "1.56"
+rust-version = "1.65"
 
 [dependencies]
-const-oid = { version = "0.9", features = ["db"], path = "../const-oid" }
-der = { version = "0.6", features = ["derive", "alloc", "flagset"], path = "../der" }
-flagset = { version = "0.4.3" }
-spki = { version = "0.6", path = "../spki" }
+const-oid = { version = "0.9.3", features = ["db"] }
+der = { version = "0.7.6", features = ["alloc", "derive", "flagset", "oid"] }
+spki = { version = "0.7.2", features = ["alloc"] }
+
+# optional dependencies
+arbitrary = { version = "1.3", features = ["derive"], optional = true }
+sha1 = { version = "0.10.0", optional = true }
+signature = { version = "2.1.0", features = ["rand_core"], optional = true }
 
 [dev-dependencies]
-hex-literal = "0.3"
-
-# NOTE: upgrading requires MSRV bumps
-# - rstest v0.13 requires 1.59 (for `async-global-executor`)
-# - rstest v0.14 requires a workspace-wide 1.60 MSRV (for namespaced features)
-rstest = "0.12"
+hex-literal = "0.4"
+rand = "0.8.5"
+rsa = { version = "0.9.2", features = ["sha2"] }
+ecdsa = { version = "0.16.7", features = ["digest", "pem"] }
+p256 = "0.13.0"
+rstest = "0.17"
+sha2 = { version = "0.10", features = ["oid"] }
+tempfile = "3.5.0"
+x509-cert-test-support = { path = "./test-support" }
 
 [features]
-alloc = ["der/alloc"]
-std = ["der/std", "spki/std"]
-pem = ["alloc", "der/pem"]
+default = ["pem", "std"]
+std = ["const-oid/std", "der/std", "spki/std"]
+
+arbitrary = ["dep:arbitrary", "std", "der/arbitrary", "spki/arbitrary"]
+builder = ["std", "sha1/default", "signature"]
+hazmat = []
+pem = ["der/pem", "spki/pem"]
 
 [package.metadata.docs.rs]
 all-features = true
diff --git a/METADATA b/METADATA
index c38c1c0..fb2e5f3 100644
--- a/METADATA
+++ b/METADATA
@@ -1,23 +1,20 @@
 # This project was upgraded with external_updater.
 # Usage: tools/external_updater/updater.sh update rust/crates/x509-cert
-# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
 
 name: "x509-cert"
 description: "Pure Rust implementation of the X.509 Public Key Infrastructure Certificate format as described in RFC 5280."
 third_party {
-  url {
-    type: HOMEPAGE
-    value: "https://crates.io/crates/x509-cert"
-  }
-  url {
-    type: ARCHIVE
-    value: "https://static.crates.io/crates/x509-cert/x509-cert-0.1.1.crate"
-  }
-  version: "0.1.1"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2022
+    year: 2023
     month: 12
-    day: 19
+    day: 15
+  }
+  homepage: "https://crates.io/crates/x509-cert"
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/x509-cert/x509-cert-0.2.4.crate"
+    version: "0.2.4"
   }
 }
diff --git a/README.md b/README.md
index e439c07..e131c7d 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
 
 ## Minimum Supported Rust Version
 
-This crate requires **Rust 1.57** at a minimum.
+This crate requires **Rust 1.65** at a minimum.
 
 We may change the MSRV in the future, but it will be accompanied by a minor
 version bump.
@@ -43,7 +43,7 @@
 [build-image]: https://github.com/RustCrypto/formats/actions/workflows/x509-cert.yml/badge.svg
 [build-link]: https://github.com/RustCrypto/formats/actions/workflows/x509-cert.yml
 [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
-[rustc-image]: https://img.shields.io/badge/rustc-1.57+-blue.svg
+[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg
 [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
 [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats
 
diff --git a/cargo_embargo.json b/cargo_embargo.json
index 9351aed..e6f2c7a 100644
--- a/cargo_embargo.json
+++ b/cargo_embargo.json
@@ -3,9 +3,7 @@
     "//apex_available:platform",
     "com.android.virt"
   ],
-  "features": [
-    "alloc"
-  ],
+  "features": [],
   "run_cargo": false,
   "variants": [
     {
diff --git a/src/anchor.rs b/src/anchor.rs
index ad7ef08..bc3a2fb 100644
--- a/src/anchor.rs
+++ b/src/anchor.rs
@@ -4,26 +4,22 @@
 use crate::{ext::Extensions, name::Name};
 use crate::{Certificate, TbsCertificate};
 
-use der::asn1::{OctetStringRef, Utf8StringRef};
+use alloc::string::String;
+use der::asn1::OctetString;
+use der::flagset::{flags, FlagSet};
 use der::{Choice, Enumerated, Sequence};
-use flagset::{flags, FlagSet};
-use spki::SubjectPublicKeyInfo;
+use spki::SubjectPublicKeyInfoOwned;
 
 /// Version identifier for TrustAnchorInfo
-#[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated)]
+#[derive(Clone, Debug, Default, Copy, PartialEq, Eq, Enumerated)]
 #[asn1(type = "INTEGER")]
 #[repr(u8)]
 pub enum Version {
     /// Version 1 (default)
+    #[default]
     V1 = 0,
 }
 
-impl Default for Version {
-    fn default() -> Self {
-        Version::V1
-    }
-}
-
 /// ```text
 /// TrustAnchorInfo ::= SEQUENCE {
 ///     version         TrustAnchorInfoVersion DEFAULT v1,
@@ -41,25 +37,25 @@
 /// ```
 #[derive(Clone, Debug, PartialEq, Eq, Sequence)]
 #[allow(missing_docs)]
-pub struct TrustAnchorInfo<'a> {
+pub struct TrustAnchorInfo {
     #[asn1(default = "Default::default")]
     pub version: Version,
 
-    pub pub_key: SubjectPublicKeyInfo<'a>,
+    pub pub_key: SubjectPublicKeyInfoOwned,
 
-    pub key_id: OctetStringRef<'a>,
+    pub key_id: OctetString,
 
     #[asn1(optional = "true")]
-    pub ta_title: Option<Utf8StringRef<'a>>,
+    pub ta_title: Option<String>,
 
     #[asn1(optional = "true")]
-    pub cert_path: Option<CertPathControls<'a>>,
+    pub cert_path: Option<CertPathControls>,
 
     #[asn1(context_specific = "1", tag_mode = "EXPLICIT", optional = "true")]
-    pub extensions: Option<Extensions<'a>>,
+    pub extensions: Option<Extensions>,
 
     #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")]
-    pub ta_title_lang_tag: Option<Utf8StringRef<'a>>,
+    pub ta_title_lang_tag: Option<String>,
 }
 
 /// ```text
@@ -74,20 +70,20 @@
 /// ```
 #[derive(Clone, Debug, Eq, PartialEq, Sequence)]
 #[allow(missing_docs)]
-pub struct CertPathControls<'a> {
-    pub ta_name: Name<'a>,
+pub struct CertPathControls {
+    pub ta_name: Name,
 
     #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")]
-    pub certificate: Option<Certificate<'a>>,
+    pub certificate: Option<Certificate>,
 
     #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")]
-    pub policy_set: Option<CertificatePolicies<'a>>,
+    pub policy_set: Option<CertificatePolicies>,
 
     #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")]
     pub policy_flags: Option<CertPolicyFlags>,
 
     #[asn1(context_specific = "3", tag_mode = "IMPLICIT", optional = "true")]
-    pub name_constr: Option<NameConstraints<'a>>,
+    pub name_constr: Option<NameConstraints>,
 
     #[asn1(context_specific = "4", tag_mode = "IMPLICIT", optional = "true")]
     pub path_len_constraint: Option<u32>,
@@ -128,12 +124,12 @@
 #[derive(Clone, Debug, PartialEq, Eq, Choice)]
 #[allow(clippy::large_enum_variant)]
 #[allow(missing_docs)]
-pub enum TrustAnchorChoice<'a> {
-    Certificate(Certificate<'a>),
+pub enum TrustAnchorChoice {
+    Certificate(Certificate),
 
     #[asn1(context_specific = "1", tag_mode = "EXPLICIT", constructed = "true")]
-    TbsCertificate(TbsCertificate<'a>),
+    TbsCertificate(TbsCertificate),
 
     #[asn1(context_specific = "2", tag_mode = "EXPLICIT", constructed = "true")]
-    TaInfo(TrustAnchorInfo<'a>),
+    TaInfo(TrustAnchorInfo),
 }
diff --git a/src/attr.rs b/src/attr.rs
index 2b4336a..d4cccc3 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -1,12 +1,21 @@
 //! Attribute-related definitions as defined in X.501 (and updated by RFC 5280).
 
 use alloc::vec::Vec;
-use const_oid::db::rfc4519::{COUNTRY_NAME, DOMAIN_COMPONENT};
-use core::fmt::{self, Write};
-
-use const_oid::db::DB;
-use der::asn1::{AnyRef, ObjectIdentifier, SetOfVec};
-use der::{Decode, Encode, Error, ErrorKind, Sequence, Tag, Tagged, ValueOrd};
+use const_oid::db::{
+    rfc4519::{COUNTRY_NAME, DOMAIN_COMPONENT, SERIAL_NUMBER},
+    Database, DB,
+};
+use core::{
+    fmt::{self, Write},
+    str::FromStr,
+};
+use der::{
+    asn1::{
+        Any, Ia5StringRef, ObjectIdentifier, PrintableStringRef, SetOfVec, TeletexStringRef,
+        Utf8StringRef,
+    },
+    Decode, Encode, Error, ErrorKind, Sequence, Tag, Tagged, ValueOrd,
+};
 
 /// X.501 `AttributeType` as defined in [RFC 5280 Appendix A.1].
 ///
@@ -24,7 +33,7 @@
 /// ```
 ///
 /// [RFC 5280 Appendix A.1]: https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1
-pub type AttributeValue<'a> = AnyRef<'a>;
+pub type AttributeValue = Any;
 
 /// X.501 `Attribute` as defined in [RFC 5280 Appendix A.1].
 ///
@@ -50,17 +59,9 @@
 /// [RFC 5280 Appendix A.1]: https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1
 #[derive(Clone, Debug, PartialEq, Eq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct Attribute<'a> {
+pub struct Attribute {
     pub oid: AttributeType,
-    pub values: SetOfVec<AttributeValue<'a>>,
-}
-
-impl<'a> TryFrom<&'a [u8]> for Attribute<'a> {
-    type Error = Error;
-
-    fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
-        Self::from_der(bytes)
-    }
+    pub values: SetOfVec<AttributeValue>,
 }
 
 /// X.501 `Attributes` as defined in [RFC 2986 Section 4].
@@ -70,7 +71,7 @@
 /// ```
 ///
 /// [RFC 2986 Section 4]: https://datatracker.ietf.org/doc/html/rfc2986#section-4
-pub type Attributes<'a> = SetOfVec<Attribute<'a>>;
+pub type Attributes = SetOfVec<Attribute>;
 
 /// X.501 `AttributeTypeAndValue` as defined in [RFC 5280 Appendix A.1].
 ///
@@ -82,11 +83,12 @@
 /// ```
 ///
 /// [RFC 5280 Appendix A.1]: https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Sequence, ValueOrd)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct AttributeTypeAndValue<'a> {
+pub struct AttributeTypeAndValue {
     pub oid: AttributeType,
-    pub value: AnyRef<'a>,
+    pub value: AttributeValue,
 }
 
 #[derive(Copy, Clone)]
@@ -141,9 +143,9 @@
     }
 }
 
-impl AttributeTypeAndValue<'_> {
+impl AttributeTypeAndValue {
     /// Parses the hex value in the `OID=#HEX` format.
-    fn encode_hex(oid: ObjectIdentifier, val: &str) -> Result<Vec<u8>, Error> {
+    fn from_hex(oid: ObjectIdentifier, val: &str) -> Result<Self, Error> {
         // Ensure an even number of hex bytes.
         let mut iter = match val.len() % 2 {
             0 => [].iter().cloned().chain(val.bytes()),
@@ -153,6 +155,7 @@
 
         // Decode der bytes from hex.
         let mut bytes = Vec::with_capacity((val.len() + 1) / 2);
+
         while let (Some(h), Some(l)) = (iter.next(), iter.next()) {
             let mut byte = 0u8;
 
@@ -168,14 +171,14 @@
             bytes.push(byte);
         }
 
-        // Serialize.
-        let value = AnyRef::from_der(&bytes)?;
-        let atv = AttributeTypeAndValue { oid, value };
-        atv.to_vec()
+        Ok(Self {
+            oid,
+            value: Any::from_der(&bytes)?,
+        })
     }
 
     /// Parses the string value in the `NAME=STRING` format.
-    fn encode_str(oid: ObjectIdentifier, val: &str) -> Result<Vec<u8>, Error> {
+    fn from_delimited_str(oid: ObjectIdentifier, val: &str) -> Result<Self, Error> {
         // Undo escaping.
         let mut parser = Parser::new();
         for c in val.bytes() {
@@ -185,13 +188,16 @@
         let tag = match oid {
             COUNTRY_NAME => Tag::PrintableString,
             DOMAIN_COMPONENT => Tag::Ia5String,
+            // Serial numbers are formatted as Printable String as per RFC 5280 Appendix A.1:
+            // https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1
+            SERIAL_NUMBER => Tag::PrintableString,
             _ => Tag::Utf8String,
         };
 
-        // Serialize.
-        let value = AnyRef::new(tag, parser.as_bytes())?;
-        let atv = AttributeTypeAndValue { oid, value };
-        atv.to_vec()
+        Ok(Self {
+            oid,
+            value: Any::new(tag, parser.as_bytes())?,
+        })
     }
 
     /// Converts an AttributeTypeAndValue string into an encoded AttributeTypeAndValue
@@ -199,7 +205,24 @@
     /// This function follows the rules in [RFC 4514].
     ///
     /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
+    #[deprecated(
+        since = "0.2.1",
+        note = "use AttributeTypeAndValue::from_str(...)?.to_der()"
+    )]
     pub fn encode_from_string(s: &str) -> Result<Vec<u8>, Error> {
+        Self::from_str(s)?.to_der()
+    }
+}
+
+/// Parse an [`AttributeTypeAndValue`] string.
+///
+/// This function follows the rules in [RFC 4514].
+///
+/// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
+impl FromStr for AttributeTypeAndValue {
+    type Err = Error;
+
+    fn from_str(s: &str) -> der::Result<Self> {
         let idx = s.find('=').ok_or_else(|| Error::from(ErrorKind::Failed))?;
         let (key, val) = s.split_at(idx);
         let val = &val[1..];
@@ -212,8 +235,8 @@
 
         // If the value is hex-encoded DER...
         match val.strip_prefix('#') {
-            Some(val) => Self::encode_hex(oid, val),
-            None => Self::encode_str(oid, val),
+            Some(val) => Self::from_hex(oid, val),
+            None => Self::from_delimited_str(oid, val),
         }
     }
 }
@@ -221,17 +244,23 @@
 /// Serializes the structure according to the rules in [RFC 4514].
 ///
 /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
-impl fmt::Display for AttributeTypeAndValue<'_> {
+impl fmt::Display for AttributeTypeAndValue {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let val = match self.value.tag() {
-            Tag::PrintableString => self.value.printable_string().ok().map(|s| s.as_str()),
-            Tag::Utf8String => self.value.utf8_string().ok().map(|s| s.as_str()),
-            Tag::Ia5String => self.value.ia5_string().ok().map(|s| s.as_str()),
-            Tag::TeletexString => self.value.teletex_string().ok().map(|s| s.as_str()),
+            Tag::PrintableString => PrintableStringRef::try_from(&self.value)
+                .ok()
+                .map(|s| s.as_str()),
+            Tag::Utf8String => Utf8StringRef::try_from(&self.value)
+                .ok()
+                .map(|s| s.as_str()),
+            Tag::Ia5String => Ia5StringRef::try_from(&self.value).ok().map(|s| s.as_str()),
+            Tag::TeletexString => TeletexStringRef::try_from(&self.value)
+                .ok()
+                .map(|s| s.as_str()),
             _ => None,
         };
 
-        if let (Some(key), Some(val)) = (DB.by_oid(&self.oid), val) {
+        if let (Some(key), Some(val)) = (DB.shortest_name_by_oid(&self.oid), val) {
             write!(f, "{}=", key.to_ascii_uppercase())?;
 
             let mut iter = val.char_indices().peekable();
@@ -245,7 +274,7 @@
                 }
             }
         } else {
-            let value = self.value.to_vec().or(Err(fmt::Error))?;
+            let value = self.value.to_der().or(Err(fmt::Error))?;
 
             write!(f, "{}=#", self.oid)?;
             for c in value {
@@ -256,3 +285,26 @@
         Ok(())
     }
 }
+
+/// Helper trait to bring shortest name by oid lookups to Database
+trait ShortestName {
+    fn shortest_name_by_oid(&self, oid: &ObjectIdentifier) -> Option<&str>;
+}
+
+impl<'a> ShortestName for Database<'a> {
+    fn shortest_name_by_oid(&self, oid: &ObjectIdentifier) -> Option<&'a str> {
+        let mut best_match: Option<&'a str> = None;
+
+        for m in self.find_names_for_oid(*oid) {
+            if let Some(previous) = best_match {
+                if m.len() < previous.len() {
+                    best_match = Some(m);
+                }
+            } else {
+                best_match = Some(m);
+            }
+        }
+
+        best_match
+    }
+}
diff --git a/src/builder.rs b/src/builder.rs
new file mode 100644
index 0000000..ec51a7e
--- /dev/null
+++ b/src/builder.rs
@@ -0,0 +1,526 @@
+//! X509 Certificate builder
+
+use alloc::vec;
+use core::fmt;
+use der::{asn1::BitString, referenced::OwnedToRef, Encode};
+use signature::{rand_core::CryptoRngCore, Keypair, RandomizedSigner, Signer};
+use spki::{
+    DynSignatureAlgorithmIdentifier, EncodePublicKey, SignatureBitStringEncoding,
+    SubjectPublicKeyInfoOwned, SubjectPublicKeyInfoRef,
+};
+
+use crate::{
+    certificate::{Certificate, TbsCertificate, Version},
+    ext::{
+        pkix::{
+            AuthorityKeyIdentifier, BasicConstraints, KeyUsage, KeyUsages, SubjectKeyIdentifier,
+        },
+        AsExtension, Extension, Extensions,
+    },
+    name::Name,
+    request::{attributes::AsAttribute, CertReq, CertReqInfo, ExtensionReq},
+    serial_number::SerialNumber,
+    time::Validity,
+};
+
+/// Error type
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum Error {
+    /// ASN.1 DER-related errors.
+    Asn1(der::Error),
+
+    /// Public key errors propagated from the [`spki::Error`] type.
+    PublicKey(spki::Error),
+
+    /// Signing error propagated for the [`signature::Error`] type.
+    Signature(signature::Error),
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for Error {}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::Asn1(err) => write!(f, "ASN.1 error: {}", err),
+            Error::PublicKey(err) => write!(f, "public key error: {}", err),
+            Error::Signature(err) => write!(f, "signature error: {}", err),
+        }
+    }
+}
+
+impl From<der::Error> for Error {
+    fn from(err: der::Error) -> Error {
+        Error::Asn1(err)
+    }
+}
+
+impl From<spki::Error> for Error {
+    fn from(err: spki::Error) -> Error {
+        Error::PublicKey(err)
+    }
+}
+
+impl From<signature::Error> for Error {
+    fn from(err: signature::Error) -> Error {
+        Error::Signature(err)
+    }
+}
+
+type Result<T> = core::result::Result<T, Error>;
+
+/// The type of certificate to build
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum Profile {
+    /// Build a root CA certificate
+    Root,
+    /// Build an intermediate sub CA certificate
+    SubCA {
+        /// issuer   Name,
+        /// represents the name signing the certificate
+        issuer: Name,
+        /// pathLenConstraint       INTEGER (0..MAX) OPTIONAL
+        /// BasicConstraints as defined in [RFC 5280 Section 4.2.1.9].
+        path_len_constraint: Option<u8>,
+    },
+    /// Build an end certificate
+    Leaf {
+        /// issuer   Name,
+        /// represents the name signing the certificate
+        issuer: Name,
+        /// should the key agreement flag of KeyUsage be enabled
+        enable_key_agreement: bool,
+        /// should the key encipherment flag of KeyUsage be enabled
+        enable_key_encipherment: bool,
+        /// should the subject key identifier extension be included
+        ///
+        /// From [RFC 5280 Section 4.2.1.2]:
+        ///  For end entity certificates, subject key identifiers SHOULD be
+        ///  derived from the public key.  Two common methods for generating key
+        ///  identifiers from the public key are identified above.
+        #[cfg(feature = "hazmat")]
+        include_subject_key_identifier: bool,
+    },
+    #[cfg(feature = "hazmat")]
+    /// Opt-out of the default extensions
+    Manual {
+        /// issuer   Name,
+        /// represents the name signing the certificate
+        /// A `None` will make it a self-signed certificate
+        issuer: Option<Name>,
+    },
+}
+
+impl Profile {
+    fn get_issuer(&self, subject: &Name) -> Name {
+        match self {
+            Profile::Root => subject.clone(),
+            Profile::SubCA { issuer, .. } => issuer.clone(),
+            Profile::Leaf { issuer, .. } => issuer.clone(),
+            #[cfg(feature = "hazmat")]
+            Profile::Manual { issuer, .. } => issuer.as_ref().unwrap_or(subject).clone(),
+        }
+    }
+
+    fn build_extensions(
+        &self,
+        spk: SubjectPublicKeyInfoRef<'_>,
+        issuer_spk: SubjectPublicKeyInfoRef<'_>,
+        tbs: &TbsCertificate,
+    ) -> Result<vec::Vec<Extension>> {
+        #[cfg(feature = "hazmat")]
+        // User opted out of default extensions set.
+        if let Profile::Manual { .. } = self {
+            return Ok(vec::Vec::default());
+        }
+
+        let mut extensions: vec::Vec<Extension> = vec::Vec::new();
+
+        match self {
+            #[cfg(feature = "hazmat")]
+            Profile::Leaf {
+                include_subject_key_identifier: false,
+                ..
+            } => {}
+            _ => extensions.push(
+                SubjectKeyIdentifier::try_from(spk)?.to_extension(&tbs.subject, &extensions)?,
+            ),
+        }
+
+        // Build Authority Key Identifier
+        match self {
+            Profile::Root => {}
+            _ => {
+                extensions.push(
+                    AuthorityKeyIdentifier::try_from(issuer_spk.clone())?
+                        .to_extension(&tbs.subject, &extensions)?,
+                );
+            }
+        }
+
+        // Build Basic Contraints extensions
+        extensions.push(match self {
+            Profile::Root => BasicConstraints {
+                ca: true,
+                path_len_constraint: None,
+            }
+            .to_extension(&tbs.subject, &extensions)?,
+            Profile::SubCA {
+                path_len_constraint,
+                ..
+            } => BasicConstraints {
+                ca: true,
+                path_len_constraint: *path_len_constraint,
+            }
+            .to_extension(&tbs.subject, &extensions)?,
+            Profile::Leaf { .. } => BasicConstraints {
+                ca: false,
+                path_len_constraint: None,
+            }
+            .to_extension(&tbs.subject, &extensions)?,
+            #[cfg(feature = "hazmat")]
+            Profile::Manual { .. } => unreachable!(),
+        });
+
+        // Build Key Usage extension
+        match self {
+            Profile::Root | Profile::SubCA { .. } => {
+                extensions.push(
+                    KeyUsage(KeyUsages::KeyCertSign | KeyUsages::CRLSign)
+                        .to_extension(&tbs.subject, &extensions)?,
+                );
+            }
+            Profile::Leaf {
+                enable_key_agreement,
+                enable_key_encipherment,
+                ..
+            } => {
+                let mut key_usage = KeyUsages::DigitalSignature | KeyUsages::NonRepudiation;
+                if *enable_key_encipherment {
+                    key_usage |= KeyUsages::KeyEncipherment;
+                }
+                if *enable_key_agreement {
+                    key_usage |= KeyUsages::KeyAgreement;
+                }
+
+                extensions.push(KeyUsage(key_usage).to_extension(&tbs.subject, &extensions)?);
+            }
+            #[cfg(feature = "hazmat")]
+            Profile::Manual { .. } => unreachable!(),
+        }
+
+        Ok(extensions)
+    }
+}
+
+/// X509 Certificate builder
+///
+/// ```
+/// use der::Decode;
+/// use x509_cert::spki::SubjectPublicKeyInfoOwned;
+/// use x509_cert::builder::{CertificateBuilder, Profile};
+/// use x509_cert::name::Name;
+/// use x509_cert::serial_number::SerialNumber;
+/// use x509_cert::time::Validity;
+/// use std::str::FromStr;
+///
+/// # const RSA_2048_DER: &[u8] = include_bytes!("../tests/examples/rsa2048-pub.der");
+/// # const RSA_2048_PRIV_DER: &[u8] = include_bytes!("../tests/examples/rsa2048-priv.der");
+/// # use rsa::{pkcs1v15::SigningKey, pkcs1::DecodeRsaPrivateKey};
+/// # use sha2::Sha256;
+/// # use std::time::Duration;
+/// # use der::referenced::RefToOwned;
+/// # fn rsa_signer() -> SigningKey<Sha256> {
+/// #     let private_key = rsa::RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER).unwrap();
+/// #     let signing_key = SigningKey::<Sha256>::new_with_prefix(private_key);
+/// #     signing_key
+/// # }
+///
+/// let serial_number = SerialNumber::from(42u32);
+/// let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
+/// let profile = Profile::Root;
+/// let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
+///
+/// let pub_key = SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER).expect("get rsa pub key");
+///
+/// let mut signer = rsa_signer();
+/// let mut builder = CertificateBuilder::new(
+///     profile,
+///     serial_number,
+///     validity,
+///     subject,
+///     pub_key,
+///     &signer,
+/// )
+/// .expect("Create certificate");
+/// ```
+pub struct CertificateBuilder<'s, S> {
+    tbs: TbsCertificate,
+    extensions: Extensions,
+    cert_signer: &'s S,
+}
+
+impl<'s, S> CertificateBuilder<'s, S>
+where
+    S: Keypair + DynSignatureAlgorithmIdentifier,
+    S::VerifyingKey: EncodePublicKey,
+{
+    /// Creates a new certificate builder
+    pub fn new(
+        profile: Profile,
+        serial_number: SerialNumber,
+        mut validity: Validity,
+        subject: Name,
+        subject_public_key_info: SubjectPublicKeyInfoOwned,
+        cert_signer: &'s S,
+    ) -> Result<Self> {
+        let verifying_key = cert_signer.verifying_key();
+        let signer_pub = verifying_key
+            .to_public_key_der()?
+            .decode_msg::<SubjectPublicKeyInfoOwned>()?;
+
+        let signature_alg = cert_signer.signature_algorithm_identifier()?;
+        let issuer = profile.get_issuer(&subject);
+
+        validity.not_before.rfc5280_adjust_utc_time()?;
+        validity.not_after.rfc5280_adjust_utc_time()?;
+
+        let tbs = TbsCertificate {
+            version: Version::V3,
+            serial_number,
+            signature: signature_alg,
+            issuer,
+            validity,
+            subject,
+            subject_public_key_info,
+            extensions: None,
+
+            // We will not generate unique identifier because as per RFC5280 Section 4.1.2.8:
+            //   CAs conforming to this profile MUST NOT generate
+            //   certificates with unique identifiers.
+            //
+            // https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.8
+            issuer_unique_id: None,
+            subject_unique_id: None,
+        };
+
+        let extensions = profile.build_extensions(
+            tbs.subject_public_key_info.owned_to_ref(),
+            signer_pub.owned_to_ref(),
+            &tbs,
+        )?;
+        Ok(Self {
+            tbs,
+            extensions,
+            cert_signer,
+        })
+    }
+
+    /// Add an extension to this certificate
+    pub fn add_extension<E: AsExtension>(&mut self, extension: &E) -> Result<()> {
+        let ext = extension.to_extension(&self.tbs.subject, &self.extensions)?;
+        self.extensions.push(ext);
+
+        Ok(())
+    }
+}
+
+/// Builder for X509 Certificate Requests
+///
+/// ```
+/// # use p256::{pkcs8::DecodePrivateKey, NistP256, ecdsa::DerSignature};
+/// # const PKCS8_PRIVATE_KEY_DER: &[u8] = include_bytes!("../tests/examples/p256-priv.der");
+/// # fn ecdsa_signer() -> ecdsa::SigningKey<NistP256> {
+/// #     let secret_key = p256::SecretKey::from_pkcs8_der(PKCS8_PRIVATE_KEY_DER).unwrap();
+/// #     ecdsa::SigningKey::from(secret_key)
+/// # }
+/// use x509_cert::{
+///     builder::{Builder, RequestBuilder},
+///     ext::pkix::{name::GeneralName, SubjectAltName},
+///     name::Name,
+/// };
+/// use std::str::FromStr;
+///
+/// use std::net::{IpAddr, Ipv4Addr};
+/// let subject = Name::from_str("CN=service.domination.world").unwrap();
+///
+/// let signer = ecdsa_signer();
+/// let mut builder = RequestBuilder::new(subject, &signer).expect("Create certificate request");
+/// builder
+///     .add_extension(&SubjectAltName(vec![GeneralName::from(IpAddr::V4(
+///         Ipv4Addr::new(192, 0, 2, 0),
+///     ))]))
+///     .unwrap();
+///
+/// let cert_req = builder.build::<DerSignature>().unwrap();
+/// ```
+pub struct RequestBuilder<'s, S> {
+    info: CertReqInfo,
+    extension_req: ExtensionReq,
+    req_signer: &'s S,
+}
+
+impl<'s, S> RequestBuilder<'s, S>
+where
+    S: Keypair + DynSignatureAlgorithmIdentifier,
+    S::VerifyingKey: EncodePublicKey,
+{
+    /// Creates a new certificate request builder
+    pub fn new(subject: Name, req_signer: &'s S) -> Result<Self> {
+        let version = Default::default();
+        let verifying_key = req_signer.verifying_key();
+        let public_key = verifying_key
+            .to_public_key_der()?
+            .decode_msg::<SubjectPublicKeyInfoOwned>()?;
+        let attributes = Default::default();
+        let extension_req = Default::default();
+
+        Ok(Self {
+            info: CertReqInfo {
+                version,
+                subject,
+                public_key,
+                attributes,
+            },
+            extension_req,
+            req_signer,
+        })
+    }
+
+    /// Add an extension to this certificate request
+    pub fn add_extension<E: AsExtension>(&mut self, extension: &E) -> Result<()> {
+        let ext = extension.to_extension(&self.info.subject, &self.extension_req.0)?;
+
+        self.extension_req.0.push(ext);
+
+        Ok(())
+    }
+
+    /// Add an attribute to this certificate request
+    pub fn add_attribute<A: AsAttribute>(&mut self, attribute: &A) -> Result<()> {
+        let attr = attribute.to_attribute()?;
+
+        self.info.attributes.insert(attr)?;
+        Ok(())
+    }
+}
+
+/// Trait for X509 builders
+///
+/// This trait defines the interface between builder and the signers.
+pub trait Builder: Sized {
+    /// The builder's object signer
+    type Signer;
+
+    /// Type built by this builder
+    type Output: Sized;
+
+    /// Return a reference to the signer.
+    fn signer(&self) -> &Self::Signer;
+
+    /// Assemble the final object from signature.
+    fn assemble(self, signature: BitString) -> Result<Self::Output>;
+
+    /// Finalize and return a serialization of the object for signature.
+    fn finalize(&mut self) -> der::Result<vec::Vec<u8>>;
+
+    /// Run the object through the signer and build it.
+    fn build<Signature>(mut self) -> Result<Self::Output>
+    where
+        Self::Signer: Signer<Signature>,
+        Signature: SignatureBitStringEncoding,
+    {
+        let blob = self.finalize()?;
+
+        let signature = self.signer().try_sign(&blob)?.to_bitstring()?;
+
+        self.assemble(signature)
+    }
+
+    /// Run the object through the signer and build it.
+    fn build_with_rng<Signature>(mut self, rng: &mut impl CryptoRngCore) -> Result<Self::Output>
+    where
+        Self::Signer: RandomizedSigner<Signature>,
+        Signature: SignatureBitStringEncoding,
+    {
+        let blob = self.finalize()?;
+
+        let signature = self
+            .signer()
+            .try_sign_with_rng(rng, &blob)?
+            .to_bitstring()?;
+
+        self.assemble(signature)
+    }
+}
+
+impl<'s, S> Builder for CertificateBuilder<'s, S>
+where
+    S: Keypair + DynSignatureAlgorithmIdentifier,
+    S::VerifyingKey: EncodePublicKey,
+{
+    type Signer = S;
+    type Output = Certificate;
+
+    fn signer(&self) -> &Self::Signer {
+        self.cert_signer
+    }
+
+    fn finalize(&mut self) -> der::Result<vec::Vec<u8>> {
+        if !self.extensions.is_empty() {
+            self.tbs.extensions = Some(self.extensions.clone());
+        }
+
+        if self.tbs.extensions.is_none() {
+            if self.tbs.issuer_unique_id.is_some() || self.tbs.subject_unique_id.is_some() {
+                self.tbs.version = Version::V2;
+            } else {
+                self.tbs.version = Version::V1;
+            }
+        }
+
+        self.tbs.to_der()
+    }
+
+    fn assemble(self, signature: BitString) -> Result<Self::Output> {
+        let signature_algorithm = self.tbs.signature.clone();
+
+        Ok(Certificate {
+            tbs_certificate: self.tbs,
+            signature_algorithm,
+            signature,
+        })
+    }
+}
+
+impl<'s, S> Builder for RequestBuilder<'s, S>
+where
+    S: Keypair + DynSignatureAlgorithmIdentifier,
+    S::VerifyingKey: EncodePublicKey,
+{
+    type Signer = S;
+    type Output = CertReq;
+
+    fn signer(&self) -> &Self::Signer {
+        self.req_signer
+    }
+
+    fn finalize(&mut self) -> der::Result<vec::Vec<u8>> {
+        self.info
+            .attributes
+            .insert(self.extension_req.clone().try_into()?)?;
+
+        self.info.to_der()
+    }
+
+    fn assemble(self, signature: BitString) -> Result<Self::Output> {
+        let algorithm = self.req_signer.signature_algorithm_identifier()?;
+
+        Ok(CertReq {
+            info: self.info,
+            algorithm,
+            signature,
+        })
+    }
+}
diff --git a/src/certificate.rs b/src/certificate.rs
index cf71948..c5a105d 100644
--- a/src/certificate.rs
+++ b/src/certificate.rs
@@ -1,17 +1,55 @@
 //! Certificate types
 
-use crate::{name::Name, time::Validity};
-
+use crate::{name::Name, serial_number::SerialNumber, time::Validity};
 use alloc::vec::Vec;
-use core::cmp::Ordering;
-
 use const_oid::AssociatedOid;
-use der::asn1::{BitStringRef, UIntRef};
-use der::{Decode, Enumerated, Error, ErrorKind, Sequence, ValueOrd};
-use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo};
+use core::{cmp::Ordering, fmt::Debug};
+use der::asn1::BitString;
+use der::{Decode, Enumerated, Error, ErrorKind, Sequence, Tag, ValueOrd};
+use spki::{AlgorithmIdentifierOwned, SubjectPublicKeyInfoOwned};
 
 #[cfg(feature = "pem")]
-use der::pem::PemLabel;
+use der::{
+    pem::{self, PemLabel},
+    DecodePem,
+};
+
+/// [`Profile`] allows the consumer of this crate to customize the behavior when parsing
+/// certificates.
+/// By default, parsing will be made in a rfc5280-compliant manner.
+pub trait Profile: PartialEq + Debug + Eq + Clone {
+    /// Checks to run when parsing serial numbers
+    fn check_serial_number(serial: &SerialNumber<Self>) -> der::Result<()> {
+        // See the note in `SerialNumber::new`: we permit lengths of 21 bytes here,
+        // since some X.509 implementations interpret the limit of 20 bytes to refer
+        // to the pre-encoded value.
+        if serial.inner.len() > SerialNumber::<Self>::MAX_DECODE_LEN {
+            Err(Tag::Integer.value_error())
+        } else {
+            Ok(())
+        }
+    }
+}
+
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+#[derive(Debug, PartialEq, Eq, Clone)]
+/// Parse certificates with rfc5280-compliant checks
+pub struct Rfc5280;
+
+impl Profile for Rfc5280 {}
+
+#[cfg(feature = "hazmat")]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+#[derive(Debug, PartialEq, Eq, Clone)]
+/// Parse raw x509 certificate and disable all the checks
+pub struct Raw;
+
+#[cfg(feature = "hazmat")]
+impl Profile for Raw {
+    fn check_serial_number(_serial: &SerialNumber<Self>) -> der::Result<()> {
+        Ok(())
+    }
+}
 
 /// Certificate `Version` as defined in [RFC 5280 Section 4.1].
 ///
@@ -20,6 +58,7 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated)]
 #[asn1(type = "INTEGER")]
 #[repr(u8)]
@@ -36,7 +75,7 @@
 
 impl ValueOrd for Version {
     fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
-        (&(*self as u8)).value_cmp(&(*other as u8))
+        (*self as u8).value_cmp(&(*other as u8))
     }
 }
 
@@ -47,6 +86,9 @@
 }
 
 /// X.509 `TbsCertificate` as defined in [RFC 5280 Section 4.1]
+pub type TbsCertificate = TbsCertificateInner<Rfc5280>;
+
+/// X.509 `TbsCertificate` as defined in [RFC 5280 Section 4.1]
 ///
 /// ASN.1 structure containing the names of the subject and issuer, a public
 /// key associated with the subject, a validity period, and other associated
@@ -71,9 +113,10 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct TbsCertificate<'a> {
+pub struct TbsCertificateInner<P: Profile = Rfc5280> {
     /// The certificate version
     ///
     /// Note that this value defaults to Version 1 per the RFC. However,
@@ -83,32 +126,30 @@
     #[asn1(context_specific = "0", default = "Default::default")]
     pub version: Version,
 
-    pub serial_number: UIntRef<'a>,
-    pub signature: AlgorithmIdentifier<'a>,
-    pub issuer: Name<'a>,
+    pub serial_number: SerialNumber<P>,
+    pub signature: AlgorithmIdentifierOwned,
+    pub issuer: Name,
     pub validity: Validity,
-    pub subject: Name<'a>,
-    pub subject_public_key_info: SubjectPublicKeyInfo<'a>,
+    pub subject: Name,
+    pub subject_public_key_info: SubjectPublicKeyInfoOwned,
 
     #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")]
-    pub issuer_unique_id: Option<BitStringRef<'a>>,
+    pub issuer_unique_id: Option<BitString>,
 
     #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")]
-    pub subject_unique_id: Option<BitStringRef<'a>>,
+    pub subject_unique_id: Option<BitString>,
 
     #[asn1(context_specific = "3", tag_mode = "EXPLICIT", optional = "true")]
-    pub extensions: Option<crate::ext::Extensions<'a>>,
+    pub extensions: Option<crate::ext::Extensions>,
 }
 
-impl<'a> TbsCertificate<'a> {
+impl<P: Profile> TbsCertificateInner<P> {
     /// Decodes a single extension
     ///
     /// 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<'b: 'a, T: Decode<'a> + AssociatedOid>(
-        &'b self,
-    ) -> Result<Option<(bool, T)>, Error> {
+    pub fn get<'a, T: Decode<'a> + AssociatedOid>(&'a self) -> Result<Option<(bool, T)>, Error> {
         let mut iter = self.filter::<T>().peekable();
         match iter.next() {
             None => Ok(None),
@@ -122,20 +163,25 @@
     /// Filters extensions by an associated OID
     ///
     /// Returns a filtered iterator over all the extensions with the OID.
-    pub fn filter<'b: 'a, T: Decode<'a> + AssociatedOid>(
-        &'b self,
-    ) -> impl 'b + Iterator<Item = Result<(bool, T), Error>> {
+    pub fn filter<'a, T: Decode<'a> + AssociatedOid>(
+        &'a self,
+    ) -> impl 'a + Iterator<Item = Result<(bool, T), Error>> {
         self.extensions
             .as_deref()
             .unwrap_or(&[])
             .iter()
             .filter(|e| e.extn_id == T::OID)
-            .map(|e| Ok((e.critical, T::from_der(e.extn_value)?)))
+            .map(|e| Ok((e.critical, T::from_der(e.extn_value.as_bytes())?)))
     }
 }
 
 /// X.509 certificates are defined in [RFC 5280 Section 4.1].
 ///
+/// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
+pub type Certificate = CertificateInner<Rfc5280>;
+
+/// X.509 certificates are defined in [RFC 5280 Section 4.1].
+///
 /// ```text
 /// Certificate  ::=  SEQUENCE  {
 ///     tbsCertificate       TBSCertificate,
@@ -145,17 +191,17 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct Certificate<'a> {
-    pub tbs_certificate: TbsCertificate<'a>,
-    pub signature_algorithm: AlgorithmIdentifier<'a>,
-    pub signature: BitStringRef<'a>,
+pub struct CertificateInner<P: Profile = Rfc5280> {
+    pub tbs_certificate: TbsCertificateInner<P>,
+    pub signature_algorithm: AlgorithmIdentifierOwned,
+    pub signature: BitString,
 }
 
 #[cfg(feature = "pem")]
-#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
-impl PemLabel for Certificate<'_> {
+impl<P: Profile> PemLabel for CertificateInner<P> {
     const PEM_LABEL: &'static str = "CERTIFICATE";
 }
 
@@ -170,4 +216,56 @@
 /// ```
 ///
 /// [RFC 6066]: https://datatracker.ietf.org/doc/html/rfc6066#section-10.1
-pub type PkiPath<'a> = Vec<Certificate<'a>>;
+pub type PkiPath = Vec<Certificate>;
+
+#[cfg(feature = "pem")]
+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> {
+        fn find_boundary<T>(haystack: &[T], needle: &[T]) -> Option<usize>
+        where
+            for<'a> &'a [T]: PartialEq,
+        {
+            haystack
+                .windows(needle.len())
+                .position(|window| window == needle)
+        }
+
+        let mut certs = Vec::new();
+        let mut position: usize = 0;
+
+        let end_boundary = &b"-----END CERTIFICATE-----"[..];
+
+        // Strip the trailing whitespaces
+        loop {
+            if input.is_empty() {
+                break;
+            }
+            let last_pos = input.len() - 1;
+
+            match input.get(last_pos) {
+                Some(b'\r') | Some(b'\n') => {
+                    input = &input[..last_pos];
+                }
+                _ => break,
+            }
+        }
+
+        while position < input.len() - 1 {
+            let rest = &input[position..];
+            let end_pos = find_boundary(rest, end_boundary)
+                .ok_or(pem::Error::PostEncapsulationBoundary)?
+                + end_boundary.len();
+
+            let cert_buf = &rest[..end_pos];
+            let cert = Self::from_pem(cert_buf)?;
+            certs.push(cert);
+
+            position += end_pos;
+        }
+
+        Ok(certs)
+    }
+}
diff --git a/src/crl.rs b/src/crl.rs
index 09256f2..6916783 100644
--- a/src/crl.rs
+++ b/src/crl.rs
@@ -2,14 +2,15 @@
 
 use crate::ext::Extensions;
 use crate::name::Name;
+use crate::serial_number::SerialNumber;
 use crate::time::Time;
 use crate::Version;
 
 use alloc::vec::Vec;
 
-use der::asn1::{BitStringRef, UIntRef};
+use der::asn1::BitString;
 use der::{Sequence, ValueOrd};
-use spki::AlgorithmIdentifier;
+use spki::AlgorithmIdentifierOwned;
 
 /// `CertificateList` as defined in [RFC 5280 Section 5.1].
 ///
@@ -24,10 +25,10 @@
 /// [RFC 5280 Section 5.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.1
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct CertificateList<'a> {
-    pub tbs_cert_list: TbsCertList<'a>,
-    pub signature_algorithm: AlgorithmIdentifier<'a>,
-    pub signature: BitStringRef<'a>,
+pub struct CertificateList {
+    pub tbs_cert_list: TbsCertList,
+    pub signature_algorithm: AlgorithmIdentifierOwned,
+    pub signature: BitString,
 }
 
 /// Implicit intermediate structure from the ASN.1 definition of `TBSCertList`.
@@ -46,10 +47,10 @@
 /// [RFC 5280 Section 5.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.1
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct RevokedCert<'a> {
-    pub serial_number: UIntRef<'a>,
+pub struct RevokedCert {
+    pub serial_number: SerialNumber,
     pub revocation_date: Time,
-    pub crl_entry_extensions: Option<Extensions<'a>>,
+    pub crl_entry_extensions: Option<Extensions>,
 }
 
 /// `TbsCertList` as defined in [RFC 5280 Section 5.1].
@@ -73,14 +74,14 @@
 /// [RFC 5280 Section 5.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.1
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct TbsCertList<'a> {
+pub struct TbsCertList {
     pub version: Version,
-    pub signature: AlgorithmIdentifier<'a>,
-    pub issuer: Name<'a>,
+    pub signature: AlgorithmIdentifierOwned,
+    pub issuer: Name,
     pub this_update: Time,
     pub next_update: Option<Time>,
-    pub revoked_certificates: Option<Vec<RevokedCert<'a>>>,
+    pub revoked_certificates: Option<Vec<RevokedCert>>,
 
     #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")]
-    pub crl_extensions: Option<Extensions<'a>>,
+    pub crl_extensions: Option<Extensions>,
 }
diff --git a/src/ext.rs b/src/ext.rs
index eb6f6fb..aa663c5 100644
--- a/src/ext.rs
+++ b/src/ext.rs
@@ -1,6 +1,7 @@
 //! Standardized X.509 Certificate Extensions
 
-use der::{Sequence, ValueOrd};
+use const_oid::AssociatedOid;
+use der::{asn1::OctetString, Sequence, ValueOrd};
 use spki::ObjectIdentifier;
 
 pub mod pkix;
@@ -22,16 +23,16 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct Extension<'a> {
+pub struct Extension {
     pub extn_id: ObjectIdentifier,
 
     #[asn1(default = "Default::default")]
     pub critical: bool,
 
-    #[asn1(type = "OCTET STRING")]
-    pub extn_value: &'a [u8],
+    pub extn_value: OctetString,
 }
 
 /// Extensions as defined in [RFC 5280 Section 4.1.2.9].
@@ -41,4 +42,26 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9
-pub type Extensions<'a> = alloc::vec::Vec<Extension<'a>>;
+pub type Extensions = alloc::vec::Vec<Extension>;
+
+/// Trait to be implemented by extensions to allow them to be formated as x509 v3 extensions by
+/// builder.
+pub trait AsExtension: AssociatedOid + der::Encode {
+    /// Should the extension be marked critical
+    fn critical(&self, subject: &crate::name::Name, extensions: &[Extension]) -> bool;
+
+    /// Returns the Extension with the content encoded.
+    fn to_extension(
+        &self,
+        subject: &crate::name::Name,
+        extensions: &[Extension],
+    ) -> Result<Extension, der::Error> {
+        let content = OctetString::new(<Self as der::Encode>::to_der(self)?)?;
+
+        Ok(Extension {
+            extn_id: <Self as AssociatedOid>::OID,
+            critical: self.critical(subject, extensions),
+            extn_value: content,
+        })
+    }
+}
diff --git a/src/ext/pkix.rs b/src/ext/pkix.rs
index dec0659..95a5e2b 100644
--- a/src/ext/pkix.rs
+++ b/src/ext/pkix.rs
@@ -31,7 +31,7 @@
 
 use alloc::vec::Vec;
 
-use der::asn1::OctetStringRef;
+use der::asn1::OctetString;
 
 /// SubjectKeyIdentifier as defined in [RFC 5280 Section 4.2.1.2].
 ///
@@ -40,14 +40,19 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.2.1.2]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.2
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct SubjectKeyIdentifier<'a>(pub OctetStringRef<'a>);
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct SubjectKeyIdentifier(pub OctetString);
 
-impl<'a> AssociatedOid for SubjectKeyIdentifier<'a> {
+impl AssociatedOid for SubjectKeyIdentifier {
     const OID: ObjectIdentifier = ID_CE_SUBJECT_KEY_IDENTIFIER;
 }
 
-impl_newtype!(SubjectKeyIdentifier<'a>, OctetStringRef<'a>);
+impl_newtype!(SubjectKeyIdentifier, OctetString);
+impl_extension!(SubjectKeyIdentifier, critical = false);
+impl_key_identifier!(
+    SubjectKeyIdentifier,
+    (|result: &[u8]| Ok(Self(OctetString::new(result)?)))
+);
 
 /// SubjectAltName as defined in [RFC 5280 Section 4.2.1.6].
 ///
@@ -57,13 +62,30 @@
 ///
 /// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct SubjectAltName<'a>(pub name::GeneralNames<'a>);
+pub struct SubjectAltName(pub name::GeneralNames);
 
-impl<'a> AssociatedOid for SubjectAltName<'a> {
+impl AssociatedOid for SubjectAltName {
     const OID: ObjectIdentifier = ID_CE_SUBJECT_ALT_NAME;
 }
 
-impl_newtype!(SubjectAltName<'a>, name::GeneralNames<'a>);
+impl_newtype!(SubjectAltName, name::GeneralNames);
+
+impl crate::ext::AsExtension for SubjectAltName {
+    fn critical(&self, subject: &crate::name::Name, _extensions: &[super::Extension]) -> bool {
+        // https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
+        //   Further, if the only subject identity included in the certificate is
+        //   an alternative name form (e.g., an electronic mail address), then the
+        //   subject distinguished name MUST be empty (an empty sequence), and the
+        //   subjectAltName extension MUST be present.  If the subject field
+        //   contains an empty sequence, then the issuing CA MUST include a
+        //   subjectAltName extension that is marked as critical.  When including
+        //   the subjectAltName extension in a certificate that has a non-empty
+        //   subject distinguished name, conforming CAs SHOULD mark the
+        //   subjectAltName extension as non-critical.
+
+        subject.is_empty()
+    }
+}
 
 /// IssuerAltName as defined in [RFC 5280 Section 4.2.1.7].
 ///
@@ -73,13 +95,14 @@
 ///
 /// [RFC 5280 Section 4.2.1.7]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.7
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct IssuerAltName<'a>(pub name::GeneralNames<'a>);
+pub struct IssuerAltName(pub name::GeneralNames);
 
-impl<'a> AssociatedOid for IssuerAltName<'a> {
+impl AssociatedOid for IssuerAltName {
     const OID: ObjectIdentifier = ID_CE_ISSUER_ALT_NAME;
 }
 
-impl_newtype!(IssuerAltName<'a>, name::GeneralNames<'a>);
+impl_newtype!(IssuerAltName, name::GeneralNames);
+impl_extension!(IssuerAltName, critical = false);
 
 /// SubjectDirectoryAttributes as defined in [RFC 5280 Section 4.2.1.8].
 ///
@@ -89,16 +112,14 @@
 ///
 /// [RFC 5280 Section 4.2.1.8]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.8
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct SubjectDirectoryAttributes<'a>(pub Vec<AttributeTypeAndValue<'a>>);
+pub struct SubjectDirectoryAttributes(pub Vec<AttributeTypeAndValue>);
 
-impl<'a> AssociatedOid for SubjectDirectoryAttributes<'a> {
+impl AssociatedOid for SubjectDirectoryAttributes {
     const OID: ObjectIdentifier = ID_CE_SUBJECT_DIRECTORY_ATTRIBUTES;
 }
 
-impl_newtype!(
-    SubjectDirectoryAttributes<'a>,
-    Vec<AttributeTypeAndValue<'a>>
-);
+impl_newtype!(SubjectDirectoryAttributes, Vec<AttributeTypeAndValue>);
+impl_extension!(SubjectDirectoryAttributes, critical = false);
 
 /// InhibitAnyPolicy as defined in [RFC 5280 Section 4.2.1.14].
 ///
@@ -115,3 +136,4 @@
 }
 
 impl_newtype!(InhibitAnyPolicy, u32);
+impl_extension!(InhibitAnyPolicy, critical = true);
diff --git a/src/ext/pkix/access.rs b/src/ext/pkix/access.rs
index 0390235..4d2d9db 100644
--- a/src/ext/pkix/access.rs
+++ b/src/ext/pkix/access.rs
@@ -16,13 +16,14 @@
 ///
 /// [RFC 5280 Section 4.2.2.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct AuthorityInfoAccessSyntax<'a>(pub Vec<AccessDescription<'a>>);
+pub struct AuthorityInfoAccessSyntax(pub Vec<AccessDescription>);
 
-impl<'a> AssociatedOid for AuthorityInfoAccessSyntax<'a> {
+impl AssociatedOid for AuthorityInfoAccessSyntax {
     const OID: ObjectIdentifier = ID_PE_AUTHORITY_INFO_ACCESS;
 }
 
-impl_newtype!(AuthorityInfoAccessSyntax<'a>, Vec<AccessDescription<'a>>);
+impl_newtype!(AuthorityInfoAccessSyntax, Vec<AccessDescription>);
+impl_extension!(AuthorityInfoAccessSyntax, critical = false);
 
 /// SubjectInfoAccessSyntax as defined in [RFC 5280 Section 4.2.2.2].
 ///
@@ -32,13 +33,14 @@
 ///
 /// [RFC 5280 Section 4.2.2.2]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.2
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct SubjectInfoAccessSyntax<'a>(pub Vec<AccessDescription<'a>>);
+pub struct SubjectInfoAccessSyntax(pub Vec<AccessDescription>);
 
-impl<'a> AssociatedOid for SubjectInfoAccessSyntax<'a> {
+impl AssociatedOid for SubjectInfoAccessSyntax {
     const OID: ObjectIdentifier = ID_PE_SUBJECT_INFO_ACCESS;
 }
 
-impl_newtype!(SubjectInfoAccessSyntax<'a>, Vec<AccessDescription<'a>>);
+impl_newtype!(SubjectInfoAccessSyntax, Vec<AccessDescription>);
+impl_extension!(SubjectInfoAccessSyntax, critical = false);
 
 /// AccessDescription as defined in [RFC 5280 Section 4.2.2.1].
 ///
@@ -52,7 +54,7 @@
 /// [RFC 5280 Section 4.2.2.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct AccessDescription<'a> {
+pub struct AccessDescription {
     pub access_method: ObjectIdentifier,
-    pub access_location: GeneralName<'a>,
+    pub access_location: GeneralName,
 }
diff --git a/src/ext/pkix/authkeyid.rs b/src/ext/pkix/authkeyid.rs
index e7644f5..60b61e5 100644
--- a/src/ext/pkix/authkeyid.rs
+++ b/src/ext/pkix/authkeyid.rs
@@ -1,8 +1,9 @@
 use super::name::GeneralNames;
+use crate::serial_number::SerialNumber;
 
 use const_oid::db::rfc5280::ID_CE_AUTHORITY_KEY_IDENTIFIER;
 use const_oid::{AssociatedOid, ObjectIdentifier};
-use der::asn1::{OctetStringRef, UIntRef};
+use der::asn1::OctetString;
 use der::Sequence;
 
 /// AuthorityKeyIdentifier as defined in [RFC 5280 Section 4.2.1.1].
@@ -18,19 +19,28 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.2.1.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.1
-#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
+#[derive(Clone, Debug, Eq, PartialEq, Sequence, Default)]
 #[allow(missing_docs)]
-pub struct AuthorityKeyIdentifier<'a> {
+pub struct AuthorityKeyIdentifier {
     #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")]
-    pub key_identifier: Option<OctetStringRef<'a>>,
+    pub key_identifier: Option<OctetString>,
 
     #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")]
-    pub authority_cert_issuer: Option<GeneralNames<'a>>,
+    pub authority_cert_issuer: Option<GeneralNames>,
 
     #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")]
-    pub authority_cert_serial_number: Option<UIntRef<'a>>,
+    pub authority_cert_serial_number: Option<SerialNumber>,
 }
 
-impl<'a> AssociatedOid for AuthorityKeyIdentifier<'a> {
+impl AssociatedOid for AuthorityKeyIdentifier {
     const OID: ObjectIdentifier = ID_CE_AUTHORITY_KEY_IDENTIFIER;
 }
+
+impl_extension!(AuthorityKeyIdentifier, critical = false);
+impl_key_identifier!(
+    AuthorityKeyIdentifier,
+    (|result: &[u8]| Ok(Self {
+        key_identifier: Some(OctetString::new(result)?),
+        ..Default::default()
+    }))
+);
diff --git a/src/ext/pkix/certpolicy.rs b/src/ext/pkix/certpolicy.rs
index bb2211f..85820c1 100644
--- a/src/ext/pkix/certpolicy.rs
+++ b/src/ext/pkix/certpolicy.rs
@@ -1,11 +1,11 @@
 //! PKIX Certificate Policies extension
 
-use alloc::vec::Vec;
+use alloc::{string::String, vec::Vec};
 
 use const_oid::db::rfc5912::ID_CE_CERTIFICATE_POLICIES;
 use const_oid::AssociatedOid;
-use der::asn1::{GeneralizedTime, Ia5StringRef, ObjectIdentifier, UIntRef, Utf8StringRef};
-use der::{AnyRef, Choice, Sequence, ValueOrd};
+use der::asn1::{GeneralizedTime, Ia5String, ObjectIdentifier, Uint};
+use der::{Any, Choice, Sequence, ValueOrd};
 
 /// CertificatePolicies as defined in [RFC 5280 Section 4.2.1.4].
 ///
@@ -14,14 +14,19 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
+//  If this extension is
+//  critical, the path validation software MUST be able to interpret this
+//  extension (including the optional qualifier), or MUST reject the
+//  certificate.
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct CertificatePolicies<'a>(pub Vec<PolicyInformation<'a>>);
+pub struct CertificatePolicies(pub Vec<PolicyInformation>);
 
-impl<'a> AssociatedOid for CertificatePolicies<'a> {
+impl AssociatedOid for CertificatePolicies {
     const OID: ObjectIdentifier = ID_CE_CERTIFICATE_POLICIES;
 }
 
-impl_newtype!(CertificatePolicies<'a>, Vec<PolicyInformation<'a>>);
+impl_newtype!(CertificatePolicies, Vec<PolicyInformation>);
+impl_extension!(CertificatePolicies);
 
 /// PolicyInformation as defined in [RFC 5280 Section 4.2.1.4].
 ///
@@ -37,9 +42,9 @@
 /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct PolicyInformation<'a> {
+pub struct PolicyInformation {
     pub policy_identifier: ObjectIdentifier,
-    pub policy_qualifiers: Option<Vec<PolicyQualifierInfo<'a>>>,
+    pub policy_qualifiers: Option<Vec<PolicyQualifierInfo>>,
 }
 
 /// PolicyQualifierInfo as defined in [RFC 5280 Section 4.2.1.4].
@@ -54,9 +59,9 @@
 /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct PolicyQualifierInfo<'a> {
+pub struct PolicyQualifierInfo {
     pub policy_qualifier_id: ObjectIdentifier,
-    pub qualifier: Option<AnyRef<'a>>,
+    pub qualifier: Option<Any>,
 }
 
 /// CpsUri as defined in [RFC 5280 Section 4.2.1.4].
@@ -66,7 +71,7 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
-pub type CpsUri<'a> = Ia5StringRef<'a>;
+pub type CpsUri = Ia5String;
 
 /// UserNotice as defined in [RFC 5280 Section 4.2.1.4].
 ///
@@ -80,9 +85,9 @@
 /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
 #[derive(Clone, Debug, Eq, PartialEq, Sequence)]
 #[allow(missing_docs)]
-pub struct UserNotice<'a> {
+pub struct UserNotice {
     pub notice_ref: Option<GeneralizedTime>,
-    pub explicit_text: Option<DisplayText<'a>>,
+    pub explicit_text: Option<DisplayText>,
 }
 
 /// NoticeReference as defined in [RFC 5280 Section 4.2.1.4].
@@ -96,9 +101,9 @@
 /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
 #[derive(Clone, Debug, Eq, PartialEq, Sequence)]
 #[allow(missing_docs)]
-pub struct NoticeReference<'a> {
-    pub organization: DisplayText<'a>,
-    pub notice_numbers: Option<Vec<UIntRef<'a>>>,
+pub struct NoticeReference {
+    pub organization: DisplayText,
+    pub notice_numbers: Option<Vec<Uint>>,
 }
 
 /// DisplayText as defined in [RFC 5280 Section 4.2.1.4].
@@ -117,10 +122,10 @@
 /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
 #[derive(Choice, Clone, Debug, Eq, PartialEq)]
 #[allow(missing_docs)]
-pub enum DisplayText<'a> {
+pub enum DisplayText {
     #[asn1(type = "IA5String")]
-    Ia5String(Ia5StringRef<'a>),
+    Ia5String(Ia5String),
 
     #[asn1(type = "UTF8String")]
-    Utf8String(Utf8StringRef<'a>),
+    Utf8String(String),
 }
diff --git a/src/ext/pkix/constraints/basic.rs b/src/ext/pkix/constraints/basic.rs
index 5972cc8..c50d8e8 100644
--- a/src/ext/pkix/constraints/basic.rs
+++ b/src/ext/pkix/constraints/basic.rs
@@ -22,3 +22,28 @@
 impl AssociatedOid for BasicConstraints {
     const OID: ObjectIdentifier = ID_CE_BASIC_CONSTRAINTS;
 }
+
+impl crate::ext::AsExtension for BasicConstraints {
+    fn critical(
+        &self,
+        _subject: &crate::name::Name,
+        _extensions: &[crate::ext::Extension],
+    ) -> bool {
+        // https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.9
+        //   Conforming CAs MUST include this extension in all CA certificates
+        //   that contain public keys used to validate digital signatures on
+        //   certificates and MUST mark the extension as critical in such
+        //   certificates.  This extension MAY appear as a critical or non-
+        //   critical extension in CA certificates that contain public keys used
+        //   exclusively for purposes other than validating digital signatures on
+        //   certificates.  Such CA certificates include ones that contain public
+        //   keys used exclusively for validating digital signatures on CRLs and
+        //   ones that contain key management public keys used with certificate
+        //   enrollment protocols.  This extension MAY appear as a critical or
+        //   non-critical extension in end entity certificates.
+
+        // NOTE(baloo): from the spec, it doesn't appear to hurt if we force the extension
+        // to be critical.
+        true
+    }
+}
diff --git a/src/ext/pkix/constraints/name.rs b/src/ext/pkix/constraints/name.rs
index 658f1e2..c05d005 100644
--- a/src/ext/pkix/constraints/name.rs
+++ b/src/ext/pkix/constraints/name.rs
@@ -19,18 +19,20 @@
 /// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10
 #[derive(Clone, Debug, Eq, PartialEq, Sequence)]
 #[allow(missing_docs)]
-pub struct NameConstraints<'a> {
+pub struct NameConstraints {
     #[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")]
-    pub permitted_subtrees: Option<GeneralSubtrees<'a>>,
+    pub permitted_subtrees: Option<GeneralSubtrees>,
 
     #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")]
-    pub excluded_subtrees: Option<GeneralSubtrees<'a>>,
+    pub excluded_subtrees: Option<GeneralSubtrees>,
 }
 
-impl<'a> AssociatedOid for NameConstraints<'a> {
+impl AssociatedOid for NameConstraints {
     const OID: ObjectIdentifier = ID_CE_NAME_CONSTRAINTS;
 }
 
+impl_extension!(NameConstraints, critical = true);
+
 /// GeneralSubtrees as defined in [RFC 5280 Section 4.2.1.10].
 ///
 /// ```text
@@ -38,7 +40,7 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10
-pub type GeneralSubtrees<'a> = Vec<GeneralSubtree<'a>>;
+pub type GeneralSubtrees = Vec<GeneralSubtree>;
 
 /// GeneralSubtree as defined in [RFC 5280 Section 4.2.1.10].
 ///
@@ -53,8 +55,8 @@
 /// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10
 #[derive(Clone, Debug, Eq, PartialEq, Sequence)]
 #[allow(missing_docs)]
-pub struct GeneralSubtree<'a> {
-    pub base: GeneralName<'a>,
+pub struct GeneralSubtree {
+    pub base: GeneralName,
 
     #[asn1(
         context_specific = "0",
diff --git a/src/ext/pkix/constraints/policy.rs b/src/ext/pkix/constraints/policy.rs
index dcb1a8c..c409737 100644
--- a/src/ext/pkix/constraints/policy.rs
+++ b/src/ext/pkix/constraints/policy.rs
@@ -24,3 +24,5 @@
 impl AssociatedOid for PolicyConstraints {
     const OID: ObjectIdentifier = ID_CE_POLICY_CONSTRAINTS;
 }
+
+impl_extension!(PolicyConstraints, critical = true);
diff --git a/src/ext/pkix/crl.rs b/src/ext/pkix/crl.rs
index d65b837..f3e9397 100644
--- a/src/ext/pkix/crl.rs
+++ b/src/ext/pkix/crl.rs
@@ -11,7 +11,7 @@
 
 use alloc::vec::Vec;
 
-use der::{asn1::UIntRef, Enumerated};
+use der::{asn1::Uint, Enumerated};
 
 /// CrlNumber as defined in [RFC 5280 Section 5.2.3].
 ///
@@ -20,14 +20,15 @@
 /// ```
 ///
 /// [RFC 5280 Section 5.2.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.3
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct CrlNumber<'a>(pub UIntRef<'a>);
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct CrlNumber(pub Uint);
 
-impl<'a> AssociatedOid for CrlNumber<'a> {
+impl AssociatedOid for CrlNumber {
     const OID: ObjectIdentifier = ID_CE_CRL_NUMBER;
 }
 
-impl_newtype!(CrlNumber<'a>, UIntRef<'a>);
+impl_newtype!(CrlNumber, Uint);
+impl_extension!(CrlNumber, critical = false);
 
 /// BaseCRLNumber as defined in [RFC 5280 Section 5.2.4].
 ///
@@ -36,14 +37,15 @@
 /// ```
 ///
 /// [RFC 5280 Section 5.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.4
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct BaseCrlNumber<'a>(pub UIntRef<'a>);
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct BaseCrlNumber(pub Uint);
 
-impl<'a> AssociatedOid for BaseCrlNumber<'a> {
+impl AssociatedOid for BaseCrlNumber {
     const OID: ObjectIdentifier = ID_CE_DELTA_CRL_INDICATOR;
 }
 
-impl_newtype!(BaseCrlNumber<'a>, UIntRef<'a>);
+impl_newtype!(BaseCrlNumber, Uint);
+impl_extension!(BaseCrlNumber, critical = true);
 
 /// CrlDistributionPoints as defined in [RFC 5280 Section 4.2.1.13].
 ///
@@ -53,13 +55,14 @@
 ///
 /// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct CrlDistributionPoints<'a>(pub Vec<dp::DistributionPoint<'a>>);
+pub struct CrlDistributionPoints(pub Vec<dp::DistributionPoint>);
 
-impl<'a> AssociatedOid for CrlDistributionPoints<'a> {
+impl AssociatedOid for CrlDistributionPoints {
     const OID: ObjectIdentifier = ID_CE_CRL_DISTRIBUTION_POINTS;
 }
 
-impl_newtype!(CrlDistributionPoints<'a>, Vec<dp::DistributionPoint<'a>>);
+impl_newtype!(CrlDistributionPoints, Vec<dp::DistributionPoint>);
+impl_extension!(CrlDistributionPoints, critical = false);
 
 /// FreshestCrl as defined in [RFC 5280 Section 5.2.6].
 ///
@@ -69,13 +72,14 @@
 ///
 /// [RFC 5280 Section 5.2.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.6
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct FreshestCrl<'a>(pub Vec<dp::DistributionPoint<'a>>);
+pub struct FreshestCrl(pub Vec<dp::DistributionPoint>);
 
-impl<'a> AssociatedOid for FreshestCrl<'a> {
+impl AssociatedOid for FreshestCrl {
     const OID: ObjectIdentifier = ID_CE_FRESHEST_CRL;
 }
 
-impl_newtype!(FreshestCrl<'a>, Vec<dp::DistributionPoint<'a>>);
+impl_newtype!(FreshestCrl, Vec<dp::DistributionPoint>);
+impl_extension!(FreshestCrl, critical = false);
 
 /// CRLReason as defined in [RFC 5280 Section 5.3.1].
 ///
@@ -114,3 +118,5 @@
 impl AssociatedOid for CrlReason {
     const OID: ObjectIdentifier = ID_CE_CRL_REASONS;
 }
+
+impl_extension!(CrlReason, critical = false);
diff --git a/src/ext/pkix/crl/dp.rs b/src/ext/pkix/crl/dp.rs
index f7d1ab7..7acd2c9 100644
--- a/src/ext/pkix/crl/dp.rs
+++ b/src/ext/pkix/crl/dp.rs
@@ -1,8 +1,8 @@
 //! PKIX distribution point types
 
 use const_oid::{db::rfc5280::ID_PE_SUBJECT_INFO_ACCESS, AssociatedOid, ObjectIdentifier};
+use der::flagset::{flags, FlagSet};
 use der::{Sequence, ValueOrd};
-use flagset::{flags, FlagSet};
 
 use crate::ext::pkix::name::{DistributionPointName, GeneralNames};
 
@@ -24,9 +24,9 @@
 /// [RFC 5280 Section 5.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5
 #[derive(Clone, Debug, Eq, PartialEq, Sequence)]
 #[allow(missing_docs)]
-pub struct IssuingDistributionPoint<'a> {
+pub struct IssuingDistributionPoint {
     #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")]
-    pub distribution_point: Option<DistributionPointName<'a>>,
+    pub distribution_point: Option<DistributionPointName>,
 
     #[asn1(
         context_specific = "1",
@@ -60,10 +60,12 @@
     pub only_contains_attribute_certs: bool,
 }
 
-impl<'a> AssociatedOid for IssuingDistributionPoint<'a> {
+impl AssociatedOid for IssuingDistributionPoint {
     const OID: ObjectIdentifier = ID_PE_SUBJECT_INFO_ACCESS;
 }
 
+impl_extension!(IssuingDistributionPoint, critical = true);
+
 /// DistributionPoint as defined in [RFC 5280 Section 4.2.1.13].
 ///
 /// ```text
@@ -76,15 +78,15 @@
 /// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13
 #[derive(Clone, Debug, PartialEq, Eq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct DistributionPoint<'a> {
+pub struct DistributionPoint {
     #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")]
-    pub distribution_point: Option<DistributionPointName<'a>>,
+    pub distribution_point: Option<DistributionPointName>,
 
     #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")]
     pub reasons: Option<ReasonFlags>,
 
     #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")]
-    pub crl_issuer: Option<GeneralNames<'a>>,
+    pub crl_issuer: Option<GeneralNames>,
 }
 
 /// ReasonFlags as defined in [RFC 5280 Section 4.2.1.13].
diff --git a/src/ext/pkix/keyusage.rs b/src/ext/pkix/keyusage.rs
index cd051fe..833db69 100644
--- a/src/ext/pkix/keyusage.rs
+++ b/src/ext/pkix/keyusage.rs
@@ -1,12 +1,12 @@
 use alloc::vec::Vec;
 
 use const_oid::db::rfc5280::{
-    ID_CE_EXT_KEY_USAGE, ID_CE_KEY_USAGE, ID_CE_PRIVATE_KEY_USAGE_PERIOD,
+    ANY_EXTENDED_KEY_USAGE, ID_CE_EXT_KEY_USAGE, ID_CE_KEY_USAGE, ID_CE_PRIVATE_KEY_USAGE_PERIOD,
 };
 use const_oid::AssociatedOid;
 use der::asn1::{GeneralizedTime, ObjectIdentifier};
+use der::flagset::{flags, FlagSet};
 use der::Sequence;
-use flagset::{flags, FlagSet};
 
 flags! {
     /// Key usage flags as defined in [RFC 5280 Section 4.2.1.3].
@@ -52,6 +52,66 @@
 }
 
 impl_newtype!(KeyUsage, FlagSet<KeyUsages>);
+impl_extension!(KeyUsage, critical = true);
+
+impl KeyUsage {
+    /// The subject public key is used for verifying digital signatures
+    pub fn digital_signature(&self) -> bool {
+        self.0.contains(KeyUsages::DigitalSignature)
+    }
+
+    /// When the subject public key is used to verify digital signatures,
+    /// it is asserted as non-repudiation.
+    pub fn non_repudiation(&self) -> bool {
+        self.0.contains(KeyUsages::NonRepudiation)
+    }
+
+    /// The subject public key is used for enciphering private or
+    /// secret keys, i.e., for key transport.
+    pub fn key_encipherment(&self) -> bool {
+        self.0.contains(KeyUsages::KeyEncipherment)
+    }
+
+    /// The subject public key is used for directly enciphering
+    /// raw user data without the use of an intermediate symmetric cipher.
+    pub fn data_encipherment(&self) -> bool {
+        self.0.contains(KeyUsages::DataEncipherment)
+    }
+
+    /// The subject public key is used for key agreement
+    pub fn key_agreement(&self) -> bool {
+        self.0.contains(KeyUsages::KeyAgreement)
+    }
+
+    /// The subject public key is used for enciphering private or
+    /// secret keys, i.e., for key transport.
+    pub fn key_cert_sign(&self) -> bool {
+        self.0.contains(KeyUsages::KeyCertSign)
+    }
+
+    /// The subject public key is used for verifying signatures
+    /// on certificate revocation lists (e.g., CRLs, delta CRLs,
+    /// or ARLs).
+    pub fn crl_sign(&self) -> bool {
+        self.0.contains(KeyUsages::CRLSign)
+    }
+
+    /// The meaning of the `encipher_only` is undefined when `key_agreement`
+    /// returns false.  When `encipher_only` returns true and
+    /// `key_agreement` also returns true, the subject public key may be
+    /// used only for enciphering data while performing key agreement.
+    pub fn encipher_only(&self) -> bool {
+        self.0.contains(KeyUsages::EncipherOnly)
+    }
+
+    /// The meaning of the `decipher_only` is undefined when `key_agreement`
+    /// returns false.  When `encipher_only` returns true and
+    /// `key_agreement` also returns true, the subject public key may be
+    /// used only for deciphering data while performing key agreement.
+    pub fn decipher_only(&self) -> bool {
+        self.0.contains(KeyUsages::DecipherOnly)
+    }
+}
 
 /// ExtKeyUsageSyntax as defined in [RFC 5280 Section 4.2.1.12].
 ///
@@ -78,6 +138,30 @@
 
 impl_newtype!(ExtendedKeyUsage, Vec<ObjectIdentifier>);
 
+impl crate::ext::AsExtension for ExtendedKeyUsage {
+    fn critical(
+        &self,
+        _subject: &crate::name::Name,
+        _extensions: &[crate::ext::Extension],
+    ) -> bool {
+        // https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12
+        //   This extension MAY, at the option of the certificate issuer, be
+        //   either critical or non-critical.
+        //
+        //   If a CA includes extended key usages to satisfy such applications,
+        //   but does not wish to restrict usages of the key, the CA can include
+        //   the special KeyPurposeId anyExtendedKeyUsage in addition to the
+        //   particular key purposes required by the applications.  Conforming CAs
+        //   SHOULD NOT mark this extension as critical if the anyExtendedKeyUsage
+        //   KeyPurposeId is present.  Applications that require the presence of a
+        //   particular purpose MAY reject certificates that include the
+        //   anyExtendedKeyUsage OID but not the particular OID expected for the
+        //   application.
+
+        !self.0.iter().any(|el| *el == ANY_EXTENDED_KEY_USAGE)
+    }
+}
+
 /// PrivateKeyUsagePeriod as defined in [RFC 3280 Section 4.2.1.4].
 ///
 /// RFC 5280 states "use of this ISO standard extension is neither deprecated nor recommended for use in the Internet PKI."
@@ -103,3 +187,34 @@
 impl AssociatedOid for PrivateKeyUsagePeriod {
     const OID: ObjectIdentifier = ID_CE_PRIVATE_KEY_USAGE_PERIOD;
 }
+
+impl_extension!(PrivateKeyUsagePeriod, critical = false);
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn digital_signature_contains_digital_signature() {
+        let key_usage = KeyUsage(KeyUsages::DigitalSignature.into());
+        assert!(key_usage.digital_signature());
+    }
+
+    #[test]
+    fn all_contains_digital_signature() {
+        let key_usage = KeyUsage(FlagSet::full());
+        assert!(key_usage.digital_signature());
+    }
+
+    #[test]
+    fn key_encipherment_not_contains_digital_signature() {
+        let key_usage = KeyUsage(KeyUsages::KeyEncipherment.into());
+        assert!(!key_usage.digital_signature());
+    }
+
+    #[test]
+    fn empty_not_contains_digital_signature() {
+        let key_usage = KeyUsage(None.into());
+        assert!(!key_usage.digital_signature());
+    }
+}
diff --git a/src/ext/pkix/name/dirstr.rs b/src/ext/pkix/name/dirstr.rs
index 2aaa732..a6a0117 100644
--- a/src/ext/pkix/name/dirstr.rs
+++ b/src/ext/pkix/name/dirstr.rs
@@ -1,4 +1,5 @@
-use der::asn1::{PrintableStringRef, TeletexStringRef, Utf8StringRef};
+use alloc::string::String;
+use der::asn1::{PrintableString, TeletexString};
 use der::{Choice, ValueOrd};
 
 /// DirectoryString as defined in [RFC 5280 Section 4.2.1.4].
@@ -40,13 +41,13 @@
 /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
 #[derive(Clone, Debug, Eq, PartialEq, Choice, ValueOrd)]
 #[allow(missing_docs)]
-pub enum DirectoryString<'a> {
+pub enum DirectoryString {
     #[asn1(type = "PrintableString")]
-    PrintableString(PrintableStringRef<'a>),
+    PrintableString(PrintableString),
 
     #[asn1(type = "TeletexString")]
-    TeletexString(TeletexStringRef<'a>),
+    TeletexString(TeletexString),
 
     #[asn1(type = "UTF8String")]
-    Utf8String(Utf8StringRef<'a>),
+    Utf8String(String),
 }
diff --git a/src/ext/pkix/name/dp.rs b/src/ext/pkix/name/dp.rs
index e895f88..0965564 100644
--- a/src/ext/pkix/name/dp.rs
+++ b/src/ext/pkix/name/dp.rs
@@ -15,10 +15,10 @@
 /// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13
 #[derive(Clone, Debug, Eq, PartialEq, Choice, ValueOrd)]
 #[allow(missing_docs)]
-pub enum DistributionPointName<'a> {
+pub enum DistributionPointName {
     #[asn1(context_specific = "0", tag_mode = "IMPLICIT", constructed = "true")]
-    FullName(GeneralNames<'a>),
+    FullName(GeneralNames),
 
     #[asn1(context_specific = "1", tag_mode = "IMPLICIT", constructed = "true")]
-    NameRelativeToCRLIssuer(RelativeDistinguishedName<'a>),
+    NameRelativeToCRLIssuer(RelativeDistinguishedName),
 }
diff --git a/src/ext/pkix/name/ediparty.rs b/src/ext/pkix/name/ediparty.rs
index 94af09b..9d10040 100644
--- a/src/ext/pkix/name/ediparty.rs
+++ b/src/ext/pkix/name/ediparty.rs
@@ -27,10 +27,10 @@
 /// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct EdiPartyName<'a> {
+pub struct EdiPartyName {
     #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")]
-    pub name_assigner: Option<DirectoryString<'a>>,
+    pub name_assigner: Option<DirectoryString>,
 
     #[asn1(context_specific = "1", tag_mode = "EXPLICIT")]
-    pub party_name: DirectoryString<'a>,
+    pub party_name: DirectoryString,
 }
diff --git a/src/ext/pkix/name/general.rs b/src/ext/pkix/name/general.rs
index f6861d4..bd0fa7e 100644
--- a/src/ext/pkix/name/general.rs
+++ b/src/ext/pkix/name/general.rs
@@ -3,7 +3,7 @@
 use super::{EdiPartyName, OtherName};
 use crate::name::Name;
 
-use der::asn1::{Ia5StringRef, ObjectIdentifier, OctetStringRef};
+use der::asn1::{Ia5String, ObjectIdentifier, OctetString};
 use der::{Choice, ValueOrd};
 
 /// GeneralNames as defined in [RFC 5280 Section 4.2.1.6].
@@ -13,7 +13,7 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
-pub type GeneralNames<'a> = alloc::vec::Vec<GeneralName<'a>>;
+pub type GeneralNames = alloc::vec::Vec<GeneralName>;
 
 /// GeneralName as defined in [RFC 5280 Section 4.2.1.6].
 ///
@@ -36,28 +36,74 @@
 /// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
 #[derive(Clone, Debug, Eq, PartialEq, Choice, ValueOrd)]
 #[allow(missing_docs)]
-pub enum GeneralName<'a> {
+pub enum GeneralName {
     #[asn1(context_specific = "0", tag_mode = "IMPLICIT", constructed = "true")]
-    OtherName(OtherName<'a>),
+    OtherName(OtherName),
 
     #[asn1(context_specific = "1", tag_mode = "IMPLICIT")]
-    Rfc822Name(Ia5StringRef<'a>),
+    Rfc822Name(Ia5String),
 
     #[asn1(context_specific = "2", tag_mode = "IMPLICIT")]
-    DnsName(Ia5StringRef<'a>),
+    DnsName(Ia5String),
 
     #[asn1(context_specific = "4", tag_mode = "EXPLICIT", constructed = "true")]
-    DirectoryName(Name<'a>),
+    DirectoryName(Name),
 
     #[asn1(context_specific = "5", tag_mode = "IMPLICIT", constructed = "true")]
-    EdiPartyName(EdiPartyName<'a>),
+    EdiPartyName(EdiPartyName),
 
     #[asn1(context_specific = "6", tag_mode = "IMPLICIT")]
-    UniformResourceIdentifier(Ia5StringRef<'a>),
+    UniformResourceIdentifier(Ia5String),
 
     #[asn1(context_specific = "7", tag_mode = "IMPLICIT")]
-    IpAddress(OctetStringRef<'a>),
+    IpAddress(OctetString),
 
     #[asn1(context_specific = "8", tag_mode = "IMPLICIT")]
     RegisteredId(ObjectIdentifier),
 }
+
+#[cfg(feature = "std")]
+impl From<std::net::IpAddr> for GeneralName {
+    fn from(ip: std::net::IpAddr) -> Self {
+        // Safety: this is unfailable here, OctetString will issue an error if you go
+        // over 256MiB, here the buffer is at most 16 bytes (ipv6). The two `expect`s
+        // below are safe.
+        let buf = match ip {
+            std::net::IpAddr::V4(v) => {
+                let value = v.octets();
+                OctetString::new(&value[..])
+                    .expect("OctetString is not expected to fail with a 4 bytes long buffer")
+            }
+            std::net::IpAddr::V6(v) => {
+                let value = v.octets();
+                OctetString::new(&value[..])
+                    .expect("OctetString is not expected to fail with a 16 bytes long buffer")
+            }
+        };
+
+        GeneralName::IpAddress(buf)
+    }
+}
+
+#[cfg(all(feature = "std", test))]
+mod tests {
+    use super::*;
+    use der::Encode;
+
+    #[test]
+    fn test_convert() {
+        use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+
+        let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
+        let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+
+        assert_eq!(
+            GeneralName::from(localhost_v4).to_der().unwrap(),
+            &[135, 4, 127, 0, 0, 1][..]
+        );
+        assert_eq!(
+            GeneralName::from(localhost_v6).to_der().unwrap(),
+            &[135, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1][..]
+        );
+    }
+}
diff --git a/src/ext/pkix/name/other.rs b/src/ext/pkix/name/other.rs
index a33601c..26b93bc 100644
--- a/src/ext/pkix/name/other.rs
+++ b/src/ext/pkix/name/other.rs
@@ -1,4 +1,4 @@
-use der::{asn1::ObjectIdentifier, AnyRef, Sequence, ValueOrd};
+use der::{asn1::ObjectIdentifier, Any, Sequence, ValueOrd};
 
 /// OtherName as defined in [RFC 5280 Section 4.2.1.6].
 ///
@@ -12,26 +12,26 @@
 /// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 #[allow(missing_docs)]
-pub struct OtherName<'a> {
+pub struct OtherName {
     pub type_id: ObjectIdentifier,
 
     #[asn1(context_specific = "0", tag_mode = "EXPLICIT")]
-    pub value: AnyRef<'a>,
+    pub value: Any,
 }
 
 #[test]
 #[cfg(test)]
 fn test() {
     use alloc::string::ToString;
-    use der::{Decode, Encode};
+    use der::{asn1::Utf8StringRef, Decode, Encode};
     use hex_literal::hex;
 
     let input = hex!("3021060A2B060104018237140203A0130C1155706E5F323134393530313330406D696C");
     let decoded = OtherName::from_der(&input).unwrap();
 
-    let onval = decoded.value.utf8_string().unwrap();
+    let onval = Utf8StringRef::try_from(&decoded.value).unwrap();
     assert_eq!(onval.to_string(), "Upn_214950130@mil");
 
-    let encoded = decoded.to_vec().unwrap();
+    let encoded = decoded.to_der().unwrap();
     assert_eq!(&input[..], &encoded);
 }
diff --git a/src/ext/pkix/policymap.rs b/src/ext/pkix/policymap.rs
index e6b55ba..1997f54 100644
--- a/src/ext/pkix/policymap.rs
+++ b/src/ext/pkix/policymap.rs
@@ -20,6 +20,7 @@
 }
 
 impl_newtype!(PolicyMappings, Vec<PolicyMapping>);
+impl_extension!(PolicyMappings, critical = true);
 
 /// PolicyMapping as defined in [RFC 5280 Section 4.2.1.5].
 ///
diff --git a/src/lib.rs b/src/lib.rs
index 1221c3c..dbf3d93 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,5 @@
 #![no_std]
-#![cfg_attr(docsrs, feature(doc_cfg))]
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
 #![doc = include_str!("../README.md")]
 #![doc(
     html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
@@ -7,6 +7,8 @@
 )]
 #![forbid(unsafe_code)]
 #![warn(
+    clippy::mod_module_files,
+    clippy::unwrap_used,
     missing_docs,
     rust_2018_idioms,
     unused_lifetimes,
@@ -32,8 +34,12 @@
 pub mod ext;
 pub mod name;
 pub mod request;
+pub mod serial_number;
 pub mod time;
 
+#[cfg(feature = "builder")]
+pub mod builder;
+
 pub use certificate::{Certificate, PkiPath, TbsCertificate, Version};
 pub use der;
 pub use spki;
diff --git a/src/macros.rs b/src/macros.rs
index 638d516..0333ef7 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -61,7 +61,7 @@
 
         #[allow(unused_lifetimes)]
         impl<'a> ::der::EncodeValue for $newtype {
-            fn encode_value(&self, encoder: &mut dyn ::der::Writer) -> ::der::Result<()> {
+            fn encode_value(&self, encoder: &mut impl ::der::Writer) -> ::der::Result<()> {
                 self.0.encode_value(encoder)
             }
 
@@ -78,3 +78,61 @@
         }
     };
 }
+
+/// Implements the AsExtension traits for every defined Extension paylooad
+macro_rules! impl_extension {
+    ($newtype:ty) => {
+        impl_extension!($newtype, critical = false);
+    };
+    ($newtype:ty, critical = $critical:expr) => {
+        impl crate::ext::AsExtension for $newtype {
+            fn critical(
+                &self,
+                _subject: &crate::name::Name,
+                _extensions: &[crate::ext::Extension],
+            ) -> bool {
+                $critical
+            }
+        }
+    };
+}
+
+/// Implements conversions between [`spki::SubjectPublicKeyInfo`] and [`SubjectKeyIdentifier`] or [`AuthorityKeyIdentifier`]
+macro_rules! impl_key_identifier {
+    ($newtype:ty, $out:expr) => {
+        #[cfg(feature = "builder")]
+        mod builder_key_identifier {
+            use super::*;
+            use der::asn1::OctetString;
+            use sha1::{Digest, Sha1};
+            use spki::SubjectPublicKeyInfoRef;
+
+            impl<'a> TryFrom<SubjectPublicKeyInfoRef<'a>> for $newtype {
+                type Error = der::Error;
+
+                fn try_from(issuer: SubjectPublicKeyInfoRef<'a>) -> Result<Self, Self::Error> {
+                    // https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.2
+                    //
+                    //  For CA certificates, subject key identifiers SHOULD be derived from
+                    //  the public key or a method that generates unique values.  Two common
+                    //  methods for generating key identifiers from the public key are:
+
+                    //     (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
+                    //          value of the BIT STRING subjectPublicKey (excluding the tag,
+                    //          length, and number of unused bits).
+
+                    //     (2) The keyIdentifier is composed of a four-bit type field with
+                    //          the value 0100 followed by the least significant 60 bits of
+                    //          the SHA-1 hash of the value of the BIT STRING
+                    //          subjectPublicKey (excluding the tag, length, and number of
+                    //          unused bits).
+
+                    // Here we're using the first method
+
+                    let result = Sha1::digest(issuer.subject_public_key.raw_bytes());
+                    $out(result.as_slice())
+                }
+            }
+        }
+    };
+}
diff --git a/src/name.rs b/src/name.rs
index 81ee4aa..ec62249 100644
--- a/src/name.rs
+++ b/src/name.rs
@@ -2,8 +2,8 @@
 
 use crate::attr::AttributeTypeAndValue;
 use alloc::vec::Vec;
-use core::fmt;
-use der::{asn1::SetOfVec, Decode, Encode};
+use core::{fmt, str::FromStr};
+use der::{asn1::SetOfVec, Encode};
 
 /// X.501 Name as defined in [RFC 5280 Section 4.1.2.4]. X.501 Name is used to represent distinguished names.
 ///
@@ -12,7 +12,7 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
-pub type Name<'a> = RdnSequence<'a>;
+pub type Name = RdnSequence;
 
 /// X.501 RDNSequence as defined in [RFC 5280 Section 4.1.2.4].
 ///
@@ -21,35 +21,47 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct RdnSequence<'a>(pub Vec<RelativeDistinguishedName<'a>>);
+pub struct RdnSequence(pub Vec<RelativeDistinguishedName>);
 
-impl RdnSequence<'_> {
-    /// Converts an RDNSequence string into an encoded RDNSequence
-    ///
-    /// This function follows the rules in [RFC 4514].
-    ///
-    /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
+impl RdnSequence {
+    /// Converts an `RDNSequence` string into an encoded `RDNSequence`.
+    #[deprecated(since = "0.2.1", note = "use RdnSequence::from_str(...)?.to_der()")]
     pub fn encode_from_string(s: &str) -> Result<Vec<u8>, der::Error> {
-        let ders = split(s, b',')
-            .map(RelativeDistinguishedName::encode_from_string)
-            .collect::<Result<Vec<_>, der::Error>>()?;
+        Self::from_str(s)?.to_der()
+    }
 
-        let mut out = Vec::new();
-        for der in ders.iter() {
-            out.push(RelativeDistinguishedName::from_der(der)?);
-        }
+    /// Is this [`RdnSequence`] empty?
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+}
 
-        RdnSequence(out).to_vec()
+/// Parse an [`RdnSequence`] string.
+///
+/// Follows the rules in [RFC 4514].
+///
+/// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
+impl FromStr for RdnSequence {
+    type Err = der::Error;
+
+    fn from_str(s: &str) -> der::Result<Self> {
+        let mut parts = split(s, b',')
+            .map(RelativeDistinguishedName::from_str)
+            .collect::<der::Result<Vec<_>>>()?;
+        parts.reverse();
+        Ok(Self(parts))
     }
 }
 
 /// Serializes the structure according to the rules in [RFC 4514].
 ///
 /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
-impl fmt::Display for RdnSequence<'_> {
+impl fmt::Display for RdnSequence {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        for (i, atv) in self.0.iter().enumerate() {
+        // As per RFC 4514 Section 2.1, the elements are reversed
+        for (i, atv) in self.0.iter().rev().enumerate() {
             match i {
                 0 => write!(f, "{}", atv)?,
                 _ => write!(f, ",{}", atv)?,
@@ -60,7 +72,7 @@
     }
 }
 
-impl_newtype!(RdnSequence<'a>, Vec<RelativeDistinguishedName<'a>>);
+impl_newtype!(RdnSequence, Vec<RelativeDistinguishedName>);
 
 /// Find the indices of all non-escaped separators.
 fn find(s: &str, b: u8) -> impl '_ + Iterator<Item = usize> {
@@ -98,7 +110,7 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
-pub type DistinguishedName<'a> = RdnSequence<'a>;
+pub type DistinguishedName = RdnSequence;
 
 /// RelativeDistinguishedName as defined in [RFC 5280 Section 4.1.2.4].
 ///
@@ -124,33 +136,50 @@
 /// ```
 ///
 /// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct RelativeDistinguishedName<'a>(pub SetOfVec<AttributeTypeAndValue<'a>>);
+pub struct RelativeDistinguishedName(pub SetOfVec<AttributeTypeAndValue>);
 
-impl RelativeDistinguishedName<'_> {
+impl RelativeDistinguishedName {
     /// Converts an RelativeDistinguishedName string into an encoded RelativeDistinguishedName
-    ///
-    /// This function follows the rules in [RFC 4514].
-    ///
-    /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
+    #[deprecated(
+        since = "0.2.1",
+        note = "use RelativeDistinguishedName::from_str(...)?.to_der()"
+    )]
     pub fn encode_from_string(s: &str) -> Result<Vec<u8>, der::Error> {
-        let ders = split(s, b'+')
-            .map(AttributeTypeAndValue::encode_from_string)
-            .collect::<Result<Vec<_>, der::Error>>()?;
+        Self::from_str(s)?.to_der()
+    }
+}
 
-        let atvs = ders
-            .iter()
-            .map(|der| AttributeTypeAndValue::from_der(der))
-            .collect::<Result<Vec<_>, der::Error>>()?;
+/// Parse a [`RelativeDistinguishedName`] string.
+///
+/// This function follows the rules in [RFC 4514].
+///
+/// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
+impl FromStr for RelativeDistinguishedName {
+    type Err = der::Error;
 
-        RelativeDistinguishedName(atvs.try_into()?).to_vec()
+    fn from_str(s: &str) -> der::Result<Self> {
+        split(s, b'+')
+            .map(AttributeTypeAndValue::from_str)
+            .collect::<der::Result<Vec<_>>>()?
+            .try_into()
+            .map(Self)
+    }
+}
+
+impl TryFrom<Vec<AttributeTypeAndValue>> for RelativeDistinguishedName {
+    type Error = der::Error;
+
+    fn try_from(vec: Vec<AttributeTypeAndValue>) -> der::Result<RelativeDistinguishedName> {
+        Ok(RelativeDistinguishedName(SetOfVec::try_from(vec)?))
     }
 }
 
 /// Serializes the structure according to the rules in [RFC 4514].
 ///
 /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
-impl fmt::Display for RelativeDistinguishedName<'_> {
+impl fmt::Display for RelativeDistinguishedName {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         for (i, atv) in self.0.iter().enumerate() {
             match i {
@@ -163,7 +192,4 @@
     }
 }
 
-impl_newtype!(
-    RelativeDistinguishedName<'a>,
-    SetOfVec<AttributeTypeAndValue<'a>>
-);
+impl_newtype!(RelativeDistinguishedName, SetOfVec<AttributeTypeAndValue>);
diff --git a/src/request.rs b/src/request.rs
index 6ab16cf..50478d8 100644
--- a/src/request.rs
+++ b/src/request.rs
@@ -1,24 +1,34 @@
 //! PKCS#10 Certification Request types
 
-use crate::ext::Extension;
-use crate::{attr::Attributes, name::Name};
+use crate::{
+    attr::{Attribute, AttributeValue, Attributes},
+    ext::Extension,
+    name::Name,
+};
 
 use alloc::vec::Vec;
 
 use const_oid::db::rfc5912::ID_EXTENSION_REQ;
 use const_oid::{AssociatedOid, ObjectIdentifier};
-use der::asn1::BitStringRef;
-use der::{Decode, Enumerated, Sequence};
-use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo};
+use der::asn1::BitString;
+use der::{
+    asn1::{Any, SetOfVec},
+    Decode, Enumerated, Sequence,
+};
+use spki::{AlgorithmIdentifierOwned, SubjectPublicKeyInfoOwned};
+
+#[cfg(feature = "pem")]
+use der::pem::PemLabel;
 
 /// Version identifier for certification request information.
 ///
 /// (RFC 2986 designates `0` as the only valid version)
-#[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated)]
+#[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated, Default)]
 #[asn1(type = "INTEGER")]
 #[repr(u8)]
 pub enum Version {
     /// Denotes PKCS#8 v1
+    #[default]
     V1 = 0,
 }
 
@@ -35,27 +45,19 @@
 ///
 /// [RFC 2986 Section 4]: https://datatracker.ietf.org/doc/html/rfc2986#section-4
 #[derive(Clone, Debug, PartialEq, Eq, Sequence)]
-pub struct CertReqInfo<'a> {
+pub struct CertReqInfo {
     /// Certification request version.
     pub version: Version,
 
     /// Subject name.
-    pub subject: Name<'a>,
+    pub subject: Name,
 
     /// Subject public key info.
-    pub public_key: SubjectPublicKeyInfo<'a>,
+    pub public_key: SubjectPublicKeyInfoOwned,
 
     /// Request attributes.
     #[asn1(context_specific = "0", tag_mode = "IMPLICIT")]
-    pub attributes: Attributes<'a>,
-}
-
-impl<'a> TryFrom<&'a [u8]> for CertReqInfo<'a> {
-    type Error = der::Error;
-
-    fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
-        Self::from_der(bytes)
-    }
+    pub attributes: Attributes,
 }
 
 /// PKCS#10 `CertificationRequest` as defined in [RFC 2986 Section 4].
@@ -70,18 +72,23 @@
 ///
 /// [RFC 2986 Section 4]: https://datatracker.ietf.org/doc/html/rfc2986#section-4
 #[derive(Clone, Debug, PartialEq, Eq, Sequence)]
-pub struct CertReq<'a> {
+pub struct CertReq {
     /// Certification request information.
-    pub info: CertReqInfo<'a>,
+    pub info: CertReqInfo,
 
     /// Signature algorithm identifier.
-    pub algorithm: AlgorithmIdentifier<'a>,
+    pub algorithm: AlgorithmIdentifierOwned,
 
     /// Signature.
-    pub signature: BitStringRef<'a>,
+    pub signature: BitString,
 }
 
-impl<'a> TryFrom<&'a [u8]> for CertReq<'a> {
+#[cfg(feature = "pem")]
+impl PemLabel for CertReq {
+    const PEM_LABEL: &'static str = "CERTIFICATE REQUEST";
+}
+
+impl<'a> TryFrom<&'a [u8]> for CertReq {
     type Error = der::Error;
 
     fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
@@ -96,11 +103,89 @@
 /// ```
 ///
 /// [RFC 5272 Section 3.1]: https://datatracker.ietf.org/doc/html/rfc5272#section-3.1
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct ExtensionReq<'a>(pub Vec<Extension<'a>>);
+#[derive(Clone, Debug, PartialEq, Eq, Default)]
+pub struct ExtensionReq(pub Vec<Extension>);
 
-impl<'a> AssociatedOid for ExtensionReq<'a> {
+impl AssociatedOid for ExtensionReq {
     const OID: ObjectIdentifier = ID_EXTENSION_REQ;
 }
 
-impl_newtype!(ExtensionReq<'a>, Vec<Extension<'a>>);
+impl_newtype!(ExtensionReq, Vec<Extension>);
+
+impl TryFrom<ExtensionReq> for Attribute {
+    type Error = der::Error;
+
+    fn try_from(extension_req: ExtensionReq) -> der::Result<Attribute> {
+        let mut values: SetOfVec<AttributeValue> = Default::default();
+        values.insert(Any::encode_from(&extension_req.0)?)?;
+
+        Ok(Attribute {
+            oid: ExtensionReq::OID,
+            values,
+        })
+    }
+}
+
+pub mod attributes {
+    //! Set of attributes that may be associated to a request
+
+    use alloc::vec;
+    use const_oid::AssociatedOid;
+    use der::{
+        asn1::{Any, ObjectIdentifier, SetOfVec},
+        EncodeValue, Length, Result, Tag, Tagged, Writer,
+    };
+
+    use crate::{attr::Attribute, ext::pkix::name::DirectoryString};
+
+    /// Trait to be implement by request attributes
+    pub trait AsAttribute: AssociatedOid + Tagged + EncodeValue + Sized {
+        /// Returns the Attribute with the content encoded.
+        fn to_attribute(&self) -> Result<Attribute> {
+            let inner: Any = der::asn1::Any::encode_from(self)?;
+
+            let values = SetOfVec::try_from(vec![inner])?;
+
+            Ok(Attribute {
+                oid: Self::OID,
+                values,
+            })
+        }
+    }
+
+    /// `ChallengePassword` as defined in [RFC 2985 Section 5.4.1]
+    ///
+    /// ```text
+    /// challengePassword ATTRIBUTE ::= {
+    ///          WITH SYNTAX DirectoryString {pkcs-9-ub-challengePassword}
+    ///          EQUALITY MATCHING RULE caseExactMatch
+    ///          SINGLE VALUE TRUE
+    ///          ID pkcs-9-at-challengePassword
+    ///  }
+    /// ```
+    ///
+    /// [RFC 2985 Section 5.4.1]: https://www.rfc-editor.org/rfc/rfc2985#page-16
+    pub struct ChallengePassword(pub DirectoryString);
+
+    impl AsAttribute for ChallengePassword {}
+
+    impl AssociatedOid for ChallengePassword {
+        const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.7");
+    }
+
+    impl Tagged for ChallengePassword {
+        fn tag(&self) -> Tag {
+            self.0.tag()
+        }
+    }
+
+    impl EncodeValue for ChallengePassword {
+        fn value_len(&self) -> Result<Length> {
+            self.0.value_len()
+        }
+
+        fn encode_value(&self, encoder: &mut impl Writer) -> Result<()> {
+            self.0.encode_value(encoder)
+        }
+    }
+}
diff --git a/src/serial_number.rs b/src/serial_number.rs
new file mode 100644
index 0000000..b14487a
--- /dev/null
+++ b/src/serial_number.rs
@@ -0,0 +1,195 @@
+//! X.509 serial number
+
+use core::{fmt::Display, marker::PhantomData};
+
+use der::{
+    asn1::{self, Int},
+    DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd,
+    Writer,
+};
+
+use crate::certificate::{Profile, Rfc5280};
+
+/// [RFC 5280 Section 4.1.2.2.]  Serial Number
+///
+///   The serial number MUST be a positive integer assigned by the CA to
+///   each certificate.  It MUST be unique for each certificate issued by a
+///   given CA (i.e., the issuer name and serial number identify a unique
+///   certificate).  CAs MUST force the serialNumber to be a non-negative
+///   integer.
+///
+///   Given the uniqueness requirements above, serial numbers can be
+///   expected to contain long integers.  Certificate users MUST be able to
+///   handle serialNumber values up to 20 octets.  Conforming CAs MUST NOT
+///   use serialNumber values longer than 20 octets.
+///
+///   Note: Non-conforming CAs may issue certificates with serial numbers
+///   that are negative or zero.  Certificate users SHOULD be prepared to
+///   gracefully handle such certificates.
+#[derive(Clone, Debug, Eq, PartialEq, ValueOrd, PartialOrd, Ord)]
+pub struct SerialNumber<P: Profile = Rfc5280> {
+    pub(crate) inner: Int,
+    _profile: PhantomData<P>,
+}
+
+impl<P: Profile> SerialNumber<P> {
+    /// Maximum length in bytes for a [`SerialNumber`]
+    pub const MAX_LEN: Length = Length::new(20);
+
+    /// See notes in `SerialNumber::new` and `SerialNumber::decode_value`.
+    pub(crate) const MAX_DECODE_LEN: Length = Length::new(21);
+
+    /// Create a new [`SerialNumber`] from a byte slice.
+    ///
+    /// The byte slice **must** represent a positive integer.
+    pub fn new(bytes: &[u8]) -> Result<Self> {
+        let inner = asn1::Uint::new(bytes)?;
+
+        // The user might give us a 20 byte unsigned integer with a high MSB,
+        // which we'd then encode with 21 octets to preserve the sign bit.
+        // RFC 5280 is ambiguous about whether this is valid, so we limit
+        // `SerialNumber` *encodings* to 20 bytes or fewer while permitting
+        // `SerialNumber` *decodings* to have up to 21 bytes below.
+        if inner.value_len()? > Self::MAX_LEN {
+            return Err(ErrorKind::Overlength.into());
+        }
+
+        Ok(Self {
+            inner: inner.into(),
+            _profile: PhantomData,
+        })
+    }
+
+    /// Borrow the inner byte slice which contains the least significant bytes
+    /// of a big endian integer value with all leading zeros stripped.
+    pub fn as_bytes(&self) -> &[u8] {
+        self.inner.as_bytes()
+    }
+}
+
+impl<P: Profile> EncodeValue for SerialNumber<P> {
+    fn value_len(&self) -> Result<Length> {
+        self.inner.value_len()
+    }
+
+    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+        self.inner.encode_value(writer)
+    }
+}
+
+impl<'a, P: Profile> DecodeValue<'a> for SerialNumber<P> {
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+        let inner = Int::decode_value(reader, header)?;
+        let serial = Self {
+            inner,
+            _profile: PhantomData,
+        };
+
+        P::check_serial_number(&serial)?;
+
+        Ok(serial)
+    }
+}
+
+impl<P: Profile> FixedTag for SerialNumber<P> {
+    const TAG: Tag = <Int as FixedTag>::TAG;
+}
+
+impl Display for SerialNumber {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        let mut iter = self.as_bytes().iter().peekable();
+
+        while let Some(byte) = iter.next() {
+            match iter.peek() {
+                Some(_) => write!(f, "{:02X}:", byte)?,
+                None => write!(f, "{:02X}", byte)?,
+            }
+        }
+
+        Ok(())
+    }
+}
+
+macro_rules! impl_from {
+    ($source:ty) => {
+        impl From<$source> for SerialNumber {
+            fn from(inner: $source) -> SerialNumber {
+                let serial_number = &inner.to_be_bytes()[..];
+                let serial_number = asn1::Uint::new(serial_number).unwrap();
+
+                // This could only fail if the big endian representation was to be more than 20
+                // bytes long. Because it's only implemented for up to u64 / usize (8 bytes).
+                SerialNumber::new(serial_number.as_bytes()).unwrap()
+            }
+        }
+    };
+}
+
+impl_from!(u8);
+impl_from!(u16);
+impl_from!(u32);
+impl_from!(u64);
+impl_from!(usize);
+
+// Implement by hand because the derive would create invalid values.
+// Use the constructor to create a valid value.
+#[cfg(feature = "arbitrary")]
+impl<'a, P: Profile> arbitrary::Arbitrary<'a> for SerialNumber<P> {
+    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
+        let len = u.int_in_range(0u32..=Self::MAX_LEN.into())?;
+
+        Self::new(u.bytes(len as usize)?).map_err(|_| arbitrary::Error::IncorrectFormat)
+    }
+
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        arbitrary::size_hint::and(u32::size_hint(depth), (0, None))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use alloc::string::ToString;
+
+    use super::*;
+
+    #[test]
+    fn serial_number_invariants() {
+        // Creating a new serial with an oversized encoding (due to high MSB) fails.
+        {
+            let too_big = [0x80; 20];
+            assert!(SerialNumber::<Rfc5280>::new(&too_big).is_err());
+        }
+
+        // Creating a new serial with the maximum encoding succeeds.
+        {
+            let just_enough = [
+                0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+            ];
+            assert!(SerialNumber::<Rfc5280>::new(&just_enough).is_ok());
+        }
+    }
+
+    #[test]
+    fn serial_number_display() {
+        {
+            let sn = SerialNumber::new(&[0x11, 0x22, 0x33]).unwrap();
+
+            assert_eq!(sn.to_string(), "11:22:33")
+        }
+
+        {
+            let sn = SerialNumber::new(&[0xAA, 0xBB, 0xCC, 0x01, 0x10, 0x00, 0x11]).unwrap();
+
+            // We force the user's serial to be positive if they give us a negative one.
+            assert_eq!(sn.to_string(), "00:AA:BB:CC:01:10:00:11")
+        }
+
+        {
+            let sn = SerialNumber::new(&[0x00, 0x00, 0x01]).unwrap();
+
+            // Leading zeroes are ignored, due to canonicalization.
+            assert_eq!(sn.to_string(), "01")
+        }
+    }
+}
diff --git a/src/time.rs b/src/time.rs
index d1f2ec5..c0ef8bf 100644
--- a/src/time.rs
+++ b/src/time.rs
@@ -3,7 +3,7 @@
 use core::fmt;
 use core::time::Duration;
 use der::asn1::{GeneralizedTime, UtcTime};
-use der::{Choice, DateTime, Decode, Error, Result, Sequence, ValueOrd};
+use der::{Choice, DateTime, Sequence, ValueOrd};
 
 #[cfg(feature = "std")]
 use std::time::SystemTime;
@@ -21,9 +21,13 @@
 ///
 /// [RFC 5280 Section 4.1.2.5]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5
 /// [RFC 5280 Appendix A]: https://tools.ietf.org/html/rfc5280#page-117
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Choice, Copy, Clone, Debug, Eq, PartialEq, ValueOrd)]
 pub enum Time {
-    /// Legacy UTC time (has 2-digit year, valid only through 2050).
+    /// Legacy UTC time (has 2-digit year, valid from 1970 to 2049).
+    ///
+    /// Note: RFC 5280 specifies 1950-2049, however due to common operations working on
+    /// `UNIX_EPOCH` this implementation's lower bound is 1970.
     #[asn1(type = "UTCTime")]
     UtcTime(UtcTime),
 
@@ -33,6 +37,10 @@
 }
 
 impl Time {
+    /// Time used for Certificate who do not expire.
+    pub const INFINITY: Time =
+        Time::GeneralTime(GeneralizedTime::from_date_time(DateTime::INFINITY));
+
     /// Get duration since `UNIX_EPOCH`.
     pub fn to_unix_duration(self) -> Duration {
         match self {
@@ -51,17 +59,30 @@
 
     /// Convert to [`SystemTime`].
     #[cfg(feature = "std")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
     pub fn to_system_time(&self) -> SystemTime {
         match self {
             Time::UtcTime(t) => t.to_system_time(),
             Time::GeneralTime(t) => t.to_system_time(),
         }
     }
+
+    /// Convert time to UTCTime representation
+    /// As per RFC 5280: 4.1.2.5, date through 2049 should be expressed as UTC Time.
+    #[cfg(feature = "builder")]
+    pub(crate) fn rfc5280_adjust_utc_time(&mut self) -> der::Result<()> {
+        if let Time::GeneralTime(t) = self {
+            let date = t.to_date_time();
+            if date.year() <= UtcTime::MAX_YEAR {
+                *self = Time::UtcTime(UtcTime::from_date_time(date)?);
+            }
+        }
+
+        Ok(())
+    }
 }
 
 impl fmt::Display for Time {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", self.to_date_time())
     }
 }
@@ -79,7 +100,6 @@
 }
 
 #[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
 impl From<Time> for SystemTime {
     fn from(time: Time) -> SystemTime {
         time.to_system_time()
@@ -87,7 +107,6 @@
 }
 
 #[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
 impl From<&Time> for SystemTime {
     fn from(time: &Time) -> SystemTime {
         time.to_system_time()
@@ -95,11 +114,10 @@
 }
 
 #[cfg(feature = "std")]
-#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
 impl TryFrom<SystemTime> for Time {
-    type Error = Error;
+    type Error = der::Error;
 
-    fn try_from(time: SystemTime) -> Result<Time> {
+    fn try_from(time: SystemTime) -> der::Result<Time> {
         Ok(GeneralizedTime::try_from(time)?.into())
     }
 }
@@ -113,6 +131,7 @@
 /// }
 /// ```
 /// [RFC 5280 Section 4.1.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.5
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
 pub struct Validity {
     /// notBefore value
@@ -125,8 +144,7 @@
 impl Validity {
     /// Creates a `Validity` which starts now and lasts for `duration`.
     #[cfg(feature = "std")]
-    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
-    pub fn from_now(duration: Duration) -> Result<Self> {
+    pub fn from_now(duration: Duration) -> der::Result<Self> {
         let now = SystemTime::now();
         let then = now + duration;
 
@@ -136,11 +154,3 @@
         })
     }
 }
-
-impl<'a> TryFrom<&'a [u8]> for Validity {
-    type Error = Error;
-
-    fn try_from(bytes: &'a [u8]) -> Result<Self> {
-        Self::from_der(bytes)
-    }
-}
diff --git a/tests/builder.rs b/tests/builder.rs
new file mode 100644
index 0000000..06aae51
--- /dev/null
+++ b/tests/builder.rs
@@ -0,0 +1,315 @@
+#![cfg(all(feature = "builder", feature = "pem"))]
+
+use der::{asn1::PrintableString, pem::LineEnding, Decode, Encode, EncodePem};
+use p256::{ecdsa::DerSignature, pkcs8::DecodePrivateKey, NistP256};
+use rsa::pkcs1::DecodeRsaPrivateKey;
+use rsa::pkcs1v15::SigningKey;
+use sha2::Sha256;
+use spki::SubjectPublicKeyInfoOwned;
+use std::{str::FromStr, time::Duration};
+use x509_cert::{
+    builder::{Builder, CertificateBuilder, Profile, RequestBuilder},
+    ext::pkix::{
+        name::{DirectoryString, GeneralName},
+        SubjectAltName,
+    },
+    name::Name,
+    request,
+    serial_number::SerialNumber,
+    time::Validity,
+};
+use x509_cert_test_support::{openssl, zlint};
+
+const RSA_2048_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-pub.der");
+const PKCS8_PUBLIC_KEY_DER: &[u8] = include_bytes!("examples/p256-pub.der");
+
+#[test]
+fn root_ca_certificate() {
+    let serial_number = SerialNumber::from(42u32);
+    let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
+    let profile = Profile::Root;
+    let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US")
+        .unwrap()
+        .to_der()
+        .unwrap();
+    let subject = Name::from_der(&subject).unwrap();
+    let pub_key =
+        SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
+
+    let signer = rsa_signer();
+    let builder =
+        CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
+            .expect("Create certificate");
+
+    let certificate = builder.build().unwrap();
+
+    let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
+    println!("{}", openssl::check_certificate(pem.as_bytes()));
+
+    let ignored = &[];
+    zlint::check_certificate(pem.as_bytes(), ignored);
+}
+
+#[test]
+fn root_ca_certificate_ecdsa() {
+    let serial_number = SerialNumber::from(42u32);
+    let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
+    let profile = Profile::Root;
+    let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US")
+        .unwrap()
+        .to_der()
+        .unwrap();
+    let subject = Name::from_der(&subject).unwrap();
+    let pub_key =
+        SubjectPublicKeyInfoOwned::try_from(PKCS8_PUBLIC_KEY_DER).expect("get ecdsa pub key");
+
+    let signer = ecdsa_signer();
+    let builder =
+        CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
+            .expect("Create certificate");
+
+    let certificate = builder.build::<DerSignature>().unwrap();
+
+    let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
+    println!("{}", openssl::check_certificate(pem.as_bytes()));
+
+    let ignored = &[];
+    zlint::check_certificate(pem.as_bytes(), ignored);
+}
+
+#[test]
+fn sub_ca_certificate() {
+    let serial_number = SerialNumber::from(42u32);
+    let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
+
+    let issuer =
+        Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
+    let profile = Profile::SubCA {
+        issuer,
+        path_len_constraint: Some(0),
+    };
+
+    let subject =
+        Name::from_str("CN=World domination task force,O=World domination Inc,C=US").unwrap();
+    let pub_key =
+        SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
+
+    let signer = ecdsa_signer();
+    let builder =
+        CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
+            .expect("Create certificate");
+
+    let certificate = builder.build::<DerSignature>().unwrap();
+
+    let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
+    println!("{}", openssl::check_certificate(pem.as_bytes()));
+
+    // TODO(baloo): not too sure we should tackle those in this API.
+    let ignored = &[
+        "w_sub_ca_aia_missing",
+        "e_sub_ca_crl_distribution_points_missing",
+        "e_sub_ca_certificate_policies_missing",
+        "w_sub_ca_aia_does_not_contain_issuing_ca_url",
+    ];
+
+    zlint::check_certificate(pem.as_bytes(), ignored);
+}
+
+#[test]
+fn leaf_certificate() {
+    let serial_number = SerialNumber::from(42u32);
+    let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
+
+    let issuer =
+        Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
+    let profile = Profile::Leaf {
+        issuer: issuer.clone(),
+        enable_key_agreement: false,
+        enable_key_encipherment: false,
+        #[cfg(feature = "hazmat")]
+        include_subject_key_identifier: true,
+    };
+
+    let subject = Name::from_str("CN=service.domination.world").unwrap();
+    let pub_key =
+        SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
+
+    let signer = ecdsa_signer();
+    let builder = CertificateBuilder::new(
+        profile,
+        serial_number.clone(),
+        validity.clone(),
+        subject.clone(),
+        pub_key.clone(),
+        &signer,
+    )
+    .expect("Create certificate");
+
+    let certificate = builder.build::<DerSignature>().unwrap();
+
+    let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
+    println!("{}", openssl::check_certificate(pem.as_bytes()));
+
+    // TODO(baloo): not too sure we should tackle those in this API.
+    let ignored = vec![
+        "e_sub_cert_aia_missing",
+        "e_sub_cert_crl_distribution_points_missing",
+        "w_sub_cert_aia_does_not_contain_issuing_ca_url",
+        // Missing policies
+        "e_sub_cert_certificate_policies_missing",
+        "e_sub_cert_cert_policy_empty",
+        // Needs to be added by the end-user
+        "e_sub_cert_aia_does_not_contain_ocsp_url",
+        // SAN needs to include DNS name (if used)
+        "e_ext_san_missing",
+        "e_subject_common_name_not_exactly_from_san",
+        // Extended key usage needs to be added by end-user and is use-case dependent
+        "e_sub_cert_eku_missing",
+    ];
+
+    zlint::check_certificate(pem.as_bytes(), &ignored);
+
+    #[cfg(feature = "hazmat")]
+    {
+        let profile = Profile::Leaf {
+            issuer,
+            enable_key_agreement: false,
+            enable_key_encipherment: false,
+            include_subject_key_identifier: false,
+        };
+        let builder =
+            CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
+                .expect("Create certificate");
+
+        let certificate = builder.build::<DerSignature>().unwrap();
+
+        let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
+        println!("{}", openssl::check_certificate(pem.as_bytes()));
+
+        // Ignore warning about leaf not having SKI extension (this is a warning not a fail, as
+        // denoted by the `w_` prefix.
+        let mut ignored = ignored;
+        ignored.push("w_ext_subject_key_identifier_missing_sub_cert");
+        zlint::check_certificate(pem.as_bytes(), &ignored);
+    }
+}
+
+#[test]
+fn pss_certificate() {
+    let serial_number = SerialNumber::from(42u32);
+    let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
+
+    let issuer =
+        Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
+    let profile = Profile::Leaf {
+        issuer,
+        enable_key_agreement: false,
+        enable_key_encipherment: false,
+        #[cfg(feature = "hazmat")]
+        include_subject_key_identifier: true,
+    };
+
+    let subject = Name::from_str("CN=service.domination.world").unwrap();
+    let pub_key =
+        SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
+
+    let signer = rsa_pss_signer();
+    let builder =
+        CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
+            .expect("Create certificate");
+
+    let certificate = builder
+        .build_with_rng::<rsa::pss::Signature>(&mut rand::thread_rng())
+        .unwrap();
+
+    let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
+    println!("{}", openssl::check_certificate(pem.as_bytes()));
+
+    // TODO(baloo): not too sure we should tackle those in this API.
+    let ignored = &[
+        "e_sub_cert_aia_missing",
+        "e_sub_cert_crl_distribution_points_missing",
+        "w_sub_cert_aia_does_not_contain_issuing_ca_url",
+        // Missing policies
+        "e_sub_cert_certificate_policies_missing",
+        "e_sub_cert_cert_policy_empty",
+        // Needs to be added by the end-user
+        "e_sub_cert_aia_does_not_contain_ocsp_url",
+        // SAN needs to include DNS name (if used)
+        "e_ext_san_missing",
+        "e_subject_common_name_not_exactly_from_san",
+        // Extended key usage needs to be added by end-user and is use-case dependent
+        "e_sub_cert_eku_missing",
+        // zlint warns on RSAPSS signature algorithms
+        "e_signature_algorithm_not_supported",
+    ];
+
+    zlint::check_certificate(pem.as_bytes(), ignored);
+}
+
+const RSA_2048_PRIV_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-priv.der");
+
+fn rsa_signer() -> SigningKey<Sha256> {
+    let private_key = rsa::RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER_EXAMPLE).unwrap();
+    let signing_key = SigningKey::<Sha256>::new(private_key);
+    signing_key
+}
+
+fn rsa_pss_signer() -> rsa::pss::SigningKey<Sha256> {
+    let private_key = rsa::RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER_EXAMPLE).unwrap();
+    let signing_key = rsa::pss::SigningKey::<Sha256>::new(private_key);
+    signing_key
+}
+
+const PKCS8_PRIVATE_KEY_DER: &[u8] = include_bytes!("examples/p256-priv.der");
+
+fn ecdsa_signer() -> ecdsa::SigningKey<NistP256> {
+    let secret_key = p256::SecretKey::from_pkcs8_der(PKCS8_PRIVATE_KEY_DER).unwrap();
+    ecdsa::SigningKey::from(secret_key)
+}
+
+#[test]
+fn certificate_request() {
+    use std::net::{IpAddr, Ipv4Addr};
+    let subject = Name::from_str("CN=service.domination.world").unwrap();
+
+    let signer = ecdsa_signer();
+    let mut builder = RequestBuilder::new(subject, &signer).expect("Create certificate request");
+    builder
+        .add_extension(&SubjectAltName(vec![GeneralName::from(IpAddr::V4(
+            Ipv4Addr::new(192, 0, 2, 0),
+        ))]))
+        .unwrap();
+
+    let cert_req = builder.build::<DerSignature>().unwrap();
+    let pem = cert_req.to_pem(LineEnding::LF).expect("generate pem");
+    use std::fs::File;
+    use std::io::Write;
+    let mut file = File::create("/tmp/ecdsa.csr").expect("create pem file");
+    file.write_all(pem.as_bytes()).expect("Create pem file");
+    println!("{}", openssl::check_request(pem.as_bytes()));
+}
+
+#[test]
+fn certificate_request_attributes() {
+    let subject = Name::from_str("CN=service.domination.world").unwrap();
+
+    let signer = ecdsa_signer();
+    let mut builder = RequestBuilder::new(subject, &signer).expect("Create certificate request");
+    builder
+        .add_attribute(&request::attributes::ChallengePassword(
+            DirectoryString::PrintableString(
+                PrintableString::new(b"password1234")
+                    .expect("create printable string with password"),
+            ),
+        ))
+        .expect("unable to add attribute");
+
+    let cert_req = builder.build::<DerSignature>().unwrap();
+    let pem = cert_req.to_pem(LineEnding::LF).expect("generate pem");
+    use std::fs::File;
+    use std::io::Write;
+    let mut file = File::create("/tmp/ecdsa.csr").expect("create pem file");
+    file.write_all(pem.as_bytes()).expect("Create pem file");
+    println!("{}", openssl::check_request(pem.as_bytes()));
+}
diff --git a/tests/certificate.rs b/tests/certificate.rs
index 86215e3..e5b3243 100644
--- a/tests/certificate.rs
+++ b/tests/certificate.rs
@@ -1,14 +1,18 @@
 //! Certificate tests
 
 use der::{
-    asn1::{BitStringRef, ContextSpecific, ObjectIdentifier, UIntRef},
+    asn1::{BitStringRef, ContextSpecific, ObjectIdentifier, PrintableStringRef, Utf8StringRef},
     Decode, DecodeValue, Encode, FixedTag, Header, Reader, Tag, Tagged,
 };
 use hex_literal::hex;
-use spki::AlgorithmIdentifier;
+use spki::AlgorithmIdentifierRef;
+use x509_cert::serial_number::SerialNumber;
 use x509_cert::Certificate;
 use x509_cert::*;
 
+#[cfg(feature = "pem")]
+use der::DecodePem;
+
 // TODO - parse and compare extension values
 const EXTENSIONS: &[(&str, bool)] = &[
     ("2.5.29.15", true),
@@ -113,15 +117,15 @@
     let defer_cert = DeferDecodeCertificate::from_der(der_encoded_cert).unwrap();
 
     let parsed_tbs = TbsCertificate::from_der(defer_cert.tbs_certificate).unwrap();
-    let reencoded_tbs = parsed_tbs.to_vec().unwrap();
+    let reencoded_tbs = parsed_tbs.to_der().unwrap();
     assert_eq!(defer_cert.tbs_certificate, reencoded_tbs);
 
-    let parsed_sigalg = AlgorithmIdentifier::from_der(defer_cert.signature_algorithm).unwrap();
-    let reencoded_sigalg = parsed_sigalg.to_vec().unwrap();
+    let parsed_sigalg = AlgorithmIdentifierRef::from_der(defer_cert.signature_algorithm).unwrap();
+    let reencoded_sigalg = parsed_sigalg.to_der().unwrap();
     assert_eq!(defer_cert.signature_algorithm, reencoded_sigalg);
 
     let parsed_sig = BitStringRef::from_der(defer_cert.signature).unwrap();
-    let reencoded_sig = parsed_sig.to_vec().unwrap();
+    let reencoded_sig = parsed_sig.to_der().unwrap();
     assert_eq!(defer_cert.signature, reencoded_sig);
 
     let parsed_coverage_tbs =
@@ -129,22 +133,22 @@
 
     // TODO - defer decode then re-encode version field
 
-    let encoded_serial = parsed_tbs.serial_number.to_vec().unwrap();
+    let encoded_serial = parsed_tbs.serial_number.to_der().unwrap();
     assert_eq!(parsed_coverage_tbs.serial_number, encoded_serial);
 
-    let encoded_signature = parsed_tbs.signature.to_vec().unwrap();
+    let encoded_signature = parsed_tbs.signature.to_der().unwrap();
     assert_eq!(parsed_coverage_tbs.signature, encoded_signature);
 
-    let encoded_issuer = parsed_tbs.issuer.to_vec().unwrap();
+    let encoded_issuer = parsed_tbs.issuer.to_der().unwrap();
     assert_eq!(parsed_coverage_tbs.issuer, encoded_issuer);
 
-    let encoded_validity = parsed_tbs.validity.to_vec().unwrap();
+    let encoded_validity = parsed_tbs.validity.to_der().unwrap();
     assert_eq!(parsed_coverage_tbs.validity, encoded_validity);
 
-    let encoded_subject = parsed_tbs.subject.to_vec().unwrap();
+    let encoded_subject = parsed_tbs.subject.to_der().unwrap();
     assert_eq!(parsed_coverage_tbs.subject, encoded_subject);
 
-    let encoded_subject_public_key_info = parsed_tbs.subject_public_key_info.to_vec().unwrap();
+    let encoded_subject_public_key_info = parsed_tbs.subject_public_key_info.to_der().unwrap();
     assert_eq!(
         parsed_coverage_tbs.subject_public_key_info,
         encoded_subject_public_key_info
@@ -152,7 +156,7 @@
 
     // TODO - either encode as context specific or decode to sequence. for know lop off context
     // specific tag and length
-    let encoded_extensions = parsed_tbs.extensions.to_vec().unwrap();
+    let encoded_extensions = parsed_tbs.extensions.to_der().unwrap();
     assert_eq!(&parsed_coverage_tbs.extensions[4..], encoded_extensions);
 }
 
@@ -174,7 +178,7 @@
         o1.to_string(),
         "1.3.6.1.4.1.311.21.8.11672683.15464451.6967228.369088.2847561.77.4994205.11305917"
     );
-    let enc_oid = o1.to_vec().unwrap();
+    let enc_oid = o1.to_der().unwrap();
     assert_eq!(
         &hex!("06252B060104018237150885C8B86B87AFF00383A99F3C96C34081ADE6494D82B0E91D85B2873D"),
         enc_oid.as_slice()
@@ -207,20 +211,28 @@
     ];
     assert_eq!(
         cert.tbs_certificate.serial_number,
-        UIntRef::new(&target_serial).unwrap()
+        SerialNumber::new(&target_serial).unwrap()
     );
     assert_eq!(
         cert.tbs_certificate.signature.oid.to_string(),
         "1.2.840.113549.1.1.11"
     );
     assert_eq!(
-        cert.tbs_certificate.signature.parameters.unwrap().tag(),
+        cert.tbs_certificate
+            .signature
+            .parameters
+            .as_ref()
+            .unwrap()
+            .tag(),
         Tag::Null
     );
-    assert_eq!(
-        cert.tbs_certificate.signature.parameters.unwrap().is_null(),
-        true
-    );
+    assert!(cert
+        .tbs_certificate
+        .signature
+        .parameters
+        .as_ref()
+        .unwrap()
+        .is_null());
 
     let mut counter = 0;
     let i = cert.tbs_certificate.issuer.0.iter();
@@ -229,20 +241,30 @@
         for atav in i1 {
             if 0 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.6");
-                assert_eq!(atav.value.printable_string().unwrap().to_string(), "US");
+                assert_eq!(
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
+                    "US"
+                );
             } else if 1 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.10");
-                assert_eq!(atav.value.printable_string().unwrap().to_string(), "Mock");
+                assert_eq!(
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
+                    "Mock"
+                );
             } else if 2 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.10");
                 assert_eq!(
-                    atav.value.utf8_string().unwrap().to_string(),
+                    Utf8StringRef::try_from(&atav.value).unwrap().to_string(),
                     "IdenTrust Services LLC"
                 );
             } else if 3 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.3");
                 assert_eq!(
-                    atav.value.utf8_string().unwrap().to_string(),
+                    Utf8StringRef::try_from(&atav.value).unwrap().to_string(),
                     "PTE IdenTrust Global Common Root CA 1"
                 );
             }
@@ -276,24 +298,35 @@
             if 0 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.3");
                 assert_eq!(
-                    atav.value.printable_string().unwrap().to_string(),
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
                     "Test Federal Bridge CA"
                 );
             } else if 1 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.11");
                 assert_eq!(
-                    atav.value.printable_string().unwrap().to_string(),
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
                     "TestFPKI"
                 );
             } else if 2 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.10");
                 assert_eq!(
-                    atav.value.printable_string().unwrap().to_string(),
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
                     "U.S. Government"
                 );
             } else if 3 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.6");
-                assert_eq!(atav.value.printable_string().unwrap().to_string(), "US");
+                assert_eq!(
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
+                    "US"
+                );
             }
             counter += 1;
         }
@@ -312,23 +345,23 @@
             .subject_public_key_info
             .algorithm
             .parameters
+            .as_ref()
             .unwrap()
             .tag(),
         Tag::Null
     );
-    assert_eq!(
-        cert.tbs_certificate
-            .subject_public_key_info
-            .algorithm
-            .parameters
-            .unwrap()
-            .is_null(),
-        true
-    );
+    assert!(cert
+        .tbs_certificate
+        .subject_public_key_info
+        .algorithm
+        .parameters
+        .as_ref()
+        .unwrap()
+        .is_null());
 
     // TODO - parse and compare public key
 
-    let exts = cert.tbs_certificate.extensions.unwrap();
+    let exts = cert.tbs_certificate.extensions.as_ref().unwrap();
     for (ext, (oid, crit)) in exts.iter().zip(EXTENSIONS) {
         assert_eq!(ext.extn_id.to_string(), *oid);
         assert_eq!(ext.critical, *crit);
@@ -339,13 +372,96 @@
         "1.2.840.113549.1.1.11"
     );
     assert_eq!(
-        cert.signature_algorithm.parameters.unwrap().tag(),
+        cert.signature_algorithm.parameters.as_ref().unwrap().tag(),
         Tag::Null
     );
-    assert_eq!(cert.signature_algorithm.parameters.unwrap().is_null(), true);
+    assert!(cert
+        .signature_algorithm
+        .parameters
+        .as_ref()
+        .unwrap()
+        .is_null());
 
     assert_eq!(
         &hex!("2A892F357BF3EF19E1211986106803FA18E66237802F1B1B0C6756CE678DB01D72CD0A4EB7171C2CDDF110ACD38AA65C35699E869C219AD7550AA4F287BB784F72EF8C9EA0E3DD103EFE5BF182EA36FFBCB45AAE65840263680534789C4F3215AF5454AD48CBC4B7A881E0135401A0BD5A849C11101DD1C66178E762C00DF59DD50F8DE9ED46FC6A0D742AE5697D87DD08DAC5291A75FB13C82FF2865C9E36799EA726137E1814E6A878C9532E8FC3D0A2A942D1CCC668FFCEAC255E6002FDE5ACDF2CE47556BB141C3A797A4BFDB673F6F1C229D7914FFEEF1505EE36F8038137D1B8F90106994BAB3E6FF0F60360A2E32F7A30B7ECEC1502DF3CC725BD6E436BA8F96A1847C9CEBB3F5A5906472292501D59BE1A98475BB1F30B677FAA8A45E351640C85B1B22661D33BD23EC6C0CA33DDD79E1120C7FC869EC4D0175ADB4A258AEAC5E8D2F0F578B8BF4B2C5DCC3269768AAA5B9E26D0592C5BB09C702C72E0A60F66D3EEB2B4983279634D59B0A2011B0E26AE796CC95D3243DF49615434E5CC06C374C3F936C005D360CAE6101F3AE7E97E29A157F5020770D4648D7877EBF8248CF3F3E68F9957A36F92D50616F2C60D3842327EF9BC0312CFF03A48C78E97254C2ADEADCA05069168443D833831FF66295A2EED685F164F1DBE01F8C897E1F63D42851682CBEE7B5A64D7BA2923D33644DBF1F7B3EDCE996F9928F043"),
         cert.signature.raw_bytes()
     );
+
+    #[cfg(feature = "pem")]
+    {
+        let pem_encoded_cert =
+            include_bytes!("examples/026EDA6FA1EDFA8C253936C75B5EEBD954BFF452.fake.pem");
+        let result = Certificate::from_pem(pem_encoded_cert);
+        let pem_cert: Certificate = result.unwrap();
+
+        assert_eq!(pem_cert, cert);
+    }
+}
+
+#[test]
+fn decode_cert_negative_serial_number() {
+    let der_encoded_cert = include_bytes!("examples/28903a635b5280fae6774c0b6da7d6baa64af2e8.der");
+
+    let cert = Certificate::from_der(der_encoded_cert).unwrap();
+    assert_eq!(
+        cert.tbs_certificate.serial_number.as_bytes(),
+        // INTEGER (125 bit) -2.370157924795571e+37
+        &[238, 43, 61, 235, 212, 33, 222, 20, 168, 98, 172, 4, 243, 221, 196, 1]
+    );
+
+    let reencoded = cert.to_der().unwrap();
+    assert_eq!(der_encoded_cert, reencoded.as_slice());
+}
+
+#[cfg(all(feature = "pem", feature = "hazmat"))]
+#[test]
+fn decode_cert_overlength_serial_number() {
+    use der::{pem::LineEnding, DecodePem, EncodePem};
+    use x509_cert::certificate::CertificateInner;
+
+    let pem_encoded_cert = include_bytes!("examples/qualcomm.pem");
+
+    assert!(Certificate::from_pem(pem_encoded_cert).is_err());
+
+    let cert = CertificateInner::<x509_cert::certificate::Raw>::from_pem(pem_encoded_cert).unwrap();
+    assert_eq!(
+        cert.tbs_certificate.serial_number.as_bytes(),
+        &[
+            0, 132, 206, 11, 246, 160, 254, 130, 78, 229, 229, 6, 202, 168, 157, 120, 198, 21, 1,
+            98, 87, 113
+        ]
+    );
+    assert_eq!(cert.tbs_certificate.serial_number.as_bytes().len(), 22);
+
+    let reencoded = cert.to_pem(LineEnding::LF).unwrap();
+    assert_eq!(pem_encoded_cert, reencoded.as_bytes());
+}
+
+#[cfg(all(feature = "pem"))]
+#[test]
+fn load_certificate_chains() {
+    let pem_encoded_chain = include_bytes!("examples/crates.io-chain.pem");
+
+    let chain = Certificate::load_pem_chain(pem_encoded_chain).expect("parse certificate chain");
+
+    assert_eq!(chain.len(), 4, "4 certificates are expected in this chain");
+}
+
+#[cfg(feature = "arbitrary")]
+#[test]
+// Purpose of this check is to ensure the arbitraty trait is provided for certificate variants
+#[allow(unused)]
+fn certificate_arbitrary() {
+    fn check_arbitrary<'a>(_arbitrary: impl arbitrary::Arbitrary<'a>) {}
+
+    fn check_certificate(certificate: x509_cert::Certificate) {
+        check_arbitrary(certificate);
+    }
+
+    #[cfg(feature = "hazmat")]
+    fn check_raw_certificate(
+        certificate: x509_cert::certificate::CertificateInner<x509_cert::certificate::Raw>,
+    ) {
+        check_arbitrary(certificate);
+    }
 }
diff --git a/tests/certreq.rs b/tests/certreq.rs
index 547524c..82ce41c 100644
--- a/tests/certreq.rs
+++ b/tests/certreq.rs
@@ -1,6 +1,7 @@
 //! Certification request (`CertReq`) tests
 
-use der::{Encode, Tag, Tagged};
+use der::asn1::{PrintableStringRef, Utf8StringRef};
+use der::{Decode, Encode, Tag, Tagged};
 use hex_literal::hex;
 use x509_cert::request::{CertReq, Version};
 
@@ -28,7 +29,7 @@
 
 #[test]
 fn decode_rsa_2048_der() {
-    let cr = CertReq::try_from(RSA_2048_DER_EXAMPLE).unwrap();
+    let cr = CertReq::from_der(RSA_2048_DER_EXAMPLE).unwrap();
 
     // Check the version.
     assert_eq!(cr.info.version, Version::V1);
@@ -38,8 +39,8 @@
     for (name, (oid, val)) in cr.info.subject.0.iter().zip(NAMES) {
         let kind = name.0.get(0).unwrap();
         let value = match kind.value.tag() {
-            Tag::Utf8String => kind.value.utf8_string().unwrap().as_str(),
-            Tag::PrintableString => kind.value.printable_string().unwrap().as_str(),
+            Tag::Utf8String => Utf8StringRef::try_from(&kind.value).unwrap().as_str(),
+            Tag::PrintableString => PrintableStringRef::try_from(&kind.value).unwrap().as_str(),
             _ => panic!("unexpected tag"),
         };
 
@@ -52,7 +53,7 @@
     let alg = cr.info.public_key.algorithm;
     assert_eq!(alg.oid, "1.2.840.113549.1.1.1".parse().unwrap());
     assert!(alg.parameters.unwrap().is_null());
-    assert_eq!(cr.info.public_key.subject_public_key, RSA_KEY);
+    assert_eq!(cr.info.public_key.subject_public_key.raw_bytes(), RSA_KEY);
 
     // Check the attributes (just one; contains extensions).
     assert_eq!(cr.info.attributes.len(), 1);
@@ -62,10 +63,10 @@
 
     // Check the extensions.
     let extensions: x509_cert::ext::Extensions =
-        attribute.values.get(0).unwrap().decode_into().unwrap();
+        attribute.values.get(0).unwrap().decode_as().unwrap();
     for (ext, (oid, val)) in extensions.iter().zip(EXTENSIONS) {
         assert_eq!(ext.extn_id, oid.parse().unwrap());
-        assert_eq!(ext.extn_value, *val);
+        assert_eq!(ext.extn_value.as_bytes(), *val);
         assert!(!ext.critical);
     }
 
@@ -80,7 +81,7 @@
 
 #[test]
 fn encode_rsa_2048_der() {
-    let cr = CertReq::try_from(RSA_2048_DER_EXAMPLE).unwrap();
-    let cr_encoded = cr.to_vec().unwrap();
+    let cr = CertReq::from_der(RSA_2048_DER_EXAMPLE).unwrap();
+    let cr_encoded = cr.to_der().unwrap();
     assert_eq!(RSA_2048_DER_EXAMPLE, cr_encoded.as_slice());
 }
diff --git a/tests/examples/026EDA6FA1EDFA8C253936C75B5EEBD954BFF452.fake.pem b/tests/examples/026EDA6FA1EDFA8C253936C75B5EEBD954BFF452.fake.pem
new file mode 100644
index 0000000..f13043d
--- /dev/null
+++ b/tests/examples/026EDA6FA1EDFA8C253936C75B5EEBD954BFF452.fake.pem
@@ -0,0 +1,61 @@
+-----BEGIN CERTIFICATE-----
+MIILDDCCCPSgAwIBAgIQfwAAAQAAAUnPcGZNAAAAAjANBgkqhkiG9w0BAQsFADBt
+MQswCQYDVQQGEwJVUzENMAsGA1UEChMETW9jazEfMB0GA1UECgwWSWRlblRydXN0
+IFNlcnZpY2VzIExMQzEuMCwGA1UEAwwlUFRFIElkZW5UcnVzdCBHbG9iYWwgQ29t
+bW9uIFJvb3QgQ0EgMTAeFw0xNDExMjAyMzAxMzBaFw0xODAxMjIxMzQzMTNaMFsx
+HzAdBgNVBAMTFlRlc3QgRmVkZXJhbCBCcmlkZ2UgQ0ExETAPBgNVBAsTCFRlc3RG
+UEtJMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxCzAJBgNVBAYTAlVTMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvBZsJer07n0I60VOfHzZ3yk4oPAM
+2Qh8pZFT6Dp8OSOxFouoib7EhoElJ66AMTO+2SUXP8DgiUOQ7qR7AdKBipqaZP1B
+T+3sjvlLr1faiCrPLmGB+GmbaORGeIwezH3J5dmVY4UBKoH4GIZvo65w99OiSf4N
+tSqE4RDqZr+KM8LoE7FnJIpCrWk1lScs7WcoLWul8KKMGhf9JcEkl1yEzrYOxRcY
+T2rilBBED07TLaTEj7vb/nq6K8rewszjmPAvI/TVoW1mXE1pzfSxVqzQ+jfPgDAN
+BEJGWwP3+qHxp3FfFAgc1QpC05366xFxbwPaMfFF6kfzSZTdIXQOtKkY+QIDAQAB
+o4IGuDCCBrQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wggIOBgNV
+HSEEggIFMIICATAZBgtghkgBhvkvAGQCAQYKYIZIAWUDAgEwAjAZBgtghkgBhvkv
+AGQCAgYKYIZIAWUDAgEwAjAZBgtghkgBhvkvAGQDAQYKYIZIAWUDAgEwAzAZBgtg
+hkgBhvkvAGQDAgYKYIZIAWUDAgEwAzAZBgtghkgBhvkvAGQOAQYKYIZIAWUDAgEw
+BTAZBgtghkgBhvkvAGQOAgYKYIZIAWUDAgEwBTAZBgtghkgBhvkvAGQMAQYKYIZI
+AWUDAgEwBDAZBgtghkgBhvkvAGQMAgYKYIZIAWUDAgEwBDAZBgtghkgBhvkvAGQP
+AQYKYIZIAWUDAgEwBjAZBgtghkgBhvkvAGQPAgYKYIZIAWUDAgEwBjAZBgtghkgB
+hvkvAGQSAAYKYIZIAWUDAgEwTjAZBgtghkgBhvkvAGQSAQYKYIZIAWUDAgEwTjAZ
+BgtghkgBhvkvAGQSAgYKYIZIAWUDAgEwTjAZBgtghkgBhvkvAGQTAQYKYIZIAWUD
+AgEwTzAZBgtghkgBhvkvAGQUAQYKYIZIAWUDAgEwUDAZBgtghkgBhvkvAGQlAQYK
+YIZIAWUDAgEwYzAZBgtghkgBhvkvAGQlAgYKYIZIAWUDAgEwYzAZBgtghkgBhvkv
+AGQmAQYKYIZIAWUDAgEwZDAZBgtghkgBhvkvAGQmAgYKYIZIAWUDAgEwZDCCAnAG
+A1UdIASCAmcwggJjMA0GC2CGSAGG+S8AZAIBMA0GC2CGSAGG+S8AZAICMA0GC2CG
+SAGG+S8AZAMBMA0GC2CGSAGG+S8AZAMCMA0GC2CGSAGG+S8AZA4BMA0GC2CGSAGG
++S8AZA4CMA0GC2CGSAGG+S8AZAwBMA0GC2CGSAGG+S8AZAwCMA0GC2CGSAGG+S8A
+ZA8BMA0GC2CGSAGG+S8AZA8CMA0GC2CGSAGG+S8AZBIAMA0GC2CGSAGG+S8AZBIB
+MA0GC2CGSAGG+S8AZBICMA0GC2CGSAGG+S8AZBMBMA0GC2CGSAGG+S8AZBQBMA0G
+C2CGSAGG+S8AZCUBMA0GC2CGSAGG+S8AZCUCMA0GC2CGSAGG+S8AZCYBMIIBUQYL
+YIZIAYb5LwBkJgIwggFAMEsGCCsGAQUFBwIBFj9odHRwczovL3NlY3VyZS5pZGVu
+dHJ1c3QuY29tL2NlcnRpZmljYXRlcy9wb2xpY3kvSUdDL2luZGV4Lmh0bWwwgfAG
+CCsGAQUFBwICMIHjGoHgVGhpcyBpcyBhIHRlc3QgY2VydGlmaWNhdGUuIERvIE5v
+dCBSZWx5LiBDZXJ0aWZpY2F0ZSB1c2UgcmVzdHJpY3RlZCB0byBSZWx5aW5nIFBh
+cnR5KHMpIGluIGFjY29yZGFuY2Ugd2l0aCBJR0MtQ1AgKHNlZSBodHRwczovL3Nl
+Y3VyZS5pZGVudHJ1c3QuY29tL2NlcnRpZmljYXRlcy9wb2xpY3kvSUdDL2luZGV4
+Lmh0bWwpLiBJc3N1ZXIncyBDUFMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZS4w
+HgYDVR0OBBcEFdvT3r8Ne2FbMoA7wCBs16rdObis/zCBxQYDVR0fBIG9MIG6MDqg
+OKA2hjRodHRwOi8vY3JsLXB0ZS5pZGVudHJ1c3QuY29tLnRlc3QvY3JsL0lHQ1Jv
+b3RjYTEuY3JsMHygeqB4hnZsZGFwOi8vbGRhcC1wdGUuaWRlbnRydXN0LmNvbS50
+ZXN0L2NuJTNESUdDJTIwUm9vdCUyMENBMSUyQ28lM0RJZGVuVHJ1c3QlMkNjJTNE
+VVMlM0ZjZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0JTNCYmluYXJ5MGEGCCsGAQUF
+BwELBFUwUzBRBggrBgEFBQcwBYZFaHR0cDovL2h0dHAuY2l0ZS5mcGtpLWxhYi5n
+b3YudGVzdC9icmlkZ2UvY2FDZXJ0c0lzc3VlZEJ5dGVzdEZCQ0EucDdjMIGRBggr
+BgEFBQcBAQSBhDCBgTBDBggrBgEFBQcwAoY3aHR0cDovL2FwcHMtc3RnLmlkZW50
+cnVzdC5jb20udGVzdC9yb290cy9JR0NSb290Y2ExLnA3YzA6BggrBgEFBQcwAYYu
+aHR0cDovL2lnY3Jvb3RwdGUub2NzcC5pZGVudHJ1c3QuY29tLnRlc3Q6ODEyNTAK
+BgNVHTYEAwIBADAgBgNVHSMEGTAXgBV8TIY6uAvViYcL7bfhG70qCLs9I/8wDQYJ
+KoZIhvcNAQELBQADggIBACqJLzV78+8Z4SEZhhBoA/oY5mI3gC8bGwxnVs5njbAd
+cs0KTrcXHCzd8RCs04qmXDVpnoacIZrXVQqk8oe7eE9y74yeoOPdED7+W/GC6jb/
+vLRarmWEAmNoBTR4nE8yFa9UVK1Iy8S3qIHgE1QBoL1ahJwREB3RxmF452LADfWd
+1Q+N6e1G/GoNdCrlaX2H3QjaxSkadfsTyC/yhlyeNnmepyYTfhgU5qh4yVMuj8PQ
+oqlC0czGaP/OrCVeYAL95azfLOR1VrsUHDp5ekv9tnP28cIp15FP/u8VBe42+AOB
+N9G4+QEGmUurPm/w9gNgouMvejC37OwVAt88xyW9bkNrqPlqGEfJzrs/WlkGRyKS
+UB1ZvhqYR1ux8wtnf6qKReNRZAyFsbImYdM70j7GwMoz3deeESDH/IaexNAXWttK
+JYrqxejS8PV4uL9LLF3MMml2iqpbnibQWSxbsJxwLHLgpg9m0+6ytJgyeWNNWbCi
+ARsOJq55bMldMkPfSWFUNOXMBsN0w/k2wAXTYMrmEB865+l+KaFX9QIHcNRkjXh3
+6/gkjPPz5o+ZV6NvktUGFvLGDThCMn75vAMSz/A6SMeOlyVMKt6tygUGkWhEPYM4
+Mf9mKVou7WhfFk8dvgH4yJfh9j1ChRaCy+57WmTXuikj0zZE2/H3s+3OmW+ZKPBD
+-----END CERTIFICATE-----
diff --git a/tests/examples/28903a635b5280fae6774c0b6da7d6baa64af2e8.der b/tests/examples/28903a635b5280fae6774c0b6da7d6baa64af2e8.der
new file mode 100644
index 0000000..f1317bf
--- /dev/null
+++ b/tests/examples/28903a635b5280fae6774c0b6da7d6baa64af2e8.der
Binary files differ
diff --git a/tests/examples/crates.io-chain.pem b/tests/examples/crates.io-chain.pem
new file mode 100644
index 0000000..1927099
--- /dev/null
+++ b/tests/examples/crates.io-chain.pem
@@ -0,0 +1,122 @@
+This is an X.509 certificate chain serialized as PEM, with a preamble.
+
+-----BEGIN CERTIFICATE-----
+MIIF/jCCBOagAwIBAgIQC6Hm8WViUmt88+VrEPNELzANBgkqhkiG9w0BAQsFADA8
+MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRwwGgYDVQQDExNBbWF6b24g
+UlNBIDIwNDggTTAyMB4XDTIzMDEyNTAwMDAwMFoXDTI0MDIyMzIzNTk1OVowFDES
+MBAGA1UEAxMJY3JhdGVzLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA5ivp2b8HKoaSyAq/Gt4ZJbELL/FhVNXhnHmPvdhvkD6vtGSxJQhbACftNBB4
+Kor8zK+6o1mQSpR1SNnQ5OKJIko4s+e7p4tuFV3b4LSxh+nNBZmBTvEmb5nCVs/c
+78hXtLPu48Ws4rd+Ujz6ZEcGfK15X+XT04sJFoQRSnkTwhO3DsRXwUXxhckvNJen
+R6i0dH3Um5I7sIfzgxMFh66akg2PE8s7/oM0VCY4+9hwvWRTqpz+Byi3XO1Ph+BZ
+cvJhLwn4t/KdGaSU7EV8+qhNu4mP6dsjCY03Gpha1wCvlh4Vh/TsqR3R4oPhhohh
++W3YdrTe8Deqs5nW9XrtB98F/QIDAQABo4IDIjCCAx4wHwYDVR0jBBgwFoAUwDFS
+zVpQw4J8dHHOy+mc+XrrguIwHQYDVR0OBBYEFB2jpSCo7Y3rXtxOmQPni/vQ8Ihd
+MFQGA1UdEQRNMEuCCWNyYXRlcy5pb4IbY2xvdWRmcm9udC1zdGF0aWMuY3JhdGVz
+Lmlvgg9pbmRleC5jcmF0ZXMuaW+CEHN0YXRpYy5jcmF0ZXMuaW8wDgYDVR0PAQH/
+BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA7BgNVHR8ENDAy
+MDCgLqAshipodHRwOi8vY3JsLnIybTAyLmFtYXpvbnRydXN0LmNvbS9yMm0wMi5j
+cmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwdQYIKwYBBQUHAQEEaTBnMC0GCCsGAQUF
+BzABhiFodHRwOi8vb2NzcC5yMm0wMi5hbWF6b250cnVzdC5jb20wNgYIKwYBBQUH
+MAKGKmh0dHA6Ly9jcnQucjJtMDIuYW1hem9udHJ1c3QuY29tL3IybTAyLmNlcjAM
+BgNVHRMBAf8EAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdwDuzdBk1dsa
+zsVct520zROiModGfLzs3sNRSFlGcR+1mwAAAYXoOwzkAAAEAwBIMEYCIQDx3bii
+KZKB7CKHMUq25cNLF5RGhfqjRl0TfA1EUJw8ngIhANii/IksRi+gF3VZuqf+NpE6
+hamc+2sTJYmG/ICe7H3UAHUAc9meiRtMlnigIH1HneayxhzQUV5xGSqMa4AQesF3
+crUAAAGF6DsNTgAABAMARjBEAiBGBvFbTLCHkRTM71r0wslHjcary8UmGQ7rd7ws
+mZcoBAIgPZYVni2CIK0+U7aijle1LqEPDI2UtgnFtrKGefXhdAUAdgBIsONr2qZH
+NA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAYXoOw0UAAAEAwBHMEUCIE39dFmq
+xAUUmiJiGW9HS0/VbEIt0wC9VI0jCli9T28kAiEAx19Sl2Hzh62E0tISm5p1vmGr
+K3J+m3u3fm5+YcuCdUUwDQYJKoZIhvcNAQELBQADggEBAI3+jl3AGFqBVq3Amo97
+u86v/zHykGQQFvb9LyFdhIhw8OmI/C89YmUy+ZEVsc0GBO5jf3Xr/tUDidggbRva
+ajaR1lv5hWC6HjASg4dX/88ew5eKxV9ddjcNb15bzuxWPLw+X2NAq9S+QRnkDZkr
+/VW0rYSnu3YOEwxys56JSDzHx/UWqkUHb1bsO6ixxN8sbKjM4UDeB9WHvLHO85B8
+b5rgtqrT2vIqO1wtxxo3TY72eDEqu8N1MfatTEaOaJEQu86meGO7Wbx6QQX3OJc3
+ulPbBw+/o2sXvYxy251skJRwvyi00dGhxGSlRmbGGmXpWY97CPkY1iJwQ73uJ4qx
+Uj0=
+-----END CERTIFICATE-----
+
+
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgITB3MSSkvL1E7HtTvq8ZSELToPoTANBgkqhkiG9w0BAQsF
+ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
+b24gUm9vdCBDQSAxMB4XDTIyMDgyMzIyMjUzMFoXDTMwMDgyMzIyMjUzMFowPDEL
+MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEcMBoGA1UEAxMTQW1hem9uIFJT
+QSAyMDQ4IE0wMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALtDGMZa
+qHneKei1by6+pUPPLljTB143Si6VpEWPc6mSkFhZb/6qrkZyoHlQLbDYnI2D7hD0
+sdzEqfnuAjIsuXQLG3A8TvX6V3oFNBFVe8NlLJHvBseKY88saLwufxkZVwk74g4n
+WlNMXzla9Y5F3wwRHwMVH443xGz6UtGSZSqQ94eFx5X7Tlqt8whi8qCaKdZ5rNak
++r9nUThOeClqFd4oXych//Rc7Y0eX1KNWHYSI1Nk31mYgiK3JvH063g+K9tHA63Z
+eTgKgndlh+WI+zv7i44HepRZjA1FYwYZ9Vv/9UkC5Yz8/yU65fgjaE+wVHM4e/Yy
+C2osrPWE7gJ+dXMCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD
+VR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNV
+HQ4EFgQUwDFSzVpQw4J8dHHOy+mc+XrrguIwHwYDVR0jBBgwFoAUhBjMhTTsvAyU
+lC4IWZzHshBOCggwewYIKwYBBQUHAQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8v
+b2NzcC5yb290Y2ExLmFtYXpvbnRydXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDov
+L2NydC5yb290Y2ExLmFtYXpvbnRydXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8E
+ODA2MDSgMqAwhi5odHRwOi8vY3JsLnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jv
+b3RjYTEuY3JsMBMGA1UdIAQMMAowCAYGZ4EMAQIBMA0GCSqGSIb3DQEBCwUAA4IB
+AQAtTi6Fs0Azfi+iwm7jrz+CSxHH+uHl7Law3MQSXVtR8RV53PtR6r/6gNpqlzdo
+Zq4FKbADi1v9Bun8RY8D51uedRfjsbeodizeBB8nXmeyD33Ep7VATj4ozcd31YFV
+fgRhvTSxNrrTlNpWkUk0m3BMPv8sg381HhA6uEYokE5q9uws/3YkKqRiEz3TsaWm
+JqIRZhMbgAfp7O7FUwFIb7UIspogZSKxPIWJpxiPo3TcBambbVtQOcNRWz5qCQdD
+slI2yayq0n2TXoHyNCLEH8rpsJRVILFsg0jc7BaFrMnF462+ajSehgj12IidNeRN
+4zl+EoNaWdpnWndvSpAEkq2P
+-----END CERTIFICATE-----
+
+
+
+-----BEGIN CERTIFICATE-----
+MIIEkjCCA3qgAwIBAgITBn+USionzfP6wq4rAfkI7rnExjANBgkqhkiG9w0BAQsF
+ADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj
+b3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4x
+OzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1
+dGhvcml0eSAtIEcyMB4XDTE1MDUyNTEyMDAwMFoXDTM3MTIzMTAxMDAwMFowOTEL
+MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
+b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
+ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
+9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
+IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
+VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
+93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
+jgSubJrIqg0CAwEAAaOCATEwggEtMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgGGMB0GA1UdDgQWBBSEGMyFNOy8DJSULghZnMeyEE4KCDAfBgNVHSMEGDAW
+gBScXwDfqgHXMCs4iKK4bUqc8hGRgzB4BggrBgEFBQcBAQRsMGowLgYIKwYBBQUH
+MAGGImh0dHA6Ly9vY3NwLnJvb3RnMi5hbWF6b250cnVzdC5jb20wOAYIKwYBBQUH
+MAKGLGh0dHA6Ly9jcnQucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY2Vy
+MD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwucm9vdGcyLmFtYXpvbnRydXN0
+LmNvbS9yb290ZzIuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQsF
+AAOCAQEAYjdCXLwQtT6LLOkMm2xF4gcAevnFWAu5CIw+7bMlPLVvUOTNNWqnkzSW
+MiGpSESrnO09tKpzbeR/FoCJbM8oAxiDR3mjEH4wW6w7sGDgd9QIpuEdfF7Au/ma
+eyKdpwAJfqxGF4PcnCZXmTA5YpaP7dreqsXMGz7KQ2hsVxa81Q4gLv7/wmpdLqBK
+bRRYh5TmOTFffHPLkIhqhBGWJ6bt2YFGpn6jcgAKUj6DiAdjd4lpFw85hdKrCEVN
+0FE6/V1dN2RMfjCyVSRCnTawXZwXgWHxyvkQAiSr6w10kY17RSlQOYiypok1JR4U
+akcjMS9cmvqtmg5iUaQqqcT5NJ0hGA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEdTCCA12gAwIBAgIJAKcOSkw0grd/MA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIw
+MAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eTAeFw0wOTA5MDIwMDAwMDBaFw0zNDA2MjgxNzM5MTZaMIGYMQswCQYDVQQGEwJV
+UzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZp
+ZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVDDrEKvlO4vW+GZdfjohTsR8/
+y8+fIBNtKTrID30892t2OGPZNmCom15cAICyL1l/9of5JUOG52kbUpqQ4XHj2C0N
+Tm/2yEnZtvMaVq4rtnQU68/7JuMauh2WLmo7WJSJR1b/JaCTcFOD2oR0FMNnngRo
+Ot+OQFodSk7PQ5E751bWAHDLUu57fa4657wx+UX2wmDPE1kCK4DMNEffud6QZW0C
+zyyRpqbn3oUYSXxmTqM6bam17jQuug0DuDPfR+uxa40l2ZvOgdFFRjKWcIfeAg5J
+Q4W2bHO7ZOphQazJ1FTfhy/HIrImzJ9ZVGif/L4qL8RVHHVAYBeFAlU5i38FAgMB
+AAGjgfAwge0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0O
+BBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMB8GA1UdIwQYMBaAFL9ft9HO3R+G9FtV
+rNzXEMIOqYjnME8GCCsGAQUFBwEBBEMwQTAcBggrBgEFBQcwAYYQaHR0cDovL28u
+c3MyLnVzLzAhBggrBgEFBQcwAoYVaHR0cDovL3guc3MyLnVzL3guY2VyMCYGA1Ud
+HwQfMB0wG6AZoBeGFWh0dHA6Ly9zLnNzMi51cy9yLmNybDARBgNVHSAECjAIMAYG
+BFUdIAAwDQYJKoZIhvcNAQELBQADggEBACMd44pXyn3pF3lM8R5V/cxTbj5HD9/G
+VfKyBDbtgB9TxF00KGu+x1X8Z+rLP3+QsjPNG1gQggL4+C/1E2DUBc7xgQjB3ad1
+l08YuW3e95ORCLp+QCztweq7dp4zBncdDQh/U90bZKuCJ/Fp1U1ervShw3WnWEQt
+8jxwmKy6abaVd38PMV4s/KCHOkdp8Hlf9BRUpJVeEXgSYCfOn8J3/yNTd126/+pZ
+59vPr5KW7ySaNRB6nJHGDn2Z9j8Z3/VyVOEVqQdZe4O/Ui5GjLIAZHYcSNPYeehu
+VsyuLAOQ1xk4meTKCRlb/weWsKh/NEnfVqn3sF/tM+2MR7cwA130A4w=
+-----END CERTIFICATE-----
+
diff --git a/tests/examples/p256-priv.der b/tests/examples/p256-priv.der
new file mode 100644
index 0000000..c0de45e
--- /dev/null
+++ b/tests/examples/p256-priv.der
Binary files differ
diff --git a/tests/examples/p256-pub.der b/tests/examples/p256-pub.der
new file mode 100644
index 0000000..67c719c
--- /dev/null
+++ b/tests/examples/p256-pub.der
Binary files differ
diff --git a/tests/examples/qualcomm.pem b/tests/examples/qualcomm.pem
new file mode 100644
index 0000000..5226062
--- /dev/null
+++ b/tests/examples/qualcomm.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICnDCCAiGgAwIBAgIWAITOC/ag/oJO5eUGyqideMYVAWJXcTAKBggqhkjOPQQD
+AzB2MSQwIgYDVQQKDBtRdWFsY29tbSBUZWNobm9sb2dpZXMsIEluYy4xKjAoBgNV
+BAsMIVF1YWxjb21tIENyeXB0b2dyYXBoaWMgT3BlcmF0aW9uczEiMCAGA1UEAwwZ
+UU1DIEF0dGVzdGF0aW9uIFJvb3QgQ0EgNDAeFw0xNzA4MDEyMjE2MzJaFw0yNzA4
+MDEyMjE2MzJaMH4xJDAiBgNVBAoMG1F1YWxjb21tIFRlY2hub2xvZ2llcywgSW5j
+LjEqMCgGA1UECwwhUXVhbGNvbW0gQ3J5cHRvZ3JhcGhpYyBPcGVyYXRpb25zMSow
+KAYDVQQDDCFRTUMgQXR0ZXN0YXRpb24gUm9vdCBDQSA0IFN1YkNBIDEwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAAQDsjssSUEFLyyBe17UmO3pMzqKS+V1jfQkhq7a7zmH
+LCrPFmfaKLm0/szdzZxn+zwhoYen3fgJIuZUaip8wAQxLe4550c1ZBl3iSTvYUbe
+J+gBz2DiJHRBOtY1bQH35NWjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0P
+AQH/BAQDAgEGMB0GA1UdDgQWBBTrVYStHPbaTn4k7bPerqZAmJcuXzAfBgNVHSME
+GDAWgBQBBnkODO3o7rgWy996xOf1BxR4VTAKBggqhkjOPQQDAwNpADBmAjEAmpM/
+Xvfawl4/A3jd0VVb6lOBh0Jy+zFz1Jz/hw+Xpm9G4XJCscBE7r7lbe2Xc1DHAjEA
+psnskI8pLJQwL80QzAwP3HvgyDUeedNpxnYNK797vqJu6uRMLsZBVHatLM1R4gyE
+-----END CERTIFICATE-----
diff --git a/tests/examples/rsa2048-priv.der b/tests/examples/rsa2048-priv.der
new file mode 100644
index 0000000..bbf1876
--- /dev/null
+++ b/tests/examples/rsa2048-priv.der
Binary files differ
diff --git a/tests/examples/rsa2048-pub.der b/tests/examples/rsa2048-pub.der
new file mode 100644
index 0000000..4148aaa
--- /dev/null
+++ b/tests/examples/rsa2048-pub.der
Binary files differ
diff --git a/tests/general_name.rs b/tests/general_name.rs
index 5447c5f..f63b4a2 100644
--- a/tests/general_name.rs
+++ b/tests/general_name.rs
@@ -50,7 +50,7 @@
         _ => panic!("unexpected decoded value"),
     }
 
-    let encoded = decoded.to_vec().unwrap();
+    let encoded = decoded.to_der().unwrap();
     assert_eq!(value, encoded);
 }
 
@@ -75,6 +75,6 @@
         _ => panic!("unexpected decoded value"),
     }
 
-    let encoded = decoded.to_vec().unwrap();
+    let encoded = decoded.to_der().unwrap();
     assert_eq!(value, encoded);
 }
diff --git a/tests/name.rs b/tests/name.rs
index e52b2c7..27af2b5 100644
--- a/tests/name.rs
+++ b/tests/name.rs
@@ -2,7 +2,7 @@
 
 use const_oid::ObjectIdentifier;
 use der::asn1::{Ia5StringRef, OctetStringRef, PrintableStringRef, SetOfVec, Utf8StringRef};
-use der::{AnyRef, Decode, Encode, Tag, Tagged};
+use der::{Any, Decode, Encode, Tag, Tagged};
 use hex_literal::hex;
 use x509_cert::attr::AttributeTypeAndValue;
 use x509_cert::name::{Name, RdnSequence, RelativeDistinguishedName};
@@ -40,23 +40,53 @@
         for atav in i1 {
             if 0 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.6");
-                assert_eq!(atav.value.printable_string().unwrap().to_string(), "US");
+                assert_eq!(
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
+                    "US"
+                );
             } else if 1 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.10");
                 assert_eq!(
-                    atav.value.printable_string().unwrap().to_string(),
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
                     "Test Certificates 2011"
                 );
             } else if 2 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.3");
                 assert_eq!(
-                    atav.value.printable_string().unwrap().to_string(),
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
                     "Good CA"
                 );
             }
             counter += 1;
         }
     }
+
+    #[cfg(feature = "std")]
+    {
+        // https://datatracker.ietf.org/doc/html/rfc4514.html#section-2.1
+        // If the RDNSequence is an empty sequence, the result is the empty or
+        // zero-length string.
+        // Otherwise, the output consists of the string encodings of each
+        // RelativeDistinguishedName in the RDNSequence (according to Section 2.2),
+        // starting with the last element of the sequence and moving backwards
+        // toward the first.
+        // The encodings of adjoining RelativeDistinguishedNames are separated by
+        // a comma (',' U+002C) character.
+        let name = rdn1a.to_string();
+        assert_eq!(name, "CN=Good CA,O=Test Certificates 2011,C=US");
+
+        // https://github.com/RustCrypto/formats/issues/1121
+        let rdn1 = Name::from_der(&hex!("3081c0310b30090603550406130255533113301106035504080c0a43616c69666f726e69613116301406035504070c0d4d6f756e7461696e205669657731133011060355040a0c0a476f6f676c65204c4c43311e301c06035504030c154f51464176444e4457732e676f6f676c652e636f6d31243022060355040b0c1b6d616e6167656d656e743a64732e67726f75702e3338393131313131293027060a0992268993f22c6401010c196964656e746974793a64732e67726f75702e33383931313131")[..]);
+        let rdn1a = rdn1.unwrap();
+        let name = rdn1a.to_string();
+        assert_eq!(name, "UID=identity:ds.group.3891111,OU=management:ds.group.3891111,CN=OQFAvDNDWs.google.com,O=Google LLC,L=Mountain View,ST=California,C=US");
+    }
 }
 
 #[test]
@@ -73,9 +103,9 @@
     for atav in i {
         let oid = atav.oid;
         assert_eq!(oid.to_string(), "2.5.4.6");
-        let value = atav.value;
+        let value = &atav.value;
         assert_eq!(value.tag(), Tag::PrintableString);
-        let ps = value.printable_string().unwrap();
+        let ps = PrintableStringRef::try_from(value).unwrap();
         assert_eq!(ps.to_string(), "US");
     }
 
@@ -99,32 +129,32 @@
     let atav1a = i.next().unwrap();
     let oid2 = atav1a.oid;
     assert_eq!(oid2.to_string(), "2.5.4.10");
-    let value2 = atav1a.value;
+    let value2 = &atav1a.value;
     assert_eq!(value2.tag(), Tag::Utf8String);
-    let utf8b = value2.utf8_string().unwrap();
+    let utf8b = Utf8StringRef::try_from(value2).unwrap();
     assert_eq!(utf8b.to_string(), "123");
 
     let atav2a = i.next().unwrap();
     let oid1 = atav2a.oid;
     assert_eq!(oid1.to_string(), "2.5.4.3");
-    let value1 = atav2a.value;
+    let value1 = &atav2a.value;
     assert_eq!(value1.tag(), Tag::Utf8String);
-    let utf8a = value1.utf8_string().unwrap();
+    let utf8a = Utf8StringRef::try_from(value1).unwrap();
     assert_eq!(utf8a.to_string(), "JOHN SMITH");
 
     let mut from_scratch = RelativeDistinguishedName::default();
-    assert!(from_scratch.0.add(*atav1a).is_ok());
-    assert!(from_scratch.0.add(*atav2a).is_ok());
-    let reencoded = from_scratch.to_vec().unwrap();
+    assert!(from_scratch.0.insert(atav1a.clone()).is_ok());
+    assert!(from_scratch.0.insert(atav2a.clone()).is_ok());
+    let reencoded = from_scratch.to_der().unwrap();
     assert_eq!(
         reencoded,
         &hex!("311F300A060355040A0C03313233301106035504030C0A4A4F484E20534D495448")
     );
 
     let mut from_scratch2 = RelativeDistinguishedName::default();
-    assert!(from_scratch2.0.add(*atav2a).is_ok());
+    assert!(from_scratch2.0.insert_ordered(atav2a.clone()).is_ok());
     // fails when caller adds items not in DER lexicographical order
-    assert!(from_scratch2.0.add(*atav1a).is_err());
+    assert!(from_scratch2.0.insert_ordered(atav1a.clone()).is_err());
 
     // allow out-of-order RDNs (see: RustCrypto/formats#625)
     assert!(RelativeDistinguishedName::from_der(
@@ -196,24 +226,24 @@
             ],
             "CN=foo,SN=bar,C=baz+L=bat",
             &[
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::CN,
-                    value: AnyRef::from(Utf8StringRef::new("foo").unwrap()),
-                }],
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::SN,
-                    value: AnyRef::from(Utf8StringRef::new("bar").unwrap()),
-                }],
                 &[
                     AttributeTypeAndValue {
                         oid: const_oid::db::rfc4519::C,
-                        value: AnyRef::from(PrintableStringRef::new("baz").unwrap()),
+                        value: Any::from(PrintableStringRef::new("baz").unwrap()),
                     },
                     AttributeTypeAndValue {
                         oid: const_oid::db::rfc4519::L,
-                        value: AnyRef::from(Utf8StringRef::new("bat").unwrap()),
+                        value: Any::from(Utf8StringRef::new("bat").unwrap()),
                     },
                 ],
+                &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::SN,
+                    value: Any::from(Utf8StringRef::new("bar").unwrap()),
+                }],
+                &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::CN,
+                    value: Any::from(Utf8StringRef::new("foo").unwrap()),
+                }],
             ],
         ),
         (
@@ -221,16 +251,16 @@
             "UID=jsmith,DC=example,DC=net",
             &[
                 &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::DC,
+                    value: Any::from(Ia5StringRef::new("net").unwrap()),
+                }],
+                &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::DC,
+                    value: Any::from(Ia5StringRef::new("example").unwrap()),
+                }],
+                &[AttributeTypeAndValue {
                     oid: const_oid::db::rfc4519::UID,
-                    value: AnyRef::from(Utf8StringRef::new("jsmith").unwrap()),
-                }],
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::DC,
-                    value: AnyRef::from(Ia5StringRef::new("example").unwrap()),
-                }],
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::DC,
-                    value: AnyRef::from(Ia5StringRef::new("net").unwrap()),
+                    value: Any::from(Utf8StringRef::new("jsmith").unwrap()),
                 }],
             ],
         ),
@@ -238,24 +268,24 @@
             &["OU=Sales+CN=J.  Smith,DC=example,DC=net"],
             "OU=Sales+CN=J.  Smith,DC=example,DC=net",
             &[
+                &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::DC,
+                    value: Any::from(Ia5StringRef::new("net").unwrap()),
+                }],
+                &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::DC,
+                    value: Any::from(Ia5StringRef::new("example").unwrap()),
+                }],
                 &[
                     AttributeTypeAndValue {
                         oid: const_oid::db::rfc4519::OU,
-                        value: AnyRef::from(Utf8StringRef::new("Sales").unwrap()),
+                        value: Any::from(Utf8StringRef::new("Sales").unwrap()),
                     },
                     AttributeTypeAndValue {
                         oid: const_oid::db::rfc4519::CN,
-                        value: AnyRef::from(Utf8StringRef::new("J.  Smith").unwrap()),
+                        value: Any::from(Utf8StringRef::new("J.  Smith").unwrap()),
                     },
                 ],
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::DC,
-                    value: AnyRef::from(Ia5StringRef::new("example").unwrap()),
-                }],
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::DC,
-                    value: AnyRef::from(Ia5StringRef::new("net").unwrap()),
-                }],
             ],
         ),
         (
@@ -263,16 +293,16 @@
             "CN=James \\\"Jim\\\" Smith\\, III,DC=example,DC=net",
             &[
                 &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::DC,
+                    value: Any::from(Ia5StringRef::new("net").unwrap()),
+                }],
+                &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::DC,
+                    value: Any::from(Ia5StringRef::new("example").unwrap()),
+                }],
+                &[AttributeTypeAndValue {
                     oid: const_oid::db::rfc4519::CN,
-                    value: AnyRef::from(Utf8StringRef::new(r#"James "Jim" Smith, III"#).unwrap()),
-                }],
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::DC,
-                    value: AnyRef::from(Ia5StringRef::new("example").unwrap()),
-                }],
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::DC,
-                    value: AnyRef::from(Ia5StringRef::new("net").unwrap()),
+                    value: Any::from(Utf8StringRef::new(r#"James "Jim" Smith, III"#).unwrap()),
                 }],
             ],
         ),
@@ -281,16 +311,16 @@
             "CN=Before\\0dAfter,DC=example,DC=net",
             &[
                 &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::DC,
+                    value: Any::from(Ia5StringRef::new("net").unwrap()),
+                }],
+                &[AttributeTypeAndValue {
+                    oid: const_oid::db::rfc4519::DC,
+                    value: Any::from(Ia5StringRef::new("example").unwrap()),
+                }],
+                &[AttributeTypeAndValue {
                     oid: const_oid::db::rfc4519::CN,
-                    value: AnyRef::from(Utf8StringRef::new("Before\rAfter").unwrap()),
-                }],
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::DC,
-                    value: AnyRef::from(Ia5StringRef::new("example").unwrap()),
-                }],
-                &[AttributeTypeAndValue {
-                    oid: const_oid::db::rfc4519::DC,
-                    value: AnyRef::from(Ia5StringRef::new("net").unwrap()),
+                    value: Any::from(Utf8StringRef::new("Before\rAfter").unwrap()),
                 }],
             ],
         ),
@@ -299,7 +329,7 @@
             "1.3.6.1.4.1.1466.0=#04024869",
             &[&[AttributeTypeAndValue {
                 oid: ObjectIdentifier::new("1.3.6.1.4.1.1466.0").unwrap(),
-                value: AnyRef::from(OctetStringRef::new(&[b'H', b'i']).unwrap()),
+                value: Any::from(OctetStringRef::new(&[b'H', b'i']).unwrap()),
             }]],
         ),
     ];
@@ -319,7 +349,11 @@
         for input in inputs.iter() {
             eprintln!("input: {}", input);
 
-            let der = RdnSequence::encode_from_string(input).unwrap();
+            let der = input
+                .parse::<RdnSequence>()
+                .and_then(|rdn| rdn.to_der())
+                .unwrap();
+
             let rdns = RdnSequence::from_der(&der).unwrap();
 
             for (l, r) in brdns.0.iter().zip(rdns.0.iter()) {
diff --git a/tests/pkix_extensions.rs b/tests/pkix_extensions.rs
index c08fcb8..108eeb5 100644
--- a/tests/pkix_extensions.rs
+++ b/tests/pkix_extensions.rs
@@ -1,6 +1,6 @@
 //! Certificate tests
 use const_oid::AssociatedOid;
-use der::asn1::UIntRef;
+use der::asn1::{Ia5StringRef, OctetString, PrintableStringRef, Utf8StringRef};
 use der::{Decode, Encode, ErrorKind, Length, Tag, Tagged};
 use hex_literal::hex;
 use x509_cert::ext::pkix::crl::dp::{DistributionPoint, ReasonFlags, Reasons};
@@ -8,7 +8,7 @@
 use x509_cert::ext::pkix::*;
 use x509_cert::ext::Extensions;
 use x509_cert::name::Name;
-use x509_cert::{Certificate, Version};
+use x509_cert::{serial_number::SerialNumber, Certificate, Version};
 
 use const_oid::db::rfc5280::*;
 use const_oid::db::rfc5912::ID_CE_CERTIFICATE_POLICIES;
@@ -17,93 +17,149 @@
     for ext in exts {
         match ext.extn_id {
             SubjectDirectoryAttributes::OID => {
-                let decoded = SubjectDirectoryAttributes::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded =
+                    SubjectDirectoryAttributes::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             SubjectKeyIdentifier::OID => {
-                let decoded = SubjectKeyIdentifier::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = SubjectKeyIdentifier::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             KeyUsage::OID => {
-                let decoded = KeyUsage::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = KeyUsage::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             PrivateKeyUsagePeriod::OID => {
-                let decoded = PrivateKeyUsagePeriod::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = PrivateKeyUsagePeriod::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             SubjectAltName::OID => {
-                let decoded = SubjectAltName::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = SubjectAltName::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             IssuerAltName::OID => {
-                let decoded = IssuerAltName::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = IssuerAltName::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             BasicConstraints::OID => {
-                let decoded = BasicConstraints::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = BasicConstraints::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             NameConstraints::OID => {
-                let decoded = NameConstraints::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = NameConstraints::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             CrlDistributionPoints::OID => {
-                let decoded = CrlDistributionPoints::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = CrlDistributionPoints::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             CertificatePolicies::OID => {
-                let decoded = CertificatePolicies::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = CertificatePolicies::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             PolicyMappings::OID => {
-                let decoded = PolicyMappings::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = PolicyMappings::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             AuthorityKeyIdentifier::OID => {
-                let decoded = AuthorityKeyIdentifier::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = AuthorityKeyIdentifier::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             PolicyConstraints::OID => {
-                let decoded = PolicyConstraints::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = PolicyConstraints::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             ExtendedKeyUsage::OID => {
-                let decoded = ExtendedKeyUsage::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = ExtendedKeyUsage::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             FreshestCrl::OID => {
-                let decoded = FreshestCrl::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = FreshestCrl::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             InhibitAnyPolicy::OID => {
-                let decoded = InhibitAnyPolicy::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = InhibitAnyPolicy::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             AuthorityInfoAccessSyntax::OID => {
-                let decoded = AuthorityInfoAccessSyntax::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded =
+                    AuthorityInfoAccessSyntax::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             SubjectInfoAccessSyntax::OID => {
-                let decoded = SubjectInfoAccessSyntax::from_der(ext.extn_value).unwrap();
-                assert_eq!(ext.extn_value, decoded.to_vec().unwrap());
+                let decoded = SubjectInfoAccessSyntax::from_der(ext.extn_value.as_bytes()).unwrap();
+                assert_eq!(
+                    ext.extn_value,
+                    decoded.to_der().and_then(OctetString::new).unwrap()
+                );
             }
 
             _ => {
@@ -138,7 +194,7 @@
     let bytes = hex!("A021060A2B060104018237140203A0130C1155706E5F323134393530313330406D696C");
     match GeneralName::from_der(&bytes).unwrap() {
         GeneralName::OtherName(other_name) => {
-            let onval = other_name.value.utf8_string().unwrap();
+            let onval = Utf8StringRef::try_from(&other_name.value).unwrap();
             assert_eq!(onval.to_string(), "Upn_214950130@mil");
         }
         _ => panic!("Failed to parse OtherName from GeneralName"),
@@ -162,27 +218,27 @@
             assert_eq!(ext.extn_id.to_string(), ID_CE_KEY_USAGE.to_string());
             assert_eq!(ext.critical, true);
 
-            let ku = KeyUsage::from_der(ext.extn_value).unwrap();
+            let ku = KeyUsage::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(KeyUsages::KeyCertSign | KeyUsages::CRLSign, ku);
 
-            let reencoded = ku.to_vec().unwrap();
+            let reencoded = ku.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
         } else if 1 == counter {
             assert_eq!(ext.extn_id.to_string(), ID_CE_BASIC_CONSTRAINTS.to_string());
             assert_eq!(ext.critical, true);
-            let bc = BasicConstraints::from_der(ext.extn_value).unwrap();
+            let bc = BasicConstraints::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(true, bc.ca);
             assert!(bc.path_len_constraint.is_none());
 
-            let reencoded = bc.to_vec().unwrap();
+            let reencoded = bc.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
         } else if 2 == counter {
             assert_eq!(ext.extn_id.to_string(), ID_CE_POLICY_MAPPINGS.to_string());
             assert_eq!(ext.critical, false);
-            let pm = PolicyMappings::from_der(ext.extn_value).unwrap();
+            let pm = PolicyMappings::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(19, pm.0.len());
 
-            let reencoded = pm.to_vec().unwrap();
+            let reencoded = pm.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
 
             let subject_domain_policy: [&str; 19] = [
@@ -247,10 +303,10 @@
                 ID_CE_CERTIFICATE_POLICIES.to_string()
             );
             assert_eq!(ext.critical, false);
-            let cps = CertificatePolicies::from_der(ext.extn_value).unwrap();
+            let cps = CertificatePolicies::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(19, cps.0.len());
 
-            let reencoded = cps.to_vec().unwrap();
+            let reencoded = cps.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
 
             let ids: [&str; 19] = [
@@ -285,7 +341,8 @@
                     for pqi in pq.iter() {
                         if 0 == counter_pq {
                             assert_eq!("1.3.6.1.5.5.7.2.1", pqi.policy_qualifier_id.to_string());
-                            let cpsval = pqi.qualifier.unwrap().ia5_string().unwrap();
+                            let cpsval =
+                                Ia5StringRef::try_from(pqi.qualifier.as_ref().unwrap()).unwrap();
                             assert_eq!(
                                 "https://secure.identrust.com/certificates/policy/IGC/index.html",
                                 cpsval.to_string()
@@ -308,14 +365,14 @@
                 ID_CE_SUBJECT_KEY_IDENTIFIER.to_string()
             );
             assert_eq!(ext.critical, false);
-            let skid = SubjectKeyIdentifier::from_der(ext.extn_value).unwrap();
+            let skid = SubjectKeyIdentifier::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(Length::new(21), skid.0.len());
             assert_eq!(
                 &hex!("DBD3DEBF0D7B615B32803BC0206CD7AADD39B8ACFF"),
                 skid.0.as_bytes()
             );
 
-            let reencoded = skid.to_vec().unwrap();
+            let reencoded = skid.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
         } else if 5 == counter {
             assert_eq!(
@@ -323,10 +380,10 @@
                 ID_CE_CRL_DISTRIBUTION_POINTS.to_string()
             );
             assert_eq!(ext.critical, false);
-            let crl_dps = CrlDistributionPoints::from_der(ext.extn_value).unwrap();
+            let crl_dps = CrlDistributionPoints::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(2, crl_dps.0.len());
 
-            let reencoded = crl_dps.to_vec().unwrap();
+            let reencoded = crl_dps.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
 
             let mut crldp_counter = 0;
@@ -381,10 +438,10 @@
                 ID_PE_SUBJECT_INFO_ACCESS.to_string()
             );
             assert_eq!(ext.critical, false);
-            let sias = SubjectInfoAccessSyntax::from_der(ext.extn_value).unwrap();
+            let sias = SubjectInfoAccessSyntax::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(1, sias.0.len());
 
-            let reencoded = sias.to_vec().unwrap();
+            let reencoded = sias.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
 
             for sia in sias.0 {
@@ -408,11 +465,11 @@
                 ID_PE_AUTHORITY_INFO_ACCESS.to_string()
             );
             assert_eq!(ext.critical, false);
-            let aias = AuthorityInfoAccessSyntax::from_der(ext.extn_value).unwrap();
+            let aias = AuthorityInfoAccessSyntax::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(2, aias.0.len());
             let mut aia_counter = 0;
 
-            let reencoded = aias.to_vec().unwrap();
+            let reencoded = aias.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
 
             for aia in aias.0 {
@@ -454,10 +511,10 @@
                 ID_CE_INHIBIT_ANY_POLICY.to_string()
             );
             assert_eq!(ext.critical, false);
-            let iap = InhibitAnyPolicy::from_der(ext.extn_value).unwrap();
+            let iap = InhibitAnyPolicy::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(0, iap.0);
 
-            let reencoded = iap.to_vec().unwrap();
+            let reencoded = iap.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
         } else if 9 == counter {
             assert_eq!(
@@ -465,13 +522,13 @@
                 ID_CE_AUTHORITY_KEY_IDENTIFIER.to_string()
             );
             assert_eq!(ext.critical, false);
-            let akid = AuthorityKeyIdentifier::from_der(ext.extn_value).unwrap();
+            let akid = AuthorityKeyIdentifier::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(
                 &hex!("7C4C863AB80BD589870BEDB7E11BBD2A08BB3D23FF"),
-                akid.key_identifier.unwrap().as_bytes()
+                akid.key_identifier.as_ref().unwrap().as_bytes()
             );
 
-            let reencoded = akid.to_vec().unwrap();
+            let reencoded = akid.to_der().and_then(OctetString::new).unwrap();
             assert_eq!(ext.extn_value, reencoded);
         }
 
@@ -486,18 +543,28 @@
     let target_serial: [u8; 1] = [2];
     assert_eq!(
         cert.tbs_certificate.serial_number,
-        UIntRef::new(&target_serial).unwrap()
+        SerialNumber::new(&target_serial).unwrap()
     );
     assert_eq!(
         cert.tbs_certificate.signature.oid.to_string(),
         "1.2.840.113549.1.1.11"
     );
     assert_eq!(
-        cert.tbs_certificate.signature.parameters.unwrap().tag(),
+        cert.tbs_certificate
+            .signature
+            .parameters
+            .as_ref()
+            .unwrap()
+            .tag(),
         Tag::Null
     );
     assert_eq!(
-        cert.tbs_certificate.signature.parameters.unwrap().is_null(),
+        cert.tbs_certificate
+            .signature
+            .parameters
+            .as_ref()
+            .unwrap()
+            .is_null(),
         true
     );
 
@@ -508,17 +575,26 @@
         for atav in i1 {
             if 0 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.6");
-                assert_eq!(atav.value.printable_string().unwrap().to_string(), "US");
+                assert_eq!(
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
+                    "US"
+                );
             } else if 1 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.10");
                 assert_eq!(
-                    atav.value.printable_string().unwrap().to_string(),
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
                     "Test Certificates 2011"
                 );
             } else if 2 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.3");
                 assert_eq!(
-                    atav.value.printable_string().unwrap().to_string(),
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
                     "Trust Anchor"
                 );
             }
@@ -550,17 +626,26 @@
         for atav in i1 {
             if 0 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.6");
-                assert_eq!(atav.value.printable_string().unwrap().to_string(), "US");
+                assert_eq!(
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
+                    "US"
+                );
             } else if 1 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.10");
                 assert_eq!(
-                    atav.value.printable_string().unwrap().to_string(),
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
                     "Test Certificates 2011"
                 );
             } else if 2 == counter {
                 assert_eq!(atav.oid.to_string(), "2.5.4.3");
                 assert_eq!(
-                    atav.value.printable_string().unwrap().to_string(),
+                    PrintableStringRef::try_from(&atav.value)
+                        .unwrap()
+                        .to_string(),
                     "Good CA"
                 );
             }
@@ -581,6 +666,7 @@
             .subject_public_key_info
             .algorithm
             .parameters
+            .as_ref()
             .unwrap()
             .tag(),
         Tag::Null
@@ -590,6 +676,7 @@
             .subject_public_key_info
             .algorithm
             .parameters
+            .as_ref()
             .unwrap()
             .is_null(),
         true
@@ -607,7 +694,7 @@
                 ID_CE_AUTHORITY_KEY_IDENTIFIER.to_string()
             );
             assert_eq!(ext.critical, false);
-            let akid = AuthorityKeyIdentifier::from_der(ext.extn_value).unwrap();
+            let akid = AuthorityKeyIdentifier::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(
                 akid.key_identifier.unwrap().as_bytes(),
                 &hex!("E47D5FD15C9586082C05AEBE75B665A7D95DA866")[..]
@@ -618,7 +705,7 @@
                 ID_CE_SUBJECT_KEY_IDENTIFIER.to_string()
             );
             assert_eq!(ext.critical, false);
-            let skid = SubjectKeyIdentifier::from_der(ext.extn_value).unwrap();
+            let skid = SubjectKeyIdentifier::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(
                 skid.0.as_bytes(),
                 &hex!("580184241BBC2B52944A3DA510721451F5AF3AC9")[..]
@@ -626,7 +713,7 @@
         } else if 2 == counter {
             assert_eq!(ext.extn_id.to_string(), ID_CE_KEY_USAGE.to_string());
             assert_eq!(ext.critical, true);
-            let ku = KeyUsage::from_der(ext.extn_value).unwrap();
+            let ku = KeyUsage::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(KeyUsages::KeyCertSign | KeyUsages::CRLSign, ku);
         } else if 3 == counter {
             assert_eq!(
@@ -634,7 +721,7 @@
                 ID_CE_CERTIFICATE_POLICIES.to_string()
             );
             assert_eq!(ext.critical, false);
-            let r = CertificatePolicies::from_der(ext.extn_value);
+            let r = CertificatePolicies::from_der(ext.extn_value.as_bytes());
             let cp = r.unwrap();
             let i = cp.0.iter();
             for p in i {
@@ -643,7 +730,7 @@
         } else if 4 == counter {
             assert_eq!(ext.extn_id.to_string(), ID_CE_BASIC_CONSTRAINTS.to_string());
             assert_eq!(ext.critical, true);
-            let bc = BasicConstraints::from_der(ext.extn_value).unwrap();
+            let bc = BasicConstraints::from_der(ext.extn_value.as_bytes()).unwrap();
             assert_eq!(bc.ca, true);
             assert_eq!(bc.path_len_constraint, Option::None);
         }
@@ -655,7 +742,7 @@
         "1.2.840.113549.1.1.11"
     );
     assert_eq!(
-        cert.signature_algorithm.parameters.unwrap().tag(),
+        cert.signature_algorithm.parameters.as_ref().unwrap().tag(),
         Tag::Null
     );
     assert_eq!(cert.signature_algorithm.parameters.unwrap().is_null(), true);
diff --git a/tests/trust_anchor_format.rs b/tests/trust_anchor_format.rs
index bcc3e69..a1bdc69 100644
--- a/tests/trust_anchor_format.rs
+++ b/tests/trust_anchor_format.rs
@@ -1,4 +1,7 @@
-use der::{Decode, Encode, SliceReader};
+use der::{
+    asn1::{Ia5StringRef, PrintableStringRef},
+    Decode, Encode, SliceReader,
+};
 use hex_literal::hex;
 use x509_cert::anchor::{CertPolicies, TrustAnchorChoice};
 use x509_cert::ext::pkix::name::GeneralName;
@@ -12,7 +15,7 @@
 
     let mut decoder = SliceReader::new(der_encoded_tac).unwrap();
     let tac = TrustAnchorChoice::decode(&mut decoder).unwrap();
-    let reencoded_tac = tac.to_vec().unwrap();
+    let reencoded_tac = tac.to_der().unwrap();
     println!("Original : {:02X?}", der_encoded_cert);
     println!("Reencoded: {:02X?}", reencoded_tac);
     assert_eq!(der_encoded_tac, reencoded_tac.as_slice());
@@ -90,20 +93,34 @@
                 for atav in i1 {
                     if 0 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.6");
-                        assert_eq!(atav.value.printable_string().unwrap().to_string(), "US");
+                        assert_eq!(
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
+                            "US"
+                        );
                     } else if 1 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.10");
                         assert_eq!(
-                            atav.value.printable_string().unwrap().to_string(),
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
                             "U.S. Government"
                         );
                     } else if 2 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.11");
-                        assert_eq!(atav.value.printable_string().unwrap().to_string(), "ECA");
+                        assert_eq!(
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
+                            "ECA"
+                        );
                     } else if 3 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.3");
                         assert_eq!(
-                            atav.value.printable_string().unwrap().to_string(),
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
                             "ECA Root CA 4"
                         );
                     }
@@ -111,7 +128,7 @@
                 }
             }
 
-            let reencoded_cert = cert_path.certificate.to_vec().unwrap();
+            let reencoded_cert = cert_path.certificate.to_der().unwrap();
             assert_eq!(der_encoded_cert, reencoded_cert.as_slice());
         }
         _ => panic!("Unexpected TrustAnchorChoice contents"),
@@ -127,7 +144,7 @@
 
     let mut decoder = SliceReader::new(der_encoded_tac).unwrap();
     let tac = TrustAnchorChoice::decode(&mut decoder).unwrap();
-    let reencoded_tac = tac.to_vec().unwrap();
+    let reencoded_tac = tac.to_der().unwrap();
     println!("Original : {:02X?}", der_encoded_cert);
     println!("Reencoded: {:02X?}", reencoded_tac);
     assert_eq!(der_encoded_tac, reencoded_tac.as_slice());
@@ -153,23 +170,34 @@
                 for atav in i1 {
                     if 0 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.6");
-                        assert_eq!(atav.value.printable_string().unwrap().to_string(), "US");
+                        assert_eq!(
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
+                            "US"
+                        );
                     } else if 1 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.10");
                         assert_eq!(
-                            atav.value.printable_string().unwrap().to_string(),
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
                             "Entrust"
                         );
                     } else if 2 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.11");
                         assert_eq!(
-                            atav.value.printable_string().unwrap().to_string(),
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
                             "Certification Authorities"
                         );
                     } else if 3 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.11");
                         assert_eq!(
-                            atav.value.printable_string().unwrap().to_string(),
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
                             "Entrust Managed Services NFI Root CA"
                         );
                     }
@@ -190,19 +218,25 @@
                                 if 0 == counter {
                                     assert_eq!(atav.oid.to_string(), "2.5.4.6");
                                     assert_eq!(
-                                        atav.value.printable_string().unwrap().to_string(),
+                                        PrintableStringRef::try_from(&atav.value)
+                                            .unwrap()
+                                            .to_string(),
                                         "US"
                                     );
                                 } else if 1 == counter {
                                     assert_eq!(atav.oid.to_string(), "2.5.4.10");
                                     assert_eq!(
-                                        atav.value.printable_string().unwrap().to_string(),
+                                        PrintableStringRef::try_from(&atav.value)
+                                            .unwrap()
+                                            .to_string(),
                                         "U.S. Government"
                                     );
                                 } else if 2 == counter {
                                     assert_eq!(atav.oid.to_string(), "2.5.4.11");
                                     assert_eq!(
-                                        atav.value.printable_string().unwrap().to_string(),
+                                        PrintableStringRef::try_from(&atav.value)
+                                            .unwrap()
+                                            .to_string(),
                                         "DoD"
                                     );
                                 }
@@ -214,7 +248,7 @@
                 }
             }
 
-            let reencoded_cert = cert_path.certificate.to_vec().unwrap();
+            let reencoded_cert = cert_path.certificate.to_der().unwrap();
             assert_eq!(der_encoded_cert, reencoded_cert.as_slice());
         }
         _ => panic!("Unexpected TrustAnchorChoice contents"),
@@ -230,7 +264,7 @@
 
     let mut decoder = SliceReader::new(der_encoded_tac).unwrap();
     let tac = TrustAnchorChoice::decode(&mut decoder).unwrap();
-    let reencoded_tac = tac.to_vec().unwrap();
+    let reencoded_tac = tac.to_der().unwrap();
     println!("Original : {:02X?}", der_encoded_cert);
     println!("Reencoded: {:02X?}", reencoded_tac);
     assert_eq!(der_encoded_tac, reencoded_tac.as_slice());
@@ -263,23 +297,34 @@
                 for atav in i1 {
                     if 0 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.6");
-                        assert_eq!(atav.value.printable_string().unwrap().to_string(), "US");
+                        assert_eq!(
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
+                            "US"
+                        );
                     } else if 1 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.10");
                         assert_eq!(
-                            atav.value.printable_string().unwrap().to_string(),
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
                             "Exostar LLC"
                         );
                     } else if 2 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.11");
                         assert_eq!(
-                            atav.value.printable_string().unwrap().to_string(),
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
                             "Certification Authorities"
                         );
                     } else if 3 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.3");
                         assert_eq!(
-                            atav.value.printable_string().unwrap().to_string(),
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
                             "Exostar Federated Identity Service Root CA 1"
                         );
                     }
@@ -300,19 +345,25 @@
                                 if 0 == counter {
                                     assert_eq!(atav.oid.to_string(), "2.5.4.6");
                                     assert_eq!(
-                                        atav.value.printable_string().unwrap().to_string(),
+                                        PrintableStringRef::try_from(&atav.value)
+                                            .unwrap()
+                                            .to_string(),
                                         "US"
                                     );
                                 } else if 1 == counter {
                                     assert_eq!(atav.oid.to_string(), "2.5.4.10");
                                     assert_eq!(
-                                        atav.value.printable_string().unwrap().to_string(),
+                                        PrintableStringRef::try_from(&atav.value)
+                                            .unwrap()
+                                            .to_string(),
                                         "U.S. Government"
                                     );
                                 } else if 2 == counter {
                                     assert_eq!(atav.oid.to_string(), "2.5.4.11");
                                     assert_eq!(
-                                        atav.value.printable_string().unwrap().to_string(),
+                                        PrintableStringRef::try_from(&atav.value)
+                                            .unwrap()
+                                            .to_string(),
                                         "DoD"
                                     );
                                 }
@@ -324,7 +375,7 @@
                 }
             }
 
-            let reencoded_cert = cert_path.certificate.to_vec().unwrap();
+            let reencoded_cert = cert_path.certificate.to_der().unwrap();
             assert_eq!(der_encoded_cert, reencoded_cert.as_slice());
         }
         _ => panic!("Unexpected TrustAnchorChoice contents"),
@@ -340,7 +391,7 @@
 
     let mut decoder = SliceReader::new(der_encoded_tac).unwrap();
     let tac = TrustAnchorChoice::decode(&mut decoder).unwrap();
-    let reencoded_tac = tac.to_vec().unwrap();
+    let reencoded_tac = tac.to_der().unwrap();
     println!("Original : {:02X?}", der_encoded_cert);
     println!("Reencoded: {:02X?}", reencoded_tac);
     assert_eq!(der_encoded_tac, reencoded_tac.as_slice());
@@ -366,17 +417,30 @@
                 for atav in i1 {
                     if 0 == counter {
                         assert_eq!(atav.oid.to_string(), "0.9.2342.19200300.100.1.25");
-                        assert_eq!(atav.value.ia5_string().unwrap().to_string(), "com");
+                        assert_eq!(
+                            Ia5StringRef::try_from(&atav.value).unwrap().to_string(),
+                            "com"
+                        );
                     } else if 1 == counter {
                         assert_eq!(atav.oid.to_string(), "0.9.2342.19200300.100.1.25");
-                        assert_eq!(atav.value.ia5_string().unwrap().to_string(), "raytheon");
+                        assert_eq!(
+                            Ia5StringRef::try_from(&atav.value).unwrap().to_string(),
+                            "raytheon"
+                        );
                     } else if 2 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.10");
-                        assert_eq!(atav.value.printable_string().unwrap().to_string(), "CAs");
+                        assert_eq!(
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
+                            "CAs"
+                        );
                     } else if 3 == counter {
                         assert_eq!(atav.oid.to_string(), "2.5.4.11");
                         assert_eq!(
-                            atav.value.printable_string().unwrap().to_string(),
+                            PrintableStringRef::try_from(&atav.value)
+                                .unwrap()
+                                .to_string(),
                             "RaytheonRoot"
                         );
                     }
@@ -389,7 +453,7 @@
                 panic!("Wrong path length constraint");
             }
 
-            let reencoded_cert = cert_path.certificate.to_vec().unwrap();
+            let reencoded_cert = cert_path.certificate.to_der().unwrap();
             assert_eq!(der_encoded_cert, reencoded_cert.as_slice());
         }
         _ => panic!("Unexpected TrustAnchorChoice contents"),
diff --git a/tests/validity.rs b/tests/validity.rs
index d243773..b2e676c 100644
--- a/tests/validity.rs
+++ b/tests/validity.rs
@@ -1,6 +1,6 @@
 //! Validity tests
 
-use der::Encode;
+use der::{Decode, Encode};
 use hex_literal::hex;
 use x509_cert::time::Validity;
 
@@ -11,7 +11,7 @@
     // 104  13:       UTCTime 01/01/2010 08:30:00 GMT
     // 119  13:       UTCTime 31/12/2030 08:30:00 GMT
     //        :       }
-    let val1 = Validity::try_from(
+    let val1 = Validity::from_der(
         &hex!("301E170D3130303130313038333030305A170D3330313233313038333030305A")[..],
     )
     .unwrap();
@@ -21,7 +21,7 @@
     //  99  13:       UTCTime 01/01/2010 08:30:00 GMT
     // 114  13:       UTCTime 01/01/2011 08:30:00 GMT
     //        :       }
-    let val2 = Validity::try_from(
+    let val2 = Validity::from_der(
         &hex!("301E170D3130303130313038333030305A170D3131303130313038333030305A")[..],
     )
     .unwrap();
@@ -51,7 +51,7 @@
     //  99  13:       UTCTime 01/01/2010 08:30:00 GMT
     // 114  15:       GeneralizedTime 01/01/2050 12:01:00 GMT
     //        :       }
-    let val3 = Validity::try_from(
+    let val3 = Validity::from_der(
         &hex!("3020170D3130303130313038333030305A180F32303530303130313132303130305A")[..],
     )
     .unwrap();
@@ -71,7 +71,7 @@
     //  99  15:       GeneralizedTime 01/01/2002 12:01:00 GMT
     // 116  13:       UTCTime 31/12/2030 08:30:00 GMT
     //        :       }
-    let val4 = Validity::try_from(
+    let val4 = Validity::from_der(
         &hex!("3020180F32303032303130313132303130305A170D3330313233313038333030305A")[..],
     )
     .unwrap();
@@ -94,11 +94,11 @@
     // 104  13:       UTCTime 01/01/2010 08:30:00 GMT
     // 119  13:       UTCTime 31/12/2030 08:30:00 GMT
     //        :       }
-    let val1 = Validity::try_from(
+    let val1 = Validity::from_der(
         &hex!("301E170D3130303130313038333030305A170D3330313233313038333030305A")[..],
     )
     .unwrap();
-    let b1 = val1.to_vec().unwrap();
+    let b1 = val1.to_der().unwrap();
     assert_eq!(
         b1,
         &hex!("301E170D3130303130313038333030305A170D3330313233313038333030305A")[..]
@@ -109,11 +109,11 @@
     //  99  13:       UTCTime 01/01/2010 08:30:00 GMT
     // 114  15:       GeneralizedTime 01/01/2050 12:01:00 GMT
     //        :       }
-    let val3 = Validity::try_from(
+    let val3 = Validity::from_der(
         &hex!("3020170D3130303130313038333030305A180F32303530303130313132303130305A")[..],
     )
     .unwrap();
-    let b3 = val3.to_vec().unwrap();
+    let b3 = val3.to_der().unwrap();
     assert_eq!(
         b3,
         &hex!("3020170D3130303130313038333030305A180F32303530303130313132303130305A")[..]
@@ -124,11 +124,11 @@
     //  99  15:       GeneralizedTime 01/01/2002 12:01:00 GMT
     // 116  13:       UTCTime 31/12/2030 08:30:00 GMT
     //        :       }
-    let val4 = Validity::try_from(
+    let val4 = Validity::from_der(
         &hex!("3020180F32303032303130313132303130305A170D3330313233313038333030305A")[..],
     )
     .unwrap();
-    let b4 = val4.to_vec().unwrap();
+    let b4 = val4.to_der().unwrap();
     assert_eq!(
         b4,
         &hex!("3020180F32303032303130313132303130305A170D3330313233313038333030305A")[..]