Lifecycle Managers

Synchronous

sync_lifecycle_manager.py

High-level orchestrator for the X.509 certificate lifecycle.

This module is the single entry-point for application code that needs to issue, store, revoke, rotate, or verify certificates. It delegates every specialised concern to the appropriate collaborator:

  • Cryptographic generation → CertificateFactory

  • File persistence → BaseStorage

  • Database registration → BaseDB

SOLID notes

SRPCertLifecycleManager coordinates operations; it contains no

cryptographic logic, no SQL, and no file I/O of its own.

OCPNew storage backends and database adapters plug in without changing

this class.

LSP : BaseStorage and BaseDB dependencies are fully substitutable. ISP : Interfaces are narrow; callers that only need issuance never interact

with revocation internals.

DIPAll three collaborators are injected at construction time; the manager

never instantiates them directly.

class tiny_ca.managers.sync_lifecycle_manager.CertLifecycleManager(storage=<tiny_ca.storage.local_storage.LocalStorage object>, factory=None, db_handler=None, logger=None)[source]

Bases: object

Orchestrates the full lifecycle of X.509 certificates.

CertLifecycleManager is the facade that application code interacts with. It coordinates four collaborators through dependency injection:

  • CertificateFactory — cryptographic generation of certificates and CRLs.

  • BaseStorage — persistent storage of PEM/key/CSR/CRL files.

  • BaseDB — registration, lookup, revocation, and rotation

    records in a relational database.

  • Logger — structured operational logging.

All three external collaborators are optional at construction time, but specific operations will raise ValueError or DBNotInitedError if a required collaborator is absent when that operation is invoked.

Parameters:
  • storage (BaseStorage) – File storage backend. Defaults to LocalStorage() which writes to ./certs relative to the working directory.

  • factory (CertificateFactory | None) – Cryptographic factory. Must be set before calling issue_certificate, generate_crl, or verify_certificate. Can be set after construction via the factory property setter.

  • db_handler (BaseDB | None) – Database adapter. When None, all operations that require persistence (status lookup, revocation, rotation) will raise DBNotInitedError.

  • logger (Logger | None) – Logger for operational messages. Falls back to DEFAULT_LOGGER.

Raises:
  • TypeError – If storage is not a BaseStorage instance.

  • TypeError – If db_handler is provided but is not a BaseDB instance.

__init__(storage=<tiny_ca.storage.local_storage.LocalStorage object>, factory=None, db_handler=None, logger=None)[source]
Parameters:
Return type:

None

cosign_certificate(cert, days_valid=None, valid_from=None)[source]
Return type:

Certificate

Parameters:
  • cert (Certificate)

  • days_valid (int | None)

  • valid_from (datetime | None)

create_self_signed_ca(config, cert_path=None, uuid_str=None, is_overwrite=False)[source]

Generate a self-signed root CA certificate and persist both artefacts.

Delegates cryptographic generation to CertificateFactory.build_self_signed_ca and then saves the certificate and private key through the configured BaseStorage. When a db_handler is present the certificate is also registered in the database.

Parameters:
  • config (CAConfig) – Pydantic model carrying common_name, organization, country, key_size, and days_valid.

  • cert_path (str | None) – Sub-directory under the storage base folder. None places the files directly in the base folder.

  • uuid_str (str | None) – Explicit UUID for the storage sub-directory. None causes the storage layer to generate one automatically.

  • is_overwrite (bool) – When True, any existing certificate with the same CN is revoked and its files are deleted before the new one is saved. When False (default), NotUniqueCertOwner is raised if a conflict exists.

Returns:

(path_to_cert_pem, path_to_key_pem) as returned by the storage layer.

Return type:

tuple[str, str]

delete_certificate(serial, cert_path=None)[source]

Hard-delete a certificate from the DB and its artefact folder from storage.

Returns True if the DB row was deleted (storage deletion is best-effort).

Return type:

bool

Parameters:
  • serial (int)

  • cert_path (str | None)

export_pkcs12(cert, private_key, password=None, name=None)[source]

Pack cert + key into a PKCS#12 bundle. Delegates to CertificateFactory.export_pkcs12.

Return type:

bytes

Parameters:
property factory: CertificateFactory | None

The active CertificateFactory used for certificate issuance.

Returns:

The current factory, or None if not yet initialised.

Return type:

CertificateFactory | None

generate_crl(cert_path=None, days_valid=1)[source]

Build, sign, and persist a fresh Certificate Revocation List.

Retrieves all currently-revoked certificates from the database, passes them to CertificateFactory.build_crl, and writes the resulting CRL to storage as crl.pem (overwriting any previous version — CRLs are always regenerated in-place).

Parameters:
  • days_valid (int) – Number of days until the CRL’s nextUpdate field. Relying parties will reject the CRL after this point. Default: 1.

  • cert_path (str | None)

Returns:

The signed CRL object (also persisted to storage).

Return type:

x509.CertificateRevocationList

Raises:
get_cert_chain(cert)[source]

Return [cert, ca_cert] chain. Delegates to CertificateFactory.get_cert_chain.

Return type:

list[Certificate]

Parameters:

cert (Certificate)

get_certificate_status(serial)[source]

Determine the current status of the certificate identified by serial.

Looks up the certificate record in the database and evaluates its state in the following priority order: 1. Not found → UNKNOWN 2. Revocation date is set → REVOKED 3. not_valid_after is in the past → EXPIRED 4. Otherwise → VALID

Parameters:

serial (int) – Integer serial number of the certificate to check.

Returns:

One of VALID, REVOKED, EXPIRED, or UNKNOWN.

Return type:

CertificateStatus

Raises:

DBNotInitedError – If no db_handler was provided.

get_expiring_soon(within_days=30)[source]

Return VALID certs expiring within within_days days. Requires db_handler.

Return type:

list[CertificateRecord]

Parameters:

within_days (int)

inspect_certificate(cert)[source]
Return type:

CertificateDetails

Parameters:

cert (Certificate)

issue_certificate(config, cert_path=None, uuid_str=None, is_overwrite=False)[source]

Issue a new end-entity certificate and persist all three artefacts.

The method generates the certificate, private key, and CSR via the configured CertificateFactory, then saves each file through BaseStorage. If a db_handler is configured the certificate metadata is also written to the database.

Artefacts written to storage

  • <file_name>.pem — the signed certificate.

  • <file_name>.key — the private key (unencrypted by default).

  • <file_name>.csr — the certificate signing request (for audit).

type config:

ClientConfig

param config:

Pydantic model containing all certificate parameters: common_name, serial_type, key_size, days_valid, email, is_server_cert, is_client_cert, san_dns, san_ip, and an optional name for the output file basename.

type config:

ClientConfig

type cert_path:

str | None

param cert_path:

Sub-directory under the storage base folder.

type cert_path:

str | None

type uuid_str:

str | None

param uuid_str:

Explicit UUID; None auto-generates one.

type uuid_str:

str | None

type is_overwrite:

bool

param is_overwrite:

Allow replacing an existing certificate with the same CN.

type is_overwrite:

bool

returns:

(certificate, private_key, csr) in-memory objects.

rtype:

tuple[x509.Certificate, rsa.RSAPrivateKey, x509.CertificateSigningRequest]

raises ValueError:

If self.factory has not been initialised.

raises NotUniqueCertOwner:

If is_overwrite is False and a certificate with the same CN already exists in the database.

Parameters:
Return type:

tuple[Certificate, object, CertificateSigningRequest]

issue_intermediate_ca(common_name, key_size=4096, days_valid=1825, valid_from=None, path_length=0, organization=None, country=None, cert_path=None, uuid_str=None)[source]

Issue a subordinate CA cert signed by this CA and save artefacts.

Returns (cert, private_key). The cert is NOT registered in the DB automatically — call register_cert_in_db if persistence is needed.

Return type:

tuple[Certificate, object]

Parameters:
  • common_name (str)

  • key_size (int)

  • days_valid (int)

  • valid_from (datetime)

  • path_length (int | None)

  • organization (str | None)

  • country (str | None)

  • cert_path (str | None)

  • uuid_str (str | None)

list_certificates(status=None, key_type=None, limit=100, offset=0)[source]

Return paginated certificate records. Requires db_handler.

Return type:

list[CertificateRecord]

Parameters:
  • status (str | None)

  • key_type (str | None)

  • limit (int)

  • offset (int)

refresh_expired_statuses()[source]

Bulk-mark expired certificates. Returns count of updated rows.

Return type:

int

renew_certificate(serial, days_valid=365, valid_from=None)[source]

Renew the certificate identified by serial: same key, new validity window.

Fetches the certificate PEM from the database, deserialises it, and delegates to CertificateFactory.renew_certificate.

Raises:
Return type:

Certificate

Parameters:
revoke_certificate(serial, reason)[source]

Revoke the certificate identified by serial.

Delegates to BaseDB.revoke_certificate. The record is updated in-place (status → REVOKED, revocation date and reason stored); no file is deleted. Call generate_crl afterwards to publish the updated revocation list.

Parameters:
  • serial (int) – Integer serial number of the certificate to revoke.

  • reason (x509.ReasonFlags) – RFC 5280 revocation reason code (e.g. x509.ReasonFlags.key_compromise).

Returns:

True if the revocation was recorded successfully; False if the operation failed (see logs for details).

Return type:

bool

Raises:

DBNotInitedError – If no db_handler was provided at construction time.

rotate_certificate(serial, config)[source]

Revoke an existing certificate and issue a replacement in a single operation.

The old certificate is revoked with reason superseded before the new one is issued. Both operations are performed against the configured db_handler; if the revocation fails an exception is propagated and the new certificate is not issued.

Parameters:
  • serial (int) – Serial number of the certificate to replace.

  • config (ClientConfig) – Parameters for the replacement certificate. The CN may differ from the original.

Returns:

(new_certificate, new_private_key, new_csr).

Return type:

tuple[x509.Certificate, rsa.RSAPrivateKey, x509.CertificateSigningRequest]

Raises:
verify_certificate(cert)[source]

Perform a full verification of cert: chain, signature, and revocation.

Combines cryptographic validation (via CertificateFactory.validate_cert) with a database revocation check (via get_certificate_status).

Validation steps

  1. Issuer field matches the CA subject.

  2. Current UTC time is within the validity window.

  3. Cryptographic signature is valid.

  4. Certificate is not listed as revoked in the database.

type cert:

Certificate

param cert:

The certificate object to verify.

type cert:

x509.Certificate

returns:

True when all checks pass.

rtype:

bool

raises ValueError:

If self.factory has not been initialised.

raises ValidationCertError:

If the certificate fails any cryptographic check or is revoked.

Parameters:

cert (Certificate)

Return type:

bool

verify_crl(crl)[source]

Verify CRL signature and expiry. Delegates to CertificateFactory.verify_crl.

Return type:

None

Parameters:

crl (CertificateRevocationList)

Asynchronous

class tiny_ca.managers.async_lifecycle_manager.AsyncCertLifecycleManager(storage=None, factory=None, db_handler=None, logger=None)[source]

Bases: object

Orchestrates the full lifecycle of X.509 certificates.

CertLifecycleManager is the facade that application code interacts with. It coordinates four collaborators through dependency injection:

  • CertificateFactory — cryptographic generation of certificates and CRLs.

  • BaseStorage — persistent storage of PEM/key/CSR/CRL files.

  • BaseDB — registration, lookup, revocation, and rotation

    records in a relational database.

  • Logger — structured operational logging.

All three external collaborators are optional at construction time, but specific operations will raise ValueError or DBNotInitedError if a required collaborator is absent when that operation is invoked.

Parameters:
  • storage (BaseStorage) – File storage backend. Defaults to LocalStorage() which writes to ./certs relative to the working directory.

  • factory (CertificateFactory | None) – Cryptographic factory. Must be set before calling issue_certificate, generate_crl, or verify_certificate. Can be set after construction via the factory property setter.

  • db_handler (BaseDB | None) – Database adapter. When None, all operations that require persistence (status lookup, revocation, rotation) will raise DBNotInitedError.

  • logger (Logger | None) – Logger for operational messages. Falls back to DEFAULT_LOGGER.

Raises:
  • TypeError – If storage is not a BaseStorage instance.

  • TypeError – If db_handler is provided but is not a BaseDB instance.

__init__(storage=None, factory=None, db_handler=None, logger=None)[source]
Parameters:
Return type:

None

async cosign_certificate(cert, days_valid=None, valid_from=None)[source]
Return type:

Certificate

Parameters:
  • cert (Certificate)

  • days_valid (int | None)

  • valid_from (datetime)

async create_self_signed_ca(config, cert_path=None, uuid_str=None, is_overwrite=False)[source]

Generate a self-signed root CA certificate and persist both artefacts.

Delegates cryptographic generation to CertificateFactory.build_self_signed_ca and then saves the certificate and private key through the configured BaseStorage. When a db_handler is present the certificate is also registered in the database.

configCAConfig

Pydantic model carrying common_name, organization, country, key_size, and days_valid.

cert_pathstr | None

Sub-directory under the storage base folder. None places the files directly in the base folder.

uuid_strstr | None

Explicit UUID for the storage sub-directory. None causes the storage layer to generate one automatically.

is_overwritebool

When True, any existing certificate with the same CN is revoked and its files are deleted before the new one is saved. When False (default), NotUniqueCertOwner is raised if a conflict exists.

tuple[str, str]

(path_to_cert_pem, path_to_key_pem) as returned by the storage layer.

>>> cert_path, key_path = await mgr.create_self_signed_ca(ca_config)
Return type:

tuple[Path, Path]

Parameters:
async delete_certificate(serial, cert_path=None)[source]

Hard-delete from DB + storage. Returns True if DB row was deleted.

Return type:

bool

Parameters:
  • serial (int)

  • cert_path (str | None)

async export_pkcs12(cert, private_key, password=None, name=None)[source]

Pack cert + key into PKCS#12 bytes. Runs in thread pool.

Return type:

bytes

Parameters:
property factory: CertificateFactory | None

The active CertificateFactory used for certificate issuance.

Returns:

The current factory, or None if not yet initialised.

Return type:

CertificateFactory | None

async generate_crl(cert_path=None, days_valid=1)[source]

Build, sign, and persist a fresh Certificate Revocation List.

Retrieves all currently-revoked certificates from the database, passes them to CertificateFactory.build_crl, and writes the resulting CRL to storage as crl.pem (overwriting any previous version — CRLs are always regenerated in-place).

Parameters:
  • days_valid (int) – Number of days until the CRL’s nextUpdate field. Relying parties will reject the CRL after this point. Default: 1.

  • cert_path (str | None)

Returns:

The signed CRL object (also persisted to storage).

Return type:

x509.CertificateRevocationList

Raises:
async get_cert_chain(cert)[source]

Return [cert, ca_cert] chain.

Return type:

list[Certificate]

Parameters:

cert (Certificate)

async get_certificate_status(serial)[source]

Determine the current status of the certificate identified by serial.

Looks up the certificate record in the database and evaluates its state in the following priority order: 1. Not found → UNKNOWN 2. Revocation date is set → REVOKED 3. not_valid_after is in the past → EXPIRED 4. Otherwise → VALID

Parameters:

serial (int) – Integer serial number of the certificate to check.

Returns:

One of VALID, REVOKED, EXPIRED, or UNKNOWN.

Return type:

CertificateStatus

Raises:

DBNotInitedError – If no db_handler was provided.

async get_expiring_soon(within_days=30)[source]

Return VALID certs expiring within within_days days.

Return type:

list[CertificateRecord]

Parameters:

within_days (int)

async inspect_certificate(cert)[source]
Return type:

CertificateDetails

Parameters:

cert (Certificate)

async issue_certificate(config, cert_path=None, uuid_str=None, is_overwrite=False)[source]

Issue a new end-entity certificate and persist all three artefacts.

The method generates the certificate, private key, and CSR via the configured CertificateFactory, then saves each file through BaseStorage. If a db_handler is configured the certificate metadata is also written to the database.

Artefacts written to storage

  • <file_name>.pem — the signed certificate.

  • <file_name>.key — the private key (unencrypted by default).

  • <file_name>.csr — the certificate signing request (for audit).

type config:

ClientConfig

param config:

Pydantic model containing all certificate parameters: common_name, serial_type, key_size, days_valid, email, is_server_cert, is_client_cert, san_dns, san_ip, and an optional name for the output file basename.

type config:

ClientConfig

type cert_path:

str | None

param cert_path:

Sub-directory under the storage base folder.

type cert_path:

str | None

type uuid_str:

str | None

param uuid_str:

Explicit UUID; None auto-generates one.

type uuid_str:

str | None

type is_overwrite:

bool

param is_overwrite:

Allow replacing an existing certificate with the same CN.

type is_overwrite:

bool

returns:

(certificate, private_key, csr) in-memory objects.

rtype:

tuple[x509.Certificate, rsa.RSAPrivateKey, x509.CertificateSigningRequest]

raises ValueError:

If self.factory has not been initialised.

raises NotUniqueCertOwner:

If is_overwrite is False and a certificate with the same CN already exists in the database.

Parameters:
Return type:

tuple[Certificate, object, CertificateSigningRequest]

async issue_intermediate_ca(common_name, key_size=4096, days_valid=1825, valid_from=None, path_length=0, organization=None, country=None, cert_path=None, uuid_str=None)[source]

Issue a subordinate CA cert signed by this CA and save artefacts.

Return type:

tuple[Certificate, object]

Parameters:
  • common_name (str)

  • key_size (int)

  • days_valid (int)

  • valid_from (datetime)

  • path_length (int | None)

  • organization (str | None)

  • country (str | None)

  • cert_path (str | None)

  • uuid_str (str | None)

async list_certificates(status=None, key_type=None, limit=100, offset=0)[source]

Return paginated certificate records. Requires db_handler.

Return type:

list[CertificateRecord]

Parameters:
  • status (str | None)

  • key_type (str | None)

  • limit (int)

  • offset (int)

async refresh_expired_statuses()[source]

Bulk-mark expired certificates. Returns count of updated rows.

Return type:

int

async renew_certificate(serial, days_valid=365, valid_from=None)[source]

Renew the certificate identified by serial: same key, new validity window.

Raises:

DBNotInitedError / CertNotFound / ValueError

Return type:

Certificate

Parameters:
async revoke_certificate(serial, reason)[source]

Revoke the certificate identified by serial.

Delegates to BaseDB.revoke_certificate. The record is updated in-place (status → REVOKED, revocation date and reason stored); no file is deleted. Call generate_crl afterwards to publish the updated revocation list.

Parameters:
  • serial (int) – Integer serial number of the certificate to revoke.

  • reason (x509.ReasonFlags) – RFC 5280 revocation reason code (e.g. x509.ReasonFlags.key_compromise).

Returns:

True if the revocation was recorded successfully; False if the operation failed (see logs for details).

Return type:

bool

Raises:

DBNotInitedError – If no db_handler was provided at construction time.

async rotate_certificate(serial, config, cert_path=None)[source]

Revoke an existing certificate and issue a replacement in a single operation.

The old certificate is revoked with reason superseded before the new one is issued. Both operations are performed against the configured db_handler; if the revocation fails an exception is propagated and the new certificate is not issued.

Parameters:
  • serial (int) – Serial number of the certificate to replace.

  • config (ClientConfig) – Parameters for the replacement certificate. The CN may differ from the original.

  • cert_path (str | None)

Returns:

(new_certificate, new_private_key, new_csr).

Return type:

tuple[x509.Certificate, rsa.RSAPrivateKey, x509.CertificateSigningRequest]

Raises:
async verify_certificate(cert)[source]

Perform a full verification of cert: chain, signature, and revocation.

Combines cryptographic validation (via CertificateFactory.validate_cert) with a database revocation check (via get_certificate_status).

Validation steps

  1. Issuer field matches the CA subject.

  2. Current UTC time is within the validity window.

  3. Cryptographic signature is valid.

  4. Certificate is not listed as revoked in the database.

type cert:

Certificate

param cert:

The certificate object to verify.

type cert:

x509.Certificate

returns:

True when all checks pass.

rtype:

bool

raises ValueError:

If self.factory has not been initialised.

raises ValidationCertError:

If the certificate fails any cryptographic check or is revoked.

Parameters:

cert (Certificate)

Return type:

bool

async verify_crl(crl)[source]

Verify CRL signature and expiry in thread pool.

Return type:

None

Parameters:

crl (CertificateRevocationList)