synta 0.1.5

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# Attribute Certificates


`synta.ac` provides RFC 5755 Attribute Certificate v2 types. Attribute Certificates (ACs)
bind a set of attributes (roles, clearances, service-authentication information) to a holder
identified by reference to their Public Key Certificate (PKC), without requiring re-issuance
of the PKC.

```python
import synta.ac as ac
```

## AttributeCertificate

```python
class AttributeCertificate:
    @staticmethod
    def from_der(data: bytes) -> AttributeCertificate: ...
    # Raises ValueError if the bytes cannot be decoded.

    @staticmethod
    def from_pem(data: bytes) -> AttributeCertificate: ...
    # Parse the first ATTRIBUTE CERTIFICATE PEM block.
    # Raises ValueError if no valid PEM block is found or the DER is invalid.

    def to_der(self) -> bytes: ...
    def to_pem(self) -> str: ...
    # PEM encoding with the "ATTRIBUTE CERTIFICATE" label (RFC 5755).

    version: int                              # always 1 for v2 (RFC 5755)
    serial_number: bytes                      # certificate serial number as big-endian bytes
    not_before: str                           # "YYYYMMDDHHmmssZ"
    not_after: str                            # "YYYYMMDDHHmmssZ"
    signature_algorithm_oid: ObjectIdentifier
    signature: bytes                          # raw signature bytes (zero-byte padding stripped)
    holder_der: bytes                         # DER bytes of the Holder SEQUENCE
    issuer_der: bytes                         # DER bytes of the AttCertIssuer CHOICE
    attributes_der: bytes                     # DER bytes of SEQUENCE OF Attribute

    def verify_issued_by(self, issuer: Certificate) -> None: ...
    # Verify the cryptographic signature against issuer's public key.
    # No AC issuer-to-subject name comparison is performed.
    # Raises ValueError if the signature is invalid or encoding fails.
```

## AttributeCertificateBuilder

Fluent builder for RFC 5755 `AttributeCertificateInfo` TBS encoding.

```python
class AttributeCertificateBuilder:
    def __init__(self) -> None: ...

    def serial_number(self, n: int) -> AttributeCertificateBuilder: ...
    def not_before(self, s: str) -> AttributeCertificateBuilder: ...   # "YYYYMMDDHHmmssZ"
    def not_after(self, s: str) -> AttributeCertificateBuilder: ...    # "YYYYMMDDHHmmssZ"
    def issuer_rfc822(self, email: str) -> AttributeCertificateBuilder: ...
    def issuer_dns(self, name: str) -> AttributeCertificateBuilder: ...
    def holder_entity_name_rfc822(self, email: str) -> AttributeCertificateBuilder: ...
    def build(self) -> bytes: ...
    # Encode the AttributeCertificateInfo SEQUENCE to DER bytes.
    # Raises ValueError if any required field is missing or encoding fails.
```

## OID constants

| Constant | Description |
|---|---|
| `ID_PE_AC_AUDIT_IDENTITY` | Audit identity extension (RFC 5755 §4.4.1) |
| `ID_PE_AA_CONTROLS` | AA controls extension (RFC 5755 §4.4.2) |
| `ID_PE_AC_PROXYING` | AC proxying extension (RFC 5755 §4.4.3) |
| `ID_CE_TARGET_INFORMATION` | Target information extension (RFC 5755 §4.3.2) |
| `ID_ACA_AUTHENTICATION_INFO` | Authentication information attribute |
| `ID_ACA_ACCESS_IDENTITY` | Access identity attribute |
| `ID_ACA_CHARGING_IDENTITY` | Charging identity attribute |
| `ID_ACA_GROUP` | Group attribute |
| `ID_ACA_ENC_ATTRS` | Encrypted attributes |
| `ID_AT_ROLE` | Role attribute type |
| `ID_AT_CLEARANCE` | Clearance attribute type |

## Usage

```python
import synta
import synta.ac as ac

# Parse an attribute certificate
with open("holder.ac", "rb") as f:
    attr_cert = ac.AttributeCertificate.from_der(f.read())

print(f"version: {attr_cert.version}")
print(f"not_before: {attr_cert.not_before}")
print(f"not_after: {attr_cert.not_after}")
print(f"sig alg: {attr_cert.signature_algorithm_oid}")

# Verify the AC signature
issuer_cert = synta.Certificate.from_der(open("issuer.der", "rb").read())
try:
    attr_cert.verify_issued_by(issuer_cert)
    print("AC signature valid")
except ValueError as e:
    print(f"Invalid: {e}")

# Decode attributes (decode holder_der/attributes_der with synta.Decoder)
import synta
dec = synta.Decoder(attr_cert.attributes_der, synta.Encoding.DER)
attrs = dec.decode_sequence()
while not attrs.is_empty():
    attr_tlv = attrs.decode_raw_tlv()
    # attr_tlv is one complete Attribute SEQUENCE
```