synta 0.1.8

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
#!/usr/bin/env python3
"""
Example 2: All Certificate properties.

Demonstrates: Certificate.from_der, Certificate.full_from_der, all Certificate
properties (serial_number, version, issuer, issuer_raw_der, subject, subject_raw_der,
not_before, not_after, signature_algorithm, signature_algorithm_oid,
signature_algorithm_params, signature_value, public_key_algorithm,
public_key_algorithm_oid, public_key_algorithm_params, public_key, tbs_bytes, to_der).
"""

import base64
import synta

# Self-signed RSA certificate (SHA-256 with RSA, no AlgorithmParameters)
_RSA_CERT_B64 = (
    "MIIDiTCCAnGgAwIBAgIUXhaeS3ad5SJp60GRJU73OQaO0xkwDQYJKoZIhvcNAQEL"
    "BQAwVDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJh"
    "bmNpc2NvMQ0wCwYDVQQKDARUZXN0MREwDwYDVQQDDAh0ZXN0LmNvbTAeFw0yNjAy"
    "MjMxMDU0MzRaFw0yNzAyMjMxMDU0MzRaMFQxCzAJBgNVBAYTAlVTMQswCQYDVQQI"
    "DAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwEVGVzdDERMA8G"
    "A1UEAwwIdGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDP"
    "9oir0NwIXFZ6gOUo//akzjNjvUhA/V1KSUY0L/iXOGWRHFcdcf4gVhoCgR+DgCV6"
    "bJKKrYPIvfEwmd8DdpPj1WU4Dztb4NNLgxquFZym2Swe0xDLQdtWoIQYerF/ER8D"
    "9Pk0qQ5QVaCO+KB3UKyXiJwcTc/LJnDqEX24mrf0ZH/HqB2GsUE3aI9aW5Lgwm9A"
    "7+gV7FrumaT7fQqpfNucWwlXU2SIRm//JKUrT0MGrh99vmmkGRZK+c9wLfIK+pny"
    "UQxSD1E395bpQTqTWIfcMWti6af3ix3GsWeoXwY+GDfZlZ1w22GjLmSgg1RMhhKZ"
    "9l+QFnI/GtmiXX2pCRZfAgMBAAGjUzBRMB0GA1UdDgQWBBRCjPvAUpiRe0Zs6DTL"
    "K+KLoTZfezAfBgNVHSMEGDAWgBRCjPvAUpiRe0Zs6DTLK+KLoTZfezAPBgNVHRMB"
    "Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC+xBpTScGlcZGYvwtWLZuF2qRu"
    "o9xhYzHXgIDJglXZ8i70O+ut2WRyI9RJOSMsa7BI2qmc87Ki9ZMCO2QIMQCQo7cB"
    "kZtQvK8iGGHhSwepMORekzdbfUUs7N4YEM3Xako1+4RzL+T1Z3qzQ6nrnQ+gYyQo"
    "GiIFKbYZONu2OlqXGQe5LPwbsPU52GUbttkxodaHgCdP7yKO/l3sDifXpaFEXJhY"
    "5RZqgSG77jymh8YKcY0X9J53OtP1So/IOS1Za137k+eYci6iCB4w511qEhSRZdCy"
    "+3NEoGrBearMcJHttGbMplR6TU6fDFRIUAdelPdWfpfmtl1iElRDwNdQkBBR"
)

# Self-signed Ed25519 certificate (no algorithm parameters)
_ED25519_CERT_B64 = (
    "MIIBCTCBvAIJAIBHPQHOoJaEMA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMMGHRl"
    "c3QtZWQyNTUxOS5leGFtcGxlLmNvbTAeFw0yNjAxMDEwMDAwMDBaFw0yNzAxMDEw"
    "MDAwMDBaMCMxITAfBgNVBAMMGHRlc3QtZWQyNTUxOS5leGFtcGxlLmNvbTAqMAUG"
    "AyqGSAOBIQADIQCKk93VN9S3P0sJrTFRqw7oqNKXl+e1VQ/3YwTIBiIoRzANBgkq"
    "hkiG9w0BAQsFAAOBgQAYv3bfBpU80lrHJYJTN7wf+rYUl1F0HLMkBHH2d0g+GHdk"
    "vDiLaYrJlIZiJMjbmxhHHLG2K0P7JZpq5CJ5dVNBa8oHa31i+C7hxGsFEJRbuwP3"
    "qs4DEF/d/oOiexhw8G97xosTEqdgdCFXLl6IIBz3u1MxB/r5Z9Yy+mFIiMnkFg=="
)


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


def demo_lazy_vs_eager():
    section("from_der (lazy) vs full_from_der (eager)")
    der = base64.b64decode(_RSA_CERT_B64)

    lazy = synta.Certificate.from_der(der)
    eager = synta.Certificate.full_from_der(der)

    # Both expose the same data
    assert lazy.subject == eager.subject
    print(f"  lazy  subject: {lazy.subject}")
    print(f"  eager subject: {eager.subject}")
    print("  Both yield the same data: OK")


def demo_all_properties():
    section("All Certificate properties (RSA cert)")
    der = base64.b64decode(_RSA_CERT_B64)
    cert = synta.Certificate.from_der(der)

    print(f"  version:                  {cert.version!r}  (0=v1, 1=v2, 2=v3)")
    print(f"  serial_number:            {cert.serial_number!r}  (Python int)")
    print(f"  issuer:                   {cert.issuer}")
    print(f"  issuer_raw_der:           <{len(cert.issuer_raw_der)} bytes>")
    print(f"  subject:                  {cert.subject}")
    print(f"  subject_raw_der:          <{len(cert.subject_raw_der)} bytes>")
    print(f"  not_before:               {cert.not_before}")
    print(f"  not_after:                {cert.not_after}")
    print(f"  signature_algorithm:      {cert.signature_algorithm}")
    print(f"  signature_algorithm_oid:  {cert.signature_algorithm_oid}")
    print(f"  signature_algorithm_params:{cert.signature_algorithm_params!r}")
    print(f"  public_key_algorithm:     {cert.public_key_algorithm}")
    print(f"  public_key_algorithm_oid: {cert.public_key_algorithm_oid}")
    print(f"  public_key_algorithm_params:{cert.public_key_algorithm_params!r}")
    print(f"  public_key:               <{len(cert.public_key)} bytes>")
    print(f"  signature_value:          <{len(cert.signature_value)} bytes>")
    print(f"  tbs_bytes:                <{len(cert.tbs_bytes)} bytes>")
    print(f"  to_der:                   <{len(cert.to_der())} bytes>")


def demo_to_der_roundtrip():
    section("to_der() round-trip")
    der = base64.b64decode(_RSA_CERT_B64)
    cert = synta.Certificate.from_der(der)
    der2 = cert.to_der()
    assert der2 == der, "Round-trip mismatch"
    cert2 = synta.Certificate.from_der(der2)
    assert cert2.serial_number == cert.serial_number
    print("  to_der round-trip: OK (DER is byte-identical)")


def demo_signature_params_difference():
    section("signature_algorithm_params: RSA has params, Ed25519 does not")
    rsa_der = base64.b64decode(_RSA_CERT_B64)
    rsa_cert = synta.Certificate.from_der(rsa_der)
    print(f"  RSA   signature_algorithm_params: {rsa_cert.signature_algorithm_params!r}")
    # RSA SHA-256 AlgorithmIdentifier carries a NULL parameters field
    assert rsa_cert.signature_algorithm_params is not None

    # For the types demo with an actually present Ed25519 cert (embedded above)
    # Note: signature_algorithm_params is None for pure ECDSA / EdDSA OIDs
    # We show this by checking the type OID
    assert str(rsa_cert.signature_algorithm_oid) == "1.2.840.113549.1.1.11"  # sha256WithRSAEncryption
    print("  RSA sig OID:  1.2.840.113549.1.1.11 (sha256WithRSAEncryption) — params present (NULL)")
    print("  Ed25519 OIDs carry no parameters field; params would be None")


def main():
    print("=" * 60)
    print("Example 2: All Certificate properties")
    print("=" * 60)
    demo_lazy_vs_eager()
    demo_all_properties()
    demo_to_der_roundtrip()
    demo_signature_params_difference()
    print("\nAll Certificate field examples completed.")


if __name__ == "__main__":
    main()