liminal-server 0.25.4

Standalone server for the liminal messaging bus
Documentation
//! Certificate-bearing offers leave the client wire frame shape unchanged.

use super::CertificateRefusal;
use crate::link_handshake::NOISE_OVERHEAD;
use std::io::Read;
use std::path::Path;
use zeroize::Zeroizing;

const MAGIC: &[u8; 8] = b"LMCERT02";

/// Builds the same certificate offer for wire and punched application admission.
///
/// # Errors
/// Missing issuer standing, unreadable certificate, proof or allocation refusal.
pub(crate) fn for_machine(
    host: &crate::link::LinkHost,
    agent: &str,
    first: &[u8],
) -> Result<Vec<u8>, CertificateRefusal> {
    let Some(peers) = host.peers() else {
        return Ok(first.to_vec());
    };
    let Some(path) = peers.certificate_path.as_deref() else {
        return Ok(first.to_vec());
    };
    let standing = host
        .standing()
        .ok_or(CertificateRefusal::StatusUnavailable)?;
    let endpoint = standing.endpoint(agent)?;
    let pass_proof = host.local().certificate_proof(
        agent,
        endpoint.path(),
        super::standing::Standing::body(),
    )?;
    let status_endpoint = standing.status_endpoint()?;
    let status_proof = host.local().certificate_proof(
        agent,
        super::standing::Standing::status_signature_path(&status_endpoint),
        &super::status::request(agent)?,
    )?;
    let proof = format!("{pass_proof}\n{status_proof}");
    configured(
        Some(path),
        first,
        &proof,
        peers.max_certificate_bytes.get(),
        peers.max_proof_bytes.get(),
    )
}

/// Packs DER and the first KK message into the existing opaque offer body.
/// Old recorded-key offers remain exactly their original Noise bytes.
///
/// # Errors
/// An unreadable, empty, oversized certificate, or an invalid handshake size.
pub fn configured(
    path: Option<&Path>,
    first: &[u8],
    proof: &str,
    bound: usize,
    proof_bound: usize,
) -> Result<Vec<u8>, CertificateRefusal> {
    let Some(path) = path else {
        return Ok(first.to_vec());
    };
    let mut file = std::fs::File::open(path).map_err(|_| CertificateRefusal::Path)?;
    if file.metadata().map_err(|_| CertificateRefusal::Path)?.len()
        > u64::try_from(bound).map_err(|_| CertificateRefusal::Bound)?
    {
        return Err(CertificateRefusal::Bound);
    }
    let mut der = Zeroizing::new(Vec::new());
    file.by_ref()
        .take(u64::try_from(bound).map_err(|_| CertificateRefusal::Bound)? + 1)
        .read_to_end(&mut der)
        .map_err(|_| CertificateRefusal::Path)?;
    pack(&der, first, proof, bound, proof_bound)
}

/// Encodes a certificate within the operator's allocation bound.
///
/// # Errors
/// Empty or oversized DER/handshake, or length conversion overflow.
pub fn pack(
    der: &[u8],
    first: &[u8],
    proof: &str,
    bound: usize,
    proof_bound: usize,
) -> Result<Vec<u8>, CertificateRefusal> {
    if der.is_empty() || der.len() > bound || bound == 0 {
        return Err(CertificateRefusal::Bound);
    }
    if first.is_empty() || first.len() > NOISE_OVERHEAD {
        return Err(CertificateRefusal::Encoding);
    }
    if proof.is_empty() || proof.len() > proof_bound {
        return Err(CertificateRefusal::Proof);
    }
    let length = u32::try_from(der.len()).map_err(|_| CertificateRefusal::Bound)?;
    let mut bytes = MAGIC.to_vec();
    bytes.extend_from_slice(&length.to_be_bytes());
    bytes.extend_from_slice(
        &u32::try_from(proof.len())
            .map_err(|_| CertificateRefusal::Bound)?
            .to_be_bytes(),
    );
    bytes.extend_from_slice(der);
    bytes.extend_from_slice(proof.as_bytes());
    bytes.extend_from_slice(first);
    Ok(bytes)
}

/// Borrows the exact DER and Noise message without allocating peer-controlled lengths.
///
/// # Errors
/// A malformed envelope or certificate exceeding the configured bound.
pub struct OfferedCertificate<'a> {
    /// Issuer-signed DER borrowed from the checked offer.
    pub der: &'a [u8],
    /// Fresh signed request header, never an app token.
    pub proof: &'a str,
}

/// Reads the bounded certificate and handshake framing.
///
/// # Errors
/// Returns the named certificate refusal for malformed or oversized fields.
pub fn unpack(
    bytes: &[u8],
    bound: usize,
    proof_bound: usize,
) -> Result<(Option<OfferedCertificate<'_>>, &[u8]), CertificateRefusal> {
    if bytes.len() <= NOISE_OVERHEAD {
        return Ok((None, bytes));
    }
    if !bytes.starts_with(MAGIC) {
        return Err(CertificateRefusal::Encoding);
    }
    let encoded = bytes.get(8..12).ok_or(CertificateRefusal::Encoding)?;
    let length = usize::try_from(u32::from_be_bytes(
        encoded
            .try_into()
            .map_err(|_| CertificateRefusal::Encoding)?,
    ))
    .map_err(|_| CertificateRefusal::Bound)?;
    if length == 0 || length > bound {
        return Err(CertificateRefusal::Bound);
    }
    let proof_length = usize::try_from(u32::from_be_bytes(
        bytes
            .get(12..16)
            .ok_or(CertificateRefusal::Encoding)?
            .try_into()
            .map_err(|_| CertificateRefusal::Encoding)?,
    ))
    .map_err(|_| CertificateRefusal::Bound)?;
    if proof_length == 0 || proof_length > proof_bound {
        return Err(CertificateRefusal::Proof);
    }
    let end = 16_usize
        .checked_add(length)
        .ok_or(CertificateRefusal::Bound)?;
    let proof_end = end
        .checked_add(proof_length)
        .ok_or(CertificateRefusal::Bound)?;
    let der = bytes.get(16..end).ok_or(CertificateRefusal::Encoding)?;
    let proof = std::str::from_utf8(
        bytes
            .get(end..proof_end)
            .ok_or(CertificateRefusal::Encoding)?,
    )
    .map_err(|_| CertificateRefusal::Proof)?;
    let first = bytes.get(proof_end..).ok_or(CertificateRefusal::Encoding)?;
    if first.is_empty() || first.len() > NOISE_OVERHEAD {
        return Err(CertificateRefusal::Encoding);
    }
    Ok((Some(OfferedCertificate { der, proof }), first))
}