Skip to content

Commit ecdeeb0

Browse files
durchjstuczyn
andcommitted
KKT + PSQ (#6203)
* Add nymkkt with KKT convenience wrappers for nym-lp integration Integrates nymkkt module from georgio/noise-psq branch to enable post-quantum key distribution for nym-lp. Changes: - Add common/nymkkt from georgio/noise-psq (KKT protocol implementation) - Add convenience wrapper layer (kkt.rs) with simplified API: - request_kem_key() - Client requests gateway's KEM key - validate_kem_response() - Client validates signed response - handle_kem_request() - Gateway handles requests - Add nymkkt to workspace members in root Cargo.toml - Export kkt module in lib.rs The KKT (Key Encapsulation Mechanism Transport) protocol enables efficient distribution of post-quantum KEM public keys. Instead of storing large PQ keys in the directory (1KB-500KB), we store 32-byte hashes and fetch actual keys on-demand via this authenticated protocol. Tests: All 5 unit tests passing (authenticated, anonymous, signature verification, hash validation) * feat(lp): add Ed25519 authentication to PSQ protocol Replace basic PSQ v0 API with authenticated v1 API that includes cryptographic authentication via Ed25519 signatures. Changes: - PSQ initiator now signs encapsulated keys with Ed25519 private key - PSQ responder verifies Ed25519 signatures before deriving PSK - Prevents MITM attacks through mutual authentication - Fixed test helpers to use role-based Ed25519 keypair assignment (initiator uses [1u8;32], responder uses [2u8;32]) Security: This adds a critical authentication layer to the post-quantum PSK derivation protocol, ensuring both parties can verify each other's identity during the handshake. Tests: All 77 tests passing (was 11 failures, now 0) * feat(lp): integrate PSQ post-quantum PSK derivation Complete integration of Post-Quantum Secure (PSQ) protocol for PSK derivation in the Lewes Protocol, replacing simple Blake3 derivation with cryptographically secure DHKEM-based PSK establishment. This commit encompasses three completed tasks: - Add KKTRequest/KKTResponse message types to LpMessage enum - Update codec to handle KKT message serialization/deserialization - Add kkt_orchestrator.rs with high-level KKT API wrappers - Enable key exchange orchestration for PSQ protocol - Add set_psk() method to NoiseProtocol for dynamic PSK injection - Integrate PSQ derivation into LpSession handshake flow - PSQ payload embedded in first Noise message (ClientHello) - Derive PSK using libcrux-psq before Noise handshake completion - Add helper functions for X25519 to KEM conversions - Add comprehensive PSQ integration tests in session_integration/ - Test PSQ handshake end-to-end flow - Validate PSK derivation correctness between initiator/responder - Test PSQ + Noise combined protocol operation Dependencies: - libcrux-psq: Post-quantum PSK protocol implementation - libcrux-kem: Key Encapsulation Mechanism primitives - nym-kkt: KKT key exchange protocol wrappers - rand 0.9: Required for KKT compatibility Security: This adds Harvest-Now-Decrypt-Later (HNDL) resistance by combining classical ECDH with post-quantum KEM for PSK derivation. Even if X25519 is broken by quantum computers, the PSK remains secure. Tests: All 77 tests passing * feat(lp): add PSQ error handling documentation and tests (nym-bbi) Formalize the "always abort" error handling strategy for PSQ failures. PSQ errors indicate attacks, misconfigurations, or protocol violations that should not be silently ignored or worked around. Changes: - Add comprehensive error handling documentation to psk.rs module - Add diagnostic logging with error categorization: * CredError → warn about potential attack * TimestampElapsed → warn about potential replay * Other errors → log as errors - Add 4 error scenario tests: * test_psq_deserialization_failure * test_handshake_abort_on_psq_failure * test_psq_invalid_signature * test_psq_state_unchanged_on_error - Add log dependency to Cargo.toml Error handling strategy: All PSQ failures abort the handshake cleanly with no retry or fallback. This prevents silent security degradation and ensures misconfigurations are detected early. State guarantees: PSQ errors leave session in clean state - dummy PSK remains, Noise HandshakeState unchanged, no partial data, no cleanup needed. Tests: 81 tests passing (77 original + 4 new error tests) Closes: nym-bbi * feat(lp): add PSK injection tracking to prevent dummy PSK usage (nym-ep2) Add safety mechanism to ensure real post-quantum PSK was injected before allowing transport mode operations (encrypt/decrypt). This prevents accidentally using the insecure dummy PSK [0u8; 32] if PSQ injection fails. Changes: - Add `psk_injected: AtomicBool` field to LpSession - Initialize to `false` in LpSession::new() - Set to `true` after successful PSK injection: * Initiator: In prepare_handshake_message() after set_psk() * Responder: In process_handshake_message() after set_psk() - Add NoiseError::PskNotInjected error variant - Add PSK injection checks in encrypt_data() and decrypt_data() * Check happens before handshake completion check * Returns PskNotInjected if flag is false - Add comprehensive PSK injection lifecycle documentation to LpSession - Add test_transport_fails_without_psk_injection test - Update test_encrypt_decrypt_before_handshake to expect PskNotInjected PSK Injection Lifecycle: 1. Session created with dummy PSK [0u8; 32] in Noise HandshakeState 2. During handshake, PSQ runs and derives real post-quantum PSK 3. Real PSK injected via set_psk() - psk_injected flag set to true 4. Handshake completes, transport mode available 5. Transport operations check psk_injected flag for safety This is defensive programming - normal PSQ flow always injects the real PSK. The safety check prevents transport mode if PSQ somehow fails silently or is bypassed due to implementation bugs. Tests: 82 tests passing (81 original + 1 new) Closes: nym-ep2 * docs(lp): fix PSK state documentation inaccuracy Correct error handling documentation to clarify that PSK slot 3 remains unmodified only on error, not in all cases. Previous: "PSK slot 3 = dummy [0u8; 32] (never modified)" Corrected: "PSK slot 3 = dummy [0u8; 32] (not modified on error)" This is more accurate since: - On error: PSK remains as dummy value (never injected) - On success: PSK is replaced with real post-quantum PSK Documentation-only change, no functional impact. * feat(lp): add KKTExchange state to state machine for pre-handshake KEM key transfer (nym-4za) Add KKTExchange state to LpStateMachine to properly orchestrate KKT (KEM Key Transfer) protocol before Noise handshake begins. This enables dynamic KEM public key exchange, allowing post-quantum KEM algorithms to be used without pre-published keys. Changes: - Add KKTExchange state and KKTComplete action to state machine - Implement automatic KKT exchange on StartHandshake: * Initiator: sends KKT request → waits for response → validates signature * Responder: waits for request → validates → sends signed KEM key - Update process_kkt_response() to accept Option<&[u8]> for hash validation: * Some(hash): full KKT validation with directory hash (future) * None: signature-only mode (current deployment) - Add local_x25519_public() helper for responder KEM key derivation - Update state flow: ReadyToHandshake → KKTExchange → Handshaking → Transport - Add PSK handle storage (psk_handle) for future re-registration - Export generate_fresh_salt() for session creation - Update psq_responder_process_message() to return encrypted PSK handle (ctxt_B) - Add comprehensive tests: * test_kkt_exchange_initiator_flow * test_kkt_exchange_responder_flow * test_kkt_exchange_full_roundtrip * test_kkt_exchange_close * test_kkt_exchange_rejects_invalid_inputs * Updated test_state_machine_simplified_flow for KKT phase All tests passing. Ready for nym-8y5 (PSQ handshake KKT integration). * docs(lp): add state machine and post-quantum security protocol documentation Add comprehensive documentation of the Lewes Protocol state machine and post-quantum security architecture to LP_PROTOCOL.md. New sections: - State Machine and Security Protocol overview - Detailed state transition diagram (ReadyToHandshake → KKTExchange → Handshaking → Transport) - Complete message sequence diagram showing KKT + PSQ + Noise flow - KKT (KEM Key Transfer) protocol specification - PSQ (Post-Quantum Secure PSK) protocol details - Security guarantees and implementation status - Algorithm choices (current X25519, future ML-KEM-768) - Message type specifications for KKT - Version 1.1 changelog entry documenting KKT/PSQ integration Documentation includes: - ASCII art state machine diagram - Message sequence diagram with all protocol phases - PSK derivation formulas - Security properties checklist - Migration path to post-quantum KEMs - Integration details (PSQ embedded in Noise, no extra round-trips) Related to nym-4za (KKTExchange state implementation). * feat(lp): use KKT-authenticated KEM key in PSQ handshake (nym-8y5) Replace direct X25519→KEM conversion with KKT-derived authenticated key in PSQ initiator flow. This ensures PSQ uses the responder's authenticated KEM public key obtained via KKT protocol instead of blindly converting their X25519 key, properly completing the post-quantum security chain. Changes: - session.rs: Extract KEM key from KKTState::Completed in prepare_handshake_message() - session.rs: Add set_kkt_completed_for_test() helper for test initialization - session.rs: Update create_handshake_test_session() to initialize KKT state - session.rs: Fix test_handshake_abort_on_psq_failure and test_psq_invalid_signature - session_manager.rs: Add init_kkt_for_test() for integration test setup - session_integration/mod.rs: Update tests for KKT-first flow (6 rounds total) - session_integration/mod.rs: Fix state machine test expectations for KKTExchange state All 87 tests passing. Unblocks nym-w8f (KKT tests) and nym-m15 (production integration). * feat(lp): simplify API to Ed25519-only, derive X25519 internally Refactored LP state machine to use Ed25519 keys exclusively in the public API, with X25519 keys derived internally via RFC 7748. This simplifies the API from 6 parameters to 4 while maintaining protocol security. **Core API Changes:** - LpStateMachine::new(): Removed explicit X25519 keypair parameters - Old: new(is_initiator, local_keypair, local_ed25519_keypair, remote_public_key, remote_ed25519_key, salt) - New: new(is_initiator, local_ed25519_keypair, remote_ed25519_key, salt) - X25519 keys now derived internally from Ed25519 using RFC 7748 - lp_id calculation moved inside state machine (uses derived X25519 keys) **Protocol Changes:** - ClientHello message extended from 65 to 97 bytes - Now includes client_ed25519_public_key field (32 bytes) - Required for PSQ authentication in KKT + PSQ handshake flow - Breaking change: gateway must extract Ed25519 from ClientHello **Gateway Updates:** - receive_client_hello() now extracts Ed25519 public key - LpGatewayHandshake::new_responder() accepts Ed25519 keys only - Removed manual X25519 conversion (handled by state machine) **Registration Client Updates:** - LpRegistrationClient now uses Ed25519 keypairs - Generate fresh ephemeral Ed25519 keys for LP registration - ClientHello includes Ed25519 public key for gateway authentication - Fixed 7 pre-existing build errors: * mixnet_client_startup_timeout field removal * IprClientConnect API change (async → sync) * Error variant renames (use helper function) * LP client key type mismatches (X25519 → Ed25519) **Test Suite:** - Updated 16+ test functions to use new 4-parameter constructor - Fixed 5 integration test failures caused by lp_id mismatch - Tests now derive X25519 from Ed25519 (matching production behavior) - Added missing PublicKey imports in test modules - All 87 tests passing (100% success rate) **Implementation Details:** - Added Ed25519RecoveryError variant to LpError enum - Type conversion: nym_crypto X25519 → nym_lp keypair types - Maintained backward compatibility for PSQ/KKT protocol flow - Session manager updated to use new API signature This change completes the Ed25519-only API migration, hiding X25519 as an implementation detail while preserving all security properties of the KKT-authenticated PSQ handshake protocol. * chore: run cargo fmt * chore: run cargo clippy --fix to resolve simple linter issues * Basic handshake working * Final tweaks * Wrap PR comments, 2024 --------- Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
1 parent 6d0e4f6 commit ecdeeb0

File tree

70 files changed

+8027
-2889
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+8027
-2889
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,6 @@ nym-api/redocly/formatted-openapi.json
6363

6464
**/settings.sql
6565
**/enter_db.sh
66-
.beads
66+
.beads
67+
CLAUDE.md
68+
docs

0 commit comments

Comments
 (0)