# 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
| `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
```