add /register endpoint for public certificate registration

Public endpoint allows anyone to obtain a client certificate for
authentication. Features:

- Higher PoW difficulty than paste creation (24 vs 20 bits)
- Auto-generates CA on first registration if not present
- Returns PKCS#12 bundle with cert, key, and CA
- Configurable via FLASKPASTE_REGISTER_POW

Endpoints:
- GET /register/challenge - Get registration PoW challenge
- POST /register - Register and receive PKCS#12 bundle
This commit is contained in:
Username
2025-12-21 10:34:02 +01:00
parent 68d51c5b3e
commit 5849c7406f
7 changed files with 577 additions and 10 deletions

View File

@@ -31,6 +31,7 @@ try:
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.serialization import pkcs12
from cryptography.x509.oid import ExtendedKeyUsageOID, NameOID
HAS_CRYPTO = True
@@ -189,6 +190,49 @@ def calculate_fingerprint(certificate: Any) -> str:
return hashlib.sha1(cert_der, usedforsecurity=False).hexdigest()
def create_pkcs12(
private_key: Any,
certificate: Any,
ca_certificate: Any,
friendly_name: str,
password: bytes | None = None,
) -> bytes:
"""Create PKCS#12 bundle containing certificate, private key, and CA cert.
Args:
private_key: Client private key object
certificate: Client certificate object
ca_certificate: CA certificate object
friendly_name: Friendly name for the certificate
password: Optional password for PKCS#12 encryption (None = no password)
Returns:
PKCS#12 bytes (DER encoded)
"""
_require_crypto()
# Build encryption algorithm - use strong encryption if password provided
if password:
encryption = (
serialization.BestAvailableEncryption(password)
if password
else serialization.NoEncryption()
)
else:
encryption = serialization.NoEncryption()
# Serialize to PKCS#12
p12_data = pkcs12.serialize_key_and_certificates(
name=friendly_name.encode("utf-8"),
key=private_key,
cert=certificate,
cas=[ca_certificate],
encryption_algorithm=encryption,
)
return p12_data
class PKI:
"""Standalone PKI manager for CA and certificate operations.