#![no_std]
include!("generated.rs");
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TrustAnchorKind {
Root,
Additional,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RootConstraint {
pub sct_not_after_sec: Option<i64>,
pub sct_all_after_sec: Option<i64>,
pub min_version: Option<&'static str>,
pub max_version_exclusive: Option<&'static str>,
pub permitted_dns_names: &'static [&'static str],
pub index_not_after: Option<u64>,
pub index_after: Option<u64>,
pub validity_starts_not_after_sec: Option<i64>,
pub validity_starts_after_sec: Option<i64>,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TrustAnchor {
pub der: &'static [u8],
pub sha256: [u8; 32],
pub kind: TrustAnchorKind,
pub crs_root_id: Option<i32>,
pub trust_anchor_id: Option<&'static [u8]>,
pub constraints: &'static [RootConstraint],
pub ev_policy_oids: &'static [&'static str],
pub display_name: Option<&'static str>,
pub eutl: bool,
pub enforce_anchor_expiry: bool,
pub enforce_anchor_constraints: bool,
}
#[must_use]
pub const fn trust_anchor_ids() -> [&'static [u8]; trust_anchor_id_count(TLS_TRUST_ANCHORS)] {
collect_trust_anchor_ids::<{ trust_anchor_id_count(TLS_TRUST_ANCHORS) }>(TLS_TRUST_ANCHORS)
}
#[must_use]
pub const fn encoded_trust_anchor_ids() -> [u8; encoded_trust_anchor_ids_len(TLS_TRUST_ANCHORS)] {
encode_trust_anchor_ids::<{ encoded_trust_anchor_ids_len(TLS_TRUST_ANCHORS) }>(
TLS_TRUST_ANCHORS,
)
}
const fn trust_anchor_id_count(anchors: &[TrustAnchor]) -> usize {
let mut anchor_index = 0;
let mut count = 0;
while anchor_index < anchors.len() {
if anchors[anchor_index].trust_anchor_id.is_some() {
count += 1;
}
anchor_index += 1;
}
count
}
const fn collect_trust_anchor_ids<const N: usize>(anchors: &[TrustAnchor]) -> [&'static [u8]; N] {
let mut ids: [&'static [u8]; N] = [&[]; N];
let mut anchor_index = 0;
let mut id_index = 0;
while anchor_index < anchors.len() {
if let Some(id) = anchors[anchor_index].trust_anchor_id {
assert!(id_index < N, "Trust Anchor ID output array is too short");
ids[id_index] = id;
id_index += 1;
}
anchor_index += 1;
}
assert!(id_index == N, "Trust Anchor ID output array is too long");
ids
}
const fn encoded_trust_anchor_ids_len(anchors: &[TrustAnchor]) -> usize {
let mut index = 0;
let mut length = 0usize;
while index < anchors.len() {
let Some(id) = anchors[index].trust_anchor_id else {
index += 1;
continue;
};
assert!(!id.is_empty(), "Trust Anchor IDs must not be empty");
assert!(
id.len() <= 255,
"Trust Anchor IDs must fit an 8-bit TLS length prefix"
);
length = match length.checked_add(id.len() + 1) {
Some(length) => length,
None => panic!("encoded Trust Anchor ID length overflow"),
};
index += 1;
}
assert!(
length <= 65_535,
"encoded Trust Anchor IDs must fit the TLS outer vector"
);
length
}
const fn encode_trust_anchor_ids<const N: usize>(anchors: &[TrustAnchor]) -> [u8; N] {
let mut encoded = [0; N];
let mut anchor_index = 0;
let mut offset = 0;
while anchor_index < anchors.len() {
let Some(id) = anchors[anchor_index].trust_anchor_id else {
anchor_index += 1;
continue;
};
encoded[offset] = id.len().to_le_bytes()[0];
offset += 1;
let mut byte_index = 0;
while byte_index < id.len() {
encoded[offset] = id[byte_index];
offset += 1;
byte_index += 1;
}
anchor_index += 1;
}
assert!(offset == N, "encoded Trust Anchor ID length mismatch");
encoded
}
#[must_use]
pub const fn trust_anchor_id_for_certificate(certificate_der: &[u8]) -> Option<&'static [u8]> {
let mut anchor_index = 0;
while anchor_index < TLS_TRUST_ANCHORS.len() {
let anchor = &TLS_TRUST_ANCHORS[anchor_index];
if byte_slices_equal(anchor.der, certificate_der) {
return anchor.trust_anchor_id;
}
anchor_index += 1;
}
None
}
const fn byte_slices_equal(left: &[u8], right: &[u8]) -> bool {
if left.len() != right.len() {
return false;
}
let mut index = 0;
while index < left.len() {
if left[index] != right[index] {
return false;
}
index += 1;
}
true
}