synta 0.1.1

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
#!/usr/bin/env python3
"""
Example 6: CRL (Certificate Revocation List) parsing.

Demonstrates: CertificateList.from_der, CertificateList.from_pem,
CertificateList.to_pem, and all CertificateList properties
(issuer, issuer_raw_der, this_update, next_update, signature_algorithm,
signature_algorithm_oid, signature_value, revoked_count, to_der).
"""

import synta

# Minimal CRL DER: RSA, CN=Test CA, thisUpdate=2026-01-01, nextUpdate=2026-07-01
_CRL_DER = bytes.fromhex(
    "3082015a3044020101300d06092a864886f70d01010b050030123110300e0603"
    "5504030c0754657374204341170d3236303130313030303030305a170d323630"
    "3730313030303030305a300d06092a864886f70d01010b050003820101004195"
    "618e7d6d6a6440919e872408156017646fd8cb0d617c6952755bfeb5b5f6391d"
    "62b7257c7f94f461851f48ef9f9ade7c05e96679c25f8cb70b619bbc34b16a9"
    "4ceaa072d66d2985407bcd6376925ba7d89fa6861cb7811c8571c9e6bb5d86a5"
    "aad7cf3b62b63e7269b90d11d0e5a5cd54fa50edc6747e997f61738866b6f00"
    "6c9bace2daba18b5bcedaa4bc25cf9add69b3680e6b170b3f57d82e74451d1a"
    "2a1968db64c7d189c8869bd47a16bf91a0c6940cda54cdcbe355176792dc787"
    "2f2a162a2482df9d7d1c6af568808962b23479bbd8229fac19cab7798d9a83f0"
    "0ea4d83a6c61a4e720966e4ee4d9c3bbc3bdb94afde24fc70c8adb265ae15104"
)


def section(title):
    print(f"\n{'' * 60}\n{title}\n{'' * 60}")


def demo_all_properties():
    section("CertificateList — all properties")
    crl = synta.CertificateList.from_der(_CRL_DER)

    print(f"  issuer:                   {crl.issuer}")
    print(f"  issuer_raw_der:           <{len(crl.issuer_raw_der)} bytes>")
    print(f"  this_update:              {crl.this_update}")
    print(f"  next_update:              {crl.next_update!r}")
    print(f"  signature_algorithm:      {crl.signature_algorithm}")
    print(f"  signature_algorithm_oid:  {crl.signature_algorithm_oid}")
    print(f"  signature_value:          <{len(crl.signature_value)} bytes>")
    print(f"  revoked_count:            {crl.revoked_count}")
    print(f"  to_der:                   <{len(crl.to_der())} bytes>")


def demo_next_update_optional():
    section("next_update — present vs absent")
    crl = synta.CertificateList.from_der(_CRL_DER)
    nu = crl.next_update
    if nu is not None:
        print(f"  next_update present: {nu}")
    else:
        print("  next_update: None (CRL omits the field)")
    # RFC 5280 §5.1.2.5: nextUpdate is OPTIONAL for indirect CRLs;
    # the field is None when the CRL does not include it


def demo_to_der_roundtrip():
    section("to_der() round-trip")
    crl = synta.CertificateList.from_der(_CRL_DER)
    der2 = crl.to_der()
    assert der2 == _CRL_DER, "DER round-trip mismatch"
    print("  to_der round-trip: OK (byte-identical)")


def demo_pem_roundtrip():
    section("from_pem / to_pem round-trip")
    crl = synta.CertificateList.from_der(_CRL_DER)
    pem = synta.CertificateList.to_pem(crl)
    assert pem.startswith(b"-----BEGIN X509 CRL-----")
    print(f"  to_pem(): {len(pem)} bytes")

    crl2 = synta.CertificateList.from_pem(pem)
    assert isinstance(crl2, synta.CertificateList)
    assert crl2.issuer == crl.issuer
    assert crl2.revoked_count == crl.revoked_count
    print(f"  from_pem(): issuer={crl2.issuer}  revoked={crl2.revoked_count}")
    print("  PEM round-trip: OK")


def main():
    print("=" * 60)
    print("Example 6: CRL parsing")
    print("=" * 60)
    demo_all_properties()
    demo_next_update_optional()
    demo_to_der_roundtrip()
    demo_pem_roundtrip()
    print("\nAll CRL examples completed.")


if __name__ == "__main__":
    main()