synta 0.1.8

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
//! Example: Parsing X.509 certificate structure
//!
//! This example demonstrates how to parse the basic structure of an
//! X.509 certificate using Synta. It shows how to navigate through
//! the certificate's ASN.1 structure.
//!
//! Note: This is a basic structural parser, not a full X.509 validator.
//! For production use, consider using a dedicated X.509 library.
//!
//! Run with: cargo run --example parse_certificate

use std::str::FromStr;
use synta::{BitStringRef, Decoder, Element, Encoding, ObjectIdentifier, Sequence};

fn main() {
    println!("=== X.509 Certificate Structure Parser ===\n");

    // A minimal self-signed certificate (DER-encoded)
    // This is a simplified example certificate
    let cert_data = create_example_certificate();

    println!("Certificate size: {} bytes", cert_data.len());
    println!(
        "First 32 bytes: {:02X?}...\n",
        &cert_data[..32.min(cert_data.len())]
    );

    // Parse the certificate
    match parse_certificate(&cert_data) {
        Ok(()) => println!("\nCertificate parsed successfully!"),
        Err(e) => println!("\nError parsing certificate: {:?}", e),
    }
}

fn parse_certificate(data: &[u8]) -> synta::Result<()> {
    // X.509 Certificate structure:
    // Certificate ::= SEQUENCE {
    //     tbsCertificate       TBSCertificate,
    //     signatureAlgorithm   AlgorithmIdentifier,
    //     signatureValue       BIT STRING
    // }

    let mut decoder = Decoder::new(data, Encoding::Der);
    let cert: Sequence = decoder.decode()?;
    let cert_elements = cert.into_elements()?;

    println!(
        "Certificate is a SEQUENCE with {} elements",
        cert_elements.len()
    );

    if cert_elements.len() < 3 {
        println!("Warning: Expected at least 3 elements (tbsCertificate, signatureAlgorithm, signatureValue)");
        return Ok(());
    }

    // Parse TBSCertificate
    if let Element::Sequence(tbs) = &cert_elements[0] {
        println!("\n1. TBSCertificate (To-Be-Signed Certificate):");
        let tbs_els = tbs.clone().into_elements()?;
        println!("   {} elements", tbs_els.len());
        parse_tbs_certificate(&tbs_els);
    }

    // Parse SignatureAlgorithm
    if let Element::Sequence(sig_alg) = &cert_elements[1] {
        println!("\n2. Signature Algorithm:");
        parse_algorithm_identifier(sig_alg);
    }

    // Parse SignatureValue
    match &cert_elements[2] {
        Element::BitString(sig) => {
            println!("\n3. Signature Value:");
            println!(
                "   {} bytes (unused bits: {})",
                sig.as_bytes().len(),
                sig.unused_bits()
            );
        }
        _ => println!("\n3. Signature Value: Unexpected type"),
    }

    Ok(())
}

fn parse_tbs_certificate(tbs_elements: &[Element<'_>]) {
    // TBSCertificate has many fields, we'll show a few
    for (i, element) in tbs_elements.iter().enumerate() {
        match element {
            Element::Integer(version) if i == 0 => {
                // Version is usually [0] EXPLICIT
                println!("   - Version/Field {}: {:?} bytes", i, version.as_bytes());
            }
            Element::Integer(serial) => {
                println!("   - Serial Number: {} bytes", serial.as_bytes().len());
            }
            Element::Sequence(seq) => {
                let len = seq.iter().count();
                println!("   - SEQUENCE at position {}: {} elements", i, len);
            }
            _ => {}
        }
    }
}

fn parse_algorithm_identifier(alg: &Sequence<'_>) {
    // AlgorithmIdentifier ::= SEQUENCE {
    //     algorithm    OBJECT IDENTIFIER,
    //     parameters   ANY DEFINED BY algorithm OPTIONAL
    // }

    if let Some(Ok(Element::ObjectIdentifier(oid))) = alg.iter().next() {
        println!("   Algorithm OID: {}", oid);

        // Try to identify common algorithms
        let oid_str = oid.to_string();
        let name = match oid_str.as_str() {
            "1.2.840.113549.1.1.1" => "RSA Encryption",
            "1.2.840.113549.1.1.5" => "SHA-1 with RSA",
            "1.2.840.113549.1.1.11" => "SHA-256 with RSA",
            "1.2.840.10045.4.3.2" => "ECDSA with SHA-256",
            _ => "Unknown",
        };
        println!("   Algorithm: {}", name);
    }

    if alg.iter().count() > 1 {
        println!("   Has parameters: yes");
    }
}

fn create_example_certificate() -> Vec<u8> {
    // Create a minimal certificate-like structure for demonstration
    // This is NOT a valid certificate, just shows the structure

    use synta::Integer;
    use synta::ToDer;

    // TBSCertificate (simplified)
    let mut tbs = Sequence::new();
    tbs.push(Element::Integer(Integer::from(2))); // Version
    tbs.push(Element::Integer(Integer::from(123456))); // Serial number

    // Signature Algorithm
    let mut sig_alg = Sequence::new();
    sig_alg.push(Element::ObjectIdentifier(
        ObjectIdentifier::from_str("1.2.840.113549.1.1.11").unwrap(),
    )); // SHA-256 with RSA

    // Signature Value
    let signature_data = vec![0xDE, 0xAD, 0xBE, 0xEF];
    let signature = BitStringRef::new(&signature_data, 0).unwrap();

    // Certificate
    let mut cert = Sequence::new();
    cert.push(Element::Sequence(tbs));
    cert.push(Element::Sequence(sig_alg));
    cert.push(Element::BitString(signature));

    // Encode
    cert.to_der().unwrap()
}