use core::fmt::{self, Write};
use num::FromPrimitive;
use num_derive::FromPrimitive;
use crate::crypto::{Crypto, PublicKey};
use crate::dm::clusters::time_sync::UtcTime;
use crate::error::{Error, ErrorCode};
use crate::tlv::{FromTLV, Octets, TLVArray, TLVElement, TLVList, ToTLV};
use crate::utils::epoch::MATTER_CERT_DOESNT_EXPIRE;
use crate::utils::iter::TryFindIterator;
use self::printer::CertPrinter;
pub use self::asn1_writer::ASN1Writer;
mod asn1_writer;
pub mod der_utils;
pub mod gen;
mod printer;
pub mod x509;
pub const MAX_CERT_TLV_LEN: usize = 400;
pub const MAX_CERT_ASN1_LEN: usize = 600;
pub const MAX_CERT_TLV_AND_ASN1_LEN: usize = MAX_CERT_TLV_LEN + MAX_CERT_ASN1_LEN;
const OID_PUB_KEY_ECPUBKEY: [u8; 7] = [0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01];
const OID_EC_TYPE_PRIME256V1: [u8; 8] = [0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07];
const OID_ECDSA_WITH_SHA256: [u8; 8] = [0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02];
const MAX_DEPTH: usize = 10;
#[derive(FromPrimitive)]
pub enum CertTag {
SerialNum = 1,
SignAlgo = 2,
Issuer = 3,
NotBefore = 4,
NotAfter = 5,
Subject = 6,
PubKeyAlgo = 7,
EcCurveId = 8,
EcPubKey = 9,
Extensions = 10,
Signature = 11,
}
#[derive(FromPrimitive, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EcCurveIdValue {
Prime256V1 = 1,
}
pub fn get_ec_curve_id(algo: u8) -> Option<EcCurveIdValue> {
num::FromPrimitive::from_u8(algo)
}
#[derive(FromPrimitive, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PubKeyAlgoValue {
EcPubKey = 1,
}
pub fn get_pubkey_algo(algo: u8) -> Option<PubKeyAlgoValue> {
num::FromPrimitive::from_u8(algo)
}
#[derive(FromPrimitive, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SignAlgoValue {
ECDSAWithSHA256 = 1,
}
pub fn get_sign_algo(algo: u8) -> Option<SignAlgoValue> {
num::FromPrimitive::from_u8(algo)
}
#[derive(Default, Debug, Clone, FromTLV, ToTLV, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[tlvargs(start = 1)]
struct BasicConstraints {
is_ca: bool,
path: Option<u8>,
}
impl BasicConstraints {
pub fn encode(&self, w: &mut dyn CertConsumer) -> Result<(), Error> {
w.start_seq("")?;
if self.is_ca {
w.bool("CA:", true)?;
}
if let Some(len) = self.path {
w.integer("Path Len Constraint", &[len])?;
}
w.end_seq()
}
}
#[derive(Debug, Clone, FromTLV, ToTLV, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[tlvargs(start = 1, lifetime = "'a", datatype = "naked")]
enum Extension<'a> {
BasicConstraints(BasicConstraints),
KeyUsage(u16),
ExtKeyUsage(TLVArray<'a, u8>),
SubjectKeyId(Octets<'a>),
AuthorityKeyId(Octets<'a>),
FutureExtensions(Octets<'a>),
}
impl<'a> Extension<'a> {
fn encode_all(
iter: impl Iterator<Item = Result<Self, Error>> + 'a,
w: &mut dyn CertConsumer,
) -> Result<(), Error> {
w.start_ctx("X509v3 extensions:", 3)?;
w.start_seq("")?;
for extension in iter {
extension?.encode(w)?;
}
w.end_seq()?;
w.end_ctx()?;
Ok(())
}
fn encode(&self, w: &mut dyn CertConsumer) -> Result<(), Error> {
const OID_BASIC_CONSTRAINTS: [u8; 3] = [0x55, 0x1D, 0x13];
const OID_KEY_USAGE: [u8; 3] = [0x55, 0x1D, 0x0F];
const OID_EXT_KEY_USAGE: [u8; 3] = [0x55, 0x1D, 0x25];
const OID_SUBJ_KEY_IDENTIFIER: [u8; 3] = [0x55, 0x1D, 0x0E];
const OID_AUTH_KEY_ID: [u8; 3] = [0x55, 0x1D, 0x23];
match self {
Extension::BasicConstraints(t) => {
Self::encode_extension_start(
"X509v3 Basic Constraints",
true,
&OID_BASIC_CONSTRAINTS,
w,
)?;
t.encode(w)?;
Self::encode_extension_end(w)?;
}
Extension::KeyUsage(t) => {
Self::encode_extension_start("X509v3 Key Usage", true, &OID_KEY_USAGE, w)?;
Self::encode_key_usage(*t, w)?;
Self::encode_extension_end(w)?;
}
Extension::ExtKeyUsage(t) => {
Self::encode_extension_start(
"X509v3 Extended Key Usage",
true,
&OID_EXT_KEY_USAGE,
w,
)?;
Self::encode_extended_key_usage(t.iter(), w)?;
Self::encode_extension_end(w)?;
}
Extension::SubjectKeyId(t) => {
Self::encode_extension_start("Subject Key ID", false, &OID_SUBJ_KEY_IDENTIFIER, w)?;
w.ostr("", t.0)?;
Self::encode_extension_end(w)?;
}
Extension::AuthorityKeyId(t) => {
Self::encode_extension_start("Auth Key ID", false, &OID_AUTH_KEY_ID, w)?;
w.start_seq("")?;
w.ctx("", 0, t.0)?;
w.end_seq()?;
Self::encode_extension_end(w)?;
}
Extension::FutureExtensions(t) => {
w.raw("Future Extensions", t.0)?;
}
}
Ok(())
}
fn encode_extension_start(
tag: &str,
critical: bool,
oid: &[u8],
w: &mut dyn CertConsumer,
) -> Result<(), Error> {
w.start_seq(tag)?;
w.oid("", oid)?;
if critical {
w.bool("critical:", true)?;
}
w.start_compound_ostr("value:")
}
fn encode_extension_end(w: &mut dyn CertConsumer) -> Result<(), Error> {
w.end_compound_ostr()?;
w.end_seq()
}
#[allow(unused_assignments)]
fn encode_key_usage(key_usage: u16, w: &mut dyn CertConsumer) -> Result<(), Error> {
let mut key_usage_str = [0u8; 2];
Self::int_to_bitstring(key_usage, &mut key_usage_str);
w.bitstr(&Self::get_print_str(key_usage), true, &key_usage_str)?;
Ok(())
}
fn encode_extended_key_usage(
list: impl Iterator<Item = Result<u8, Error>>,
w: &mut dyn CertConsumer,
) -> Result<(), Error> {
const OID_SERVER_AUTH: [u8; 8] = [0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01];
const OID_CLIENT_AUTH: [u8; 8] = [0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02];
const OID_CODE_SIGN: [u8; 8] = [0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03];
const OID_EMAIL_PROT: [u8; 8] = [0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04];
const OID_TIMESTAMP: [u8; 8] = [0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x08];
const OID_OCSP_SIGN: [u8; 8] = [0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x09];
let encoding = [
("", &[0; 8]),
("ServerAuth", &OID_SERVER_AUTH),
("ClientAuth", &OID_CLIENT_AUTH),
("CodeSign", &OID_CODE_SIGN),
("EmailProtection", &OID_EMAIL_PROT),
("Timestamp", &OID_TIMESTAMP),
("OCSPSign", &OID_OCSP_SIGN),
];
w.start_seq("")?;
for t in list {
let t = t? as usize;
if t > 0 && t <= encoding.len() {
w.oid(encoding[t].0, encoding[t].1)?;
} else {
error!("Skipping encoding key usage out of bounds");
}
}
w.end_seq()
}
fn get_print_str(key_usage: u16) -> heapless::String<256> {
const KEY_USAGE_DIGITAL_SIGN: u16 = 0x0001;
const KEY_USAGE_NON_REPUDIATION: u16 = 0x0002;
const KEY_USAGE_KEY_ENCIPHERMENT: u16 = 0x0004;
const KEY_USAGE_DATA_ENCIPHERMENT: u16 = 0x0008;
const KEY_USAGE_KEY_AGREEMENT: u16 = 0x0010;
const KEY_USAGE_KEY_CERT_SIGN: u16 = 0x0020;
const KEY_USAGE_CRL_SIGN: u16 = 0x0040;
const KEY_USAGE_ENCIPHER_ONLY: u16 = 0x0080;
const KEY_USAGE_DECIPHER_ONLY: u16 = 0x0100;
macro_rules! add_if {
($key:ident, $bit:ident,$str:literal) => {
if ($key & $bit) != 0 {
$str
} else {
""
}
};
}
let mut string = heapless::String::new();
write_unwrap!(
&mut string,
"{}{}{}{}{}{}{}{}{}",
add_if!(key_usage, KEY_USAGE_DIGITAL_SIGN, "digitalSignature "),
add_if!(key_usage, KEY_USAGE_NON_REPUDIATION, "nonRepudiation "),
add_if!(key_usage, KEY_USAGE_KEY_ENCIPHERMENT, "keyEncipherment "),
add_if!(key_usage, KEY_USAGE_DATA_ENCIPHERMENT, "dataEncipherment "),
add_if!(key_usage, KEY_USAGE_KEY_AGREEMENT, "keyAgreement "),
add_if!(key_usage, KEY_USAGE_KEY_CERT_SIGN, "keyCertSign "),
add_if!(key_usage, KEY_USAGE_CRL_SIGN, "CRLSign "),
add_if!(key_usage, KEY_USAGE_ENCIPHER_ONLY, "encipherOnly "),
add_if!(key_usage, KEY_USAGE_DECIPHER_ONLY, "decipherOnly "),
);
string
}
fn int_to_bitstring(mut a: u16, buf: &mut [u8]) {
if buf.len() >= 2 {
buf[0] = Self::reverse_byte((a & 0xff) as u8);
a >>= 8;
buf[1] = Self::reverse_byte((a & 0xff) as u8);
}
}
fn reverse_byte(byte: u8) -> u8 {
const LOOKUP: [u8; 16] = [
0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b,
0x07, 0x0f,
];
(LOOKUP[(byte & 0x0f) as usize] << 4) | LOOKUP[(byte >> 4) as usize]
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
enum DNTag {
CommonName = 1,
Surname = 2,
SerialNum = 3,
CountryName = 4,
LocalityName = 5,
StateName = 6,
OrgName = 7,
OrgUnitName = 8,
Title = 9,
Name = 10,
GivenName = 11,
Intials = 12,
GenQalifier = 13,
DnQualifier = 14,
Pseudonym = 15,
DomainComponent = 16,
NodeId = 17,
FirmwareSignId = 18,
IcaId = 19,
RootCaId = 20,
FabricId = 21,
NocCat = 22,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum DNValue<'a> {
Uint(u64),
Utf8(&'a str),
PrintableStr(&'a str),
}
#[derive(FromTLV, ToTLV, Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[tlvargs(lifetime = "'a")]
struct DN<'a>(TLVElement<'a>);
impl<'a> DN<'a> {
pub fn tag(&self) -> Result<DNTag, Error> {
let ctx = self.0.try_ctx()?.ok_or(ErrorCode::Invalid)? & 0x7f;
Ok(DNTag::from_u8(ctx).ok_or(ErrorCode::Invalid)?)
}
pub fn is_printable(&self) -> Result<bool, Error> {
let ctx = self.0.try_ctx()?.ok_or(ErrorCode::Invalid)?;
Ok(ctx >= 0x80)
}
fn uint(&self) -> Result<u64, Error> {
self.0.u64()
}
fn value(&self) -> Result<DNValue<'a>, Error> {
if let Ok(value) = self.0.utf8() {
if self.is_printable()? {
Ok(DNValue::PrintableStr(value))
} else {
Ok(DNValue::Utf8(value))
}
} else {
self.0.u64().map(DNValue::Uint)
}
}
fn encode_all(
values: impl Iterator<Item = Result<Self, Error>> + 'a,
tag: &str,
w: &mut dyn CertConsumer,
) -> Result<(), Error> {
const OID_COMMON_NAME: [u8; 3] = [0x55_u8, 0x04, 0x03];
const OID_SURNAME: [u8; 3] = [0x55_u8, 0x04, 0x04];
const OID_SERIAL_NUMBER: [u8; 3] = [0x55_u8, 0x04, 0x05];
const OID_COUNTRY_NAME: [u8; 3] = [0x55_u8, 0x04, 0x06];
const OID_LOCALITY_NAME: [u8; 3] = [0x55_u8, 0x04, 0x07];
const OID_STATE_NAME: [u8; 3] = [0x55_u8, 0x04, 0x08];
const OID_ORGANIZATION_NAME: [u8; 3] = [0x55_u8, 0x04, 0x0A];
const OID_ORGANIZATIONAL_UNIT_NAME: [u8; 3] = [0x55_u8, 0x04, 0x0B];
const OID_TITLE: [u8; 3] = [0x55_u8, 0x04, 0x0C];
const OID_NAME: [u8; 3] = [0x55_u8, 0x04, 0x29];
const OID_GIVEN_NAME: [u8; 3] = [0x55_u8, 0x04, 0x2A];
const OID_INITIALS: [u8; 3] = [0x55_u8, 0x04, 0x2B];
const OID_GENERATION_QUALIFIER: [u8; 3] = [0x55_u8, 0x04, 0x2C];
const OID_DN_QUALIFIER: [u8; 3] = [0x55_u8, 0x04, 0x2E];
const OID_PSEUDONYM: [u8; 3] = [0x55_u8, 0x04, 0x41];
const OID_DOMAIN_COMPONENT: [u8; 10] = [
0x09_u8, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19,
];
const OID_MATTER_NODE_ID: [u8; 10] = [
0x2B_u8, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x01, 0x01,
];
const OID_MATTER_FW_SIGNING_ID: [u8; 10] = [
0x2B_u8, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x01, 0x02,
];
const OID_MATTER_ICAC_ID: [u8; 10] = [
0x2B_u8, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x01, 0x03,
];
const OID_MATTER_RCAC_ID: [u8; 10] = [
0x2B_u8, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x01, 0x04,
];
const OID_MATTER_FABRIC_ID: [u8; 10] = [
0x2B_u8, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x01, 0x05,
];
const OID_MATTER_CASE_AUTH_TAG: [u8; 10] = [
0x2B_u8, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x01, 0x06,
];
const DN_ENCODING: [(&str, &[u8], Option<IntToStringLen>); 22] = [
("Common Name:", &OID_COMMON_NAME, None),
("Surname:", &OID_SURNAME, None),
("Serial Number", &OID_SERIAL_NUMBER, None),
("Country Name", &OID_COUNTRY_NAME, None),
("Locality name", &OID_LOCALITY_NAME, None),
("State Name", &OID_STATE_NAME, None),
("Org Name", &OID_ORGANIZATION_NAME, None),
("OU Name", &OID_ORGANIZATIONAL_UNIT_NAME, None),
("Title", &OID_TITLE, None),
("Name", &OID_NAME, None),
("Given Name", &OID_GIVEN_NAME, None),
("Initials", &OID_INITIALS, None),
("Gen Qualifier", &OID_GENERATION_QUALIFIER, None),
("DN Qualifier", &OID_DN_QUALIFIER, None),
("Pseudonym", &OID_PSEUDONYM, None),
("Domain Component", &OID_DOMAIN_COMPONENT, None),
(
"Chip Node Id:",
&OID_MATTER_NODE_ID,
Some(IntToStringLen::Len16),
),
(
"Chip Firmware Signing Id:",
&OID_MATTER_FW_SIGNING_ID,
Some(IntToStringLen::Len16),
),
(
"Chip ICA Id:",
&OID_MATTER_ICAC_ID,
Some(IntToStringLen::Len16),
),
(
"Chip Root CA Id:",
&OID_MATTER_RCAC_ID,
Some(IntToStringLen::Len16),
),
(
"Chip Fabric Id:",
&OID_MATTER_FABRIC_ID,
Some(IntToStringLen::Len16),
),
(
"Chip NOC CAT Id:",
&OID_MATTER_CASE_AUTH_TAG,
Some(IntToStringLen::Len8),
),
];
w.start_seq(tag)?;
for dn in values {
let dn = dn?;
let tag = dn.tag();
if let Ok(tag) = &tag {
let index = *tag as usize - 1;
if index <= DN_ENCODING.len() {
let this = &DN_ENCODING[index];
dn.encode(this.0, this.1, w, this.2)?;
} else {
error!("Invalid DN, too high {:?}", tag);
}
} else {
error!("Non Matter DNs are not yet supported {:?}", tag);
}
}
w.end_seq()?;
Ok(())
}
fn encode(
&self,
name: &str,
oid: &[u8],
w: &mut dyn CertConsumer,
expected_len: Option<IntToStringLen>,
) -> Result<(), Error> {
w.start_set("")?;
w.start_seq("")?;
w.oid(name, oid)?;
match self.value()? {
DNValue::Uint(v) => match expected_len {
Some(IntToStringLen::Len16) => {
let mut string = heapless::String::<32>::new();
write_unwrap!(&mut string, "{:016X}", v);
w.utf8str("", &string)?
}
Some(IntToStringLen::Len8) => {
let mut string = heapless::String::<32>::new();
write_unwrap!(&mut string, "{:08X}", v);
w.utf8str("", &string)?
}
_ => {
error!("Invalid encoding");
Err(ErrorCode::Invalid)?
}
},
DNValue::Utf8(v) => {
w.utf8str("", v)?;
}
DNValue::PrintableStr(v) => {
w.printstr("", v)?;
}
}
w.end_seq()?;
w.end_set()
}
}
#[derive(Copy, Clone)]
enum IntToStringLen {
Len16,
Len8,
}
#[derive(FromTLV, ToTLV, Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[tlvargs(lifetime = "'a")]
pub struct CertRef<'a>(TLVElement<'a>);
impl<'a> CertRef<'a> {
pub const fn new(tlv: TLVElement<'a>) -> Self {
Self(tlv)
}
fn serial_no(&self) -> Result<&[u8], Error> {
self.0.structure()?.find_ctx(1)?.str()
}
fn sign_algo(&self) -> Result<u8, Error> {
self.0.structure()?.find_ctx(2)?.u8()
}
fn issuer(&self) -> Result<TLVList<'a, DN<'a>>, Error> {
TLVList::new(self.0.structure()?.find_ctx(3)?)
}
fn not_before(&self) -> Result<u32, Error> {
self.0.structure()?.find_ctx(4)?.u32()
}
fn not_after(&self) -> Result<u32, Error> {
self.0.structure()?.find_ctx(5)?.u32()
}
fn subject(&self) -> Result<TLVList<'a, DN<'a>>, Error> {
TLVList::new(self.0.structure()?.find_ctx(6)?)
}
fn pubkey_algo(&self) -> Result<u8, Error> {
self.0.structure()?.find_ctx(7)?.u8()
}
fn ec_curve_id(&self) -> Result<u8, Error> {
self.0.structure()?.find_ctx(8)?.u8()
}
pub fn pubkey(&self) -> Result<&[u8], Error> {
self.0.structure()?.find_ctx(9)?.str()
}
fn extensions(&self) -> Result<TLVList<'a, Extension<'a>>, Error> {
TLVList::new(self.0.structure()?.find_ctx(10)?)
}
fn signature(&self) -> Result<&[u8], Error> {
self.0.structure()?.find_ctx(11)?.str()
}
pub fn get_node_id(&self) -> Result<u64, Error> {
let dn = self
.subject()?
.iter()
.do_try_find(|dn| Ok(dn.tag()? == DNTag::NodeId))?
.ok_or(ErrorCode::NoNodeId)?;
dn.uint()
}
pub fn get_cat_ids(&self, output: &mut [u32]) -> Result<(), Error> {
let mut offset = 0;
self.subject()?.iter().try_for_each(|dn| {
let dn = dn?;
if dn.tag()? == DNTag::NocCat {
if offset == output.len() {
Err(ErrorCode::InvalidData)?;
}
output[offset] = dn.uint()? as u32;
offset += 1;
}
Ok(())
})
}
pub fn get_fabric_id(&self) -> Result<u64, Error> {
let dn = self
.subject()?
.iter()
.do_try_find(|dn| Ok(dn.tag()? == DNTag::FabricId))?
.ok_or(ErrorCode::NoFabricId)?;
dn.uint()
}
pub fn get_ca_id(&self) -> Result<u64, Error> {
let dn = self
.subject()?
.iter()
.do_try_find(|dn| {
let tag = dn.tag()?;
Ok(tag == DNTag::RootCaId || tag == DNTag::IcaId)
})?
.ok_or(ErrorCode::InvalidData)?;
dn.uint()
}
fn get_subject_key_id(&self) -> Result<&[u8], Error> {
let extension = self
.extensions()?
.iter()
.do_try_find(|extension| Ok(matches!(extension, Extension::SubjectKeyId(_))))?
.ok_or(Error::new(ErrorCode::Invalid))?;
let Extension::SubjectKeyId(id) = extension else {
unreachable!();
};
Ok(id.0)
}
fn basic_constraints(&self) -> Result<Option<(bool, Option<u8>)>, Error> {
let ext = self
.extensions()?
.iter()
.do_try_find(|e| Ok(matches!(e, Extension::BasicConstraints(_))))?;
Ok(match ext {
Some(Extension::BasicConstraints(bc)) => Some((bc.is_ca, bc.path)),
_ => None,
})
}
pub fn basic_constraints_path_len(&self) -> Result<Option<u8>, Error> {
Ok(self.basic_constraints()?.and_then(|(_, p)| p))
}
fn has_critical_future_extension(&self) -> Result<bool, Error> {
for ext in self.extensions()?.iter() {
if let Extension::FutureExtensions(bytes) = ext? {
if der_blob_has_critical_extension(bytes.0)? {
return Ok(true);
}
}
}
Ok(false)
}
fn key_usage(&self) -> Result<Option<u16>, Error> {
let ext = self
.extensions()?
.iter()
.do_try_find(|e| Ok(matches!(e, Extension::KeyUsage(_))))?;
Ok(match ext {
Some(Extension::KeyUsage(bits)) => Some(bits),
_ => None,
})
}
fn ext_key_usage_has_all(&self, required: &[u8]) -> Result<bool, Error> {
let ext = self
.extensions()?
.iter()
.do_try_find(|e| Ok(matches!(e, Extension::ExtKeyUsage(_))))?;
let Some(Extension::ExtKeyUsage(list)) = ext else {
return Ok(false);
};
for need in required {
let mut found = false;
for v in list.iter() {
if v? == *need {
found = true;
break;
}
}
if !found {
return Ok(false);
}
}
Ok(true)
}
fn cert_type(&self) -> Result<MatterCertType, Error> {
for dn in self.subject()?.iter() {
match dn?.tag()? {
DNTag::NodeId => return Ok(MatterCertType::Noc),
DNTag::IcaId => return Ok(MatterCertType::Icac),
DNTag::RootCaId => return Ok(MatterCertType::Rcac),
_ => {}
}
}
Err(ErrorCode::InvalidData.into())
}
fn is_authority(&self, their: &CertRef) -> Result<bool, Error> {
let their_subject = their.get_subject_key_id()?;
let authority = self.extensions()?.iter().do_try_find(|extension| {
Ok(if let Extension::AuthorityKeyId(id) = extension {
id.0 == their_subject
} else {
false
})
})?;
Ok(authority.is_some())
}
pub fn is_self_signed(&self) -> Result<bool, Error> {
self.is_authority(self)
}
pub fn as_asn1(&self, buf: &mut [u8]) -> Result<usize, Error> {
let mut w = ASN1Writer::new(buf);
self.encode(&mut w)?;
Ok(w.as_slice().len())
}
pub fn verify_chain_start<C: Crypto>(
&'a self,
crypto: C,
utc_time: UtcTime,
) -> CertVerifier<'a, C> {
CertVerifier::new(self, crypto, utc_time)
}
fn encode(&self, w: &mut dyn CertConsumer) -> Result<(), Error> {
w.start_seq("")?;
w.start_ctx("Version:", 0)?;
w.integer("", &[2])?;
w.end_ctx()?;
w.integer("Serial Num:", self.serial_no()?)?;
w.start_seq("Signature Algorithm:")?;
let (str, oid) = match get_sign_algo(self.sign_algo()?).ok_or(ErrorCode::Invalid)? {
SignAlgoValue::ECDSAWithSHA256 => ("ECDSA with SHA256", OID_ECDSA_WITH_SHA256),
};
w.oid(str, &oid)?;
w.end_seq()?;
DN::encode_all(self.issuer()?.iter(), "Issuer:", w)?;
w.start_seq("Validity:")?;
w.utctime("Not Before:", self.not_before()?.into())?;
if self.not_after()? == 0 {
w.utctime("Not After:", MATTER_CERT_DOESNT_EXPIRE)?;
} else {
w.utctime("Not After:", self.not_after()?.into())?;
}
w.end_seq()?;
DN::encode_all(self.subject()?.iter(), "Subject:", w)?;
w.start_seq("")?;
w.start_seq("Public Key Algorithm")?;
let (str, pub_key) = match get_pubkey_algo(self.pubkey_algo()?).ok_or(ErrorCode::Invalid)? {
PubKeyAlgoValue::EcPubKey => ("ECPubKey", OID_PUB_KEY_ECPUBKEY),
};
w.oid(str, &pub_key)?;
let (str, curve_id) =
match get_ec_curve_id(self.ec_curve_id()?).ok_or(ErrorCode::Invalid)? {
EcCurveIdValue::Prime256V1 => ("Prime256v1", OID_EC_TYPE_PRIME256V1),
};
w.oid(str, &curve_id)?;
w.end_seq()?;
w.bitstr("Public-Key:", false, self.pubkey()?)?;
w.end_seq()?;
Extension::encode_all(self.extensions()?.iter(), w)?;
w.end_seq()
}
}
impl fmt::Display for CertRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut printer = CertPrinter::new(f);
self.encode(&mut printer).map_err(|_| fmt::Error)?;
writeln!(
f,
"Signature: {:x?}",
self.signature().map_err(|_| fmt::Error)?
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum MatterCertType {
Rcac,
Icac,
Noc,
}
fn der_blob_has_critical_extension(bytes: &[u8]) -> Result<bool, Error> {
use der::asn1::{AnyRef, ObjectIdentifier, OctetStringRef};
use der::{Decode, Reader, SliceReader, Tag};
let mut reader = SliceReader::new(bytes).map_err(|_| ErrorCode::InvalidData)?;
while !reader.is_finished() {
let any = AnyRef::decode(&mut reader).map_err(|_| ErrorCode::InvalidData)?;
let mut inner = SliceReader::new(any.value()).map_err(|_| ErrorCode::InvalidData)?;
ObjectIdentifier::decode(&mut inner).map_err(|_| ErrorCode::InvalidData)?;
if !inner.is_finished()
&& inner.peek_tag().map_err(|_| ErrorCode::InvalidData)? == Tag::Boolean
&& bool::decode(&mut inner).map_err(|_| ErrorCode::InvalidData)?
{
return Ok(true);
}
let _ = OctetStringRef::decode(&mut inner).map_err(|_| ErrorCode::InvalidData)?;
}
Ok(false)
}
pub struct CertVerifier<'a, C> {
cert: &'a CertRef<'a>,
crypto: C,
utc_time: UtcTime,
depth: u8,
}
impl<'a, C: Crypto> CertVerifier<'a, C> {
pub const fn new(cert: &'a CertRef<'a>, crypto: C, utc_time: UtcTime) -> Self {
Self {
cert,
crypto,
utc_time,
depth: 0,
}
}
fn verify_usage(&self) -> Result<(), Error> {
use self::x509::key_usage_tlv;
if self.cert.has_critical_future_extension()? {
Err(ErrorCode::InvalidData)?;
}
let cert_type = self.cert.cert_type()?;
let key_usage = self
.cert
.key_usage()?
.ok_or_else(|| Error::new(ErrorCode::InvalidData))?;
match cert_type {
MatterCertType::Noc => {
if self.depth != 0 {
Err(ErrorCode::InvalidData)?;
}
let (is_ca, _) = self
.cert
.basic_constraints()?
.ok_or_else(|| Error::new(ErrorCode::InvalidData))?;
if is_ca {
Err(ErrorCode::InvalidData)?;
}
if (key_usage & key_usage_tlv::DIGITAL_SIGNATURE) == 0 {
Err(ErrorCode::InvalidData)?;
}
const SERVER_AUTH: u8 = 1;
const CLIENT_AUTH: u8 = 2;
if !self
.cert
.ext_key_usage_has_all(&[SERVER_AUTH, CLIENT_AUTH])?
{
Err(ErrorCode::InvalidData)?;
}
}
MatterCertType::Icac | MatterCertType::Rcac => {
let (is_ca, path_len) = self
.cert
.basic_constraints()?
.ok_or_else(|| Error::new(ErrorCode::InvalidData))?;
if !is_ca {
Err(ErrorCode::InvalidData)?;
}
if (key_usage & key_usage_tlv::KEY_CERT_SIGN) == 0 {
Err(ErrorCode::InvalidData)?;
}
if let (Some(max_intermediates), depth) = (path_len, self.depth) {
if depth > 0 && depth - 1 > max_intermediates {
Err(ErrorCode::InvalidData)?;
}
}
}
}
Ok(())
}
pub fn add_cert<'p>(
self,
parent: &'p CertRef<'p>,
buf: &mut [u8],
) -> Result<CertVerifier<'p, C>, Error>
where
'a: 'p,
{
if !self.cert.is_authority(parent)? {
Err(ErrorCode::InvalidAuthKey)?;
}
{
let len = self.cert.as_asn1(buf)?;
let asn1 = &buf[..len];
let result = self
.crypto
.pub_key(parent.pubkey()?.try_into()?)?
.verify(asn1, self.cert.signature()?.try_into()?)?;
if !result {
Err(ErrorCode::InvalidSignature)?;
}
}
let not_before = self.cert.not_before()? as u64;
let not_after = self.cert.not_after()?;
if not_after > 0 && self.utc_time.any_secs() > not_after as u64 {
Err(ErrorCode::InvalidTime)?;
}
if let Some(secs) = self.utc_time.reliable_secs() {
if secs < not_before {
Err(ErrorCode::InvalidTime)?;
}
}
self.verify_usage()?;
Ok(CertVerifier {
cert: parent,
crypto: self.crypto,
utc_time: self.utc_time,
depth: self.depth.saturating_add(1),
})
}
pub fn finalise(self, buf: &mut [u8]) -> Result<(), Error> {
let cert = self.cert;
self.add_cert(cert, buf)?;
Ok(())
}
}
pub trait CertConsumer {
fn start_seq(&mut self, tag: &str) -> Result<(), Error>;
fn end_seq(&mut self) -> Result<(), Error>;
fn integer(&mut self, tag: &str, i: &[u8]) -> Result<(), Error>;
fn printstr(&mut self, tag: &str, s: &str) -> Result<(), Error>;
fn utf8str(&mut self, tag: &str, s: &str) -> Result<(), Error>;
fn bitstr(&mut self, tag: &str, truncate: bool, s: &[u8]) -> Result<(), Error>;
fn ostr(&mut self, tag: &str, s: &[u8]) -> Result<(), Error>;
fn start_compound_ostr(&mut self, tag: &str) -> Result<(), Error>;
fn end_compound_ostr(&mut self) -> Result<(), Error>;
fn bool(&mut self, tag: &str, b: bool) -> Result<(), Error>;
fn start_set(&mut self, tag: &str) -> Result<(), Error>;
fn end_set(&mut self) -> Result<(), Error>;
fn ctx(&mut self, tag: &str, id: u8, val: &[u8]) -> Result<(), Error>;
fn start_ctx(&mut self, tag: &str, id: u8) -> Result<(), Error>;
fn end_ctx(&mut self) -> Result<(), Error>;
fn oid(&mut self, tag: &str, oid: &[u8]) -> Result<(), Error>;
fn utctime(&mut self, tag: &str, epoch: u64) -> Result<(), Error>;
fn raw(&mut self, tag: &str, data: &[u8]) -> Result<(), Error>;
}
#[cfg(test)]
mod tests {
use crate::crypto::test_only_crypto;
use crate::dm::clusters::time_sync::UtcTime;
use crate::error::ErrorCode;
use crate::tlv::{FromTLV, TLVElement, TagType, ToTLV};
use crate::utils::storage::WriteBuf;
use super::CertRef;
#[test]
fn test_asn1_encode_success() {
{
let mut asn1_buf = [0u8; 1000];
let c = CertRef::new(TLVElement::new(CHIP_CERT_INPUT1));
let len = unwrap!(c.as_asn1(&mut asn1_buf));
assert_eq!(ASN1_OUTPUT1, &asn1_buf[..len]);
}
{
let mut asn1_buf = [0u8; 1000];
let c = CertRef::new(TLVElement::new(CHIP_CERT_INPUT2));
let len = unwrap!(c.as_asn1(&mut asn1_buf));
assert_eq!(ASN1_OUTPUT2, &asn1_buf[..len]);
}
{
let mut asn1_buf = [0u8; 1000];
let c = CertRef::new(TLVElement::new(CHIP_CERT_TXT_IN_DN));
let len = unwrap!(c.as_asn1(&mut asn1_buf));
assert_eq!(ASN1_OUTPUT_TXT_IN_DN, &asn1_buf[..len]);
}
}
#[test]
fn test_verify_chain_success() {
let mut buf = [0; 1000];
let noc = CertRef::new(TLVElement::new(NOC1_SUCCESS));
let icac = CertRef::new(TLVElement::new(ICAC1_SUCCESS));
let rca = CertRef::new(TLVElement::new(RCA1_SUCCESS));
let time = UtcTime::Reliable(unwrap!(noc.not_before()) as u64 * 1_000_000);
let a = noc.verify_chain_start(test_only_crypto(), time);
unwrap!(
unwrap!(unwrap!(a.add_cert(&icac, &mut buf)).add_cert(&rca, &mut buf))
.finalise(&mut buf)
);
}
#[test]
fn test_verify_chain_incomplete() {
let mut buf = [0; 1000];
let noc = CertRef::new(TLVElement::new(NOC1_SUCCESS));
let icac = CertRef::new(TLVElement::new(ICAC1_SUCCESS));
let time = UtcTime::Reliable(unwrap!(noc.not_before()) as u64 * 1_000_000);
let a = noc.verify_chain_start(test_only_crypto(), time);
assert_eq!(
Err(ErrorCode::InvalidAuthKey),
unwrap!(a.add_cert(&icac, &mut buf))
.finalise(&mut buf)
.map_err(|e| e.code())
);
}
#[test]
fn test_auth_key_chain_incorrect() {
let mut buf = [0; 1000];
let noc = CertRef::new(TLVElement::new(NOC1_AUTH_KEY_FAIL));
let icac = CertRef::new(TLVElement::new(ICAC1_SUCCESS));
let a = noc.verify_chain_start(test_only_crypto(), UtcTime::Reliable(0));
assert_eq!(
Err(ErrorCode::InvalidAuthKey),
a.add_cert(&icac, &mut buf)
.map(|_| ())
.map_err(|e| e.code())
);
}
#[test]
fn test_zero_value_of_not_after_field() {
let mut buf = [0; 1000];
let noc = CertRef::new(TLVElement::new(NOC_NOT_AFTER_ZERO));
let rca = CertRef::new(TLVElement::new(RCA_FOR_NOC_NOT_AFTER_ZERO));
let time = UtcTime::Reliable(unwrap!(noc.not_before()) as u64 * 1_000_000);
let v = noc.verify_chain_start(test_only_crypto(), time);
let v = unwrap!(v.add_cert(&rca, &mut buf));
unwrap!(v.finalise(&mut buf));
}
#[test]
fn test_cert_corrupted() {
let mut buf = [0; 1000];
let noc = CertRef::new(TLVElement::new(NOC1_CORRUPT_CERT));
let icac = CertRef::new(TLVElement::new(ICAC1_SUCCESS));
let a = noc.verify_chain_start(test_only_crypto(), UtcTime::Reliable(0));
assert_eq!(
Err(ErrorCode::InvalidSignature),
a.add_cert(&icac, &mut buf)
.map(|_| ())
.map_err(|e| e.code())
);
}
#[test]
fn test_tlv_conversions() {
const TEST_INPUT: &[&[u8]; 4] = &[NOC1_SUCCESS, ICAC1_SUCCESS, ICAC2_SUCCESS, RCA1_SUCCESS];
for input in TEST_INPUT.iter() {
info!("Testing next input...");
let root = TLVElement::new(input);
let cert = unwrap!(CertRef::from_tlv(&root));
let mut buf = [0u8; 1024];
let mut wb = WriteBuf::new(&mut buf);
unwrap!(cert.to_tlv(&TagType::Anonymous, &mut wb));
let root2 = TLVElement::new(wb.as_slice());
let cert2 = unwrap!(CertRef::from_tlv(&root2));
assert_eq!(cert, cert2);
}
}
#[test]
fn test_unordered_extensions() {
let mut buf = [0; 1000];
let cert = CertRef::new(TLVElement::new(UNORDERED_EXTENSIONS_CHIP));
let asn1_len = unwrap!(cert.as_asn1(&mut buf));
assert_eq!(&buf[..asn1_len], UNORDERED_EXTENSIONS_DER);
}
#[test]
fn test_der_blob_has_critical_extension() {
use super::der_blob_has_critical_extension;
const NON_CRITICAL: &[u8] = &[
0x30, 0x0A, 0x06, 0x03, 0x55, 0x1D, 0x63, 0x01, 0x01, 0x00, 0x04, 0x00,
];
const CRITICAL: &[u8] = &[
0x30, 0x0A, 0x06, 0x03, 0x55, 0x1D, 0x63, 0x01, 0x01, 0xFF, 0x04, 0x00,
];
const DEFAULTED: &[u8] = &[
0x30, 0x07, 0x06, 0x03, 0x55, 0x1D, 0x63, 0x04, 0x00,
];
assert!(!unwrap!(der_blob_has_critical_extension(&[])));
assert!(!unwrap!(der_blob_has_critical_extension(NON_CRITICAL)));
assert!(!unwrap!(der_blob_has_critical_extension(DEFAULTED)));
assert!(unwrap!(der_blob_has_critical_extension(CRITICAL)));
let mut two_noncritical = heapless::Vec::<u8, 64>::new();
unwrap!(two_noncritical.extend_from_slice(NON_CRITICAL));
unwrap!(two_noncritical.extend_from_slice(DEFAULTED));
assert!(!unwrap!(der_blob_has_critical_extension(&two_noncritical)));
let mut second_is_critical = heapless::Vec::<u8, 64>::new();
unwrap!(second_is_critical.extend_from_slice(NON_CRITICAL));
unwrap!(second_is_critical.extend_from_slice(CRITICAL));
assert!(unwrap!(der_blob_has_critical_extension(
&second_is_critical
)));
}
#[test]
fn test_extension_accessors_on_known_chain() {
use super::x509::key_usage_tlv;
use super::MatterCertType;
let noc = CertRef::new(TLVElement::new(NOC1_SUCCESS));
let icac = CertRef::new(TLVElement::new(ICAC1_SUCCESS));
let rca = CertRef::new(TLVElement::new(RCA1_SUCCESS));
assert_eq!(unwrap!(noc.cert_type()), MatterCertType::Noc);
let (noc_ca, noc_path) = unwrap!(unwrap!(noc.basic_constraints()));
assert!(!noc_ca, "NOC must have cA = FALSE");
assert_eq!(noc_path, None, "NOC must not carry pathLenConstraint");
let noc_ku = unwrap!(unwrap!(noc.key_usage()));
assert_ne!(
noc_ku & key_usage_tlv::DIGITAL_SIGNATURE,
0,
"NOC KeyUsage must include digitalSignature"
);
assert!(
unwrap!(noc.ext_key_usage_has_all(&[1, 2])),
"NOC ExtKeyUsage must include both serverAuth (1) and clientAuth (2)"
);
assert!(
!unwrap!(noc.has_critical_future_extension()),
"test NOC carries no future-extensions"
);
assert_eq!(unwrap!(icac.cert_type()), MatterCertType::Icac);
let (icac_ca, icac_path) = unwrap!(unwrap!(icac.basic_constraints()));
assert!(icac_ca, "ICAC must have cA = TRUE");
assert!(
matches!(icac_path, None | Some(0)),
"unexpected pathLenConstraint on ICAC: {icac_path:?}"
);
let icac_ku = unwrap!(unwrap!(icac.key_usage()));
assert_ne!(
icac_ku & key_usage_tlv::KEY_CERT_SIGN,
0,
"ICAC KeyUsage must include keyCertSign"
);
assert!(
!unwrap!(icac.ext_key_usage_has_all(&[1, 2])),
"ICAC has no ExtendedKeyUsage extension"
);
assert_eq!(unwrap!(rca.cert_type()), MatterCertType::Rcac);
let (rca_ca, rca_path) = unwrap!(unwrap!(rca.basic_constraints()));
assert!(rca_ca, "RCAC must have cA = TRUE");
assert_eq!(rca_path, None, "RCAC must not carry pathLenConstraint");
assert_eq!(unwrap!(rca.basic_constraints_path_len()), None);
let rca_ku = unwrap!(unwrap!(rca.key_usage()));
assert_ne!(
rca_ku & key_usage_tlv::KEY_CERT_SIGN,
0,
"RCAC KeyUsage must include keyCertSign"
);
}
const NOC1_SUCCESS: &[u8] = &[
0x15, 0x30, 0x1, 0x1, 0x1, 0x24, 0x2, 0x1, 0x37, 0x3, 0x24, 0x13, 0x1, 0x24, 0x15, 0x1,
0x18, 0x26, 0x4, 0x80, 0x22, 0x81, 0x27, 0x26, 0x5, 0x80, 0x25, 0x4d, 0x3a, 0x37, 0x6,
0x26, 0x11, 0x2, 0x5c, 0xbc, 0x0, 0x24, 0x15, 0x1, 0x18, 0x24, 0x7, 0x1, 0x24, 0x8, 0x1,
0x30, 0x9, 0x41, 0x4, 0xba, 0x22, 0x56, 0x43, 0x4f, 0x59, 0x98, 0x32, 0x8d, 0xb8, 0xcb,
0x3f, 0x24, 0x90, 0x9a, 0x96, 0x94, 0x43, 0x46, 0x67, 0xc2, 0x11, 0xe3, 0x80, 0x26, 0x65,
0xfc, 0x65, 0x37, 0x77, 0x3, 0x25, 0x18, 0xd8, 0xdc, 0x85, 0xfa, 0xe6, 0x42, 0xe7, 0x55,
0xc9, 0x37, 0xcc, 0xb, 0x78, 0x84, 0x3d, 0x2f, 0xac, 0x81, 0x88, 0x2e, 0x69, 0x0, 0xa5,
0xfc, 0xcd, 0xe0, 0xad, 0xb2, 0x69, 0xca, 0x73, 0x37, 0xa, 0x35, 0x1, 0x28, 0x1, 0x18,
0x24, 0x2, 0x1, 0x36, 0x3, 0x4, 0x2, 0x4, 0x1, 0x18, 0x30, 0x4, 0x14, 0x39, 0x68, 0x16,
0x1e, 0xb5, 0x56, 0x6d, 0xd3, 0xf8, 0x61, 0xf2, 0x95, 0xf3, 0x55, 0xa0, 0xfb, 0xd2, 0x82,
0xc2, 0x29, 0x30, 0x5, 0x14, 0xce, 0x60, 0xb4, 0x28, 0x96, 0x72, 0x27, 0x64, 0x81, 0xbc,
0x4f, 0x0, 0x78, 0xa3, 0x30, 0x48, 0xfe, 0x6e, 0x65, 0x86, 0x18, 0x30, 0xb, 0x40, 0x2,
0x88, 0x42, 0x0, 0x6f, 0xcc, 0xe0, 0xf0, 0x6c, 0xd9, 0xf9, 0x5e, 0xe4, 0xc2, 0xaa, 0x1f,
0x57, 0x71, 0x62, 0xdb, 0x6b, 0x4e, 0xe7, 0x55, 0x3f, 0xc6, 0xc7, 0x9f, 0xf8, 0x30, 0xeb,
0x16, 0x6e, 0x6d, 0xc6, 0x9c, 0xb, 0xb7, 0xe2, 0xb8, 0xe3, 0xe7, 0x57, 0x88, 0x7b, 0xda,
0xe5, 0x79, 0x39, 0x6d, 0x2c, 0x37, 0xb2, 0x7f, 0xc3, 0x63, 0x2f, 0x7e, 0x70, 0xab, 0x5a,
0x2c, 0xf7, 0x5b, 0x18,
];
const ICAC1_SUCCESS: &[u8] = &[
21, 48, 1, 1, 0, 36, 2, 1, 55, 3, 36, 20, 0, 36, 21, 1, 24, 38, 4, 128, 34, 129, 39, 38, 5,
128, 37, 77, 58, 55, 6, 36, 19, 1, 36, 21, 1, 24, 36, 7, 1, 36, 8, 1, 48, 9, 65, 4, 86, 25,
119, 24, 63, 212, 255, 43, 88, 61, 233, 121, 52, 102, 223, 233, 0, 251, 109, 161, 239, 224,
204, 220, 119, 48, 192, 111, 182, 45, 255, 190, 84, 160, 149, 117, 11, 139, 7, 188, 85,
219, 156, 182, 85, 19, 8, 184, 223, 2, 227, 64, 107, 174, 52, 245, 12, 186, 201, 242, 191,
241, 231, 80, 55, 10, 53, 1, 41, 1, 24, 36, 2, 96, 48, 4, 20, 206, 96, 180, 40, 150, 114,
39, 100, 129, 188, 79, 0, 120, 163, 48, 72, 254, 110, 101, 134, 48, 5, 20, 212, 86, 147,
190, 112, 121, 244, 156, 112, 107, 7, 111, 17, 28, 109, 229, 100, 164, 68, 116, 24, 48, 11,
64, 243, 8, 190, 128, 155, 254, 245, 21, 205, 241, 217, 246, 204, 182, 247, 41, 81, 91, 33,
155, 230, 223, 212, 116, 33, 162, 208, 148, 100, 89, 175, 253, 78, 212, 7, 69, 207, 140,
45, 129, 249, 64, 104, 70, 68, 43, 164, 19, 126, 114, 138, 79, 104, 238, 20, 226, 88, 118,
105, 56, 12, 92, 31, 171, 24,
];
const ICAC2_SUCCESS: &[u8] = &[
21, 48, 1, 16, 67, 38, 73, 198, 26, 31, 20, 101, 57, 46, 16, 143, 77, 160, 128, 161, 36, 2,
1, 55, 3, 39, 20, 255, 90, 200, 17, 145, 105, 71, 215, 24, 38, 4, 123, 59, 211, 42, 38, 5,
35, 11, 27, 52, 55, 6, 39, 19, 254, 111, 27, 53, 189, 134, 103, 200, 24, 36, 7, 1, 36, 8,
1, 48, 9, 65, 4, 88, 188, 13, 87, 50, 3, 213, 248, 182, 12, 240, 164, 220, 127, 150, 65,
81, 244, 125, 24, 48, 203, 83, 111, 133, 175, 182, 10, 40, 80, 147, 28, 39, 121, 183, 61,
159, 178, 231, 133, 75, 189, 143, 136, 191, 254, 115, 228, 186, 129, 56, 137, 213, 177, 13,
46, 97, 202, 95, 41, 5, 16, 24, 228, 55, 10, 53, 1, 41, 1, 36, 2, 0, 24, 48, 5, 20, 243,
119, 107, 152, 3, 212, 205, 76, 85, 38, 158, 240, 27, 213, 11, 235, 33, 21, 38, 5, 48, 4,
20, 88, 240, 172, 159, 2, 82, 193, 71, 83, 67, 184, 97, 99, 61, 125, 67, 232, 202, 171,
107, 36, 2, 96, 24, 48, 11, 64, 70, 43, 150, 195, 194, 170, 43, 125, 91, 213, 210, 221,
175, 131, 131, 85, 22, 247, 213, 18, 101, 189, 30, 134, 20, 226, 217, 145, 41, 225, 181,
150, 28, 200, 52, 237, 218, 195, 144, 209, 205, 73, 88, 114, 139, 216, 85, 170, 63, 238,
164, 69, 35, 69, 39, 87, 211, 234, 57, 98, 19, 43, 13, 0, 24,
];
const NOC1_AUTH_KEY_FAIL: &[u8] = &[
0x15, 0x30, 0x1, 0x1, 0x1, 0x24, 0x2, 0x1, 0x37, 0x3, 0x24, 0x13, 0x1, 0x24, 0x15, 0x1,
0x18, 0x26, 0x4, 0x80, 0x22, 0x81, 0x27, 0x26, 0x5, 0x80, 0x25, 0x4d, 0x3a, 0x37, 0x6,
0x26, 0x11, 0x2, 0x5c, 0xbc, 0x0, 0x24, 0x15, 0x1, 0x18, 0x24, 0x7, 0x1, 0x24, 0x8, 0x1,
0x30, 0x9, 0x41, 0x4, 0xba, 0x22, 0x56, 0x43, 0x4f, 0x59, 0x98, 0x32, 0x8d, 0xb8, 0xcb,
0x3f, 0x24, 0x90, 0x9a, 0x96, 0x94, 0x43, 0x46, 0x67, 0xc2, 0x11, 0xe3, 0x80, 0x26, 0x65,
0xfc, 0x65, 0x37, 0x77, 0x3, 0x25, 0x18, 0xd8, 0xdc, 0x85, 0xfa, 0xe6, 0x42, 0xe7, 0x55,
0xc9, 0x37, 0xcc, 0xb, 0x78, 0x84, 0x3d, 0x2f, 0xac, 0x81, 0x88, 0x2e, 0x69, 0x0, 0xa5,
0xfc, 0xcd, 0xe0, 0xad, 0xb2, 0x69, 0xca, 0x73, 0x37, 0xa, 0x35, 0x1, 0x28, 0x1, 0x18,
0x24, 0x2, 0x1, 0x36, 0x3, 0x4, 0x2, 0x4, 0x1, 0x18, 0x30, 0x4, 0x14, 0x39, 0x68, 0x16,
0x1e, 0xb5, 0x56, 0x6d, 0xd3, 0xf8, 0x61, 0xf2, 0x95, 0xf3, 0x55, 0xa0, 0xfb, 0xd2, 0x82,
0xc2, 0x29, 0x30, 0x5, 0x14, 0xce, 0x61, 0xb4, 0x28, 0x96, 0x72, 0x27, 0x64, 0x81, 0xbc,
0x4f, 0x0, 0x78, 0xa3, 0x30, 0x48, 0xfe, 0x6e, 0x65, 0x86, 0x18, 0x30, 0xb, 0x40, 0x2,
0x88, 0x42, 0x0, 0x6f, 0xcc, 0xe0, 0xf0, 0x6c, 0xd9, 0xf9, 0x5e, 0xe4, 0xc2, 0xaa, 0x1f,
0x57, 0x71, 0x62, 0xdb, 0x6b, 0x4e, 0xe7, 0x55, 0x3f, 0xc6, 0xc7, 0x9f, 0xf8, 0x30, 0xeb,
0x16, 0x6e, 0x6d, 0xc6, 0x9c, 0xb, 0xb7, 0xe2, 0xb8, 0xe3, 0xe7, 0x57, 0x88, 0x7b, 0xda,
0xe5, 0x79, 0x39, 0x6d, 0x2c, 0x37, 0xb2, 0x7f, 0xc3, 0x63, 0x2f, 0x7e, 0x70, 0xab, 0x5a,
0x2c, 0xf7, 0x5b, 0x18,
];
const NOC1_CORRUPT_CERT: &[u8] = &[
0x15, 0x30, 0x1, 0x1, 0x1, 0x24, 0x2, 0x1, 0x37, 0x3, 0x24, 0x13, 0x1, 0x24, 0x15, 0x1,
0x18, 0x26, 0x4, 0x80, 0x22, 0x81, 0x27, 0x26, 0x5, 0x80, 0x25, 0x4d, 0x3a, 0x37, 0x6,
0x26, 0x11, 0x2, 0x5c, 0xbc, 0x0, 0x24, 0x15, 0x1, 0x18, 0x24, 0x7, 0x1, 0x24, 0x8, 0x1,
0x30, 0x9, 0x41, 0x4, 0xba, 0x23, 0x56, 0x43, 0x4f, 0x59, 0x98, 0x32, 0x8d, 0xb8, 0xcb,
0x3f, 0x24, 0x90, 0x9a, 0x96, 0x94, 0x43, 0x46, 0x67, 0xc2, 0x11, 0xe3, 0x80, 0x26, 0x65,
0xfc, 0x65, 0x37, 0x77, 0x3, 0x25, 0x18, 0xd8, 0xdc, 0x85, 0xfa, 0xe6, 0x42, 0xe7, 0x55,
0xc9, 0x37, 0xcc, 0xb, 0x78, 0x84, 0x3d, 0x2f, 0xac, 0x81, 0x88, 0x2e, 0x69, 0x0, 0xa5,
0xfc, 0xcd, 0xe0, 0xad, 0xb2, 0x69, 0xca, 0x73, 0x37, 0xa, 0x35, 0x1, 0x28, 0x1, 0x18,
0x24, 0x2, 0x1, 0x36, 0x3, 0x4, 0x2, 0x4, 0x1, 0x18, 0x30, 0x4, 0x14, 0x39, 0x68, 0x16,
0x1e, 0xb5, 0x56, 0x6d, 0xd3, 0xf8, 0x61, 0xf2, 0x95, 0xf3, 0x55, 0xa0, 0xfb, 0xd2, 0x82,
0xc2, 0x29, 0x30, 0x5, 0x14, 0xce, 0x60, 0xb4, 0x28, 0x96, 0x72, 0x27, 0x64, 0x81, 0xbc,
0x4f, 0x0, 0x78, 0xa3, 0x30, 0x48, 0xfe, 0x6e, 0x65, 0x86, 0x18, 0x30, 0xb, 0x40, 0x2,
0x88, 0x42, 0x0, 0x6f, 0xcc, 0xe0, 0xf0, 0x6c, 0xd9, 0xf9, 0x5e, 0xe4, 0xc2, 0xaa, 0x1f,
0x57, 0x71, 0x62, 0xdb, 0x6b, 0x4e, 0xe7, 0x55, 0x3f, 0xc6, 0xc7, 0x9f, 0xf8, 0x30, 0xeb,
0x16, 0x6e, 0x6d, 0xc6, 0x9c, 0xb, 0xb7, 0xe2, 0xb8, 0xe3, 0xe7, 0x57, 0x88, 0x7b, 0xda,
0xe5, 0x79, 0x39, 0x6d, 0x2c, 0x37, 0xb2, 0x7f, 0xc3, 0x63, 0x2f, 0x7e, 0x70, 0xab, 0x5a,
0x2c, 0xf7, 0x5b, 0x18,
];
const RCA1_SUCCESS: &[u8] = &[
0x15, 0x30, 0x1, 0x1, 0x0, 0x24, 0x2, 0x1, 0x37, 0x3, 0x24, 0x14, 0x0, 0x24, 0x15, 0x1,
0x18, 0x26, 0x4, 0x80, 0x22, 0x81, 0x27, 0x26, 0x5, 0x80, 0x25, 0x4d, 0x3a, 0x37, 0x6,
0x24, 0x14, 0x0, 0x24, 0x15, 0x1, 0x18, 0x24, 0x7, 0x1, 0x24, 0x8, 0x1, 0x30, 0x9, 0x41,
0x4, 0x6d, 0x70, 0x7e, 0x4b, 0x98, 0xf6, 0x2b, 0xab, 0x44, 0xd6, 0xfe, 0xa3, 0x2e, 0x39,
0xd8, 0xc3, 0x0, 0xa0, 0xe, 0xa8, 0x6c, 0x83, 0xff, 0x69, 0xd, 0xe8, 0x42, 0x1, 0xeb, 0xd,
0xaa, 0x68, 0x5d, 0xcb, 0x97, 0x2, 0x80, 0x1d, 0xa8, 0x50, 0x2, 0x2e, 0x5a, 0xa2, 0x5a,
0x2e, 0x51, 0x26, 0x4, 0xd2, 0x39, 0x62, 0xcd, 0x82, 0x38, 0x63, 0x28, 0xbf, 0x15, 0x1c,
0xa6, 0x27, 0xe0, 0xd7, 0x37, 0xa, 0x35, 0x1, 0x29, 0x1, 0x18, 0x24, 0x2, 0x60, 0x30, 0x4,
0x14, 0xd4, 0x56, 0x93, 0xbe, 0x70, 0x79, 0xf4, 0x9c, 0x70, 0x6b, 0x7, 0x6f, 0x11, 0x1c,
0x6d, 0xe5, 0x64, 0xa4, 0x44, 0x74, 0x30, 0x5, 0x14, 0xd4, 0x56, 0x93, 0xbe, 0x70, 0x79,
0xf4, 0x9c, 0x70, 0x6b, 0x7, 0x6f, 0x11, 0x1c, 0x6d, 0xe5, 0x64, 0xa4, 0x44, 0x74, 0x18,
0x30, 0xb, 0x40, 0x3, 0xd, 0x77, 0xe1, 0x9e, 0xea, 0x9c, 0x5, 0x5c, 0xcc, 0x47, 0xe8, 0xb3,
0x18, 0x1a, 0xd1, 0x74, 0xee, 0xc6, 0x2e, 0xa1, 0x20, 0x16, 0xbd, 0x20, 0xb4, 0x3d, 0xac,
0x24, 0xbe, 0x17, 0xf9, 0xe, 0xb7, 0x9a, 0x98, 0xc8, 0xbc, 0x6a, 0xce, 0x99, 0x2a, 0x2e,
0x63, 0x4c, 0x76, 0x6, 0x45, 0x93, 0xd3, 0x7c, 0x4, 0x0, 0xe4, 0xc7, 0x78, 0xe9, 0x83,
0x5b, 0xc, 0x33, 0x61, 0x5c, 0x2e, 0x18,
];
const CHIP_CERT_INPUT1: &[u8] = &[
0x15, 0x30, 0x01, 0x01, 0x00, 0x24, 0x02, 0x01, 0x37, 0x03, 0x24, 0x14, 0x00, 0x24, 0x15,
0x03, 0x18, 0x26, 0x04, 0x80, 0x22, 0x81, 0x27, 0x26, 0x05, 0x80, 0x25, 0x4d, 0x3a, 0x37,
0x06, 0x24, 0x13, 0x01, 0x24, 0x15, 0x03, 0x18, 0x24, 0x07, 0x01, 0x24, 0x08, 0x01, 0x30,
0x09, 0x41, 0x04, 0x69, 0xda, 0xe9, 0x42, 0x88, 0xcf, 0x64, 0x94, 0x2d, 0xd5, 0x0a, 0x74,
0x2d, 0x50, 0xe8, 0x5e, 0xbe, 0x15, 0x53, 0x24, 0xe5, 0xc5, 0x6b, 0xe5, 0x7f, 0xc1, 0x41,
0x11, 0x21, 0xdd, 0x46, 0xa3, 0x0d, 0x63, 0xc3, 0xe3, 0x90, 0x7a, 0x69, 0x64, 0xdd, 0x66,
0x78, 0x10, 0xa6, 0xc8, 0x0f, 0xfd, 0xb6, 0xf2, 0x9b, 0x88, 0x50, 0x93, 0x77, 0x9e, 0xf7,
0xb4, 0xda, 0x94, 0x11, 0x33, 0x1e, 0xfe, 0x37, 0x0a, 0x35, 0x01, 0x29, 0x01, 0x18, 0x24,
0x02, 0x60, 0x30, 0x04, 0x14, 0xdf, 0xfb, 0x79, 0xf1, 0x2b, 0xbf, 0x68, 0x18, 0x59, 0x7f,
0xf7, 0xe8, 0xaf, 0x88, 0x91, 0x1c, 0x72, 0x32, 0xf7, 0x52, 0x30, 0x05, 0x14, 0xed, 0x31,
0x5e, 0x1a, 0xb7, 0xb9, 0x7a, 0xca, 0x04, 0x79, 0x5d, 0x82, 0x57, 0x7a, 0xd7, 0x0a, 0x75,
0xd0, 0xdb, 0x7a, 0x18, 0x30, 0x0b, 0x40, 0xe5, 0xd4, 0xe6, 0x0e, 0x98, 0x62, 0x2f, 0xaa,
0x59, 0xe0, 0x28, 0x59, 0xc2, 0xd4, 0xcd, 0x34, 0x85, 0x7f, 0x93, 0xbe, 0x14, 0x35, 0xa3,
0x76, 0x8a, 0xc9, 0x2f, 0x59, 0x39, 0xa0, 0xb0, 0x75, 0xe8, 0x8e, 0x11, 0xa9, 0xc1, 0x9e,
0xaa, 0xab, 0xa0, 0xdb, 0xb4, 0x79, 0x63, 0xfc, 0x02, 0x03, 0x27, 0x25, 0xac, 0x21, 0x6f,
0xef, 0x27, 0xab, 0x0f, 0x90, 0x09, 0x99, 0x05, 0xa8, 0x60, 0xd8, 0x18,
];
const CHIP_CERT_INPUT2: &[u8] = &[
0x15, 0x30, 0x01, 0x01, 0x01, 0x24, 0x02, 0x01, 0x37, 0x03, 0x24, 0x13, 0x01, 0x24, 0x15,
0x03, 0x18, 0x26, 0x04, 0x80, 0x22, 0x81, 0x27, 0x26, 0x05, 0x80, 0x25, 0x4d, 0x3a, 0x37,
0x06, 0x26, 0x11, 0x69, 0xb6, 0x01, 0x00, 0x24, 0x15, 0x03, 0x18, 0x24, 0x07, 0x01, 0x24,
0x08, 0x01, 0x30, 0x09, 0x41, 0x04, 0x93, 0x04, 0xc6, 0xc4, 0xe1, 0xbc, 0x9a, 0xc8, 0xf5,
0xb3, 0x7f, 0x83, 0xd6, 0x7f, 0x79, 0xc5, 0x35, 0xdc, 0x7f, 0xac, 0x87, 0xca, 0xcd, 0x08,
0x80, 0x4a, 0x55, 0x60, 0x80, 0x09, 0xd3, 0x9b, 0x4a, 0xc8, 0xe7, 0x7b, 0x4d, 0x5c, 0x82,
0x88, 0x24, 0xdf, 0x1c, 0xfd, 0xef, 0xb4, 0xbc, 0xb7, 0x2f, 0x36, 0xf7, 0x2b, 0xb2, 0xcc,
0x14, 0x69, 0x63, 0xcc, 0x89, 0xd2, 0x74, 0x3f, 0xd1, 0x98, 0x37, 0x0a, 0x35, 0x01, 0x28,
0x01, 0x18, 0x24, 0x02, 0x01, 0x36, 0x03, 0x04, 0x02, 0x04, 0x01, 0x18, 0x30, 0x04, 0x14,
0x9c, 0xe7, 0xd9, 0xa8, 0x6b, 0xf8, 0x71, 0xfa, 0x08, 0x10, 0xa3, 0xf2, 0x3a, 0x95, 0x30,
0xb1, 0x9e, 0xae, 0xc4, 0x2c, 0x30, 0x05, 0x14, 0xdf, 0xfb, 0x79, 0xf1, 0x2b, 0xbf, 0x68,
0x18, 0x59, 0x7f, 0xf7, 0xe8, 0xaf, 0x88, 0x91, 0x1c, 0x72, 0x32, 0xf7, 0x52, 0x18, 0x30,
0x0b, 0x40, 0xcf, 0x01, 0x37, 0x65, 0xd6, 0x8a, 0xca, 0xd8, 0x33, 0x9f, 0x0f, 0x4f, 0xd5,
0xed, 0x48, 0x42, 0x91, 0xca, 0xab, 0xf7, 0xae, 0xe1, 0x3b, 0x2b, 0xef, 0x9f, 0x43, 0x5a,
0x96, 0xe0, 0xa5, 0x38, 0x8e, 0x39, 0xd0, 0x20, 0x8a, 0x0c, 0x92, 0x2b, 0x21, 0x7d, 0xf5,
0x6c, 0x1d, 0x65, 0x6c, 0x0f, 0xd1, 0xe8, 0x55, 0x14, 0x5e, 0x27, 0xfd, 0xa4, 0xac, 0xf9,
0x93, 0xdb, 0x29, 0x49, 0xaa, 0x71, 0x18,
];
const CHIP_CERT_TXT_IN_DN: &[u8] = &[
0x15, 0x30, 0x1, 0x1, 0x1, 0x24, 0x2, 0x1, 0x37, 0x3, 0x2c, 0x84, 0x2, 0x55, 0x53, 0x2c,
0x7, 0x6, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x1, 0xb, 0x4d, 0x61, 0x74, 0x74, 0x65,
0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x27, 0x14, 0x1, 0x0, 0x0, 0x0, 0xfe, 0xff, 0xff, 0xff,
0x18, 0x26, 0x4, 0x7f, 0xd2, 0x43, 0x29, 0x26, 0x5, 0x7f, 0x94, 0x5b, 0xe5, 0x37, 0x6,
0x2c, 0x84, 0x2, 0x55, 0x53, 0x2c, 0x7, 0x6, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x1,
0xb, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x27, 0x14, 0x1,
0x0, 0x0, 0x0, 0xfe, 0xff, 0xff, 0xff, 0x18, 0x24, 0x7, 0x1, 0x24, 0x8, 0x1, 0x30, 0x9,
0x41, 0x4, 0x5b, 0x37, 0xdf, 0x65, 0x49, 0xc2, 0xd, 0xc8, 0xd7, 0x22, 0xa6, 0xb8, 0xac,
0xb6, 0x60, 0xa8, 0xa7, 0x64, 0xce, 0x7b, 0xaf, 0x6c, 0x6c, 0x22, 0x4f, 0x7e, 0xe8, 0x43,
0x49, 0x68, 0x4a, 0xd7, 0xd8, 0x9, 0xff, 0x65, 0x0, 0x33, 0xd1, 0x52, 0x7d, 0xcf, 0x1f,
0xba, 0xac, 0x6a, 0x9c, 0x3a, 0xd8, 0xb4, 0x1e, 0xda, 0xc9, 0x9, 0xf7, 0xb5, 0xc7, 0x60,
0xfd, 0x54, 0x2c, 0x89, 0x23, 0x75, 0x37, 0xa, 0x35, 0x1, 0x29, 0x1, 0x24, 0x2, 0x1, 0x18,
0x24, 0x2, 0x60, 0x30, 0x4, 0x14, 0x72, 0xc2, 0x1, 0xf7, 0x57, 0x19, 0x13, 0xb3, 0x48,
0xca, 0x0, 0xca, 0x7b, 0x45, 0xf4, 0x77, 0x46, 0x68, 0xc9, 0x7e, 0x30, 0x5, 0x14, 0x72,
0xc2, 0x1, 0xf7, 0x57, 0x19, 0x13, 0xb3, 0x48, 0xca, 0x0, 0xca, 0x7b, 0x45, 0xf4, 0x77,
0x46, 0x68, 0xc9, 0x7e, 0x18, 0x30, 0xb, 0x40, 0x65, 0x16, 0x4b, 0x16, 0x6a, 0xdf, 0xf1,
0x8c, 0x15, 0x61, 0xa, 0x8c, 0xe9, 0x1b, 0xd7, 0x3, 0xe9, 0xc1, 0xf6, 0x77, 0xb7, 0x11,
0xce, 0x13, 0x35, 0x5, 0x15, 0x2d, 0xf0, 0xda, 0x15, 0x11, 0x16, 0x75, 0xac, 0x55, 0x91,
0xce, 0xe7, 0x86, 0x85, 0x1c, 0xdd, 0x9e, 0xfd, 0xad, 0x29, 0x66, 0x74, 0xbe, 0xbc, 0xb2,
0xa3, 0xa3, 0x20, 0x9b, 0xcd, 0xe7, 0xb3, 0x9, 0xdb, 0x55, 0x2c, 0x6f, 0x18,
];
const ASN1_OUTPUT1: &[u8] = &[
0x30, 0x82, 0x01, 0x80, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0a, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x44, 0x31, 0x20, 0x30, 0x1e,
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x04, 0x0c, 0x10, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01,
0x05, 0x0c, 0x10, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31, 0x32, 0x33, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x44, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b,
0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x03, 0x0c, 0x10, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x20, 0x30,
0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x05, 0x0c, 0x10,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x33, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x69, 0xda,
0xe9, 0x42, 0x88, 0xcf, 0x64, 0x94, 0x2d, 0xd5, 0x0a, 0x74, 0x2d, 0x50, 0xe8, 0x5e, 0xbe,
0x15, 0x53, 0x24, 0xe5, 0xc5, 0x6b, 0xe5, 0x7f, 0xc1, 0x41, 0x11, 0x21, 0xdd, 0x46, 0xa3,
0x0d, 0x63, 0xc3, 0xe3, 0x90, 0x7a, 0x69, 0x64, 0xdd, 0x66, 0x78, 0x10, 0xa6, 0xc8, 0x0f,
0xfd, 0xb6, 0xf2, 0x9b, 0x88, 0x50, 0x93, 0x77, 0x9e, 0xf7, 0xb4, 0xda, 0x94, 0x11, 0x33,
0x1e, 0xfe, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
0x0e, 0x04, 0x16, 0x04, 0x14, 0xdf, 0xfb, 0x79, 0xf1, 0x2b, 0xbf, 0x68, 0x18, 0x59, 0x7f,
0xf7, 0xe8, 0xaf, 0x88, 0x91, 0x1c, 0x72, 0x32, 0xf7, 0x52, 0x30, 0x1f, 0x06, 0x03, 0x55,
0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xed, 0x31, 0x5e, 0x1a, 0xb7, 0xb9, 0x7a,
0xca, 0x04, 0x79, 0x5d, 0x82, 0x57, 0x7a, 0xd7, 0x0a, 0x75, 0xd0, 0xdb, 0x7a,
];
const ASN1_OUTPUT2: &[u8] = &[
0x30, 0x82, 0x01, 0xa1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0a, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x44, 0x31, 0x20, 0x30, 0x1e,
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x03, 0x0c, 0x10, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31,
0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01,
0x05, 0x0c, 0x10, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31, 0x32, 0x33, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x44, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b,
0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x01, 0x0c, 0x10, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x42, 0x36, 0x36, 0x39, 0x31, 0x20, 0x30,
0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x05, 0x0c, 0x10,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x33, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x93, 0x04,
0xc6, 0xc4, 0xe1, 0xbc, 0x9a, 0xc8, 0xf5, 0xb3, 0x7f, 0x83, 0xd6, 0x7f, 0x79, 0xc5, 0x35,
0xdc, 0x7f, 0xac, 0x87, 0xca, 0xcd, 0x08, 0x80, 0x4a, 0x55, 0x60, 0x80, 0x09, 0xd3, 0x9b,
0x4a, 0xc8, 0xe7, 0x7b, 0x4d, 0x5c, 0x82, 0x88, 0x24, 0xdf, 0x1c, 0xfd, 0xef, 0xb4, 0xbc,
0xb7, 0x2f, 0x36, 0xf7, 0x2b, 0xb2, 0xcc, 0x14, 0x69, 0x63, 0xcc, 0x89, 0xd2, 0x74, 0x3f,
0xd1, 0x98, 0xa3, 0x81, 0x83, 0x30, 0x81, 0x80, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x20, 0x06, 0x03, 0x55, 0x1d, 0x25,
0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x1d, 0x06,
0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9c, 0xe7, 0xd9, 0xa8, 0x6b, 0xf8, 0x71,
0xfa, 0x08, 0x10, 0xa3, 0xf2, 0x3a, 0x95, 0x30, 0xb1, 0x9e, 0xae, 0xc4, 0x2c, 0x30, 0x1f,
0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xdf, 0xfb, 0x79, 0xf1,
0x2b, 0xbf, 0x68, 0x18, 0x59, 0x7f, 0xf7, 0xe8, 0xaf, 0x88, 0x91, 0x1c, 0x72, 0x32, 0xf7,
0x52,
];
const ASN1_OUTPUT_TXT_IN_DN: &[u8] = &[
0x30, 0x82, 0x01, 0xa9, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0a, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x56, 0x31, 0x0b, 0x30, 0x09,
0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x14, 0x30, 0x12,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0b, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x52,
0x6f, 0x6f, 0x74, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82,
0xa2, 0x7c, 0x01, 0x04, 0x0c, 0x10, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x45, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x32,
0x30, 0x38, 0x32, 0x30, 0x33, 0x30, 0x35, 0x35, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32, 0x31,
0x31, 0x32, 0x30, 0x38, 0x32, 0x30, 0x33, 0x30, 0x35, 0x35, 0x5a, 0x30, 0x56, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0f, 0x30, 0x0d,
0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x14,
0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0b, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72,
0x20, 0x52, 0x6f, 0x6f, 0x74, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0xa2, 0x7c, 0x01, 0x04, 0x0c, 0x10, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
0x45, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x5b, 0x37, 0xdf, 0x65, 0x49, 0xc2, 0x0d, 0xc8, 0xd7,
0x22, 0xa6, 0xb8, 0xac, 0xb6, 0x60, 0xa8, 0xa7, 0x64, 0xce, 0x7b, 0xaf, 0x6c, 0x6c, 0x22,
0x4f, 0x7e, 0xe8, 0x43, 0x49, 0x68, 0x4a, 0xd7, 0xd8, 0x09, 0xff, 0x65, 0x00, 0x33, 0xd1,
0x52, 0x7d, 0xcf, 0x1f, 0xba, 0xac, 0x6a, 0x9c, 0x3a, 0xd8, 0xb4, 0x1e, 0xda, 0xc9, 0x09,
0xf7, 0xb5, 0xc7, 0x60, 0xfd, 0x54, 0x2c, 0x89, 0x23, 0x75, 0xa3, 0x66, 0x30, 0x64, 0x30,
0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01,
0xff, 0x02, 0x01, 0x01, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
0x14, 0x72, 0xc2, 0x01, 0xf7, 0x57, 0x19, 0x13, 0xb3, 0x48, 0xca, 0x00, 0xca, 0x7b, 0x45,
0xf4, 0x77, 0x46, 0x68, 0xc9, 0x7e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
0x30, 0x16, 0x80, 0x14, 0x72, 0xc2, 0x01, 0xf7, 0x57, 0x19, 0x13, 0xb3, 0x48, 0xca, 0x00,
0xca, 0x7b, 0x45, 0xf4, 0x77, 0x46, 0x68, 0xc9, 0x7e,
];
const NOC_NOT_AFTER_ZERO: &[u8] = &[
0x15, 0x30, 0x1, 0x1, 0x1, 0x24, 0x2, 0x1, 0x37, 0x3, 0x27, 0x14, 0xfc, 0x8d, 0xcf, 0x45,
0x19, 0xff, 0x9a, 0x9a, 0x24, 0x15, 0x1, 0x18, 0x26, 0x4, 0x21, 0x39, 0x5a, 0x2c, 0x24,
0x5, 0x0, 0x37, 0x6, 0x24, 0x15, 0x1, 0x26, 0x11, 0x6c, 0x4a, 0x95, 0xd2, 0x18, 0x24, 0x7,
0x1, 0x24, 0x8, 0x1, 0x30, 0x9, 0x41, 0x4, 0x41, 0x7f, 0xb1, 0x61, 0xb0, 0xbe, 0x19, 0x41,
0x81, 0xb9, 0x9f, 0xe8, 0x7b, 0xdd, 0xdf, 0xc4, 0x46, 0xe0, 0x74, 0xba, 0x83, 0x21, 0xda,
0x3d, 0xf7, 0x88, 0x68, 0x14, 0xa6, 0x9d, 0xa9, 0x14, 0x88, 0x94, 0x1e, 0xd3, 0x86, 0x62,
0xc7, 0x6f, 0xb4, 0x79, 0xd2, 0xaf, 0x34, 0xe7, 0xd6, 0x4d, 0x87, 0x29, 0x67, 0x10, 0x73,
0xb9, 0x81, 0xe0, 0x9, 0xe1, 0x13, 0xbb, 0x6a, 0xd2, 0x21, 0xaa, 0x37, 0xa, 0x35, 0x1,
0x28, 0x1, 0x18, 0x24, 0x2, 0x1, 0x36, 0x3, 0x4, 0x2, 0x4, 0x1, 0x18, 0x30, 0x4, 0x14,
0x98, 0xaf, 0xa1, 0x3d, 0x41, 0x67, 0x7a, 0x34, 0x8c, 0x67, 0x6c, 0xcc, 0x17, 0x6e, 0xd5,
0x58, 0xd8, 0x2b, 0x86, 0x8, 0x30, 0x5, 0x14, 0xf8, 0xcf, 0xd0, 0x45, 0x6b, 0xe, 0xd1,
0x6f, 0xc5, 0x67, 0xdf, 0x81, 0xd7, 0xe9, 0xb7, 0xeb, 0x39, 0x78, 0xec, 0x40, 0x18, 0x30,
0xb, 0x40, 0xf9, 0x80, 0x94, 0xbf, 0xcf, 0x72, 0xa5, 0x54, 0x87, 0x12, 0x35, 0xc, 0x38,
0x79, 0xa8, 0xb, 0x21, 0x94, 0xb5, 0x71, 0x2, 0xcb, 0xb, 0xda, 0xf9, 0x6c, 0x54, 0xcb,
0x50, 0x4b, 0x2, 0x5, 0xea, 0xff, 0xfd, 0xb2, 0x1b, 0x24, 0x30, 0x79, 0xb1, 0x69, 0x87,
0xa5, 0x7, 0xc6, 0x76, 0x15, 0x70, 0xc0, 0xec, 0x14, 0xd3, 0x9f, 0x1a, 0xa7, 0xe1, 0xca,
0x25, 0x2e, 0x44, 0xfc, 0x96, 0x4d, 0x18,
];
const RCA_FOR_NOC_NOT_AFTER_ZERO: &[u8] = &[
0x15, 0x30, 0x1, 0x1, 0x0, 0x24, 0x2, 0x1, 0x37, 0x3, 0x27, 0x14, 0xfc, 0x8d, 0xcf, 0x45,
0x19, 0xff, 0x9a, 0x9a, 0x24, 0x15, 0x1, 0x18, 0x26, 0x4, 0xb1, 0x2a, 0x38, 0x2c, 0x26,
0x5, 0x31, 0x5e, 0x19, 0x2e, 0x37, 0x6, 0x27, 0x14, 0xfc, 0x8d, 0xcf, 0x45, 0x19, 0xff,
0x9a, 0x9a, 0x24, 0x15, 0x1, 0x18, 0x24, 0x7, 0x1, 0x24, 0x8, 0x1, 0x30, 0x9, 0x41, 0x4,
0x15, 0x69, 0x1e, 0x7b, 0x6a, 0xea, 0x5, 0xdb, 0xf8, 0x4b, 0xfd, 0xdc, 0x6c, 0x75, 0x46,
0x74, 0xb0, 0x60, 0xdb, 0x4, 0x71, 0xb6, 0xd0, 0x52, 0xf2, 0xf8, 0xe6, 0xbb, 0xd, 0xe5,
0x60, 0x1f, 0x84, 0x66, 0x4f, 0x3c, 0x90, 0x89, 0xa6, 0xc6, 0x99, 0x61, 0xfb, 0x89, 0xf7,
0xa, 0xa6, 0xe4, 0xa2, 0x21, 0xd3, 0x37, 0x30, 0x1b, 0xd2, 0x11, 0xc5, 0xcc, 0x0, 0xf4,
0x7a, 0x14, 0xfc, 0x3c, 0x37, 0xa, 0x35, 0x1, 0x29, 0x1, 0x18, 0x24, 0x2, 0x60, 0x30, 0x4,
0x14, 0xf8, 0xcf, 0xd0, 0x45, 0x6b, 0xe, 0xd1, 0x6f, 0xc5, 0x67, 0xdf, 0x81, 0xd7, 0xe9,
0xb7, 0xeb, 0x39, 0x78, 0xec, 0x40, 0x30, 0x5, 0x14, 0xf8, 0xcf, 0xd0, 0x45, 0x6b, 0xe,
0xd1, 0x6f, 0xc5, 0x67, 0xdf, 0x81, 0xd7, 0xe9, 0xb7, 0xeb, 0x39, 0x78, 0xec, 0x40, 0x18,
0x30, 0xb, 0x40, 0x4c, 0xae, 0xac, 0xc1, 0x26, 0xdd, 0x56, 0xc, 0x85, 0x86, 0xbc, 0xeb,
0xa2, 0xb5, 0xb7, 0xdf, 0x49, 0x92, 0x62, 0xcd, 0x2a, 0xb6, 0x4e, 0xc5, 0x31, 0x7c, 0xd9,
0xb, 0x1c, 0xe9, 0x6e, 0xe5, 0x82, 0xc7, 0xb8, 0xda, 0x22, 0x31, 0x7b, 0x23, 0x5a, 0x2a,
0xe6, 0x76, 0x28, 0xb6, 0xd4, 0xc7, 0x7b, 0x1c, 0x9c, 0x85, 0x71, 0x5f, 0xe6, 0xf6, 0x21,
0x50, 0x5c, 0xa7, 0x7c, 0xc7, 0x1d, 0x9a, 0x18,
];
const UNORDERED_EXTENSIONS_CHIP: &[u8] = &[
0x15, 0x30, 0x01, 0x10, 0x44, 0x9d, 0xeb, 0xca, 0x2e, 0x2e, 0x98, 0x42, 0xe0, 0x87, 0x6f,
0x8b, 0xfa, 0x23, 0xe4, 0x54, 0x24, 0x02, 0x01, 0x37, 0x03, 0x27, 0x14, 0xf6, 0x56, 0xb7,
0x85, 0xf4, 0xbf, 0x30, 0x00, 0x18, 0x26, 0x04, 0xe2, 0xdc, 0xbc, 0x2a, 0x26, 0x05, 0x72,
0xdb, 0xc2, 0x59, 0x37, 0x06, 0x27, 0x14, 0xf6, 0x56, 0xb7, 0x85, 0xf4, 0xbf, 0x30, 0x00,
0x18, 0x24, 0x07, 0x01, 0x24, 0x08, 0x01, 0x30, 0x09, 0x41, 0x04, 0xac, 0x73, 0x46, 0xeb,
0x93, 0xc3, 0x42, 0x58, 0xf1, 0x69, 0x63, 0x65, 0xa6, 0x9f, 0xbe, 0xcb, 0x33, 0xd4, 0x82,
0xd9, 0xdf, 0xc7, 0x3e, 0x94, 0x61, 0x58, 0x83, 0xba, 0x2e, 0x3a, 0xb2, 0xdd, 0x19, 0xcb,
0x8c, 0x12, 0x2e, 0x19, 0x0e, 0x90, 0x2c, 0xb8, 0xec, 0xb9, 0xaa, 0xea, 0x10, 0x00, 0xbb,
0x60, 0xeb, 0xe3, 0x92, 0xb9, 0x2c, 0x78, 0xbb, 0x41, 0xfd, 0x5c, 0xdc, 0xc3, 0x0f, 0x46,
0x37, 0x0a, 0x35, 0x01, 0x29, 0x01, 0x18, 0x30, 0x04, 0x14, 0x2b, 0x33, 0x55, 0x73, 0xc7,
0xc9, 0x12, 0x46, 0x59, 0xe8, 0xe5, 0xfc, 0x50, 0xc5, 0x68, 0x76, 0xfc, 0x93, 0xdc, 0x0b,
0x24, 0x02, 0x61, 0x30, 0x05, 0x14, 0x2b, 0x33, 0x55, 0x73, 0xc7, 0xc9, 0x12, 0x46, 0x59,
0xe8, 0xe5, 0xfc, 0x50, 0xc5, 0x68, 0x76, 0xfc, 0x93, 0xdc, 0x0b, 0x18, 0x30, 0x0b, 0x40,
0x48, 0x8a, 0x6d, 0xf0, 0xa5, 0x9c, 0x3d, 0xb5, 0x5a, 0x29, 0xeb, 0xf6, 0x9a, 0xba, 0x7a,
0xd2, 0x49, 0xb8, 0xcc, 0xe7, 0x33, 0xe3, 0xaa, 0x45, 0x99, 0x6e, 0x34, 0x3a, 0xe3, 0x23,
0x1d, 0x30, 0x94, 0x36, 0x77, 0x33, 0x50, 0x9a, 0x28, 0x9b, 0x25, 0x42, 0xba, 0xaf, 0x13,
0x50, 0xda, 0xe8, 0x43, 0xb4, 0xe1, 0x49, 0x8c, 0x61, 0x0d, 0xab, 0x24, 0xcd, 0xe2, 0x1c,
0xb2, 0x5a, 0x36, 0xd5, 0x18,
];
const UNORDERED_EXTENSIONS_DER: &[u8] = &[
0x30, 0x82, 0x01, 0x4b, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x44, 0x9d, 0xeb, 0xca,
0x2e, 0x2e, 0x98, 0x42, 0xe0, 0x87, 0x6f, 0x8b, 0xfa, 0x23, 0xe4, 0x54, 0x30, 0x0a, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x22, 0x31, 0x20, 0x30, 0x1e,
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x04, 0x0c, 0x10, 0x30,
0x30, 0x33, 0x30, 0x42, 0x46, 0x46, 0x34, 0x38, 0x35, 0x42, 0x37, 0x35, 0x36, 0x46, 0x36,
0x30, 0x1e, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x39, 0x32, 0x30, 0x32, 0x30, 0x31, 0x39, 0x34,
0x36, 0x5a, 0x17, 0x0d, 0x34, 0x37, 0x30, 0x39, 0x32, 0x30, 0x32, 0x31, 0x31, 0x39, 0x34,
0x36, 0x5a, 0x30, 0x22, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01,
0x82, 0xa2, 0x7c, 0x01, 0x04, 0x0c, 0x10, 0x30, 0x30, 0x33, 0x30, 0x42, 0x46, 0x46, 0x34,
0x38, 0x35, 0x42, 0x37, 0x35, 0x36, 0x46, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01,
0x07, 0x03, 0x42, 0x00, 0x04, 0xac, 0x73, 0x46, 0xeb, 0x93, 0xc3, 0x42, 0x58, 0xf1, 0x69,
0x63, 0x65, 0xa6, 0x9f, 0xbe, 0xcb, 0x33, 0xd4, 0x82, 0xd9, 0xdf, 0xc7, 0x3e, 0x94, 0x61,
0x58, 0x83, 0xba, 0x2e, 0x3a, 0xb2, 0xdd, 0x19, 0xcb, 0x8c, 0x12, 0x2e, 0x19, 0x0e, 0x90,
0x2c, 0xb8, 0xec, 0xb9, 0xaa, 0xea, 0x10, 0x00, 0xbb, 0x60, 0xeb, 0xe3, 0x92, 0xb9, 0x2c,
0x78, 0xbb, 0x41, 0xfd, 0x5c, 0xdc, 0xc3, 0x0f, 0x46, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f,
0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2b, 0x33, 0x55, 0x73,
0xc7, 0xc9, 0x12, 0x46, 0x59, 0xe8, 0xe5, 0xfc, 0x50, 0xc5, 0x68, 0x76, 0xfc, 0x93, 0xdc,
0x0b, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
0x01, 0x86, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
0x2b, 0x33, 0x55, 0x73, 0xc7, 0xc9, 0x12, 0x46, 0x59, 0xe8, 0xe5, 0xfc, 0x50, 0xc5, 0x68,
0x76, 0xfc, 0x93, 0xdc, 0x0b,
];
}