# 6. `example_certificate_builder.py` — X.509 certificate building
[← Example index](index.md) · [example_certificate_builder.py on Codeberg](https://codeberg.org/abbra/synta/src/branch/main/examples/example_certificate_builder.py)
Bindings: `CertificateBuilder` (`issuer_name`, `subject_name`, `public_key`,
`public_key_der`, `serial_number`, `not_valid_before_utc`, `not_valid_after_utc`,
`add_extension`, `sign`, `sign_unsigned`); `NameBuilder`; `PrivateKey.generate_ec`;
`PublicKey.to_der`; `synta.ext.SubjectAlternativeNameBuilder`,
`synta.ext.ExtendedKeyUsageBuilder`, `synta.ext.basic_constraints`,
`synta.ext.key_usage`, `synta.ext.subject_key_identifier`,
`synta.ext.authority_key_identifier`, `synta.ext.KU_*` bitmask constants.
- Generate a self-signed CA certificate with `PrivateKey.generate_ec("P-256")`,
`NameBuilder`, and `CertificateBuilder` (basicConstraints CA:TRUE, keyUsage
keyCertSign+cRLSign, subjectKeyIdentifier); verify DER round-trip.
- Issue a leaf certificate signed by the CA key with `issuer_name` from
`ca_cert.subject_raw_der`, SAN from `SubjectAlternativeNameBuilder`, EKU
from `ExtendedKeyUsageBuilder` (serverAuth), basicConstraints CA:FALSE,
authorityKeyIdentifier, and keyUsage digitalSignature+keyEncipherment.
- Demonstrate `public_key_der()` setter: pass pre-encoded SPKI DER bytes directly
(zero re-encoding); verify `cert.subject_public_key_info_der` round-trip.
- Show `sign_unsigned()` (RFC 9925): confirm `signature_algorithm_oid` is
`id-alg-unsigned` (1.3.6.1.5.5.7.6.36) and `signature_value` is empty.
## Source
```python
#!/usr/bin/env python3
"""
Example 6: X.509 certificate building.
Demonstrates: CertificateBuilder (issuer_name, subject_name, public_key,
public_key_der, serial_number, not_valid_before_utc, not_valid_after_utc,
add_extension, sign, sign_unsigned); NameBuilder; PrivateKey.generate_ec;
PublicKey.to_der; synta.ext.SubjectAlternativeNameBuilder,
synta.ext.ExtendedKeyUsageBuilder, synta.ext.basic_constraints,
synta.ext.key_usage, synta.ext.subject_key_identifier,
synta.ext.authority_key_identifier, synta.ext.KU_* constants.
"""
import datetime
import synta
import synta.ext as ext
def section(title):
print(f"\n{'─' * 60}\n{title}\n{'─' * 60}")
_UTC = datetime.timezone.utc
_NOW = datetime.datetime(2026, 1, 1, tzinfo=_UTC)
_TWO_YEARS = datetime.datetime(2028, 1, 1, tzinfo=_UTC)
_ONE_YEAR = datetime.datetime(2027, 1, 1, tzinfo=_UTC)
def demo_self_signed_ca():
section("CertificateBuilder — self-signed CA certificate")
# Generate an EC P-256 key pair for the CA.
ca_key = synta.PrivateKey.generate_ec("P-256")
assert ca_key.key_type == "ec"
assert ca_key.public_key.curve_name == "P-256"
# Build the CA distinguished name.
ca_name = (
synta.NameBuilder()
.country("US")
.organization("Synta")
.common_name("Test CA")
.build()
)
print(f" CA name DER: <{len(ca_name)} bytes>")
# Encode extensions for a CA certificate.
bc_der = ext.basic_constraints(ca=True, path_length=0)
ku_der = ext.key_usage(ext.KU_KEY_CERT_SIGN | ext.KU_CRL_SIGN)
spki_der = ca_key.public_key.to_der()
ski_der = ext.subject_key_identifier(spki_der)
# Build and sign the self-signed CA certificate.
ca_cert = (
synta.CertificateBuilder()
.issuer_name(ca_name)
.subject_name(ca_name)
.public_key(ca_key.public_key)
.serial_number(1)
.not_valid_before_utc(_NOW)
.not_valid_after_utc(_TWO_YEARS)
.add_extension("2.5.29.19", True, bc_der) # basicConstraints critical
.add_extension("2.5.29.15", True, ku_der) # keyUsage critical
.add_extension("2.5.29.14", False, ski_der) # subjectKeyIdentifier
.sign(ca_key, "sha256")
)
assert isinstance(ca_cert, synta.Certificate)
print(f" CA cert issuer: {ca_cert.issuer}")
print(f" CA cert subject: {ca_cert.subject}")
print(f" CA cert serial: {ca_cert.serial_number}")
print(f" CA cert DER: <{len(ca_cert.to_der())} bytes>")
# Verify DER round-trip
ca_cert2 = synta.Certificate.from_der(ca_cert.to_der())
assert ca_cert2.issuer == ca_cert.issuer
assert ca_cert2.subject == ca_cert.subject
print(" DER round-trip: OK")
# Confirm basicConstraints is present and critical
bc_ext = ca_cert.get_extension_value_der("2.5.29.19")
assert bc_ext is not None
print(f" basicConstraints value: {bc_ext.hex()}")
return ca_cert, ca_key
def demo_leaf_certificate(ca_cert, ca_key):
section("CertificateBuilder — leaf certificate signed by CA")
# Generate a fresh EC P-256 key for the leaf.
leaf_key = synta.PrivateKey.generate_ec("P-256")
# Build the leaf subject name.
leaf_name = (
synta.NameBuilder()
.common_name("leaf.example.com")
.build()
)
# Build extensions for the leaf certificate.
san_der = (
ext.SubjectAlternativeNameBuilder()
.dns_name("leaf.example.com")
.dns_name("www.leaf.example.com")
.build()
)
eku_der = (
ext.ExtendedKeyUsageBuilder()
.server_auth()
.build()
)
bc_ee = ext.basic_constraints(ca=False)
ku_ee = ext.key_usage(ext.KU_DIGITAL_SIGNATURE | ext.KU_KEY_ENCIPHERMENT)
spki_der = leaf_key.public_key.to_der()
ski_der = ext.subject_key_identifier(spki_der)
# Authority key identifier derived from the CA's public key
ca_spki_der = ca_key.public_key.to_der()
aki_der = ext.authority_key_identifier(ca_spki_der)
# Use the CA cert's subject_raw_der as the leaf's issuer.
leaf_cert = (
synta.CertificateBuilder()
.issuer_name(ca_cert.subject_raw_der)
.subject_name(leaf_name)
.public_key(leaf_key.public_key)
.serial_number(2)
.not_valid_before_utc(_NOW)
.not_valid_after_utc(_ONE_YEAR)
.add_extension("2.5.29.17", False, san_der) # subjectAltName
.add_extension("2.5.29.37", False, eku_der) # extendedKeyUsage
.add_extension("2.5.29.19", False, bc_ee) # basicConstraints
.add_extension("2.5.29.15", True, ku_ee) # keyUsage critical
.add_extension("2.5.29.14", False, ski_der) # subjectKeyIdentifier
.add_extension("2.5.29.35", False, aki_der) # authorityKeyIdentifier
.sign(ca_key, "sha256")
)
assert isinstance(leaf_cert, synta.Certificate)
print(f" Leaf cert issuer: {leaf_cert.issuer}")
print(f" Leaf cert subject: {leaf_cert.subject}")
print(f" Leaf cert serial: {leaf_cert.serial_number}")
print(f" Leaf cert DER: <{len(leaf_cert.to_der())} bytes>")
print(f" signature_algorithm: {leaf_cert.signature_algorithm}")
# Check the SAN extension is present
san_ext = leaf_cert.get_extension_value_der("2.5.29.17")
assert san_ext is not None
print(f" subjectAltName value: <{len(san_ext)} bytes> OK")
# Check the EKU extension is present
eku_ext = leaf_cert.get_extension_value_der("2.5.29.37")
assert eku_ext is not None
print(f" extendedKeyUsage value: <{len(eku_ext)} bytes> OK")
# DER round-trip
leaf_cert2 = synta.Certificate.from_der(leaf_cert.to_der())
assert leaf_cert2.subject == leaf_cert.subject
assert leaf_cert2.serial_number == 2
print(" DER round-trip: OK")
return leaf_cert
def demo_public_key_der_setter():
section("CertificateBuilder.public_key_der — use pre-encoded SPKI bytes")
key = synta.PrivateKey.generate_ec("P-256")
spki_der = key.public_key.to_der() # raw SubjectPublicKeyInfo DER
name_der = synta.NameBuilder().common_name("SPKI DER Test").build()
bc_der = ext.basic_constraints()
cert = (
synta.CertificateBuilder()
.issuer_name(name_der)
.subject_name(name_der)
.public_key_der(spki_der) # pre-encoded SPKI
.serial_number(99)
.not_valid_before_utc(_NOW)
.not_valid_after_utc(_ONE_YEAR)
.add_extension("2.5.29.19", False, bc_der)
.sign(key, "sha256")
)
assert isinstance(cert, synta.Certificate)
assert cert.serial_number == 99
# The public key DER stored in the cert must match what we passed
assert cert.subject_public_key_info_der == spki_der
print(f" subject_public_key_info_der matches input SPKI: OK")
print(f" cert DER: <{len(cert.to_der())} bytes>")
def demo_sign_unsigned():
section("CertificateBuilder.sign_unsigned — RFC 9925 unsigned certificate")
key = synta.PrivateKey.generate_ec("P-256")
name_der = synta.NameBuilder().common_name("Unsigned Root").build()
bc_der = ext.basic_constraints(ca=True, path_length=0)
ku_der = ext.key_usage(ext.KU_KEY_CERT_SIGN | ext.KU_CRL_SIGN)
spki_der = key.public_key.to_der()
ski_der = ext.subject_key_identifier(spki_der)
unsigned_cert = (
synta.CertificateBuilder()
.issuer_name(name_der)
.subject_name(name_der)
.public_key(key.public_key)
.serial_number(1)
.not_valid_before_utc(_NOW)
.not_valid_after_utc(_TWO_YEARS)
.add_extension("2.5.29.19", True, bc_der)
.add_extension("2.5.29.15", True, ku_der)
.add_extension("2.5.29.14", False, ski_der)
.sign_unsigned()
)
assert isinstance(unsigned_cert, synta.Certificate)
print(f" unsigned cert issuer: {unsigned_cert.issuer}")
print(f" signature_algorithm: {unsigned_cert.signature_algorithm}")
# RFC 9925: id-alg-unsigned = 1.3.6.1.5.5.7.6.36
assert str(unsigned_cert.signature_algorithm_oid) == "1.3.6.1.5.5.7.6.36", (
f"expected id-alg-unsigned OID, got {unsigned_cert.signature_algorithm_oid}"
)
print(f" id-alg-unsigned OID: {unsigned_cert.signature_algorithm_oid} OK")
# Signature value is a zero-length BIT STRING
assert len(unsigned_cert.signature_value) == 0
print(f" signature_value length: {len(unsigned_cert.signature_value)} (zero — OK)")
# DER round-trip
unsigned_cert2 = synta.Certificate.from_der(unsigned_cert.to_der())
assert unsigned_cert2.subject == unsigned_cert.subject
print(" DER round-trip: OK")
def main():
print("=" * 60)
print("Example 31: X.509 certificate building")
print("=" * 60)
ca_cert, ca_key = demo_self_signed_ca()
demo_leaf_certificate(ca_cert, ca_key)
demo_public_key_der_setter()
demo_sign_unsigned()
print("\nAll certificate builder examples completed.")
if __name__ == "__main__":
main()
```