synta 0.1.1

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
#!/usr/bin/env python3
"""
Example 5: PKCS#10 CSR parsing.

Demonstrates: CertificationRequest.from_der, CertificationRequest.from_pem,
CertificationRequest.to_pem, and all CertificationRequest properties
(subject, subject_raw_der, version, signature_algorithm, signature_algorithm_oid,
signature, public_key_algorithm, public_key_algorithm_oid, public_key, to_der).
"""

import synta

# Minimal CSR DER: RSA 2048, CN=test.example.com, O=Test Corp, C=US
_CSR_DER = bytes.fromhex(
    "3082028130820169020100303c3119301706035504030c10746573742e657861"
    "6d706c652e636f6d31123010060355040a0c095465737420436f7270310b3009"
    "06035504061302555330820122300d06092a864886f70d01010105000382010f"
    "003082010a0282010100ab58e2a00789193f4f9bf38287609d7cbe41abe69809"
    "2c9cab84867392a941c22599fbae06edfde4c2e347c303ff3766c29c07cbdc7"
    "54dfe963d7bda8518c81102f8e783913787ade8e2e4084e152f7895bf84ab9a"
    "494b2ebd682ae5ee4ffea728d4a03ba55e4c98d93c155f547c78387fcd1576e"
    "f3d4cac56304af2d8e1ddb64a512ce5e48cf4af16b223475abeb2ea37ed30aa"
    "4c7e5cde8df2a2e3a02fda1fa3f921c9925f52e9f7545b61152f0409f57666f"
    "2b48442d5fe172f241b838e4d5372935e4bf612d7152fea25a4e1a8d2cd1281"
    "b80ab20dd28405d7e29079c13d0b26ef1a5fe6d4266447a27a569a4803de0e1"
    "0ed799975b5eb68e670379bba230203010001a000300d06092a864886f70d01"
    "010b050003820101008644c965a495f06031835ceab2edb4de43dc52a2bef6b"
    "2d8d21acaf8f05704006b1608cf46c54582f113ba22a2e343e62bdcff600a97"
    "6b27dc68d44e8060fd66f23e87504f824f4cc9345778609dd73d140461f72ed"
    "85150a30704b9a32e1e7a858055adb88dcb54eca8993dcb34b6f681fbb8a6c7"
    "b9429bac8f433bdb777f7893b0f67d8ed83f5cf65a02fe840fe8999d4540b88"
    "8d9e1df0f4b1adc2535f8a298c2961138aa7d161ad39f0452b1bb76cf6fe4d7"
    "3a3a1108ecac1939addad1e83322b2c0ebf5b98acd20fae9b6bf6a7a844f5d5"
    "f679e3d3059c3e465050ae8860532b8e1aaa87a68a93410e44db25297e9638d"
    "8f06eb86c5ccfb00b27a010785"
)


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


def demo_all_properties():
    section("CertificationRequest — all properties")
    csr = synta.CertificationRequest.from_der(_CSR_DER)

    print(f"  version:                  {csr.version!r}  (0 = v1)")
    print(f"  subject:                  {csr.subject}")
    print(f"  subject_raw_der:          <{len(csr.subject_raw_der)} bytes>")
    print(f"  signature_algorithm:      {csr.signature_algorithm}")
    print(f"  signature_algorithm_oid:  {csr.signature_algorithm_oid}")
    print(f"  signature:                <{len(csr.signature)} bytes>")
    print(f"  public_key_algorithm:     {csr.public_key_algorithm}")
    print(f"  public_key_algorithm_oid: {csr.public_key_algorithm_oid}")
    print(f"  public_key:               <{len(csr.public_key)} bytes>")
    print(f"  to_der:                   <{len(csr.to_der())} bytes>")


def demo_pem_roundtrip():
    section("from_pem / to_pem round-trip")
    csr = synta.CertificationRequest.from_der(_CSR_DER)

    # Serialize to PEM
    pem = synta.CertificationRequest.to_pem(csr)
    assert pem.startswith(b"-----BEGIN CERTIFICATE REQUEST-----"), repr(pem[:40])
    print(f"  to_pem(): {len(pem)} bytes")
    print(f"  First line: {pem.split(b'\\n')[0].decode()}")

    # Re-parse from PEM
    csr2 = synta.CertificationRequest.from_pem(pem)
    assert isinstance(csr2, synta.CertificationRequest)
    assert csr2.subject == csr.subject
    print(f"  from_pem(): subject={csr2.subject}")
    print("  PEM round-trip: OK")


def demo_subject_raw_der():
    section("Verify subject_raw_der by re-decoding as Name SEQUENCE")
    csr = synta.CertificationRequest.from_der(_CSR_DER)
    raw = csr.subject_raw_der
    print(f"  subject_raw_der: <{len(raw)} bytes>  starts 0x{raw[0]:02x}")

    # The raw bytes are a DER SEQUENCE (0x30) wrapping the RDN sequence
    assert raw[0] == 0x30, f"Expected SEQUENCE tag, got 0x{raw[0]:02x}"

    # Decode the outermost SEQUENCE to reach the first RDN
    dec = synta.Decoder(raw, synta.Encoding.DER)
    outer = dec.decode_sequence()          # SEQUENCE (Name)
    rdn_set = outer.decode_set()           # SET (RelativeDistinguishedName)
    atv_seq = rdn_set.decode_sequence()    # SEQUENCE (AttributeTypeAndValue)
    oid = atv_seq.decode_oid()
    value_obj = atv_seq.decode_any()
    print(f"  First RDN: OID={oid}  value={value_obj!r}")


def main():
    print("=" * 60)
    print("Example 5: PKCS#10 CSR parsing")
    print("=" * 60)
    demo_all_properties()
    demo_pem_roundtrip()
    demo_subject_raw_der()
    print("\nAll CSR examples completed.")


if __name__ == "__main__":
    main()