wasat.certs
Client certificate generation and storage management for Gemini connections.
ClientCertCallback
ClientCertCallback = Callable[
[AnyURI, ClientCertificateStore],
Coroutine[
None,
None,
Literal["transient", "persistent", "ignore"],
],
]
Async callback function signature for resolving a client certificate requirement.
This callback is invoked when a client certificate is required. It receives the requested URI (GeminiURI or TitanURI) and the ClientCertificateStore instance to query or update.
ClientCertificate
ClientCertificate(
cert_pem: bytes,
*,
key_pem: bytes | None = None,
cert_path: Path | None = None,
key_path: Path | None = None,
scopes: tuple[str, ...] | list[str] = (),
)
Representation of a client TLS X.509 certificate and private key pair.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
bytes
|
The raw PEM-encoded certificate bytes. |
required |
|
bytes | None
|
Optional raw PEM-encoded private key bytes. |
None
|
|
Path | None
|
Optional filesystem path to the certificate PEM file. |
None
|
|
Path | None
|
Optional filesystem path to the private key PEM file. |
None
|
|
tuple[str, ...] | list[str]
|
Tuple or list of Gemini scopes associated with this certificate. |
()
|
cert_path
property
cert_path: Path | None
The filesystem path to the certificate PEM file, or None if in-memory.
country
property
country: str | None
The two-letter country code from the certificate subject, or None.
email
property
email: str | None
The email address from the certificate subject, or None if not present.
is_self_signed
property
is_self_signed: bool
Whether the certificate is self-signed (subject equals issuer).
issuer_common_name
property
issuer_common_name: str | None
The Common Name (CN) from the certificate issuer, or None if not present.
key_path
property
key_path: Path | None
The filesystem path to the private key PEM file, or None if in-memory.
key_pem
property
key_pem: bytes | None
The raw PEM-encoded private key bytes, or None if not available.
key_size
property
key_size: int | None
The key size in bits (for RSA) or curve size (for ECDSA), or None.
key_type
property
key_type: str
The type of public key in the certificate ('ecdsa', 'rsa', or 'unknown').
organisation
property
organisation: str | None
The organisation name from the certificate subject, or None if not present.
raw_x509
property
raw_x509: Certificate
The underlying cryptography X.509 Certificate instance.
scopes
property
The tuple of Gemini scopes associated with this certificate.
subject_alternative_names
property
Tuple of Subject Alternative Names (DNS names) in the certificate.
subject_common_name
property
subject_common_name: str | None
The Common Name (CN) from the certificate subject, or None if not present.
user_id
property
user_id: str | None
The user ID from the certificate subject, or None if not present.
export
export(
target_path: str | Path,
*,
key_path: str | Path | None = None,
combined: bool = False,
) -> tuple[Path, Path | None]
Export certificate and private key to disk with safe file permissions.
When exporting private keys, files are written with restricted permissions (0600).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path
|
File or directory destination for the exported certificate. |
required |
|
str | Path | None
|
Optional specific file destination for the private key. |
None
|
|
bool
|
If True, writes certificate and key into a single combined PEM file. |
False
|
Returns:
| Type | Description |
|---|---|
tuple[Path, Path | None]
|
A tuple of (cert_path, key_path) representing the exported files. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If combined is True and key_path is also specified. |
OSError
|
If creating directories or writing files fails. |
from_file
classmethod
from_file(
cert_path: str | Path,
key_path: str | Path | None = None,
scopes: Sequence[str | AnyURI] = (),
) -> ClientCertificate
Construct a ClientCertificate instance from PEM files on disk.
If key_path is omitted, cert_path is checked for an embedded private
key bundle in addition to the certificate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path
|
Path to the certificate PEM file (or combined bundle). |
required |
|
str | Path | None
|
Optional path to the private key PEM file. |
None
|
|
Sequence[str | AnyURI]
|
Sequence of Gemini/Titan scopes or URIs associated with this certificate. |
()
|
Returns:
| Type | Description |
|---|---|
ClientCertificate
|
A new ClientCertificate instance. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If cert_path or key_path does not exist. |
ValueError
|
If no valid certificate block can be parsed. |
from_pem
classmethod
from_pem(
cert_pem: bytes | str,
*,
key_pem: bytes | str | None = None,
scopes: Sequence[str | AnyURI] = (),
) -> ClientCertificate
Construct a ClientCertificate instance from PEM bytes or text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
bytes | str
|
PEM-encoded certificate bytes or string (can be a combined certificate and private key bundle). |
required |
|
bytes | str | None
|
Optional separate PEM-encoded private key bytes or string. |
None
|
|
Sequence[str | AnyURI]
|
Sequence of Gemini/Titan scopes or URIs associated with this certificate. |
()
|
Returns:
| Type | Description |
|---|---|
ClientCertificate
|
A new ClientCertificate instance. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no valid certificate block is present in the input. |
ClientCertificateStore
Bases: Protocol
Protocol defining the interface for client certificate storage and retrieval.
associate_scope
async
associate_scope(
identifier: str | Path | AnyURI | ClientCertificate,
scope_or_uri: str | AnyURI,
) -> None
Associate an existing certificate in the store with an additional scope or URI.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | AnyURI | ClientCertificate
|
Target certificate reference (ClientCertificate, URI, fingerprint, or file path/name). |
required |
|
str | AnyURI
|
The scope string or URI to associate. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the certificate cannot be identified in the store. |
RuntimeError
|
If updating the store index fails. |
close
async
close() -> None
Close the store, cleaning up transient resources if necessary.
create_certificate
async
create_certificate(
name: str,
*,
scopes: Sequence[str | AnyURI] = (),
transient: bool = False,
common_name: str | None = None,
valid_days: int | None = 365,
key_type: Literal["ecdsa", "rsa"] = "ecdsa",
rsa_key_size: int = 2048,
ecdsa_curve: str = "secp256r1",
email: str | None = None,
user_id: str | None = None,
domain: str | None = None,
organisation: str | None = None,
country: str | None = None,
) -> ClientCertificate
Generate and save a new client certificate and private key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str
|
Base name for the certificate file. |
required |
|
Sequence[str | AnyURI]
|
Sequence of Gemini/Titan scopes or URIs to associate with the certificate. |
()
|
|
bool
|
If True, the certificate is generated in a temporary directory and not registered in the persistent store. |
False
|
|
str | None
|
The Common Name (CN) for the certificate. Defaults to |
None
|
|
int | None
|
Number of days the certificate should be valid. If None, the certificate will expire on 9999-12-31. |
365
|
|
Literal['ecdsa', 'rsa']
|
The key type to generate ('ecdsa' or 'rsa'). |
'ecdsa'
|
|
int
|
RSA key size in bits. |
2048
|
|
str
|
ECDSA curve name. |
'secp256r1'
|
|
str | None
|
Optional email address. |
None
|
|
str | None
|
Optional user identifier. |
None
|
|
str | None
|
Optional domain name for Subject Alternative Name. |
None
|
|
str | None
|
Optional organisation name. |
None
|
|
str | None
|
Optional two-letter country code. |
None
|
Returns:
| Type | Description |
|---|---|
ClientCertificate
|
The created ClientCertificate instance. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the key type is unsupported, the RSA key size is not one of 2048, 3072, or 4096, the ECDSA curve is not 'secp256r1' or 'secp384r1', or the country code is not exactly two characters. |
OSError
|
If creating directories or writing the certificate or key file to disk fails. |
RuntimeError
|
If saving the credentials or updating the store index fails. |
create_credentials
async
create_credentials(
uri: AnyURI,
*,
transient: bool = False,
common_name: str | None = None,
valid_days: int | None = 365,
key_type: Literal["ecdsa", "rsa"] = "ecdsa",
rsa_key_size: int = 2048,
ecdsa_curve: str = "secp256r1",
email: str | None = None,
user_id: str | None = None,
domain: str | None = None,
organisation: str | None = None,
country: str | None = None,
) -> tuple[Path, Path]
Generate and save a new self-signed client certificate and private key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
|
bool
|
If True, the certificate is generated in a temporary directory and not registered in the persistent store. |
False
|
|
str | None
|
The Common Name (CN) for the certificate. Defaults to the host. |
None
|
|
int | None
|
Number of days the certificate should be valid. If None, the certificate will expire on 9999-12-31. |
365
|
|
Literal['ecdsa', 'rsa']
|
The key type to generate ('ecdsa' or 'rsa'). |
'ecdsa'
|
|
int
|
RSA key size in bits. |
2048
|
|
str
|
ECDSA curve name. |
'secp256r1'
|
|
str | None
|
Optional email address. |
None
|
|
str | None
|
Optional user identifier. |
None
|
|
str | None
|
Optional domain name for Subject Alternative Name. |
None
|
|
str | None
|
Optional organisation name. |
None
|
|
str | None
|
Optional two-letter country code. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[Path, Path]
|
A tuple of (cert_path, key_path) representing the generated certificate and key. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the key type is unsupported, the RSA key size is not one of 2048, 3072, or 4096, the ECDSA curve is not 'secp256r1' or 'secp384r1', or the country code is not exactly two characters. |
OSError
|
If creating directories or writing the certificate or key file to disk fails. |
RuntimeError
|
If saving the credentials or updating the store index fails. |
delete_certificate
async
delete_certificate(
identifier: str | Path | AnyURI | ClientCertificate,
) -> bool
Delete a client certificate and its private key, removing all associated scopes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | AnyURI | ClientCertificate
|
Target certificate reference (ClientCertificate, URI, fingerprint, or file path/name). |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the certificate was found and deleted, False otherwise. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If updating the store index fails. |
delete_credentials
async
Delete the certificate and key associated with the matching scope.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if deleted, False if no matching scope was found. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If updating the store index fails. |
delete_exact_scope
async
delete_exact_scope(scope_or_uri: str | AnyURI) -> bool
Delete the exact scope association, removing the certificate files if unused.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | AnyURI
|
The scope string or URI to delete. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the scope was found and deleted, False otherwise. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If updating the store index fails. |
disassociate_scope
async
disassociate_scope(scope_or_uri: str | AnyURI) -> bool
Disassociate a scope or URI without deleting the certificate files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | AnyURI
|
The scope string or URI to disassociate. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if an association was removed, False if no matching scope was registered. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If updating the store index fails. |
export_certificate
async
export_certificate(
identifier: str | Path | AnyURI | ClientCertificate,
target_path: str | Path,
*,
key_path: str | Path | None = None,
combined: bool = False,
) -> tuple[Path, Path | None]
Export a stored client certificate and its private key to disk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | AnyURI | ClientCertificate
|
Target certificate reference (ClientCertificate, URI, fingerprint, or file path/name). |
required |
|
str | Path
|
File or directory destination for the exported certificate. |
required |
|
str | Path | None
|
Optional specific file destination for the private key. |
None
|
|
bool
|
If True, exports certificate and key into a single combined PEM file. |
False
|
Returns:
| Type | Description |
|---|---|
tuple[Path, Path | None]
|
A tuple of (cert_path, key_path) representing the exported files. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the certificate cannot be found in the store, or if combined is True and key_path is specified. |
OSError
|
If creating directories or writing files fails. |
get_certificate
async
get_certificate(
identifier: str | Path | AnyURI,
) -> ClientCertificate | None
Retrieve a client certificate by scope, URI, fingerprint, or filename.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | AnyURI
|
A URI (GeminiURI or TitanURI), scope string, SHA-256 fingerprint, or certificate file path/name. |
required |
Returns:
| Type | Description |
|---|---|
ClientCertificate | None
|
The matching ClientCertificate instance, or None if not found. |
get_credentials
async
Retrieve the certificate and private key paths matching the given URI.
This should perform path prefix matching to find the most specific matching certificate for the requested host, port, and path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
Returns:
| Type | Description |
|---|---|
tuple[Path, Path] | None
|
A tuple of (cert_path, key_path) or None if no certificate is stored |
tuple[Path, Path] | None
|
for this URI's scope. |
has_exact_credentials
async
Check if a certificate exists for the exact scope of the URI.
This checks if a certificate has been registered specifically for the exact host, port, and path of the given URI (without traversing parent scopes).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if a certificate is registered for this exact scope, False otherwise. |
import_certificate
async
import_certificate(
source: str | Path | bytes | ClientCertificate,
*,
key_source: str | Path | bytes | None = None,
name: str | None = None,
scopes: Sequence[str | AnyURI] = (),
transient: bool = False,
) -> ClientCertificate
Import an existing client certificate and key into the store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | bytes | ClientCertificate
|
File path, PEM string/bytes, or ClientCertificate instance. |
required |
|
str | Path | bytes | None
|
Optional separate file path or PEM string/bytes for the private key. |
None
|
|
str | None
|
Optional base name for the imported certificate files in the store. If omitted, derived from the certificate common name, fingerprint, or source filename. |
None
|
|
Sequence[str | AnyURI]
|
Optional sequence of Gemini/Titan scopes or URIs to associate with the imported certificate. |
()
|
|
bool
|
If True, imports the certificate into transient storage. |
False
|
Returns:
| Type | Description |
|---|---|
ClientCertificate
|
The imported ClientCertificate instance. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the certificate cannot be parsed. |
FileNotFoundError
|
If a specified file path does not exist. |
OSError
|
If reading or writing files fails. |
RuntimeError
|
If saving the store index fails. |
list_certificates
async
list_certificates() -> list[ClientCertificate]
List all client certificates stored in this certificate store.
Returns:
| Type | Description |
|---|---|
list[ClientCertificate]
|
A list of ClientCertificate instances. |
register_credentials
async
register_credentials(
uri: AnyURI,
cert_path: str | Path,
key_path: str | Path,
*,
transient: bool = False,
) -> None
Register existing certificate and private key paths for the URI's scope.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
|
str | Path
|
Path to the existing client certificate. |
required |
|
str | Path
|
Path to the existing private key. |
required |
|
bool
|
If True, registers as transient. |
False
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the registry is persistent, and the source files do not exist at the specified paths. |
OSError
|
If copying the certificate or private key files fails, or if creating the persistent store directory fails. |
RuntimeError
|
If registering or persisting the credentials in the store index fails. |
FileClientCertificateStore
Bases: ClientCertificateStore
File-based client certificate and key store.
Saves certificate files as PEM pairs and maintains a certs.json registry file
mapping Gemini scopes (host[:port]/path) to certificate filenames.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path
|
The directory where certificates, keys, and the index are stored. |
required |
store_dir
instance-attribute
The directory path for storing certificates and index.
associate_scope
async
associate_scope(
identifier: str | Path | AnyURI | ClientCertificate,
scope_or_uri: str | AnyURI,
) -> None
Associate an existing certificate in the store with an additional scope or URI.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | AnyURI | ClientCertificate
|
Target certificate reference (ClientCertificate, URI, fingerprint, or file path/name). |
required |
|
str | AnyURI
|
The scope string or URI to associate. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the certificate cannot be identified in the store. |
RuntimeError
|
If updating the store index fails. |
close
async
close() -> None
Close the store, cleaning up transient directories if any were created.
create_certificate
async
create_certificate(
name: str,
*,
scopes: Sequence[str | AnyURI] = (),
transient: bool = False,
common_name: str | None = None,
valid_days: int | None = 365,
key_type: Literal["ecdsa", "rsa"] = "ecdsa",
rsa_key_size: int = 2048,
ecdsa_curve: str = "secp256r1",
email: str | None = None,
user_id: str | None = None,
domain: str | None = None,
organisation: str | None = None,
country: str | None = None,
) -> ClientCertificate
Generate and save a new client certificate and private key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str
|
Base name for the certificate file. |
required |
|
Sequence[str | AnyURI]
|
Sequence of Gemini scopes or URIs to associate with the certificate. |
()
|
|
bool
|
If True, the certificate is generated in a temporary directory and not registered in the persistent store. |
False
|
|
str | None
|
The Common Name (CN) for the certificate. Defaults to |
None
|
|
int | None
|
Number of days the certificate should be valid. If None, the certificate will expire on 9999-12-31. |
365
|
|
Literal['ecdsa', 'rsa']
|
The key type to generate ('ecdsa' or 'rsa'). |
'ecdsa'
|
|
int
|
RSA key size in bits. |
2048
|
|
str
|
ECDSA curve name. |
'secp256r1'
|
|
str | None
|
Optional email address. |
None
|
|
str | None
|
Optional user identifier. |
None
|
|
str | None
|
Optional domain name for Subject Alternative Name. |
None
|
|
str | None
|
Optional organisation name. |
None
|
|
str | None
|
Optional two-letter country code. |
None
|
Returns:
| Type | Description |
|---|---|
ClientCertificate
|
The created ClientCertificate instance. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the key type is unsupported, the RSA key size is not one of 2048, 3072, or 4096, the ECDSA curve is not 'secp256r1' or 'secp384r1', or the country code is not exactly two characters. |
OSError
|
If creating directories or writing the certificate or key file to disk fails. |
RuntimeError
|
If saving the credentials or updating the store index fails. |
create_credentials
async
create_credentials(
uri: AnyURI,
*,
transient: bool = False,
common_name: str | None = None,
valid_days: int | None = 365,
key_type: Literal["ecdsa", "rsa"] = "ecdsa",
rsa_key_size: int = 2048,
ecdsa_curve: str = "secp256r1",
email: str | None = None,
user_id: str | None = None,
domain: str | None = None,
organisation: str | None = None,
country: str | None = None,
) -> tuple[Path, Path]
Generate and save a new self-signed client certificate and private key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
|
bool
|
If True, the certificate is generated in a temporary directory and not registered in the persistent store. |
False
|
|
str | None
|
The Common Name (CN) for the certificate. Defaults to the host. |
None
|
|
int | None
|
Number of days the certificate should be valid. If None, the certificate will expire on 9999-12-31. |
365
|
|
Literal['ecdsa', 'rsa']
|
The key type to generate ('ecdsa' or 'rsa'). |
'ecdsa'
|
|
int
|
RSA key size in bits. |
2048
|
|
str
|
ECDSA curve name. |
'secp256r1'
|
|
str | None
|
Optional email address. |
None
|
|
str | None
|
Optional user identifier. |
None
|
|
str | None
|
Optional domain name for Subject Alternative Name. |
None
|
|
str | None
|
Optional organisation name. |
None
|
|
str | None
|
Optional two-letter country code. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[Path, Path]
|
A tuple of (cert_path, key_path) representing the generated certificate and key. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the key type is unsupported, the RSA key size is not one of 2048, 3072, or 4096, the ECDSA curve is not 'secp256r1' or 'secp384r1', or the country code is not exactly two characters. |
OSError
|
If creating the persistent store directory or the temporary transient directory fails, or if writing the certificate or key file to disk fails. |
RuntimeError
|
If saving the updated index ( |
delete_certificate
async
delete_certificate(
identifier: str | Path | AnyURI | ClientCertificate,
) -> bool
Delete a client certificate and its private key, removing all associated scopes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | AnyURI | ClientCertificate
|
Target certificate reference (ClientCertificate, URI, fingerprint, or file path/name). |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the certificate was found and deleted, False otherwise. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If updating the store index fails. |
delete_credentials
async
Delete the certificate and key associated with the matching scope.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if deleted, False if no matching scope was found. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If saving the updated index ( |
delete_exact_scope
async
delete_exact_scope(scope_or_uri: str | AnyURI) -> bool
Delete the exact scope association, removing the certificate files if unused.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | AnyURI
|
The scope string or URI to delete. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the scope was found and deleted, False otherwise. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If updating the store index fails. |
disassociate_scope
async
disassociate_scope(scope_or_uri: str | AnyURI) -> bool
Disassociate a scope or URI without deleting the certificate files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | AnyURI
|
The scope string or URI to disassociate. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if an association was removed, False if no matching scope was registered. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If updating the store index fails. |
export_certificate
async
export_certificate(
identifier: str | Path | AnyURI | ClientCertificate,
target_path: str | Path,
*,
key_path: str | Path | None = None,
combined: bool = False,
) -> tuple[Path, Path | None]
Export a stored client certificate and its private key to disk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | AnyURI | ClientCertificate
|
Target certificate reference (ClientCertificate, URI, fingerprint, or file path/name). |
required |
|
str | Path
|
File or directory destination for the exported certificate. |
required |
|
str | Path | None
|
Optional specific file destination for the private key. |
None
|
|
bool
|
If True, exports certificate and key into a single combined PEM file. |
False
|
Returns:
| Type | Description |
|---|---|
tuple[Path, Path | None]
|
A tuple of (cert_path, key_path) representing the exported files. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the certificate cannot be found in the store, or if combined is True and key_path is specified. |
OSError
|
If creating directories or writing files fails. |
get_certificate
async
get_certificate(
identifier: str | Path | AnyURI,
) -> ClientCertificate | None
Retrieve a client certificate by scope, URI, fingerprint, or filename.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | AnyURI
|
A URI (GeminiURI or TitanURI), scope string, SHA-256 fingerprint, or certificate file path/name. |
required |
Returns:
| Type | Description |
|---|---|
ClientCertificate | None
|
The matching ClientCertificate instance, or None if not found. |
get_credentials
async
Retrieve the certificate and private key paths matching the given URI.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
Returns:
| Type | Description |
|---|---|
tuple[Path, Path] | None
|
A tuple of (cert_path, key_path) or None if no certificate is stored |
tuple[Path, Path] | None
|
for this URI's scope. |
has_exact_credentials
async
Check if a certificate exists for the exact scope of the URI.
This checks if a certificate has been registered specifically for the exact host, port, and path of the given URI (without traversing parent scopes).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if a certificate is registered for this exact scope, False otherwise. |
import_certificate
async
import_certificate(
source: str | Path | bytes | ClientCertificate,
*,
key_source: str | Path | bytes | None = None,
name: str | None = None,
scopes: Sequence[str | AnyURI] = (),
transient: bool = False,
) -> ClientCertificate
Import an existing client certificate and key into the store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path | bytes | ClientCertificate
|
File path, PEM string/bytes, or ClientCertificate instance. |
required |
|
str | Path | bytes | None
|
Optional separate file path or PEM string/bytes for the private key. |
None
|
|
str | None
|
Optional base name for the imported certificate files in the store. If omitted, derived from the certificate common name, fingerprint, or source filename. |
None
|
|
Sequence[str | AnyURI]
|
Optional sequence of Gemini/Titan scopes or URIs to associate with the imported certificate. |
()
|
|
bool
|
If True, imports the certificate into transient storage. |
False
|
Returns:
| Type | Description |
|---|---|
ClientCertificate
|
The imported ClientCertificate instance. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the certificate cannot be parsed. |
FileNotFoundError
|
If a specified file path does not exist. |
OSError
|
If reading or writing files fails. |
RuntimeError
|
If saving the store index fails. |
list_certificates
async
list_certificates() -> list[ClientCertificate]
List all client certificates stored in this certificate store.
Returns:
| Type | Description |
|---|---|
list[ClientCertificate]
|
A list of ClientCertificate instances. |
register_credentials
async
register_credentials(
uri: AnyURI,
cert_path: str | Path,
key_path: str | Path,
*,
transient: bool = False,
) -> None
Register existing certificate and private key paths for the URI's scope.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
AnyURI
|
The target URI (GeminiURI or TitanURI). |
required |
|
str | Path
|
Path to the existing client certificate. |
required |
|
str | Path
|
Path to the existing private key. |
required |
|
bool
|
If True, registers as transient. |
False
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If |
OSError
|
If |
RuntimeError
|
If |
ServerCertificate
Representation of a server TLS X.509 certificate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
bytes
|
The raw DER-encoded certificate bytes. |
required |
is_self_signed
property
is_self_signed: bool
Whether the certificate is self-signed (subject equals issuer).
issuer_common_name
property
issuer_common_name: str | None
The Common Name (CN) from the certificate issuer, or None if not present.
raw_x509
property
raw_x509: Certificate
The underlying cryptography X.509 Certificate instance.
subject_alternative_names
property
Tuple of Subject Alternative Names (DNS names) in the certificate.
subject_common_name
property
subject_common_name: str | None
The Common Name (CN) from the certificate subject, or None if not present.
from_der
classmethod
from_der(cert_der: bytes) -> ServerCertificate
Construct a ServerCertificate instance from raw DER bytes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
bytes
|
The raw DER-encoded certificate bytes. |
required |
Returns:
| Type | Description |
|---|---|
ServerCertificate
|
A new ServerCertificate instance. |
generate_self_signed_cert
generate_self_signed_cert(
common_name: str,
*,
key_type: Literal["ecdsa", "rsa"] = "ecdsa",
rsa_key_size: int = 2048,
ecdsa_curve: str = "secp256r1",
valid_days: int | None = 365,
email: str | None = None,
user_id: str | None = None,
domain: str | None = None,
organisation: str | None = None,
country: str | None = None,
) -> tuple[bytes, bytes]
Generate a self-signed client certificate and private key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str
|
The Common Name (CN) for the certificate. |
required |
|
Literal['ecdsa', 'rsa']
|
The key type to generate ('ecdsa' or 'rsa'). |
'ecdsa'
|
|
int
|
RSA key size in bits. |
2048
|
|
str
|
ECDSA curve name. |
'secp256r1'
|
|
int | None
|
Certificate validity in days. If None, the certificate will expire on 9999-12-31. |
365
|
|
str | None
|
Optional email address. |
None
|
|
str | None
|
Optional user identifier. |
None
|
|
str | None
|
Optional domain name for Subject Alternative Name. |
None
|
|
str | None
|
Optional organisation name. |
None
|
|
str | None
|
Optional two-letter country code. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[bytes, bytes]
|
A tuple containing (cert_pem, key_pem) as bytes. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the key type is unsupported, the RSA key size is not one of 2048, 3072, or 4096, the ECDSA curve is not 'secp256r1' or 'secp384r1', or the country code is not exactly two characters. |
get_candidate_scopes
normalize_scope
normalize_scope(scope_or_uri: str | AnyURI) -> str
Normalise a GeminiURI, TitanURI, or scope string into a canonical scope string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | AnyURI
|
A GeminiURI or TitanURI instance, or a scope string (e.g. 'example.com/path' or 'gemini://example.com:1965/path' or 'titan://example.com/path;size=10'). |
required |
Returns:
| Type | Description |
|---|---|
str
|
The canonical scope string in 'host:port/path' format. |