- Replace paramiko-based OpenSSH private key serialization with
cryptography's PrivateFormat.OpenSSH backend.
The old code relied on paramiko.RSAKey, paramiko.DSSKey, etc. to write
private keys, but Paramiko 5.1.0 removed DSSKey entirely and changed
constructor APIs, causing crashes.
- Add explicit fallback path in _load_ssh_private_with_paramiko that
guards against missing DSSKey (getattr paramiko 'DSSKey', append only
when present), modern private_key attribute vs legacy signing_key,
and Ed25519 PyNaCl key material conversion.
- Add two new test coverage methods:
test_ssh_private_roundtrip – round-trip RSA/DSA/EC/Ed25519
unencrypted and password-encrypted, verifying OpenSSH PEM header
and DER preservation.
test_ssh_private_paramiko_fallback – explicitly exercise the
Paramiko fallback for RSA and EC keys, confirming it still works
under locked Paramiko 5.1.0.
Also clean up the comment in load_key_bytes to reflect the new fallback
behavior rather than the old 'encrypted OpenSSH keys not supported' note.
- Encode EC coordinates and private d with curve-width (32/48/66 bytes) to satisfy RFC 7518,
preserving leading zero octets.
- Restrict JWK values to registered JOSE names: P-256, P-384, P-521, secp256k1.
Raise ValueError for unregistered curves (P-192, P-224, Brainpool).
- Add regression tests: deterministic coordinate/private-value widths, leading-zero
preservation, supported curve names, and rejection of unsupported curves.
- Mypy clean; all core and backend tests pass.
- Parse and validate from snapshot JSON, reject future/missing timestamps
- Enforce snapshot age vs in cache and stale fallback (no lifetime extension on repeat S3 reads)
- OCSP: , ,
- Remove unused from signer
- Publisher heartbeats: , republish clean snapshots past interval, preserve dirty-only behavior and concurrency
- Config/env/docker/docs updates for heartbeat
Rolling upgrade: enable publisher heartbeats before deploying the age-enforcing responder so existing snapshots remain within the age window.
Replace the backtracking _PEM_BLOCK regex with a forward-only scanner
that indexes END markers by label, so repeated unterminated headers do
not cause the regex to rescan the remaining input.
Impact: 80 KiB payload went from 8.34 s to 0.001 s.
Add shared serial collision checking against existing certificates and
issuer revocations, reuse it for automatic serial allocation, and enforce
it for user-supplied serials so duplicate serials no longer break the
OCSP snapshot.
make keep_serial renewal require replace_old, refuse keep_serial +
revoke_old, and reject serials already revoked by the issuer so revoked
serials cannot be inherited by renewed certificates.