Support parsing attestations in tests

Test: libkeystore_attestation_test
Change-Id: I7c2191e076923323d5e0d857bc7274cc56c6d967
diff --git a/keystore2/test_utils/attestation/Android.bp b/keystore2/test_utils/attestation/Android.bp
new file mode 100644
index 0000000..dbf02d0
--- /dev/null
+++ b/keystore2/test_utils/attestation/Android.bp
@@ -0,0 +1,54 @@
+// Copyright 2024, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_security_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_security_license"],
+}
+
+rust_defaults {
+    name: "libkeystore_attestation_defaults",
+    crate_name: "keystore_attestation",
+    srcs: ["lib.rs"],
+    defaults: [
+        "keymint_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+        "libder",
+        "liblog_rust",
+        "libspki",
+        "libx509_cert",
+    ],
+}
+
+rust_library {
+    name: "libkeystore_attestation",
+    defaults: ["libkeystore_attestation_defaults"],
+}
+
+rust_test {
+    name: "libkeystore_attestation_test",
+    defaults: ["libkeystore_attestation_defaults"],
+    rustlibs: [
+        "libhex",
+    ],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    compile_multilib: "first",
+}
diff --git a/keystore2/test_utils/attestation/lib.rs b/keystore2/test_utils/attestation/lib.rs
new file mode 100644
index 0000000..8ae4fc0
--- /dev/null
+++ b/keystore2/test_utils/attestation/lib.rs
@@ -0,0 +1,693 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Attestation parsing.
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
+    HardwareAuthenticatorType::HardwareAuthenticatorType, KeyOrigin::KeyOrigin,
+    KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue as KPV,
+    KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, Tag::Tag, TagType::TagType,
+};
+use der::asn1::{Null, ObjectIdentifier, OctetStringRef, SetOfVec};
+use der::{oid::AssociatedOid, DerOrd, Enumerated, Reader, Sequence, SliceReader};
+use der::{Decode, EncodeValue, Length};
+use std::borrow::Cow;
+
+/// Determine the tag type for a tag, based on the top 4 bits of the tag number.
+fn tag_type(tag: Tag) -> TagType {
+    let raw_type = (tag.0 as u32) & 0xf0000000;
+    TagType(raw_type as i32)
+}
+
+/// Determine the raw tag value with tag type information stripped out.
+fn raw_tag_value(tag: Tag) -> u32 {
+    (tag.0 as u32) & 0x0fffffffu32
+}
+
+/// OID value for the Android Attestation extension.
+pub const ATTESTATION_EXTENSION_OID: ObjectIdentifier =
+    ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11129.2.1.17");
+
+/// Attestation extension contents
+#[derive(Debug, Clone, Sequence, PartialEq)]
+pub struct AttestationExtension<'a> {
+    /// Attestation version.
+    pub attestation_version: i32,
+    /// Security level that created the attestation.
+    pub attestation_security_level: SecurityLevel,
+    /// Keymint version.
+    pub keymint_version: i32,
+    /// Security level of the KeyMint instance holding the key.
+    pub keymint_security_level: SecurityLevel,
+    /// Attestation challenge.
+    #[asn1(type = "OCTET STRING")]
+    pub attestation_challenge: &'a [u8],
+    /// Unique ID.
+    #[asn1(type = "OCTET STRING")]
+    pub unique_id: &'a [u8],
+    /// Software-enforced key characteristics.
+    pub sw_enforced: AuthorizationList<'a>,
+    /// Hardware-enforced key characteristics.
+    pub hw_enforced: AuthorizationList<'a>,
+}
+
+impl<'a> AssociatedOid for AttestationExtension<'a> {
+    const OID: ObjectIdentifier = ATTESTATION_EXTENSION_OID;
+}
+
+/// Security level enumeration
+#[repr(u32)]
+#[derive(Debug, Clone, Copy, Enumerated, PartialEq)]
+pub enum SecurityLevel {
+    /// Software.
+    Software = 0,
+    /// TEE.
+    TrustedEnvironment = 1,
+    /// StrongBox.
+    Strongbox = 2,
+}
+
+/// Root of Trust ASN.1 structure
+#[derive(Debug, Clone, Sequence)]
+pub struct RootOfTrust<'a> {
+    /// Verified boot key hash.
+    #[asn1(type = "OCTET STRING")]
+    pub verified_boot_key: &'a [u8],
+    /// Device bootloader lock state.
+    pub device_locked: bool,
+    /// Verified boot state.
+    pub verified_boot_state: VerifiedBootState,
+    /// Verified boot hash
+    #[asn1(type = "OCTET STRING")]
+    pub verified_boot_hash: &'a [u8],
+}
+
+/// Attestation Application ID ASN.1 structure
+#[derive(Debug, Clone, Sequence)]
+pub struct AttestationApplicationId<'a> {
+    /// Package info.
+    pub package_info_records: SetOfVec<PackageInfoRecord<'a>>,
+    /// Signatures.
+    pub signature_digests: SetOfVec<OctetStringRef<'a>>,
+}
+
+/// Package record
+#[derive(Debug, Clone, Sequence)]
+pub struct PackageInfoRecord<'a> {
+    /// Package name
+    pub package_name: OctetStringRef<'a>,
+    /// Package version
+    pub version: i64,
+}
+
+impl<'a> DerOrd for PackageInfoRecord<'a> {
+    fn der_cmp(&self, other: &Self) -> Result<std::cmp::Ordering, der::Error> {
+        self.package_name.der_cmp(&other.package_name)
+    }
+}
+
+/// Verified Boot State as ASN.1 ENUMERATED type.
+#[repr(u32)]
+#[derive(Debug, Clone, Copy, Enumerated)]
+pub enum VerifiedBootState {
+    /// Verified.
+    Verified = 0,
+    /// Self-signed.
+    SelfSigned = 1,
+    /// Unverified.
+    Unverified = 2,
+    /// Failed.
+    Failed = 3,
+}
+
+/// Struct corresponding to an ASN.1 DER-serialized `AuthorizationList`.
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
+pub struct AuthorizationList<'a> {
+    /// Key authorizations.
+    pub auths: Cow<'a, [KeyParameter]>,
+}
+
+impl<'a> From<Vec<KeyParameter>> for AuthorizationList<'a> {
+    /// Build an `AuthorizationList` using a set of key parameters.
+    fn from(auths: Vec<KeyParameter>) -> Self {
+        AuthorizationList { auths: auths.into() }
+    }
+}
+
+impl<'a> Sequence<'a> for AuthorizationList<'a> {}
+
+/// Stub (non-)implementation of DER-encoding, needed to implement [`Sequence`].
+impl<'a> EncodeValue for AuthorizationList<'a> {
+    fn value_len(&self) -> der::Result<Length> {
+        unimplemented!("Only decoding is implemented");
+    }
+    fn encode_value(&self, _writer: &mut impl der::Writer) -> der::Result<()> {
+        unimplemented!("Only decoding is implemented");
+    }
+}
+
+/// Implementation of [`der::DecodeValue`] which constructs an [`AuthorizationList`] from bytes.
+impl<'a> der::DecodeValue<'a> for AuthorizationList<'a> {
+    fn decode_value<R: der::Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
+        // Decode tags in the expected order.
+        let contents = decoder.read_slice(header.length)?;
+        let mut reader = SliceReader::new(contents)?;
+        let decoder = &mut reader;
+        let mut auths = Vec::new();
+        let mut next: Option<u32> = None;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::PURPOSE)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ALGORITHM)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::KEY_SIZE)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::BLOCK_MODE)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::DIGEST)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::PADDING)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::CALLER_NONCE)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::MIN_MAC_LENGTH)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::EC_CURVE)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::RSA_PUBLIC_EXPONENT)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::RSA_OAEP_MGF_DIGEST)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ROLLBACK_RESISTANCE)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::EARLY_BOOT_ONLY)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ACTIVE_DATETIME)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ORIGINATION_EXPIRE_DATETIME)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::USAGE_EXPIRE_DATETIME)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::USAGE_COUNT_LIMIT)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::USER_SECURE_ID)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::NO_AUTH_REQUIRED)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::USER_AUTH_TYPE)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::AUTH_TIMEOUT)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ALLOW_WHILE_ON_BODY)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::TRUSTED_USER_PRESENCE_REQUIRED)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::TRUSTED_CONFIRMATION_REQUIRED)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::UNLOCKED_DEVICE_REQUIRED)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::CREATION_DATETIME)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::CREATION_DATETIME)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ORIGIN)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ROOT_OF_TRUST)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::OS_VERSION)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::OS_PATCHLEVEL)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_APPLICATION_ID)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_BRAND)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_DEVICE)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_PRODUCT)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_SERIAL)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_SERIAL)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_SERIAL)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_IMEI)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_MEID)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_MANUFACTURER)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_MODEL)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::VENDOR_PATCHLEVEL)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::BOOT_PATCHLEVEL)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::DEVICE_UNIQUE_ATTESTATION)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::ATTESTATION_ID_SECOND_IMEI)?;
+        next = decode_opt_field(decoder, next, &mut auths, Tag::MODULE_HASH)?;
+
+        if next.is_some() {
+            // Extra tag encountered.
+            return Err(decoder.error(der::ErrorKind::Incomplete {
+                expected_len: Length::ZERO,
+                actual_len: decoder.remaining_len(),
+            }));
+        }
+
+        Ok(auths.into())
+    }
+}
+
+/// Attempt to decode an optional field associated with `expected_tag` from the `decoder`.
+///
+/// If `already_read_asn1_tag` is provided, then that ASN.1 tag has already been read from the
+/// `decoder` and its associated data is next.
+///
+/// (Because the field is optional, we might not read the tag we expect, but instead a later tag
+/// from the list.  If this happens, the actual decoded ASN.1 tag value is returned to the caller to
+/// be passed in on the next call to this function.)
+///
+/// If the decoded or re-used ASN.1 tag is the expected one, continue on to read the associated
+/// value and populate it in `auths`.
+fn decode_opt_field<'a, R: der::Reader<'a>>(
+    decoder: &mut R,
+    already_read_asn1_tag: Option<u32>,
+    auths: &mut Vec<KeyParameter>,
+    expected_tag: Tag,
+) -> Result<Option<u32>, der::Error> {
+    // Decode the ASN.1 tag if no tag is provided
+    let asn1_tag = match already_read_asn1_tag {
+        Some(tag) => Some(tag),
+        None => decode_explicit_tag_from_bytes(decoder)?,
+    };
+    let expected_asn1_tag = raw_tag_value(expected_tag);
+    match asn1_tag {
+        Some(v) if v == expected_asn1_tag => {
+            // Decode the length of the inner encoding
+            let inner_len = Length::decode(decoder)?;
+            if decoder.remaining_len() < inner_len {
+                return Err(der::ErrorKind::Incomplete {
+                    expected_len: inner_len,
+                    actual_len: decoder.remaining_len(),
+                }
+                .into());
+            }
+            let next_tlv = decoder.tlv_bytes()?;
+            decode_value_from_bytes(expected_tag, next_tlv, auths)?;
+            Ok(None)
+        }
+        Some(tag) => Ok(Some(tag)), // Return the tag for which the value is unread.
+        None => Ok(None),
+    }
+}
+
+/// Decode one or more `KeyParameterValue`s of the type associated with `tag` from the `decoder`,
+/// and add them to `auths`.
+fn decode_value_from_bytes(
+    tag: Tag,
+    data: &[u8],
+    auths: &mut Vec<KeyParameter>,
+) -> Result<(), der::Error> {
+    match tag_type(tag) {
+        TagType::ENUM_REP => {
+            let values = SetOfVec::<i32>::from_der(data)?;
+            for value in values.as_slice() {
+                auths.push(KeyParameter {
+                    tag,
+                    value: match tag {
+                        Tag::BLOCK_MODE => KPV::BlockMode(BlockMode(*value)),
+                        Tag::PADDING => KPV::PaddingMode(PaddingMode(*value)),
+                        Tag::DIGEST => KPV::Digest(Digest(*value)),
+                        Tag::RSA_OAEP_MGF_DIGEST => KPV::Digest(Digest(*value)),
+                        Tag::PURPOSE => KPV::KeyPurpose(KeyPurpose(*value)),
+                        _ => return Err(der::ErrorKind::TagNumberInvalid.into()),
+                    },
+                });
+            }
+        }
+        TagType::UINT_REP => {
+            let values = SetOfVec::<i32>::from_der(data)?;
+            for value in values.as_slice() {
+                auths.push(KeyParameter { tag, value: KPV::Integer(*value) });
+            }
+        }
+        TagType::ENUM => {
+            let value = i32::from_der(data)?;
+            auths.push(KeyParameter {
+                tag,
+                value: match tag {
+                    Tag::ALGORITHM => KPV::Algorithm(Algorithm(value)),
+                    Tag::EC_CURVE => KPV::EcCurve(EcCurve(value)),
+                    Tag::ORIGIN => KPV::Origin(KeyOrigin(value)),
+                    Tag::USER_AUTH_TYPE => {
+                        KPV::HardwareAuthenticatorType(HardwareAuthenticatorType(value))
+                    }
+                    _ => return Err(der::ErrorKind::TagNumberInvalid.into()),
+                },
+            });
+        }
+        TagType::UINT => {
+            let value = i32::from_der(data)?;
+            auths.push(KeyParameter { tag, value: KPV::Integer(value) });
+        }
+        TagType::ULONG => {
+            let value = i64::from_der(data)?;
+            auths.push(KeyParameter { tag, value: KPV::LongInteger(value) });
+        }
+        TagType::DATE => {
+            let value = i64::from_der(data)?;
+            auths.push(KeyParameter { tag, value: KPV::DateTime(value) });
+        }
+        TagType::BOOL => {
+            let _value = Null::from_der(data)?;
+            auths.push(KeyParameter { tag, value: KPV::BoolValue(true) });
+        }
+        TagType::BYTES if tag == Tag::ROOT_OF_TRUST => {
+            // Special case: root of trust is an ASN.1 `SEQUENCE` not an `OCTET STRING` so don't
+            // decode the bytes.
+            auths.push(KeyParameter { tag: Tag::ROOT_OF_TRUST, value: KPV::Blob(data.to_vec()) });
+        }
+        TagType::BYTES | TagType::BIGNUM => {
+            let value = OctetStringRef::from_der(data)?.as_bytes().to_vec();
+            auths.push(KeyParameter { tag, value: KPV::Blob(value) });
+        }
+        _ => {
+            return Err(der::ErrorKind::TagNumberInvalid.into());
+        }
+    }
+    Ok(())
+}
+
+/// Decode an explicit ASN.1 tag value, coping with large (>=31) tag values
+/// (which the `der` crate doesn't deal with).  Returns `Ok(None)` if the
+/// decoder is empty.
+fn decode_explicit_tag_from_bytes<'a, R: der::Reader<'a>>(
+    decoder: &mut R,
+) -> Result<Option<u32>, der::Error> {
+    if decoder.remaining_len() == Length::ZERO {
+        return Ok(None);
+    }
+    let b1 = decoder.read_byte()?;
+    let tag = if b1 & 0b00011111 == 0b00011111u8 {
+        // The initial byte of 0xbf indicates a larger (>=31) value for the ASN.1 tag:
+        // - 0bXY...... = class
+        // - 0b..C..... = constructed/primitive bit
+        // - 0b...11111 = marker indicating high tag form, tag value to follow
+        //
+        // The top three bits should be 0b101 = constructed context-specific
+        if b1 & 0b11100000 != 0b10100000 {
+            return Err(der::ErrorKind::TagNumberInvalid.into());
+        }
+
+        // The subsequent encoded tag value is broken down into 7-bit chunks (in big-endian order),
+        // and each chunk gets a high bit of 1 except the last, which gets a high bit of zero.
+        let mut bit_count = 0;
+        let mut tag: u32 = 0;
+        loop {
+            let b = decoder.read_byte()?;
+            let low_b = b & 0b01111111;
+            if bit_count == 0 && low_b == 0 {
+                // The first part of the tag number is zero, implying it is not miminally encoded.
+                return Err(der::ErrorKind::TagNumberInvalid.into());
+            }
+
+            bit_count += 7;
+            if bit_count > 32 {
+                // Tag value has more bits than the output type can hold.
+                return Err(der::ErrorKind::TagNumberInvalid.into());
+            }
+            tag = (tag << 7) | (low_b as u32);
+            if b & 0x80u8 == 0x00u8 {
+                // Top bit clear => this is the final part of the value.
+                if tag < 31 {
+                    // Tag is small enough that it should have been in short form.
+                    return Err(der::ErrorKind::TagNumberInvalid.into());
+                }
+                break tag;
+            }
+        }
+    } else {
+        // Get the tag value from the low 5 bits.
+        (b1 & 0b00011111u8) as u32
+    };
+    Ok(Some(tag))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use der::Encode;
+
+    const SIG: &[u8; 32] = &[
+        0xa4, 0x0d, 0xa8, 0x0a, 0x59, 0xd1, 0x70, 0xca, 0xa9, 0x50, 0xcf, 0x15, 0xc1, 0x8c, 0x45,
+        0x4d, 0x47, 0xa3, 0x9b, 0x26, 0x98, 0x9d, 0x8b, 0x64, 0x0e, 0xcd, 0x74, 0x5b, 0xa7, 0x1b,
+        0xf5, 0xdc,
+    ];
+    const VB_KEY: &[u8; 32] = &[0; 32];
+    const VB_HASH: &[u8; 32] = &[
+        0x6f, 0x84, 0xe6, 0x02, 0x73, 0x9d, 0x86, 0x2c, 0x93, 0x2a, 0x28, 0xf0, 0xa5, 0x27, 0x65,
+        0xa4, 0xae, 0xc2, 0x27, 0x8c, 0xb6, 0x3b, 0xe9, 0xbb, 0x63, 0xc7, 0xa8, 0xc7, 0x03, 0xad,
+        0x8e, 0xc1,
+    ];
+
+    /// Build a sample `AuthorizationList` suitable for use as `sw_enforced`.
+    fn sw_enforced() -> AuthorizationList<'static> {
+        let sig = OctetStringRef::new(SIG).unwrap();
+        let package = PackageInfoRecord {
+            package_name: OctetStringRef::new(b"android.keystore.cts").unwrap(),
+            version: 34,
+        };
+        let mut package_info_records = SetOfVec::new();
+        package_info_records.insert(package).unwrap();
+        let mut signature_digests = SetOfVec::new();
+        signature_digests.insert(sig).unwrap();
+        let aaid = AttestationApplicationId { package_info_records, signature_digests };
+        AuthorizationList {
+            auths: vec![
+                KeyParameter { tag: Tag::CREATION_DATETIME, value: KPV::DateTime(0x01903116c71f) },
+                KeyParameter {
+                    tag: Tag::ATTESTATION_APPLICATION_ID,
+                    value: KPV::Blob(aaid.to_der().unwrap()),
+                },
+            ]
+            .into(),
+        }
+    }
+
+    /// Build a sample `AuthorizationList` suitable for use as `hw_enforced`.
+    fn hw_enforced() -> AuthorizationList<'static> {
+        let rot = RootOfTrust {
+            verified_boot_key: VB_KEY,
+            device_locked: false,
+            verified_boot_state: VerifiedBootState::Unverified,
+            verified_boot_hash: VB_HASH,
+        };
+        AuthorizationList {
+            auths: vec![
+                KeyParameter { tag: Tag::PURPOSE, value: KPV::KeyPurpose(KeyPurpose::AGREE_KEY) },
+                KeyParameter { tag: Tag::ALGORITHM, value: KPV::Algorithm(Algorithm::EC) },
+                KeyParameter { tag: Tag::KEY_SIZE, value: KPV::Integer(256) },
+                KeyParameter { tag: Tag::DIGEST, value: KPV::Digest(Digest::NONE) },
+                KeyParameter { tag: Tag::EC_CURVE, value: KPV::EcCurve(EcCurve::CURVE_25519) },
+                KeyParameter { tag: Tag::NO_AUTH_REQUIRED, value: KPV::BoolValue(true) },
+                KeyParameter { tag: Tag::ORIGIN, value: KPV::Origin(KeyOrigin::GENERATED) },
+                KeyParameter { tag: Tag::ROOT_OF_TRUST, value: KPV::Blob(rot.to_der().unwrap()) },
+                KeyParameter { tag: Tag::OS_VERSION, value: KPV::Integer(140000) },
+                KeyParameter { tag: Tag::OS_PATCHLEVEL, value: KPV::Integer(202404) },
+                KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KPV::Integer(20240405) },
+                KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KPV::Integer(20240405) },
+            ]
+            .into(),
+        }
+    }
+
+    #[test]
+    fn test_decode_auth_list_1() {
+        let want = sw_enforced();
+        let data = hex::decode(concat!(
+            "3055",     //  SEQUENCE
+            "bf853d08", //  [701]
+            "0206",     //  INTEGER
+            "01903116c71f",
+            "bf854545",                                 //  [709]
+            "0443",                                     //  OCTET STRING
+            "3041",                                     //  SEQUENCE
+            "311b",                                     //  SET
+            "3019",                                     //  SEQUENCE
+            "0414",                                     //  OCTET STRING
+            "616e64726f69642e6b657973746f72652e637473", //  "android.keystore.cts"
+            "020122",                                   //  INTEGER
+            "3122",                                     //  SET
+            "0420",                                     //  OCTET STRING
+            "a40da80a59d170caa950cf15c18c454d",
+            "47a39b26989d8b640ecd745ba71bf5dc",
+        ))
+        .unwrap();
+        let got = AuthorizationList::from_der(&data).unwrap();
+        assert_eq!(got, want);
+    }
+
+    #[test]
+    fn test_decode_auth_list_2() {
+        let want = hw_enforced();
+        let data = hex::decode(concat!(
+            "3081a1",   //  SEQUENCE
+            "a105",     //  [1]
+            "3103",     //  SET
+            "020106",   //  INTEGER
+            "a203",     //  [2]
+            "020103",   //  INTEGER 3
+            "a304",     //  [4]
+            "02020100", //  INTEGER 256
+            "a505",     //  [5]
+            "3103",     //  SET
+            "020100",   //  INTEGER 0
+            "aa03",     //  [10]
+            "020104",   //  INTEGER 4
+            "bf837702", //  [503]
+            "0500",     //  NULL
+            "bf853e03", //  [702]
+            "020100",   //  INTEGER 0
+            "bf85404c", //  [704]
+            "304a",     //  SEQUENCE
+            "0420",     //  OCTET STRING
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "010100", //  BOOLEAN
+            "0a0102", //  ENUMERATED
+            "0420",   //  OCTET STRING
+            "6f84e602739d862c932a28f0a52765a4",
+            "aec2278cb63be9bb63c7a8c703ad8ec1",
+            "bf854105",     //  [705]
+            "02030222e0",   //  INTEGER
+            "bf854205",     //  [706]
+            "02030316a4",   //  INTEGER
+            "bf854e06",     //  [718]
+            "02040134d815", //  INTEGER
+            "bf854f06",     //  [709]
+            "02040134d815", //  INTEGER
+        ))
+        .unwrap();
+        let got = AuthorizationList::from_der(&data).unwrap();
+        assert_eq!(got, want);
+    }
+
+    #[test]
+    fn test_decode_extension() {
+        let zeroes = [0; 128];
+        let want = AttestationExtension {
+            attestation_version: 300,
+            attestation_security_level: SecurityLevel::TrustedEnvironment,
+            keymint_version: 300,
+            keymint_security_level: SecurityLevel::TrustedEnvironment,
+            attestation_challenge: &zeroes,
+            unique_id: &[],
+            sw_enforced: sw_enforced(),
+            hw_enforced: hw_enforced(),
+        };
+
+        let data = hex::decode(concat!(
+            // Full extension would include the following prefix:
+            // "308201a2",             //  SEQUENCE
+            // "060a",                 //  OBJECT IDENTIFIER
+            // "2b06010401d679020111", //  Android attestation extension (1.3.6.1.4.1.11129.2.1.17)
+            // "04820192",             //  OCTET STRING
+            "3082018e", //  SEQUENCE
+            "0202012c", //  INTEGER 300
+            "0a0101",   //  ENUMERATED 1
+            "0202012c", //  INTEGER 300
+            "0a0101",   //  ENUMERATED 1
+            "048180",   //  OCTET STRING
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "0400", //  OCTET STRING
+            // softwareEnforced
+            "3055",     //  SEQUENCE
+            "bf853d08", //  [701]
+            "0206",     //  INTEGER
+            "01903116c71f",
+            "bf854545",                                 //  [709]
+            "0443",                                     //  OCTET STRING
+            "3041",                                     //  SEQUENCE
+            "311b",                                     //  SET
+            "3019",                                     //  SEQUENCE
+            "0414",                                     //  OCTET STRING
+            "616e64726f69642e6b657973746f72652e637473", //  "android.keystore.cts"
+            "020122",                                   //  INTEGER
+            "3122",                                     //  SET
+            "0420",                                     //  OCTET STRING
+            "a40da80a59d170caa950cf15c18c454d",
+            "47a39b26989d8b640ecd745ba71bf5dc",
+            // softwareEnforced
+            "3081a1",   //  SEQUENCE
+            "a105",     //  [1]
+            "3103",     //  SET
+            "020106",   //  INTEGER
+            "a203",     //  [2]
+            "020103",   //  INTEGER 3
+            "a304",     //  [4]
+            "02020100", //  INTEGER 256
+            "a505",     //  [5]
+            "3103",     //  SET
+            "020100",   //  INTEGER 0
+            "aa03",     //  [10]
+            "020104",   //  INTEGER 4
+            "bf837702", //  [503]
+            "0500",     //  NULL
+            "bf853e03", //  [702]
+            "020100",   //  INTEGER 0
+            "bf85404c", //  [704]
+            "304a",     //  SEQUENCE
+            "0420",     //  OCTET STRING
+            "00000000000000000000000000000000",
+            "00000000000000000000000000000000",
+            "010100", //  BOOLEAN
+            "0a0102", //  ENUMERATED
+            "0420",   //  OCTET STRING
+            "6f84e602739d862c932a28f0a52765a4",
+            "aec2278cb63be9bb63c7a8c703ad8ec1",
+            "bf854105",     //  [705]
+            "02030222e0",   //  INTEGER
+            "bf854205",     //  [706]
+            "02030316a4",   //  INTEGER
+            "bf854e06",     //  [718]
+            "02040134d815", //  INTEGER
+            "bf854f06",     //  [719]
+            "02040134d815", //  INTEGER
+        ))
+        .unwrap();
+        let got = AttestationExtension::from_der(&data).unwrap();
+        assert_eq!(got, want);
+    }
+
+    #[test]
+    fn test_decode_empty_auth_list() {
+        let want = AuthorizationList::default();
+        let data = hex::decode(
+            "3000", //  SEQUENCE
+        )
+        .unwrap();
+        let got = AuthorizationList::from_der(&data).unwrap();
+        assert_eq!(got, want);
+    }
+
+    #[test]
+    fn test_decode_explicit_tag() {
+        let err = Err(der::ErrorKind::TagNumberInvalid.into());
+        let tests = [
+            (vec![], Ok(None)),
+            (vec![0b10100000], Ok(Some(0))),
+            (vec![0b10100001], Ok(Some(1))),
+            (vec![0b10100010], Ok(Some(2))),
+            (vec![0b10111110], Ok(Some(30))),
+            (vec![0b10111111, 0b00011111], Ok(Some(31))),
+            (vec![0b10111111, 0b00100000], Ok(Some(32))),
+            (vec![0b10111111, 0b01111111], Ok(Some(127))),
+            (vec![0b10111111, 0b10000001, 0b00000000], Ok(Some(128))),
+            (vec![0b10111111, 0b10000010, 0b00000000], Ok(Some(256))),
+            (vec![0b10111111, 0b10000001, 0b10000000, 0b00000001], Ok(Some(16385))),
+            (vec![0b10111111, 0b10010000, 0b10000000, 0b10000000, 0b00000000], Ok(Some(33554432))),
+            // Top bits ignored for low tag numbers
+            (vec![0b00000000], Ok(Some(0))),
+            (vec![0b00000001], Ok(Some(1))),
+            // High tag numbers should start with 0b101
+            (vec![0b10011111, 0b00100000], err),
+            (vec![0b11111111, 0b00100000], err),
+            (vec![0b00111111, 0b00100000], err),
+            // High tag numbers should be minimally encoded
+            (vec![0b10111111, 0b10000000, 0b10000001, 0b00000000], err),
+            (vec![0b10111111, 0b00011110], err),
+            // Bigger than u32
+            (
+                vec![
+                    0b10111111, 0b10000001, 0b10000000, 0b10000000, 0b10000000, 0b10000000,
+                    0b00000000,
+                ],
+                err,
+            ),
+            // Incomplete tag
+            (vec![0b10111111, 0b10000001], Err(der::Error::incomplete(der::Length::new(2)))),
+        ];
+
+        for (input, want) in tests {
+            let mut reader = SliceReader::new(&input).unwrap();
+            let got = decode_explicit_tag_from_bytes(&mut reader);
+            assert_eq!(got, want, "for input {}", hex::encode(input));
+        }
+    }
+}