Unified FastAPI server with modular architecture for encryption key management, telemetry, pepper storage, and integrity verification.
- Keyserver Module: Post-quantum public key distribution with ML-KEM and ML-DSA support
- Telemetry Module: Anonymous usage statistics collection
- Pepper Module: Secure pepper storage with TOTP 2FA and deadman switch (opt-in)
- Integrity Module: Encrypted file metadata hash verification (opt-in)
- Dual Authentication: JWT tokens (keyserver/telemetry) + mTLS certificates (pepper/integrity)
- Async Architecture: AsyncIO + asyncpg for high concurrency
- Docker Ready: Complete Docker Compose setup with fixed IPs
- Modular Design: Enable/disable modules independently via configuration
Copy the example environment file:
cp .env.example .envEdit .env and change the secrets:
# IMPORTANT: Change these to random 32+ character strings!
KEYSERVER_TOKEN_SECRET=your-keyserver-secret-min-32-chars
TELEMETRY_TOKEN_SECRET=your-telemetry-secret-min-32-chars
# Database password
POSTGRES_PASSWORD=your-secure-database-passworddocker-compose up -dThe server will start on http://localhost:8080
Check health:
curl http://localhost:8080/healthCheck modules:
curl http://localhost:8080/infoGET /health- Health checkGET /ready- Readiness check (database connectivity)GET /info- Server informationGET /docs- OpenAPI documentation (if DEBUG=true)
GET /api/v1/keys/search?q=<query>- Search for public key
POST /api/v1/keys/register- Register and get tokenPOST /api/v1/keys- Upload public keyPOST /api/v1/keys/{fingerprint}/revoke- Revoke key
GET /api/v1/telemetry/stats- Get aggregated statistics
POST /api/v1/telemetry/register- Register and get tokenPOST /api/v1/telemetry/events- Submit telemetry events
Status: Opt-in (disabled by default)
Authentication: Client certificate signed by your self-signed CA
GET /profile- Get client profile (auto-registers on first connection)PUT /profile- Update profile nameDELETE /profile- Delete account [TOTP required]POST /totp/setup- Setup TOTP 2FAPOST /totp/verify- Verify TOTP setupDELETE /totp- Disable TOTP [TOTP required]POST /peppers- Store pepperGET /peppers- List peppersGET /peppers/{name}- Get pepperPUT /peppers/{name}- Update pepperDELETE /peppers/{name}- Delete pepperGET /deadman- Get deadman switch statusPUT /deadman- Configure deadman switchPOST /deadman/checkin- Check in (reset timer)POST /panic- Wipe all peppers [TOTP required]
Setup: See docs/MTLS_SETUP.md and scripts/README.md
Status: Opt-in (disabled by default)
Authentication: Client certificate signed by your self-signed CA
GET /profile- Get client profile (auto-registers on first connection)PUT /profile- Update profile namePOST /hashes- Store metadata hashGET /hashes- List all hashesGET /hashes/{file_id}- Get specific hashPUT /hashes/{file_id}- Update hashDELETE /hashes/{file_id}- Delete specific hashDELETE /hashes- Delete all hashesPOST /verify- Verify single hash (detects tampering)POST /verify/batch- Batch verify multiple hashesGET /stats- Get verification statistics
Setup: See docs/MTLS_SETUP.md and scripts/README.md
Tokens are module-specific and cannot be used across modules:
- Keyserver token has issuer:
openssl_encrypt_keyserver - Telemetry token has issuer:
openssl_encrypt_telemetry
This prevents a Keyserver token from being used for Telemetry endpoints and vice versa.
Security Model: Self-signed CA only (public CAs are NOT accepted)
These modules are non-public and require client certificates signed by YOUR private Certificate Authority:
- One-time setup: Create your self-signed CA
- Per client/device: Generate client certificates signed by your CA
- Server verification: Server only trusts certificates from your CA
- Auto-registration: Clients auto-register on first connection
Quick Start:
# 1. Create CA (one-time)
cd scripts
./setup_ca.sh
# 2. Generate client certificate
./create_client_cert.sh alice
# 3. Distribute to client
tar czf alice-bundle.tar.gz certs/alice.{key,crt} certs/ca.crt
# 4. Client connects
curl --cert alice.crt --key alice.key --cacert ca.crt \
https://server/api/v1/pepper/profileSee detailed documentation:
- mTLS Setup Guide - Complete setup instructions
- Certificate Management Scripts - Helper scripts usage
# 1. Register with keyserver
RESPONSE=$(curl -X POST http://localhost:8080/api/v1/keys/register)
TOKEN=$(echo $RESPONSE | jq -r '.token')
# 2. Upload a key (requires key bundle JSON)
curl -X POST http://localhost:8080/api/v1/keys \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @key_bundle.json
# 3. Search for the key (public, no auth)
curl "http://localhost:8080/api/v1/keys/search?q=alice"# 1. Register with telemetry
RESPONSE=$(curl -X POST http://localhost:8080/api/v1/telemetry/register)
TOKEN=$(echo $RESPONSE | jq -r '.token')
# 2. Submit events
curl -X POST http://localhost:8080/api/v1/telemetry/events \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @events.json
# 3. View stats (public, no auth)
curl http://localhost:8080/api/v1/telemetry/stats| Variable | Description | Default |
|---|---|---|
POSTGRES_USER |
Database user | openssl_server |
POSTGRES_PASSWORD |
Database password | change_me_in_production |
POSTGRES_DB |
Database name | openssl_encrypt |
POSTGRES_HOST |
Database host | db |
POSTGRES_PORT |
Database port | 5432 |
SERVER_HOST |
Server bind address | 0.0.0.0 |
SERVER_PORT |
Server port | 8080 |
DEBUG |
Debug mode | false |
LOG_LEVEL |
Log level | INFO |
KEYSERVER_TOKEN_SECRET |
Keyserver JWT secret (32+ chars) | - |
TELEMETRY_TOKEN_SECRET |
Telemetry JWT secret (32+ chars) | - |
KEYSERVER_ENABLED |
Enable keyserver module | true |
TELEMETRY_ENABLED |
Enable telemetry module | true |
CORS_ORIGINS |
CORS allowed origins | * |
The Docker Compose setup uses fixed IPs on the 172.28.0.0/16 subnet:
- Database:
172.28.0.2 - API Server:
172.28.0.3
This allows for predictable networking and easier integration with external services.
- Install PostgreSQL:
# macOS
brew install postgresql@16
# Ubuntu/Debian
sudo apt-get install postgresql-16- Create database:
createdb openssl_encrypt- Install dependencies:
pip install -r requirements.txt- Set environment variables:
export POSTGRES_HOST=localhost
export KEYSERVER_TOKEN_SECRET="dev-keyserver-secret-min-32-chars"
export TELEMETRY_TOKEN_SECRET="dev-telemetry-secret-min-32-chars"- Run server:
python -m uvicorn server:app --reload# Register with keyserver
KS_TOKEN=$(curl -X POST http://localhost:8080/api/v1/keys/register | jq -r '.token')
# Try to use keyserver token for telemetry (should fail with 401)
curl -X POST http://localhost:8080/api/v1/telemetry/events \
-H "Authorization: Bearer $KS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"events": []}'
# Response: {"detail": "Token not valid for this service"}openssl_encrypt_server/
├── server.py # Main entry point
├── config.py # Configuration
├── core/
│ ├── auth/
│ │ └── token.py # JWT TokenAuth class
│ ├── database.py # Async SQLAlchemy
│ └── exceptions.py # Exception handlers
└── modules/
├── keyserver/ # Keyserver module
│ ├── models.py # KSClient, KSKey (ks_ tables)
│ ├── schemas.py # Pydantic schemas
│ ├── auth.py # Keyserver auth instance
│ ├── routes.py # API routes
│ ├── service.py # Business logic
│ └── verification.py # PQC signature verification
└── telemetry/ # Telemetry module
├── models.py # TMClient, TMEvent (tm_ tables)
├── schemas.py # Pydantic schemas
├── auth.py # Telemetry auth instance
├── routes.py # API routes
└── service.py # Business logic
ks_clients- Registered keyserver clientsks_keys- Public keys with metadataks_access_log- Access audit log
tm_clients- Registered telemetry clientstm_events- Telemetry eventstm_daily_stats- Aggregated statistics
- Unique Secrets: Each module MUST have a different token secret (validated at startup)
- Minimum Length: Token secrets must be at least 32 characters
- Issuer Claims: JWT tokens include issuer claims for module isolation
- Expiry: Tokens expire after 365 days (configurable)
The keyserver uses liboqs (Open Quantum Safe) for post-quantum signature verification:
- Supports ML-DSA-44, ML-DSA-65, ML-DSA-87 (Dilithium)
- Verifies self-signatures on all uploaded keys
- Validates fingerprints against calculated hashes
The server is designed to run behind a reverse proxy (e.g., Nginx):
- Server binds to internal port (default: 8080)
- Proxy handles TLS termination
- Proxy forwards to backend on
http://172.28.0.3:8080
Example Nginx config (basic):
upstream openssl_encrypt_api {
server 172.28.0.3:8080;
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/ssl/certs/api.crt;
ssl_certificate_key /etc/ssl/private/api.key;
location / {
proxy_pass http://openssl_encrypt_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}For modules requiring client certificate authentication (pepper, integrity), configure Nginx to pass the raw certificate:
upstream openssl_encrypt_api {
server 172.28.0.3:8080;
}
server {
listen 443 ssl http2;
server_name pepper.example.com integrity.example.com;
# Server certificate (Let's Encrypt or your own)
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
# Client certificate verification (your self-signed CA)
ssl_client_certificate /path/to/your/ca.crt;
ssl_verify_client optional; # Optional so keyserver/telemetry still work
location / {
proxy_pass http://openssl_encrypt_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Pass raw client certificate (URL-encoded PEM)
# Backend will compute SHA-256 fingerprint from this
proxy_set_header X-Client-Cert $ssl_client_escaped_cert;
}
}Key points:
- Use
$ssl_client_escaped_certto pass the URL-encoded PEM certificate - Backend server computes SHA-256 fingerprint from the certificate
- This works with Nginx's default SHA-1 fingerprint variable
ssl_verify_client optionalallows non-mTLS endpoints to work on same domain
This server is designed to support additional modules:
- Pepper Module (mTLS auth) - Secure pepper storage with dead man's switch
- Integrity Module (JWT auth) - Metadata hash verification
See SERVER_CONSOLIDATION_SPEC_v3.md for the full roadmap.
Same as parent project (Hippocratic License 3.0)
For issues or questions, please refer to the main project repository.