304 lines
9.2 KiB
Rust
304 lines
9.2 KiB
Rust
use crate::ccr::model::{
|
|
AspaPayloadSet, AspaPayloadState, CCR_VERSION_V0, CcrContentInfo, CcrDigestAlgorithm,
|
|
ManifestInstance, ManifestState, RoaPayloadSet, RoaPayloadState, RouterKey, RouterKeySet,
|
|
RouterKeyState, RpkiCanonicalCacheRepresentation, TrustAnchorState,
|
|
};
|
|
use crate::data_model::common::BigUnsigned;
|
|
use crate::data_model::oid::{OID_CT_RPKI_CCR_RAW, OID_SHA256_RAW};
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum CcrEncodeError {
|
|
#[error("CCR model validation failed: {0}")]
|
|
Validate(String),
|
|
|
|
#[error("GeneralizedTime formatting failed: {0}")]
|
|
ProducedAtFormat(String),
|
|
}
|
|
|
|
pub fn encode_content_info(content_info: &CcrContentInfo) -> Result<Vec<u8>, CcrEncodeError> {
|
|
content_info.validate().map_err(CcrEncodeError::Validate)?;
|
|
let content_der = encode_ccr(&content_info.content)?;
|
|
Ok(encode_sequence(&[
|
|
encode_oid(OID_CT_RPKI_CCR_RAW),
|
|
encode_explicit(0, &content_der),
|
|
]))
|
|
}
|
|
|
|
pub fn encode_ccr(ccr: &RpkiCanonicalCacheRepresentation) -> Result<Vec<u8>, CcrEncodeError> {
|
|
ccr.validate().map_err(CcrEncodeError::Validate)?;
|
|
let mut fields = Vec::new();
|
|
if ccr.version != CCR_VERSION_V0 {
|
|
fields.push(encode_explicit(0, &encode_integer_u32(ccr.version)));
|
|
}
|
|
fields.push(encode_digest_algorithm(&ccr.hash_alg));
|
|
fields.push(encode_generalized_time(ccr.produced_at)?);
|
|
if let Some(mfts) = &ccr.mfts {
|
|
fields.push(encode_explicit(1, &encode_manifest_state(mfts)?));
|
|
}
|
|
if let Some(vrps) = &ccr.vrps {
|
|
fields.push(encode_explicit(2, &encode_roa_payload_state(vrps)?));
|
|
}
|
|
if let Some(vaps) = &ccr.vaps {
|
|
fields.push(encode_explicit(3, &encode_aspa_payload_state(vaps)?));
|
|
}
|
|
if let Some(tas) = &ccr.tas {
|
|
fields.push(encode_explicit(4, &encode_trust_anchor_state(tas)?));
|
|
}
|
|
if let Some(rks) = &ccr.rks {
|
|
fields.push(encode_explicit(5, &encode_router_key_state(rks)?));
|
|
}
|
|
Ok(encode_sequence(&fields))
|
|
}
|
|
|
|
pub fn encode_manifest_state(state: &ManifestState) -> Result<Vec<u8>, CcrEncodeError> {
|
|
state.validate().map_err(CcrEncodeError::Validate)?;
|
|
let mis = encode_manifest_state_payload_der(&state.mis)?;
|
|
Ok(encode_sequence(&[
|
|
mis,
|
|
encode_generalized_time(state.most_recent_update)?,
|
|
encode_octet_string(&state.hash),
|
|
]))
|
|
}
|
|
|
|
pub fn encode_manifest_state_payload_der(
|
|
instances: &[ManifestInstance],
|
|
) -> Result<Vec<u8>, CcrEncodeError> {
|
|
Ok(encode_sequence(
|
|
&instances
|
|
.iter()
|
|
.map(encode_manifest_instance)
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
))
|
|
}
|
|
|
|
fn encode_manifest_instance(instance: &ManifestInstance) -> Result<Vec<u8>, CcrEncodeError> {
|
|
instance.validate().map_err(CcrEncodeError::Validate)?;
|
|
let mut fields = vec![
|
|
encode_octet_string(&instance.hash),
|
|
encode_integer_u64(instance.size),
|
|
encode_octet_string(&instance.aki),
|
|
encode_integer_bigunsigned(&instance.manifest_number),
|
|
encode_generalized_time(instance.this_update)?,
|
|
encode_sequence(&instance.locations),
|
|
];
|
|
if !instance.subordinates.is_empty() {
|
|
fields.push(encode_sequence(
|
|
&instance
|
|
.subordinates
|
|
.iter()
|
|
.map(|ski| encode_octet_string(ski))
|
|
.collect::<Vec<_>>(),
|
|
));
|
|
}
|
|
Ok(encode_sequence(&fields))
|
|
}
|
|
|
|
pub fn encode_roa_payload_state(state: &RoaPayloadState) -> Result<Vec<u8>, CcrEncodeError> {
|
|
state.validate().map_err(CcrEncodeError::Validate)?;
|
|
let rps = encode_roa_payload_state_payload_der(&state.rps)?;
|
|
Ok(encode_sequence(&[rps, encode_octet_string(&state.hash)]))
|
|
}
|
|
|
|
pub fn encode_roa_payload_state_payload_der(
|
|
sets: &[RoaPayloadSet],
|
|
) -> Result<Vec<u8>, CcrEncodeError> {
|
|
Ok(encode_sequence(
|
|
&sets
|
|
.iter()
|
|
.map(encode_roa_payload_set)
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
))
|
|
}
|
|
|
|
fn encode_roa_payload_set(set: &RoaPayloadSet) -> Result<Vec<u8>, CcrEncodeError> {
|
|
set.validate().map_err(CcrEncodeError::Validate)?;
|
|
Ok(encode_sequence(&[
|
|
encode_integer_u32(set.as_id),
|
|
encode_sequence(&set.ip_addr_blocks),
|
|
]))
|
|
}
|
|
|
|
pub fn encode_aspa_payload_state(state: &AspaPayloadState) -> Result<Vec<u8>, CcrEncodeError> {
|
|
state.validate().map_err(CcrEncodeError::Validate)?;
|
|
let aps = encode_aspa_payload_state_payload_der(&state.aps)?;
|
|
Ok(encode_sequence(&[aps, encode_octet_string(&state.hash)]))
|
|
}
|
|
|
|
pub fn encode_aspa_payload_state_payload_der(
|
|
sets: &[AspaPayloadSet],
|
|
) -> Result<Vec<u8>, CcrEncodeError> {
|
|
Ok(encode_sequence(
|
|
&sets
|
|
.iter()
|
|
.map(encode_aspa_payload_set)
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
))
|
|
}
|
|
|
|
fn encode_aspa_payload_set(set: &AspaPayloadSet) -> Result<Vec<u8>, CcrEncodeError> {
|
|
set.validate().map_err(CcrEncodeError::Validate)?;
|
|
Ok(encode_sequence(&[
|
|
encode_integer_u32(set.customer_as_id),
|
|
encode_sequence(
|
|
&set.providers
|
|
.iter()
|
|
.map(|provider| encode_integer_u32(*provider))
|
|
.collect::<Vec<_>>(),
|
|
),
|
|
]))
|
|
}
|
|
|
|
pub fn encode_trust_anchor_state(state: &TrustAnchorState) -> Result<Vec<u8>, CcrEncodeError> {
|
|
state.validate().map_err(CcrEncodeError::Validate)?;
|
|
let skis = encode_trust_anchor_state_payload_der(&state.skis)?;
|
|
Ok(encode_sequence(&[skis, encode_octet_string(&state.hash)]))
|
|
}
|
|
|
|
pub fn encode_trust_anchor_state_payload_der(skis: &[Vec<u8>]) -> Result<Vec<u8>, CcrEncodeError> {
|
|
Ok(encode_sequence(
|
|
&skis
|
|
.iter()
|
|
.map(|ski| encode_octet_string(ski))
|
|
.collect::<Vec<_>>(),
|
|
))
|
|
}
|
|
|
|
pub fn encode_router_key_state(state: &RouterKeyState) -> Result<Vec<u8>, CcrEncodeError> {
|
|
state.validate().map_err(CcrEncodeError::Validate)?;
|
|
let rksets = encode_router_key_state_payload_der(&state.rksets)?;
|
|
Ok(encode_sequence(&[rksets, encode_octet_string(&state.hash)]))
|
|
}
|
|
|
|
pub fn encode_router_key_state_payload_der(
|
|
sets: &[RouterKeySet],
|
|
) -> Result<Vec<u8>, CcrEncodeError> {
|
|
Ok(encode_sequence(
|
|
&sets
|
|
.iter()
|
|
.map(encode_router_key_set)
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
))
|
|
}
|
|
|
|
fn encode_router_key_set(set: &RouterKeySet) -> Result<Vec<u8>, CcrEncodeError> {
|
|
set.validate().map_err(CcrEncodeError::Validate)?;
|
|
Ok(encode_sequence(&[
|
|
encode_integer_u32(set.as_id),
|
|
encode_sequence(
|
|
&set.router_keys
|
|
.iter()
|
|
.map(encode_router_key)
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
),
|
|
]))
|
|
}
|
|
|
|
fn encode_router_key(key: &RouterKey) -> Result<Vec<u8>, CcrEncodeError> {
|
|
key.validate().map_err(CcrEncodeError::Validate)?;
|
|
Ok(encode_sequence(&[
|
|
encode_octet_string(&key.ski),
|
|
key.spki_der.clone(),
|
|
]))
|
|
}
|
|
|
|
fn encode_digest_algorithm(alg: &CcrDigestAlgorithm) -> Vec<u8> {
|
|
match alg {
|
|
CcrDigestAlgorithm::Sha256 => encode_sequence(&[encode_oid(OID_SHA256_RAW)]),
|
|
}
|
|
}
|
|
|
|
fn encode_generalized_time(t: time::OffsetDateTime) -> Result<Vec<u8>, CcrEncodeError> {
|
|
let t = t.to_offset(time::UtcOffset::UTC);
|
|
let s = format!(
|
|
"{:04}{:02}{:02}{:02}{:02}{:02}Z",
|
|
t.year(),
|
|
u8::from(t.month()),
|
|
t.day(),
|
|
t.hour(),
|
|
t.minute(),
|
|
t.second()
|
|
);
|
|
Ok(encode_tlv(0x18, s.into_bytes()))
|
|
}
|
|
|
|
fn encode_integer_u32(v: u32) -> Vec<u8> {
|
|
encode_integer_bytes(unsigned_integer_bytes(v as u64))
|
|
}
|
|
|
|
fn encode_integer_u64(v: u64) -> Vec<u8> {
|
|
encode_integer_bytes(unsigned_integer_bytes(v))
|
|
}
|
|
|
|
fn encode_integer_bigunsigned(v: &BigUnsigned) -> Vec<u8> {
|
|
encode_integer_bytes(v.bytes_be.clone())
|
|
}
|
|
|
|
fn encode_integer_bytes(mut bytes: Vec<u8>) -> Vec<u8> {
|
|
if bytes.is_empty() {
|
|
bytes.push(0);
|
|
}
|
|
if bytes[0] & 0x80 != 0 {
|
|
bytes.insert(0, 0);
|
|
}
|
|
encode_tlv(0x02, bytes)
|
|
}
|
|
|
|
fn unsigned_integer_bytes(v: u64) -> Vec<u8> {
|
|
if v == 0 {
|
|
return vec![0];
|
|
}
|
|
let mut out = Vec::new();
|
|
let mut n = v;
|
|
while n > 0 {
|
|
out.push((n & 0xFF) as u8);
|
|
n >>= 8;
|
|
}
|
|
out.reverse();
|
|
out
|
|
}
|
|
|
|
fn encode_oid(raw_body: &[u8]) -> Vec<u8> {
|
|
encode_tlv(0x06, raw_body.to_vec())
|
|
}
|
|
|
|
fn encode_octet_string(bytes: &[u8]) -> Vec<u8> {
|
|
encode_tlv(0x04, bytes.to_vec())
|
|
}
|
|
|
|
fn encode_explicit(tag_number: u8, inner_der: &[u8]) -> Vec<u8> {
|
|
encode_tlv(0xA0 + tag_number, inner_der.to_vec())
|
|
}
|
|
|
|
fn encode_sequence(elements: &[Vec<u8>]) -> Vec<u8> {
|
|
let total_len: usize = elements.iter().map(Vec::len).sum();
|
|
let mut buf = Vec::with_capacity(total_len);
|
|
for element in elements {
|
|
buf.extend_from_slice(element);
|
|
}
|
|
encode_tlv(0x30, buf)
|
|
}
|
|
|
|
fn encode_tlv(tag: u8, value: Vec<u8>) -> Vec<u8> {
|
|
let mut out = Vec::with_capacity(1 + 9 + value.len());
|
|
out.push(tag);
|
|
encode_length(value.len(), &mut out);
|
|
out.extend_from_slice(&value);
|
|
out
|
|
}
|
|
|
|
fn encode_length(len: usize, out: &mut Vec<u8>) {
|
|
if len < 0x80 {
|
|
out.push(len as u8);
|
|
return;
|
|
}
|
|
let mut bytes = Vec::new();
|
|
let mut value = len;
|
|
while value > 0 {
|
|
bytes.push((value & 0xFF) as u8);
|
|
value >>= 8;
|
|
}
|
|
bytes.reverse();
|
|
out.push(0x80 | (bytes.len() as u8));
|
|
out.extend_from_slice(&bytes);
|
|
}
|