A Python-based Certificate Authority for managing X.509 certificates
Project description
certificate-authority
A comprehensive Python-based Certificate Authority (CA) for managing X.509 certificates. This library provides a complete solution for creating and managing a certificate authority, including support for certificate issuance, revocation, and various certificate formats.
Requirements
- Python 3.9 - 3.14
- OpenSSL 3.0 or higher (required by cryptography 42.0.0)
Features
- Create and manage a Certificate Authority (CA)
- Issue server and client certificates
- Support for certificate revocation (CRL)
- Multiple key types support (RSA, ECDSA, Ed25519, Ed448)
- Export certificates in various formats (PEM, PKCS12, JKS)
- Async/await support for all operations
- Command-line interface (CLI)
- Comprehensive test suite
- Type hints throughout the codebase
Installation
pip install certificate-authority
For development:
pip install certificate-authority[dev]
Quick Start
Using as a Library
import asyncio
from CA import CertificateAuthority
from CA.models.certificate import CertificateRequest
async def main():
# Initialize CA
ca = CertificateAuthority("./ca") # Uses default directory in current working directory
await ca.initialize(
common_name="My Root CA",
country="US",
state="California",
locality="San Francisco",
org="My Company",
org_unit="IT"
)
# Issue a server certificate
request = CertificateRequest(
common_name="example.com",
organization="My Company",
country="US",
san_dns_names=["example.com", "*.example.com"],
valid_days=365
)
cert = await ca.issue_certificate(request, cert_type="server")
# Export as PKCS12
pkcs12_data = await ca.export_pkcs12(cert, "password123")
with open("server.p12", "wb") as f:
f.write(pkcs12_data)
asyncio.run(main())
Using the CLI
Basic usage:
python -m CA [OPTIONS] COMMAND [ARGS]...
Global options:
--ca-dir: Directory for CA files (default: "./ca" - relative to current directory)--verbose, -v: Enable verbose output
Available commands:
Initialize CA
python -m CA init [OPTIONS]
Options:
--common-name TEXT CA certificate common name [required]
--country TEXT Two-letter country code
--state TEXT State or province name
--locality TEXT Locality name
--org TEXT Organization name
--org-unit TEXT Organizational unit name
--key-type [rsa|ec|ed25519|ed448] Key type to use [default: rsa]
--key-size INTEGER Key size for RSA [default: 2048]
--curve TEXT Curve name for EC keys
Issue Certificate
python -m CA issue [client|server|ca] [OPTIONS]
Options:
--common-name TEXT Certificate common name [required]
--country TEXT Two-letter country code
--state TEXT State or province name
--locality TEXT Locality name
--org TEXT Organization name
--org-unit TEXT Organizational unit name
--email TEXT Email address
--key-type [rsa|ec|ed25519|ed448] Key type to use [default: rsa]
--key-size INTEGER Key size for RSA [default: 2048]
--curve TEXT Curve name for EC keys
--days INTEGER Validity period in days [default: 365]
--san-dns TEXT Subject Alternative Name DNS entries (comma-separated)
--san-ip TEXT Subject Alternative Name IP addresses (comma-separated)
--path-length INTEGER CA path length constraint (CA certificates only)
Revoke Certificate
python -m CA revoke SERIAL [OPTIONS]
Options:
--reason [unspecified|key_compromise|ca_compromise|affiliation_changed|
superseded|cessation_of_operation|certificate_hold|
remove_from_crl|privilege_withdrawn|aa_compromise]
Renew Certificate
python -m CA renew SERIAL
List Certificates
python -m CA list [OPTIONS]
Options:
--type [server|client|ca] Filter by certificate type
--revoked List only revoked certificates
Export Certificate
python -m CA export SERIAL [OPTIONS]
Options:
--format [pem|pkcs12|jks] Export format [default: pem]
--password TEXT Password for PKCS12/JKS export
--out TEXT Output file (default: <serial>.<format>)
CRL Management
python -m CA crl generate Generate a new CRL
Examples:
# Create a new CA in the default directory (./ca)
python -m CA init --common-name "My Root CA" --country US --state California --org "My Company"
# Create a CA in a custom directory
python -m CA --ca-dir /path/to/custom/ca init --common-name "My Root CA" --country US --state California --org "My Company"
# Issue a server certificate (uses ./ca by default)
python -m CA issue server --common-name example.com --san-dns "example.com,*.example.com" --san-ip "10.0.0.1"
# Use a specific CA directory for all operations
export CA_DIR=/path/to/custom/ca # Optional: set default CA directory in environment
python -m CA --ca-dir "${CA_DIR:-./ca}" issue client --common-name "client1" --org "My Company" --key-type ed25519
# Issue an intermediate CA certificate
python -m CA issue ca --common-name "Intermediate CA" --path-length 0
# Revoke a certificate with reason
python -m CA revoke 1234 --reason key_compromise
# List all server certificates
python -m CA list --type server
# List revoked certificates
python -m CA list --revoked
# Export certificate in different formats
python -m CA export 1234 --format pem --out cert.pem
python -m CA export 1234 --format pkcs12 --password secret --out cert.p12
python -m CA export 1234 --format jks --password secret --out cert.jks
# Generate CRL
python -m CA crl generate
Development
- Clone the repository:
git clone https://github.com/paigeadelethompson/certificate-authority.git
cd certificate-authority
- Install hatch:
pip install hatch
- Run tests:
hatch run test
- Code Quality Tools:
Format code:
hatch run format # Runs autoflake, autopep8, black, and isort in the correct order
Run all linters:
hatch run lint # Runs all formatting and linting tools in the correct order
The CI pipeline will run all these checks in this order:
- Code formatting (autoflake, autopep8, black, isort)
- Linting (flake8, pylint)
- Type checking (mypy)
- Tests (pytest)
All checks must pass for a PR to be merged.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
-
Fork the repository
-
Create your feature branch (
git checkout -b feature/amazing-feature) -
Commit your changes (
git commit -m 'Add some amazing feature') -
Run code quality tools and rebase formatting fixes:
# First, run formatting hatch run format # If any files were modified, stage them git add . # Then rebase and squash formatting changes into your feature commits git rebase -i origin/main # In the rebase editor, mark formatting-only commits as 'fixup' # to merge them into their parent feature commit
This keeps the commit history clean by avoiding separate formatting commits.
-
Ensure all checks pass:
hatch run lint # Run all linters hatch run test # Run tests
-
Push to your branch (
git push origin feature/amazing-feature) -
Open a Pull Request
Commit Guidelines
- Keep commits focused on single changes
- Use semantic commit messages (see Versioning section)
- Rebase formatting fixes into their related feature commits
- If you have multiple commits, consider squashing related changes
Example of good commit sequence:
feat: add Ed25519 key support
- Core Ed25519 implementation
- Tests for Ed25519
- (Formatting fixes squashed in)
fix: correct key size validation
- Update validation logic
- Add test cases
- (Formatting fixes squashed in)
Example of what to avoid:
feat: add Ed25519 key support
style: format Ed25519 files
fix: fix linting issues in Ed25519
fix: more formatting
Releases and Publishing
This project uses automated releases through GitHub Actions and PyPI's Trusted Publisher system. The process is:
-
Commits to main branch should follow semantic versioning format:
fix:prefix for bug fixes (0.1.0 -> 0.1.1)feat:prefix for new features (0.1.0 -> 0.2.0)BREAKING CHANGE:in commit body for breaking changes (0.1.0 -> 1.0.0)
-
To create a new release:
# Create a new version tag git tag v0.1.0 # Push the tag to trigger release git push origin v0.1.0
-
The release workflow will automatically:
- Build the package
- Create a GitHub release
- Publish to PyPI using Trusted Publisher
Note: Only maintainers with proper access can publish releases. The release process requires:
- Write access to the GitHub repository
- The repository to be properly configured with PyPI's Trusted Publisher system
License
This project is licensed under the MIT License - see the LICENSE file for details.
Versioning
This project uses python-semantic-release for automated version management. Versions are automatically determined from commit messages:
fix:prefix in commit = patch version bump (0.1.0 -> 0.1.1)feat:prefix in commit = minor version bump (0.1.0 -> 0.2.0)BREAKING CHANGE:in commit body = major version bump (0.1.0 -> 1.0.0)
Example commit messages:
fix: correct certificate renewal date calculation
feat: add support for Ed25519 keys
feat: replace JKS export implementation
BREAKING CHANGE: new API for certificate store
Versions are automatically managed when pushing to main branch. The GitHub Actions workflow will:
- Run all tests
- Create a new version if needed based on commits
- Create a GitHub release
- Publish to PyPI
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters