#[cfg(feature = "derive")]
fn main() {
use std::str::FromStr;
use synta::{
BitString, FromDer, Integer, ObjectIdentifier, OctetString, PrintableString, ToDer, UtcTime,
};
use synta_derive::{Asn1Choice, Asn1Sequence};
println!("=== Derive Macro Usage Example ===\n");
#[derive(Asn1Sequence, Debug, Clone)]
struct AlgorithmIdentifier {
algorithm: ObjectIdentifier,
parameters: Option<OctetString>,
}
#[derive(Asn1Sequence, Debug, Clone)]
struct Validity {
not_before: UtcTime,
not_after: UtcTime,
}
#[derive(Asn1Sequence, Debug, Clone)]
struct Name {
common_name: PrintableString,
}
#[derive(Asn1Sequence, Debug, Clone)]
struct TBSCertificate {
#[asn1(tag(0, explicit))]
version: Option<Integer>,
serial_number: Integer,
signature: AlgorithmIdentifier,
issuer: Name,
validity: Validity,
subject: Name,
}
#[derive(Asn1Sequence, Debug, Clone)]
struct Certificate {
tbs_certificate: TBSCertificate,
signature_algorithm: AlgorithmIdentifier,
signature_value: BitString,
}
#[derive(Asn1Choice, Debug, Clone)]
enum Time {
Utc(UtcTime),
}
println!("1. Creating Certificate Structure\n");
let alg_id = AlgorithmIdentifier {
algorithm: ObjectIdentifier::from_str("1.2.840.113549.1.1.11").unwrap(), parameters: None,
};
let validity = Validity {
not_before: UtcTime::new(2024, 1, 1, 0, 0, 0).unwrap(),
not_after: UtcTime::new(2025, 1, 1, 0, 0, 0).unwrap(),
};
let issuer = Name {
common_name: PrintableString::new("Example CA".to_string()).unwrap(),
};
let subject = Name {
common_name: PrintableString::new("example.com".to_string()).unwrap(),
};
let tbs = TBSCertificate {
version: Some(Integer::from(2)), serial_number: Integer::from(123456),
signature: alg_id.clone(),
issuer: issuer.clone(),
validity,
subject,
};
let cert = Certificate {
tbs_certificate: tbs,
signature_algorithm: alg_id,
signature_value: BitString::new(vec![0xDE, 0xAD, 0xBE, 0xEF], 0).unwrap(),
};
println!("Created certificate with:");
println!(" - Version: v3");
println!(" - Serial: 123456");
println!(" - Algorithm: SHA-256 with RSA (1.2.840.113549.1.1.11)");
println!(" - Issuer: Example CA");
println!(" - Subject: example.com");
println!("\n2. Encoding Certificate\n");
let encoded = cert.to_der().expect("Failed to encode certificate");
println!("Encoded certificate: {} bytes", encoded.len());
println!(
"First 32 bytes: {:02X?}...",
&encoded[..32.min(encoded.len())]
);
println!("\n3. Decoding Certificate\n");
let decoded_cert = Certificate::from_der(&encoded).expect("Failed to decode certificate");
println!("Successfully decoded certificate!");
println!(
" - Serial number matches: {}",
decoded_cert.tbs_certificate.serial_number.as_i64().unwrap() == 123456
);
println!(
" - Version matches: {}",
decoded_cert.tbs_certificate.version.is_some()
);
println!("\n4. Tagged Fields Example\n");
println!("Version field uses [0] EXPLICIT tag");
println!("This wrapping is automatic with #[asn1(tag(0, explicit))]");
println!("\n5. CHOICE Type Example\n");
let time = Time::Utc(UtcTime::new(2024, 6, 15, 12, 30, 0).unwrap());
let encoded_time = time.to_der().expect("Failed to encode time");
println!("Encoded CHOICE (Time): {} bytes", encoded_time.len());
let decoded_time = Time::from_der(&encoded_time).expect("Failed to decode time");
match decoded_time {
Time::Utc(utc) => println!("Decoded UTC time: {:?}", utc),
}
println!("\n=== Summary ===\n");
println!("Derive macros eliminate ~150 lines of boilerplate per struct!");
println!("No manual Encode/Decode/Tagged implementations needed.");
println!("Tagged fields (#[asn1(tag(...))]) are handled automatically.");
println!("CHOICE types work seamlessly with enums.");
}
#[cfg(not(feature = "derive"))]
fn main() {
println!("This example requires the 'derive' feature.");
println!("Run with: cargo run --example derive_usage --features derive");
}