synta 0.1.5

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# Migrating from OpenSSL

Guide for Rust developers moving from OpenSSL bindings (`openssl` crate or manual
`openssl-sys` calls) to the synta and synta-certificate crates.

## Why migrate

| Aspect | OpenSSL (Rust bindings) | Synta |
|--------|------------------------|-------|
| Safety | Unsafe FFI under the hood | Pure Rust; no unsafe in hot paths |
| Error handling | `openssl::error::ErrorStack` (global queue) | `synta::Error` (return value) |
| Encoding API | `i2d_*` / `d2i_*` C round-trips | `Encoder` / `Decoder` types |
| Lifetime complexity | `ForeignType` references, `&OpenSslRef` | Rust lifetimes on borrowed types |
| no_std | Not supported | Supported (alloc-only feature level) |
| Post-quantum | Not supported in stable builds | ML-DSA / ML-KEM built-in |

## Decoding comparison

**OpenSSL (`openssl` crate)**

```rust,ignore
use openssl::asn1::Asn1Integer;
use openssl::bn::BigNum;

let asn1_int = Asn1Integer::from_der(data)?;
let bn = asn1_int.to_bn()?;
let value = bn.to_dec_str()?;
```

**Synta**

```rust,ignore
use synta::{Decoder, Encoding};
use synta::Integer;

let mut dec = Decoder::new(data, Encoding::Der);
let integer: Integer = dec.decode()?;
let value: i64 = integer.as_i64().unwrap_or_default();
```

## Encoding comparison

**OpenSSL (`openssl` crate)**

```rust,ignore
use openssl::asn1::Asn1Integer;
use openssl::bn::BigNum;

let bn = BigNum::from_u32(42)?;
let asn1_int = Asn1Integer::from_bn(&bn)?;
let der = asn1_int.to_der()?;
```

**Synta**

```rust,ignore
use synta::{Encoder, Encoding, Integer};

let mut enc = Encoder::new(Encoding::Der);
enc.encode(&Integer::from(42u32))?;
let der = enc.finish()?;
```

## X.509 certificate parsing

**OpenSSL (`openssl` crate)**

```rust,ignore
use openssl::x509::X509;

let cert = X509::from_der(der)?;
let serial = cert.serial_number().to_bn()?.to_hex_str()?;
let issuer = cert.issuer_name();
let not_before = cert.not_before();
let not_after = cert.not_after();
```

**Synta**

```rust,ignore
use synta::{Decoder, Encoding};
use synta_certificate::Certificate;

let mut dec = Decoder::new(der, Encoding::Der);
let cert: Certificate = dec.decode()?;

let serial = &cert.tbs_certificate.serial_number;
let issuer = &cert.tbs_certificate.issuer;
let not_before = &cert.tbs_certificate.validity.not_before;
let not_after  = &cert.tbs_certificate.validity.not_after;
```

## Certificate building

**OpenSSL (`openssl` crate)**

```rust,ignore
use openssl::x509::{X509, X509Builder};
use openssl::x509::extension::BasicConstraints;
use openssl::pkey::PKey;
use openssl::hash::MessageDigest;

let mut builder = X509Builder::new()?;
builder.set_version(2)?;
builder.set_serial_number(&serial)?;
builder.set_issuer_name(&issuer_name)?;
builder.set_subject_name(&subject_name)?;
builder.set_not_before(&not_before)?;
builder.set_not_after(&not_after)?;
builder.set_pubkey(&pubkey)?;

let bc = BasicConstraints::new().critical().ca().build()?;
builder.append_extension(bc)?;
builder.sign(&private_key, MessageDigest::sha256())?;

let cert = builder.build();
let der = cert.to_der()?;
```

**Synta**

```rust,ignore
use synta::{Integer, UtcTime};
use synta_certificate::{
    CertificateBuilder, OpensslCertificateSigner,
    Time, encode_basic_constraints, oids,
};
use openssl::pkey::PKey;

let signer = OpensslCertificateSigner::new(&pkey, "sha256");

// Encode the BasicConstraints extension value (CA=true, pathLen=0)
let bc_der = encode_basic_constraints(true, Some(0)).unwrap();

let der = CertificateBuilder::new()
    .serial_number(Integer::from(1i64))
    .issuer_name(issuer_der)
    .subject_name(subject_der)
    .not_valid_before(Time::UtcTime(UtcTime::new(2024, 1, 1, 0, 0, 0).unwrap()))
    .not_valid_after(Time::UtcTime(UtcTime::new(2025, 1, 1, 0, 0, 0).unwrap()))
    .public_key_der(spki_der)
    .add_extension_oid(oids::BASIC_CONSTRAINTS, true, &bc_der)
    .sign(&signer)?;
```

## Certificate chain verification

**OpenSSL (`openssl` crate)**

```rust,ignore
use openssl::ssl::{SslConnector, SslMethod};
use openssl::x509::store::X509StoreBuilder;

let mut store_builder = X509StoreBuilder::new()?;
store_builder.add_cert(root_cert)?;
let store = store_builder.build();

// OpenSSL verifies as part of TLS handshake or via X509_verify_cert
```

**Synta**

```rust,ignore
use synta_x509_verification::{
    ops::VerificationCertificate,
    policy::PolicyDefinition,
    trust_store::Store,
    types::DNSName,
    verify, RevocationChecks,
};
use synta_certificate::OpensslSignatureVerifier;

let root = VerificationCertificate::new(parse(&root_der), &root_der);
let store = Store::new([root]);
let hostname = DNSName::new("example.com").unwrap();
let now = std::time::SystemTime::now()
    .duration_since(std::time::UNIX_EPOCH)?
    .as_secs() as i64;

let policy = PolicyDefinition::new_server(
    OpensslSignatureVerifier,
    vec![synta_x509_verification::policy::Subject::Dns(hostname)],
    now,
);
let chain = verify(&leaf, &[intermediate], &policy, &store, RevocationChecks::default())?;
```

## Type mapping

| OpenSSL (`openssl` crate) | Synta |
|--------------------------|-------|
| `openssl::asn1::Asn1Integer` | `synta::Integer` |
| `openssl::asn1::Asn1String` | `synta::Utf8String` / `synta::IA5String` / etc. |
| `openssl::asn1::Asn1Object` | `synta::ObjectIdentifier` |
| `openssl::asn1::Asn1OctetString` | `synta::OctetString` |
| `openssl::asn1::Asn1BitString` | `synta::BitString` |
| `openssl::x509::X509` | `synta_certificate::Certificate<'a>` |
| `openssl::x509::X509Name` | `synta_certificate::Name<'a>` |
| `openssl::x509::X509NameEntry` | `synta_certificate::AttributeTypeAndValue<'a>` |
| `openssl::x509::X509Crl` | `synta_certificate::crl::CertificateList<'a>` |

## Error handling

**OpenSSL (`openssl` crate)**

```rust,ignore
use openssl::error::ErrorStack;

match some_openssl_call() {
    Ok(val) => { /* use val */ }
    Err(e) => {
        // ErrorStack: may contain multiple queued errors
        eprintln!("OpenSSL error: {}", e);
    }
}
```

**Synta**

```rust,ignore
use synta::Error;

match decoder.decode::<MyType>() {
    Ok(val) => { /* use val */ }
    Err(e) => {
        // Single Error value with position info
        eprintln!("Decode error: {}", e);
    }
}
```

## Benefits of migrating

1. **No global error state** — errors are returned values, not extracted from a
   thread-local queue.
2. **Lifetime-safe zero-copy** — borrowed variants (`OctetStringRef<'a>`,
   `BitStringRef<'a>`) eliminate copies without unsafe code.
3. **Post-quantum ready** — ML-DSA and ML-KEM are first-class algorithm types with
   parameter validation.
4. **no_std support** — drop `std` and keep `alloc` for embedded or WebAssembly
   targets.
5. **Schema-driven codegen** — write ASN.1 schemas and generate complete, typed
   structs rather than hand-coding decode/encode logic.