From 678f65343910f55c2d15e6012fefe8c21a2e8ff2 Mon Sep 17 00:00:00 2001 From: Bug Magnet Date: Tue, 20 Aug 2024 16:51:20 +0200 Subject: [PATCH] Enable Daita in the PacketTunnel actor --- ...swift => EphemeralPeerExchangeActor.swift} | 22 +-- ...or.swift => EphemeralPeerNegotiator.swift} | 38 ++--- .../PacketTunnelProvider+TCPConnection.swift | 38 ++--- .../include/mullvad_rust_runtime.h | 49 ++++--- ... => EphemeralPeerExchangeActorTests.swift} | 18 +-- .../MullvadPostQuantum+Stubs.swift | 18 ++- .../TCPConnection.swift | 2 +- .../TCPUnsafeListener.swift | 2 +- .../TunnelObfuscationTests.swift | 2 +- .../UDPConnection.swift | 2 +- ...iver.swift => EphemeralPeerReceiver.swift} | 17 ++- .../Protocols/EphemeralPeerReceiving.swift | 26 ++++ .../Protocols/PostQuantumKeyReceiving.swift | 19 --- ios/MullvadVPN.xcodeproj/project.pbxproj | 134 +++++++++--------- .../Coordinators/ApplicationCoordinator.swift | 2 +- .../SimulatorTunnelProviderHost.swift | 3 +- .../MapConnectionStatusOperation.swift | 4 +- .../TunnelManager/StopTunnelOperation.swift | 2 +- .../TunnelManager/TunnelManager.swift | 2 +- .../TunnelManager/TunnelState+UI.swift | 9 +- .../TunnelManager/TunnelState.swift | 11 +- .../Tunnel/TunnelControlView.swift | 2 +- .../Tunnel/TunnelViewController.swift | 2 +- .../PacketTunnelActorReducerTests.swift | 7 +- .../PacketTunnelProvider.swift | 38 ++--- ... => EphemeralPeerExchangingPipeline.swift} | 30 ++-- ...t => MultiHopEphemeralPeerExchanger.swift} | 79 +++++++---- .../SingleHopEphemeralPeerExchanger.swift | 90 ++++++++++++ .../SingleHopPostQuantumKeyExchanging.swift | 65 --------- .../WireGuardAdapter/WgAdapter.swift | 15 +- .../WireGuardAdapter+Async.swift | 16 ++- ...uantumKey.swift => EphemeralPeerKey.swift} | 9 +- ...ft => EphemeralPeerNegotiationState.swift} | 18 +-- .../Actor/ObservedState+Extensions.swift | 4 +- .../Actor/ObservedState.swift | 14 +- ...cketTunnelActor+ConnectionMonitoring.swift | 4 +- .../Actor/PacketTunnelActor+ErrorState.swift | 6 +- .../Actor/PacketTunnelActor+PostQuantum.swift | 26 ++-- .../Actor/PacketTunnelActor+Public.swift | 12 +- .../Actor/PacketTunnelActor.swift | 39 +++-- .../Actor/PacketTunnelActorCommand.swift | 14 +- .../Actor/PacketTunnelActorReducer.swift | 24 ++-- ... => EphemeralPeerExchangingProtocol.swift} | 3 +- .../Protocols/TunnelAdapterProtocol.swift | 5 +- .../Actor/State+Extensions.swift | 23 ++- ios/PacketTunnelCore/Actor/State.swift | 9 +- ...phemeralPeerExchangingPipelineTests.swift} | 107 ++++++++++---- .../EphemeralPeerExchangeActorStub.swift} | 20 +-- .../{ => Mocks}/KeyExchangingResultStub.swift | 9 +- .../Mocks/TunnelAdapterDummy.swift | 6 +- ...MultiHopEphemeralPeerExchangerTests.swift} | 76 +++++++--- .../PacketTunnelActorTests.swift | 2 +- ...ingleHopEphemeralPeerExchangerTests.swift} | 63 ++++++-- .../ios_runtime.rs | 77 +++++----- .../ios_tcp_connection.rs | 9 +- .../mod.rs | 66 ++++++--- mullvad-ios/src/lib.rs | 2 +- 57 files changed, 872 insertions(+), 539 deletions(-) rename ios/MullvadRustRuntime/{PostQuantumKeyExchangeActor.swift => EphemeralPeerExchangeActor.swift} (85%) rename ios/MullvadRustRuntime/{PostQuantumKeyNegotiator.swift => EphemeralPeerNegotiator.swift} (60%) rename ios/MullvadRustRuntimeTests/{MullvadPostQuantumTests.swift => EphemeralPeerExchangeActorTests.swift} (81%) rename ios/MullvadTypes/Protocols/{PostQuantumKeyReceiver.swift => EphemeralPeerReceiver.swift} (61%) create mode 100644 ios/MullvadTypes/Protocols/EphemeralPeerReceiving.swift delete mode 100644 ios/MullvadTypes/Protocols/PostQuantumKeyReceiving.swift rename ios/PacketTunnel/PostQuantum/{PostQuantumKeyExchangingPipeline.swift => EphemeralPeerExchangingPipeline.swift} (55%) rename ios/PacketTunnel/PostQuantum/{MultiHopPostQuantumKeyExchanging.swift => MultiHopEphemeralPeerExchanger.swift} (52%) create mode 100644 ios/PacketTunnel/PostQuantum/SingleHopEphemeralPeerExchanger.swift delete mode 100644 ios/PacketTunnel/PostQuantum/SingleHopPostQuantumKeyExchanging.swift rename ios/PacketTunnelCore/Actor/{PostQuantumKey.swift => EphemeralPeerKey.swift} (53%) rename ios/PacketTunnelCore/Actor/{PostQuantumNegotiationState.swift => EphemeralPeerNegotiationState.swift} (67%) rename ios/PacketTunnelCore/Actor/Protocols/{PostQuantumKeyExchangingProtocol.swift => EphemeralPeerExchangingProtocol.swift} (73%) rename ios/PacketTunnelCoreTests/{PostQuantumKeyExchangingPipelineTests.swift => EphemeralPeerExchangingPipelineTests.swift} (53%) rename ios/PacketTunnelCoreTests/{PostQuantumKeyExchangeActorStub.swift => Mocks/EphemeralPeerExchangeActorStub.swift} (50%) rename ios/PacketTunnelCoreTests/{ => Mocks}/KeyExchangingResultStub.swift (62%) rename ios/PacketTunnelCoreTests/{MultiHopPostQuantumKeyExchangingTests.swift => MultiHopEphemeralPeerExchangerTests.swift} (57%) rename ios/PacketTunnelCoreTests/{SingleHopPostQuantumKeyExchangingTests.swift => SingleHopEphemeralPeerExchangerTests.swift} (58%) rename mullvad-ios/src/{post_quantum_proxy => ephemeral_peer_proxy}/ios_runtime.rs (70%) rename mullvad-ios/src/{post_quantum_proxy => ephemeral_peer_proxy}/ios_tcp_connection.rs (95%) rename mullvad-ios/src/{post_quantum_proxy => ephemeral_peer_proxy}/mod.rs (71%) diff --git a/ios/MullvadRustRuntime/PostQuantumKeyExchangeActor.swift b/ios/MullvadRustRuntime/EphemeralPeerExchangeActor.swift similarity index 85% rename from ios/MullvadRustRuntime/PostQuantumKeyExchangeActor.swift rename to ios/MullvadRustRuntime/EphemeralPeerExchangeActor.swift index a854d83cd8d7..397b656d612b 100644 --- a/ios/MullvadRustRuntime/PostQuantumKeyExchangeActor.swift +++ b/ios/MullvadRustRuntime/EphemeralPeerExchangeActor.swift @@ -1,5 +1,5 @@ // -// PostQuantumKeyExchangeActor.swift +// EphemeralPeerExchangeActor.swift // PacketTunnel // // Created by Marco Nikic on 2024-04-12. @@ -12,15 +12,15 @@ import MullvadTypes import NetworkExtension import WireGuardKitTypes -public protocol PostQuantumKeyExchangeActorProtocol { - func startNegotiation(with privateKey: PrivateKey) +public protocol EphemeralPeerExchangeActorProtocol { + func startNegotiation(with privateKey: PrivateKey, enablePostQuantum: Bool, enableDaita: Bool) func endCurrentNegotiation() func reset() } -public class PostQuantumKeyExchangeActor: PostQuantumKeyExchangeActorProtocol { +public class EphemeralPeerExchangeActor: EphemeralPeerExchangeActorProtocol { struct Negotiation { - var negotiator: PostQuantumKeyNegotiating + var negotiator: EphemeralPeerNegotiating var inTunnelTCPConnection: NWTCPConnection var tcpConnectionObserver: NSKeyValueObservation @@ -36,7 +36,7 @@ public class PostQuantumKeyExchangeActor: PostQuantumKeyExchangeActorProtocol { private var timer: DispatchSourceTimer? private var keyExchangeRetriesIterator: AnyIterator! private let iteratorProvider: () -> AnyIterator - private let negotiationProvider: PostQuantumKeyNegotiating.Type + private let negotiationProvider: EphemeralPeerNegotiating.Type // Callback in the event of the negotiation failing on startup var onFailure: () -> Void @@ -44,7 +44,7 @@ public class PostQuantumKeyExchangeActor: PostQuantumKeyExchangeActorProtocol { public init( packetTunnel: any TunnelProvider, onFailure: @escaping (() -> Void), - negotiationProvider: PostQuantumKeyNegotiating.Type = PostQuantumKeyNegotiator.self, + negotiationProvider: EphemeralPeerNegotiating.Type = EphemeralPeerNegotiator.self, iteratorProvider: @escaping () -> AnyIterator ) { self.packetTunnel = packetTunnel @@ -71,7 +71,7 @@ public class PostQuantumKeyExchangeActor: PostQuantumKeyExchangeActorProtocol { /// It is reset after every successful key exchange. /// /// - Parameter privateKey: The device's current private key - public func startNegotiation(with privateKey: PrivateKey) { + public func startNegotiation(with privateKey: PrivateKey, enablePostQuantum: Bool, enableDaita: Bool) { endCurrentNegotiation() let negotiator = negotiationProvider.init() @@ -99,9 +99,11 @@ public class PostQuantumKeyExchangeActor: PostQuantumKeyExchangeActorProtocol { gatewayIP: IPv4Gateway, devicePublicKey: privateKey.publicKey, presharedKey: ephemeralSharedKey, - postQuantumKeyReceiver: packetTunnel, + peerReceiver: packetTunnel, tcpConnection: inTunnelTCPConnection, - postQuantumKeyExchangeTimeout: tcpConnectionTimeout + peerExchangeTimeout: tcpConnectionTimeout, + enablePostQuantum: enablePostQuantum, + enableDaita: enableDaita ) { // Cancel the negotiation to shut down any remaining use of the TCP connection on the Rust side self.negotiation?.cancel() diff --git a/ios/MullvadRustRuntime/PostQuantumKeyNegotiator.swift b/ios/MullvadRustRuntime/EphemeralPeerNegotiator.swift similarity index 60% rename from ios/MullvadRustRuntime/PostQuantumKeyNegotiator.swift rename to ios/MullvadRustRuntime/EphemeralPeerNegotiator.swift index c653fc8983c7..ffc0dc15b394 100644 --- a/ios/MullvadRustRuntime/PostQuantumKeyNegotiator.swift +++ b/ios/MullvadRustRuntime/EphemeralPeerNegotiator.swift @@ -12,14 +12,16 @@ import NetworkExtension import WireGuardKitTypes // swiftlint:disable function_parameter_count -public protocol PostQuantumKeyNegotiating { +public protocol EphemeralPeerNegotiating { func startNegotiation( gatewayIP: IPv4Address, devicePublicKey: PublicKey, presharedKey: PrivateKey, - postQuantumKeyReceiver: any TunnelProvider, + peerReceiver: any TunnelProvider, tcpConnection: NWTCPConnection, - postQuantumKeyExchangeTimeout: Duration + peerExchangeTimeout: Duration, + enablePostQuantum: Bool, + enableDaita: Bool ) -> Bool func cancelKeyNegotiation() @@ -27,35 +29,37 @@ public protocol PostQuantumKeyNegotiating { init() } -/** - Attempt to start the asynchronous process of key negotiation. Returns true if successfully started, false if failed. - */ -public class PostQuantumKeyNegotiator: PostQuantumKeyNegotiating { +/// Requests an ephemeral peer asynchronously. +public class EphemeralPeerNegotiator: EphemeralPeerNegotiating { required public init() {} - var cancelToken: PostQuantumCancelToken? + var cancelToken: EphemeralPeerCancelToken? public func startNegotiation( gatewayIP: IPv4Address, devicePublicKey: PublicKey, presharedKey: PrivateKey, - postQuantumKeyReceiver: any TunnelProvider, + peerReceiver: any TunnelProvider, tcpConnection: NWTCPConnection, - postQuantumKeyExchangeTimeout: Duration + peerExchangeTimeout: Duration, + enablePostQuantum: Bool, + enableDaita: Bool ) -> Bool { // swiftlint:disable:next force_cast - let postQuantumKeyReceiver = Unmanaged.passUnretained(postQuantumKeyReceiver as! PostQuantumKeyReceiver) + let ephemeralPeerReceiver = Unmanaged.passUnretained(peerReceiver as! EphemeralPeerReceiver) .toOpaque() let opaqueConnection = Unmanaged.passUnretained(tcpConnection).toOpaque() - var cancelToken = PostQuantumCancelToken() + var cancelToken = EphemeralPeerCancelToken() - let result = negotiate_post_quantum_key( + let result = request_ephemeral_peer( devicePublicKey.rawValue.map { $0 }, presharedKey.rawValue.map { $0 }, - postQuantumKeyReceiver, + ephemeralPeerReceiver, opaqueConnection, &cancelToken, - UInt64(postQuantumKeyExchangeTimeout.timeInterval) + UInt64(peerExchangeTimeout.timeInterval), + enablePostQuantum, + enableDaita ) guard result == 0 else { return false @@ -66,12 +70,12 @@ public class PostQuantumKeyNegotiator: PostQuantumKeyNegotiating { public func cancelKeyNegotiation() { guard var cancelToken else { return } - cancel_post_quantum_key_exchange(&cancelToken) + cancel_ephemeral_peer_exchange(&cancelToken) } deinit { guard var cancelToken else { return } - drop_post_quantum_key_exchange_token(&cancelToken) + drop_ephemeral_peer_exchange_token(&cancelToken) } } diff --git a/ios/MullvadRustRuntime/PacketTunnelProvider+TCPConnection.swift b/ios/MullvadRustRuntime/PacketTunnelProvider+TCPConnection.swift index 4c1b3b1607d9..e19750d4dcae 100644 --- a/ios/MullvadRustRuntime/PacketTunnelProvider+TCPConnection.swift +++ b/ios/MullvadRustRuntime/PacketTunnelProvider+TCPConnection.swift @@ -78,35 +78,41 @@ func tcpConnectionReceive( } } -/// End sequence of a quantum-secure pre shared key exchange. +/// End sequence of an ephemeral peer exchange. /// -/// This FFI function is called by Rust when the quantum-secure pre shared key exchange has either failed, or succeeded. +/// This FFI function is called by Rust when an ephemeral peer negotiation succeeded or failed. /// When both the `rawPresharedKey` and the `rawEphemeralKey` are raw pointers to 32 bytes data arrays, -/// the quantum-secure key exchange is considered successful. In any other case, the exchange is considered failed. +/// the quantum-secure key exchange is considered successful. +/// If the `rawPresharedKey` is nil, but there is a valid `rawEphemeralKey`, it means a Daita peer has been negotiated with. +/// If `rawEphemeralKey` is nil, the negotiation is considered failed. /// /// - Parameters: -/// - rawPacketTunnel: A raw pointer to the running instance of `NEPacketTunnelProvider` +/// - rawEphemeralPeerReceiver: A raw pointer to the running instance of `NEPacketTunnelProvider` /// - rawPresharedKey: A raw pointer to the quantum-secure pre shared key /// - rawEphemeralKey: A raw pointer to the ephemeral private key of the device -@_cdecl("swift_post_quantum_key_ready") +@_cdecl("swift_ephemeral_peer_ready") func receivePostQuantumKey( - rawPostQuantumKeyReceiver: UnsafeMutableRawPointer?, + rawEphemeralPeerReceiver: UnsafeMutableRawPointer?, rawPresharedKey: UnsafeMutableRawPointer?, rawEphemeralKey: UnsafeMutableRawPointer? ) { - guard let rawPostQuantumKeyReceiver else { return } - let postQuantumKeyReceiver = Unmanaged.fromOpaque(rawPostQuantumKeyReceiver) + guard let rawEphemeralPeerReceiver else { return } + let ephemeralPeerReceiver = Unmanaged.fromOpaque(rawEphemeralPeerReceiver) .takeUnretainedValue() - guard - let rawPresharedKey, - let rawEphemeralKey, - let ephemeralKey = PrivateKey(rawValue: Data(bytes: rawEphemeralKey, count: 32)), - let key = PreSharedKey(rawValue: Data(bytes: rawPresharedKey, count: 32)) - else { - postQuantumKeyReceiver.keyExchangeFailed() + // If there are no private keys for the ephemeral peer, then the negotiation either failed, or timed out. + guard let rawEphemeralKey, + let ephemeralKey = PrivateKey(rawValue: Data(bytes: rawEphemeralKey, count: 32)) else { + ephemeralPeerReceiver.ephemeralPeerExchangeFailed() return } - postQuantumKeyReceiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey) + // If there is a pre-shared key, an ephemeral peer was negotiated with Post Quantum options + // Otherwise, a Daita enabled ephemeral peer was requested + if let rawPresharedKey, let key = PreSharedKey(rawValue: Data(bytes: rawPresharedKey, count: 32)) { + ephemeralPeerReceiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey) + } else { + ephemeralPeerReceiver.receiveEphemeralPeerPrivateKey(ephemeralKey) + } + return } diff --git a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h index 9b5c8bd4c159..c42d2ae84074 100644 --- a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h +++ b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h @@ -5,9 +5,9 @@ #include #include -typedef struct PostQuantumCancelToken { +typedef struct EphemeralPeerCancelToken { void *context; -} PostQuantumCancelToken; +} EphemeralPeerCancelToken; typedef struct ProxyHandle { void *context; @@ -17,28 +17,28 @@ typedef struct ProxyHandle { extern const uint16_t CONFIG_SERVICE_PORT; /** - * Called by the Swift side to signal that the quantum-secure key exchange should be cancelled. + * Called by the Swift side to signal that the ephemeral peer exchange should be cancelled. * After this call, the cancel token is no longer valid. * * # Safety - * `sender` must be pointing to a valid instance of a `PostQuantumCancelToken` created by the + * `sender` must be pointing to a valid instance of a `EphemeralPeerCancelToken` created by the * `PacketTunnelProvider`. */ -void cancel_post_quantum_key_exchange(const struct PostQuantumCancelToken *sender); +void cancel_ephemeral_peer_exchange(const struct EphemeralPeerCancelToken *sender); /** - * Called by the Swift side to signal that the Rust `PostQuantumCancelToken` can be safely dropped + * Called by the Swift side to signal that the Rust `EphemeralPeerCancelToken` can be safely dropped * from memory. * * # Safety - * `sender` must be pointing to a valid instance of a `PostQuantumCancelToken` created by the + * `sender` must be pointing to a valid instance of a `EphemeralPeerCancelToken` created by the * `PacketTunnelProvider`. */ -void drop_post_quantum_key_exchange_token(const struct PostQuantumCancelToken *sender); +void drop_ephemeral_peer_exchange_token(const struct EphemeralPeerCancelToken *sender); /** * Called by Swift whenever data has been written to the in-tunnel TCP connection when exchanging - * quantum-resistant pre shared keys. + * quantum-resistant pre shared keys, or ephemeral peers. * * If `bytes_sent` is 0, this indicates that the connection was closed or that an error occurred. * @@ -50,7 +50,7 @@ void handle_sent(uintptr_t bytes_sent, const void *sender); /** * Called by Swift whenever data has been read from the in-tunnel TCP connection when exchanging - * quantum-resistant pre shared keys. + * quantum-resistant pre shared keys, or ephemeral peers. * * If `data` is null or empty, this indicates that the connection was closed or that an error * occurred. An empty buffer is sent to the underlying reader to signal EOF. @@ -63,7 +63,7 @@ void handle_sent(uintptr_t bytes_sent, const void *sender); void handle_recv(const uint8_t *data, uintptr_t data_len, const void *sender); /** - * Entry point for exchanging post quantum keys on iOS. + * Entry point for requesting ephemeral peers on iOS. * The TCP connection must be created to go through the tunnel. * # Safety * `public_key` and `ephemeral_key` must be valid respective `PublicKey` and `PrivateKey` types. @@ -72,12 +72,14 @@ void handle_recv(const uint8_t *data, uintptr_t data_len, const void *sender); * connection instances. * `cancel_token` should be owned by the caller of this function. */ -int32_t negotiate_post_quantum_key(const uint8_t *public_key, - const uint8_t *ephemeral_key, - const void *packet_tunnel, - const void *tcp_connection, - struct PostQuantumCancelToken *cancel_token, - uint64_t post_quantum_key_exchange_timeout); +int32_t request_ephemeral_peer(const uint8_t *public_key, + const uint8_t *ephemeral_key, + const void *packet_tunnel, + const void *tcp_connection, + struct EphemeralPeerCancelToken *cancel_token, + uint64_t peer_exchange_timeout, + bool enable_post_quantum, + bool enable_daita); /** * Called when there is data to send on the TCP connection. @@ -95,12 +97,15 @@ extern void swift_nw_tcp_connection_send(const void *connection, extern void swift_nw_tcp_connection_read(const void *connection, const void *sender); /** - * Called when the preshared post quantum key is ready. - * `raw_preshared_key` might be NULL if the key negotiation failed. + * Called when the preshared post quantum key is ready, + * or when a Daita peer has been successfully requested. + * `raw_preshared_key` will be NULL if: + * - The post quantum key negotiation failed + * - A Daita peer has been requested without enabling post quantum keys. */ -extern void swift_post_quantum_key_ready(const void *raw_packet_tunnel, - const uint8_t *raw_preshared_key, - const uint8_t *raw_ephemeral_private_key); +extern void swift_ephemeral_peer_ready(const void *raw_packet_tunnel, + const uint8_t *raw_preshared_key, + const uint8_t *raw_ephemeral_private_key); /** * # Safety diff --git a/ios/MullvadRustRuntimeTests/MullvadPostQuantumTests.swift b/ios/MullvadRustRuntimeTests/EphemeralPeerExchangeActorTests.swift similarity index 81% rename from ios/MullvadRustRuntimeTests/MullvadPostQuantumTests.swift rename to ios/MullvadRustRuntimeTests/EphemeralPeerExchangeActorTests.swift index 1d9fe2f2f6ee..662aeef9087e 100644 --- a/ios/MullvadRustRuntimeTests/MullvadPostQuantumTests.swift +++ b/ios/MullvadRustRuntimeTests/EphemeralPeerExchangeActorTests.swift @@ -1,6 +1,6 @@ // -// MullvadPostQuantumTests.swift -// MullvadPostQuantumTests +// EphemeralPeerExchangeActorTests.swift +// MullvadRustRuntimeTests // // Created by Marco Nikic on 2024-06-12. // Copyright © 2024 Mullvad VPN AB. All rights reserved. @@ -14,7 +14,7 @@ import NetworkExtension @testable import WireGuardKitTypes import XCTest -class MullvadPostQuantumTests: XCTestCase { +class EphemeralPeerExchangeActorTests: XCTestCase { var tcpConnection: NWTCPConnectionStub! var tunnelProvider: TunnelProviderStub! @@ -26,7 +26,7 @@ class MullvadPostQuantumTests: XCTestCase { func testKeyExchangeFailsWhenNegotiationCannotStart() { let negotiationFailure = expectation(description: "Negotiation failed") - let keyExchangeActor = PostQuantumKeyExchangeActor( + let keyExchangeActor = EphemeralPeerExchangeActor( packetTunnel: tunnelProvider, onFailure: { negotiationFailure.fulfill() @@ -36,7 +36,7 @@ class MullvadPostQuantumTests: XCTestCase { ) let privateKey = PrivateKey() - keyExchangeActor.startNegotiation(with: privateKey) + keyExchangeActor.startNegotiation(with: privateKey, enablePostQuantum: true, enableDaita: false) tcpConnection.becomeViable() wait(for: [negotiationFailure]) @@ -46,7 +46,7 @@ class MullvadPostQuantumTests: XCTestCase { let negotiationFailure = expectation(description: "Negotiation failed") // Setup the actor to wait only 10 milliseconds before declaring the TCP connection is not ready in time. - let keyExchangeActor = PostQuantumKeyExchangeActor( + let keyExchangeActor = EphemeralPeerExchangeActor( packetTunnel: tunnelProvider, onFailure: { negotiationFailure.fulfill() @@ -56,7 +56,7 @@ class MullvadPostQuantumTests: XCTestCase { ) let privateKey = PrivateKey() - keyExchangeActor.startNegotiation(with: privateKey) + keyExchangeActor.startNegotiation(with: privateKey, enablePostQuantum: true, enableDaita: false) wait(for: [negotiationFailure]) } @@ -65,7 +65,7 @@ class MullvadPostQuantumTests: XCTestCase { let unexpectedNegotiationFailure = expectation(description: "Unexpected negotiation failure") unexpectedNegotiationFailure.isInverted = true - let keyExchangeActor = PostQuantumKeyExchangeActor( + let keyExchangeActor = EphemeralPeerExchangeActor( packetTunnel: tunnelProvider, onFailure: { unexpectedNegotiationFailure.fulfill() @@ -75,7 +75,7 @@ class MullvadPostQuantumTests: XCTestCase { ) let privateKey = PrivateKey() - keyExchangeActor.startNegotiation(with: privateKey) + keyExchangeActor.startNegotiation(with: privateKey, enablePostQuantum: true, enableDaita: false) let negotiationProvider = try XCTUnwrap( keyExchangeActor.negotiation? diff --git a/ios/MullvadRustRuntimeTests/MullvadPostQuantum+Stubs.swift b/ios/MullvadRustRuntimeTests/MullvadPostQuantum+Stubs.swift index 04ada1293a2f..683e1ab8de61 100644 --- a/ios/MullvadRustRuntimeTests/MullvadPostQuantum+Stubs.swift +++ b/ios/MullvadRustRuntimeTests/MullvadPostQuantum+Stubs.swift @@ -1,6 +1,6 @@ // // MullvadPostQuantum+Stubs.swift -// MullvadPostQuantumTests +// MullvadRustRuntimeTests // // Created by Marco Nikic on 2024-06-12. // Copyright © 2024 Mullvad VPN AB. All rights reserved. @@ -43,7 +43,7 @@ class TunnelProviderStub: TunnelProvider { } } -class FailedNegotiatorStub: PostQuantumKeyNegotiating { +class FailedNegotiatorStub: EphemeralPeerNegotiating { var onCancelKeyNegotiation: (() -> Void)? required init() { @@ -58,9 +58,11 @@ class FailedNegotiatorStub: PostQuantumKeyNegotiating { gatewayIP: IPv4Address, devicePublicKey: WireGuardKitTypes.PublicKey, presharedKey: WireGuardKitTypes.PrivateKey, - postQuantumKeyReceiver packetTunnel: any MullvadTypes.TunnelProvider, + peerReceiver packetTunnel: any MullvadTypes.TunnelProvider, tcpConnection: NWTCPConnection, - postQuantumKeyExchangeTimeout: MullvadTypes.Duration + peerExchangeTimeout: MullvadTypes.Duration, + enablePostQuantum: Bool, + enableDaita: Bool ) -> Bool { false } func cancelKeyNegotiation() { @@ -68,7 +70,7 @@ class FailedNegotiatorStub: PostQuantumKeyNegotiating { } } -class SuccessfulNegotiatorStub: PostQuantumKeyNegotiating { +class SuccessfulNegotiatorStub: EphemeralPeerNegotiating { var onCancelKeyNegotiation: (() -> Void)? required init() { onCancelKeyNegotiation = nil @@ -82,9 +84,11 @@ class SuccessfulNegotiatorStub: PostQuantumKeyNegotiating { gatewayIP: IPv4Address, devicePublicKey: WireGuardKitTypes.PublicKey, presharedKey: WireGuardKitTypes.PrivateKey, - postQuantumKeyReceiver packetTunnel: any MullvadTypes.TunnelProvider, + peerReceiver packetTunnel: any MullvadTypes.TunnelProvider, tcpConnection: NWTCPConnection, - postQuantumKeyExchangeTimeout: MullvadTypes.Duration + peerExchangeTimeout: MullvadTypes.Duration, + enablePostQuantum: Bool, + enableDaita: Bool ) -> Bool { true } func cancelKeyNegotiation() { diff --git a/ios/MullvadRustRuntimeTests/TCPConnection.swift b/ios/MullvadRustRuntimeTests/TCPConnection.swift index 64c4e2a77d51..c8543b4879c8 100644 --- a/ios/MullvadRustRuntimeTests/TCPConnection.swift +++ b/ios/MullvadRustRuntimeTests/TCPConnection.swift @@ -1,6 +1,6 @@ // // TCPConnection.swift -// TunnelObfuscationTests +// MullvadRustRuntimeTests // // Created by pronebird on 27/06/2023. // Copyright © 2023 Mullvad VPN AB. All rights reserved. diff --git a/ios/MullvadRustRuntimeTests/TCPUnsafeListener.swift b/ios/MullvadRustRuntimeTests/TCPUnsafeListener.swift index 7d7b9ed949ab..d01fc29dbb48 100644 --- a/ios/MullvadRustRuntimeTests/TCPUnsafeListener.swift +++ b/ios/MullvadRustRuntimeTests/TCPUnsafeListener.swift @@ -1,6 +1,6 @@ // // TCPUnsafeListener.swift -// TunnelObfuscationTests +// MullvadRustRuntimeTests // // Created by pronebird on 27/06/2023. // Copyright © 2023 Mullvad VPN AB. All rights reserved. diff --git a/ios/MullvadRustRuntimeTests/TunnelObfuscationTests.swift b/ios/MullvadRustRuntimeTests/TunnelObfuscationTests.swift index b2e28a468ff9..7372842c8d81 100644 --- a/ios/MullvadRustRuntimeTests/TunnelObfuscationTests.swift +++ b/ios/MullvadRustRuntimeTests/TunnelObfuscationTests.swift @@ -1,6 +1,6 @@ // // TunnelObfuscationTests.swift -// TunnelObfuscationTests +// MullvadRustRuntimeTests // // Created by pronebird on 27/06/2023. // Copyright © 2023 Mullvad VPN AB. All rights reserved. diff --git a/ios/MullvadRustRuntimeTests/UDPConnection.swift b/ios/MullvadRustRuntimeTests/UDPConnection.swift index 8848643c053b..f0886e5fb57f 100644 --- a/ios/MullvadRustRuntimeTests/UDPConnection.swift +++ b/ios/MullvadRustRuntimeTests/UDPConnection.swift @@ -1,6 +1,6 @@ // // UDPConnection.swift -// TunnelObfuscationTests +// MullvadRustRuntimeTests // // Created by pronebird on 27/06/2023. // Copyright © 2023 Mullvad VPN AB. All rights reserved. diff --git a/ios/MullvadTypes/Protocols/PostQuantumKeyReceiver.swift b/ios/MullvadTypes/Protocols/EphemeralPeerReceiver.swift similarity index 61% rename from ios/MullvadTypes/Protocols/PostQuantumKeyReceiver.swift rename to ios/MullvadTypes/Protocols/EphemeralPeerReceiver.swift index afba29801c1e..e5fc68f68a47 100644 --- a/ios/MullvadTypes/Protocols/PostQuantumKeyReceiver.swift +++ b/ios/MullvadTypes/Protocols/EphemeralPeerReceiver.swift @@ -10,23 +10,28 @@ import Foundation import NetworkExtension import WireGuardKitTypes -public class PostQuantumKeyReceiver: PostQuantumKeyReceiving, TunnelProvider { +public class EphemeralPeerReceiver: EphemeralPeerReceiving, TunnelProvider { unowned let tunnelProvider: NEPacketTunnelProvider public init(tunnelProvider: NEPacketTunnelProvider) { self.tunnelProvider = tunnelProvider } - // MARK: - PostQuantumKeyReceiving + // MARK: - EphemeralPeerReceiving public func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) { - guard let receiver = tunnelProvider as? PostQuantumKeyReceiving else { return } + guard let receiver = tunnelProvider as? EphemeralPeerReceiving else { return } receiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey) } - public func keyExchangeFailed() { - guard let receiver = tunnelProvider as? PostQuantumKeyReceiving else { return } - receiver.keyExchangeFailed() + public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey) { + guard let receiver = tunnelProvider as? EphemeralPeerReceiving else { return } + receiver.receiveEphemeralPeerPrivateKey(ephemeralPeerPrivateKey) + } + + public func ephemeralPeerExchangeFailed() { + guard let receiver = tunnelProvider as? EphemeralPeerReceiving else { return } + receiver.ephemeralPeerExchangeFailed() } // MARK: - TunnelProvider diff --git a/ios/MullvadTypes/Protocols/EphemeralPeerReceiving.swift b/ios/MullvadTypes/Protocols/EphemeralPeerReceiving.swift new file mode 100644 index 000000000000..d55ec09f1ff6 --- /dev/null +++ b/ios/MullvadTypes/Protocols/EphemeralPeerReceiving.swift @@ -0,0 +1,26 @@ +// +// EphemeralPeerReceiving.swift +// MullvadTypes +// +// Created by Andrew Bulhak on 2024-03-05. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import WireGuardKitTypes + +public protocol EphemeralPeerReceiving { + /// Called when successfully requesting an ephemeral peer with Post Quantum PSK enabled + /// + /// - Parameters: + /// - key: The preshared key used by the Ephemeral Peer + /// - ephemeralKey: The private key used by the Ephemeral Peer + func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) + + /// Called when successfully requesting an ephemeral peer with Daita enabled, and Post Quantum PSK disabled + /// - Parameter _:_ The private key used by the Ephemeral Peer + func receiveEphemeralPeerPrivateKey(_: PrivateKey) + + /// Called when an ephemeral peer could not be successfully negotiated + func ephemeralPeerExchangeFailed() +} diff --git a/ios/MullvadTypes/Protocols/PostQuantumKeyReceiving.swift b/ios/MullvadTypes/Protocols/PostQuantumKeyReceiving.swift deleted file mode 100644 index 50809c50b168..000000000000 --- a/ios/MullvadTypes/Protocols/PostQuantumKeyReceiving.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// PostQuantumKeyReceiving.swift -// MullvadTypes -// -// Created by Andrew Bulhak on 2024-03-05. -// Copyright © 2024 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import WireGuardKitTypes - -public protocol PostQuantumKeyReceiving { - func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) - func keyExchangeFailed() -} - -public enum PostQuantumKeyReceivingError: Error { - case invalidKey -} diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 588f358751f4..9bee09d01bce 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -42,7 +42,7 @@ 449275422C3570CA000526DE /* ICMP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 449275412C3570CA000526DE /* ICMP.swift */; }; 449872E12B7BBC5400094DDC /* TunnelSettingsUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 449872E02B7BBC5400094DDC /* TunnelSettingsUpdate.swift */; }; 449872E42B7CB96300094DDC /* TunnelSettingsUpdateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 449872E32B7CB96300094DDC /* TunnelSettingsUpdateTests.swift */; }; - 449EBA262B975B9700DFA4EB /* PostQuantumKeyReceiving.swift in Sources */ = {isa = PBXBuildFile; fileRef = 449EBA252B975B9700DFA4EB /* PostQuantumKeyReceiving.swift */; }; + 449EBA262B975B9700DFA4EB /* EphemeralPeerReceiving.swift in Sources */ = {isa = PBXBuildFile; fileRef = 449EBA252B975B9700DFA4EB /* EphemeralPeerReceiving.swift */; }; 44B02E3B2BC5732D008EDF34 /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44B02E3A2BC5732D008EDF34 /* LoggingTests.swift */; }; 44B02E3C2BC5B8A5008EDF34 /* Bundle+ProductVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5891BF1B25E3E3EB006D6FB0 /* Bundle+ProductVersion.swift */; }; 44B3C43A2BFE2C800079782C /* PacketTunnelActorReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44B3C4392BFE2C800079782C /* PacketTunnelActorReducer.swift */; }; @@ -679,7 +679,7 @@ A90763C32B2858630045ADF0 /* Socks5Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90763C22B2858630045ADF0 /* Socks5Configuration.swift */; }; A90763C52B2858B40045ADF0 /* AnyIPEndpoint+Socks5.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90763C42B2858B40045ADF0 /* AnyIPEndpoint+Socks5.swift */; }; A90763C72B2858DC0045ADF0 /* CancellableChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90763C62B2858DC0045ADF0 /* CancellableChain.swift */; }; - A90C48672C36BC2600DCB94C /* PostQuantumKeyReceiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90C48662C36BC2600DCB94C /* PostQuantumKeyReceiver.swift */; }; + A90C48672C36BC2600DCB94C /* EphemeralPeerReceiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90C48662C36BC2600DCB94C /* EphemeralPeerReceiver.swift */; }; A90C48692C36BF3900DCB94C /* TunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90C48682C36BF3900DCB94C /* TunnelProvider.swift */; }; A91614D12B108D1B00F416EB /* TransportLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91614D02B108D1B00F416EB /* TransportLayer.swift */; }; A91614D62B10B26B00F416EB /* TunnelControlViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91614D52B10B26B00F416EB /* TunnelControlViewModel.swift */; }; @@ -827,7 +827,7 @@ A9D9A4AE2C36CFE9004088DD /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = A9D9A4AD2C36CFE9004088DD /* WireGuardKitTypes */; }; A9D9A4B12C36D10E004088DD /* ShadowSocksProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0DDE40F2B220458006B57A7 /* ShadowSocksProxy.swift */; }; A9D9A4B22C36D12D004088DD /* UDPOverTCPObfuscator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584023212A406BF5007B27AC /* UDPOverTCPObfuscator.swift */; }; - A9D9A4BB2C36D397004088DD /* PostQuantumKeyNegotiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9EB4F9C2B7FAB21002A2D7A /* PostQuantumKeyNegotiator.swift */; }; + A9D9A4BB2C36D397004088DD /* EphemeralPeerNegotiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9EB4F9C2B7FAB21002A2D7A /* EphemeralPeerNegotiator.swift */; }; A9D9A4C42C36D53C004088DD /* MullvadRustRuntime.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A992DA1D2C24709F00DE7CE5 /* MullvadRustRuntime.framework */; }; A9D9A4CC2C36D54E004088DD /* TCPUnsafeListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585A02E82A4B283000C6CAFF /* TCPUnsafeListener.swift */; }; A9D9A4CD2C36D54E004088DD /* UDPConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585A02EA2A4B285800C6CAFF /* UDPConnection.swift */; }; @@ -863,7 +863,7 @@ F03A69F92C2AD414000E2E7E /* FormsheetPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03A69F82C2AD413000E2E7E /* FormsheetPresentationController.swift */; }; F04413612BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; }; F04413622BA45CE30018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; }; - F04AF92D2C466013004A8314 /* PostQuantumNegotiationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04AF92C2C466013004A8314 /* PostQuantumNegotiationState.swift */; }; + F04AF92D2C466013004A8314 /* EphemeralPeerNegotiationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */; }; F04FBE612A8379EE009278D7 /* AppPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04FBE602A8379EE009278D7 /* AppPreferences.swift */; }; F050AE4E2B70D7F8003F4EDB /* LocationCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F050AE4D2B70D7F8003F4EDB /* LocationCellViewModel.swift */; }; F050AE522B70DFC0003F4EDB /* LocationSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = F050AE512B70DFC0003F4EDB /* LocationSection.swift */; }; @@ -874,13 +874,13 @@ F050AE5E2B739A73003F4EDB /* LocationDataSourceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F050AE5D2B739A73003F4EDB /* LocationDataSourceProtocol.swift */; }; F050AE602B73A41E003F4EDB /* AllLocationDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F050AE5F2B73A41E003F4EDB /* AllLocationDataSource.swift */; }; F050AE622B74DBAC003F4EDB /* CustomListsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F050AE612B74DBAC003F4EDB /* CustomListsDataSource.swift */; }; - F0570CD12C4FB8E1007BDF2D /* PostQuantumKeyExchangingPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919762C453FAF00C301F3 /* PostQuantumKeyExchangingPipeline.swift */; }; - F0570CD22C4FB8E1007BDF2D /* SingleHopPostQuantumKeyExchanging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919782C45402E00C301F3 /* SingleHopPostQuantumKeyExchanging.swift */; }; - F0570CD42C4FB8E1007BDF2D /* MultiHopPostQuantumKeyExchanging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F059197C2C454C9200C301F3 /* MultiHopPostQuantumKeyExchanging.swift */; }; + F0570CD12C4FB8E1007BDF2D /* EphemeralPeerExchangingPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919762C453FAF00C301F3 /* EphemeralPeerExchangingPipeline.swift */; }; + F0570CD22C4FB8E1007BDF2D /* SingleHopEphemeralPeerExchanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919782C45402E00C301F3 /* SingleHopEphemeralPeerExchanger.swift */; }; + F0570CD42C4FB8E1007BDF2D /* MultiHopEphemeralPeerExchanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = F059197C2C454C9200C301F3 /* MultiHopEphemeralPeerExchanger.swift */; }; F05769B92C6656E400D9778B /* TunnelSettingsPropagator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05769B82C6656E400D9778B /* TunnelSettingsPropagator.swift */; }; F05769BB2C6661EE00D9778B /* TunnelSettingsStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05769BA2C6661EE00D9778B /* TunnelSettingsStrategy.swift */; }; - F05919752C45194B00C301F3 /* PostQuantumKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919742C45194B00C301F3 /* PostQuantumKey.swift */; }; - F05919802C45515200C301F3 /* PostQuantumKeyExchangeActor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A948809A2BC9308D0090A44C /* PostQuantumKeyExchangeActor.swift */; }; + F05919752C45194B00C301F3 /* EphemeralPeerKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919742C45194B00C301F3 /* EphemeralPeerKey.swift */; }; + F05919802C45515200C301F3 /* EphemeralPeerExchangeActor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A948809A2BC9308D0090A44C /* EphemeralPeerExchangeActor.swift */; }; F05F39942B21C6C6006E60A7 /* relays.json in Resources */ = {isa = PBXBuildFile; fileRef = 58F3C0A524A50155003E76BE /* relays.json */; }; F05F39972B21C735006E60A7 /* RelayCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820675A26E6576800655B05 /* RelayCache.swift */; }; F05F39982B21C73C006E60A7 /* CachedRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA87626B024A600B8C587 /* CachedRelays.swift */; }; @@ -891,10 +891,10 @@ F072D3CF2C07122400906F64 /* SettingsUpdaterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F072D3CE2C07122400906F64 /* SettingsUpdaterTests.swift */; }; F072D3D22C071AD100906F64 /* ShadowsocksLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F072D3D12C071AD100906F64 /* ShadowsocksLoaderTests.swift */; }; F073FCB32C6617D70062EA1D /* TunnelStore+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = F073FCB22C6617D70062EA1D /* TunnelStore+Stubs.swift */; }; - F07751552C50F149006E6A12 /* PostQuantumKeyExchangeActorStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C4C9BF2C495E7500A79006 /* PostQuantumKeyExchangeActorStub.swift */; }; - F07751572C50F149006E6A12 /* PostQuantumKeyExchangingPipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F053F4B92C4A94D300FBD937 /* PostQuantumKeyExchangingPipelineTests.swift */; }; - F07751582C50F149006E6A12 /* MultiHopPostQuantumKeyExchangingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C4C9BD2C49477B00A79006 /* MultiHopPostQuantumKeyExchangingTests.swift */; }; - F07751592C50F149006E6A12 /* SingleHopPostQuantumKeyExchangingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0A163882C47B46300592300 /* SingleHopPostQuantumKeyExchangingTests.swift */; }; + F07751552C50F149006E6A12 /* EphemeralPeerExchangeActorStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C4C9BF2C495E7500A79006 /* EphemeralPeerExchangeActorStub.swift */; }; + F07751572C50F149006E6A12 /* EphemeralPeerExchangingPipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F053F4B92C4A94D300FBD937 /* EphemeralPeerExchangingPipelineTests.swift */; }; + F07751582C50F149006E6A12 /* MultiHopEphemeralPeerExchangerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C4C9BD2C49477B00A79006 /* MultiHopEphemeralPeerExchangerTests.swift */; }; + F07751592C50F149006E6A12 /* SingleHopEphemeralPeerExchangerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0A163882C47B46300592300 /* SingleHopEphemeralPeerExchangerTests.swift */; }; F07B53572C53B5270024F547 /* LocalNetworkIPs.swift in Sources */ = {isa = PBXBuildFile; fileRef = F07B53562C53B5270024F547 /* LocalNetworkIPs.swift */; }; F07BF2622A26279100042943 /* RedeemVoucherOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F07BF2612A26279100042943 /* RedeemVoucherOperation.swift */; }; F07C9D952B220C77006F1C5E /* libmullvad_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 01F1FF1D29F0627D007083C3 /* libmullvad_ios.a */; }; @@ -903,11 +903,11 @@ F08827872B318C840020A383 /* ShadowsocksCipherOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DFF7D92B02862E00F864E0 /* ShadowsocksCipherOptions.swift */; }; F08827882B318F960020A383 /* PersistentAccessMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 586C0D962B04E0AC00E7CDD7 /* PersistentAccessMethod.swift */; }; F08827892B3192110020A383 /* AccessMethodRepositoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58EF875A2B16385400C098B2 /* AccessMethodRepositoryProtocol.swift */; }; - F08B6B772C52878400D0A121 /* MullvadPostQuantumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98F1B502C19C48D003C869E /* MullvadPostQuantumTests.swift */; }; - F08B6B782C528B8A00D0A121 /* PostQuantumKeyExchangingProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F059197E2C454CE000C301F3 /* PostQuantumKeyExchangingProtocol.swift */; }; - F08B6B7C2C528C6300D0A121 /* SingleHopPostQuantumKeyExchanging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919782C45402E00C301F3 /* SingleHopPostQuantumKeyExchanging.swift */; }; - F08B6B7D2C528C6300D0A121 /* PostQuantumKeyExchangingPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919762C453FAF00C301F3 /* PostQuantumKeyExchangingPipeline.swift */; }; - F08B6B7E2C528C6300D0A121 /* MultiHopPostQuantumKeyExchanging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F059197C2C454C9200C301F3 /* MultiHopPostQuantumKeyExchanging.swift */; }; + F08B6B772C52878400D0A121 /* EphemeralPeerExchangeActorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98F1B502C19C48D003C869E /* EphemeralPeerExchangeActorTests.swift */; }; + F08B6B782C528B8A00D0A121 /* EphemeralPeerExchangingProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F059197E2C454CE000C301F3 /* EphemeralPeerExchangingProtocol.swift */; }; + F08B6B7C2C528C6300D0A121 /* SingleHopEphemeralPeerExchanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919782C45402E00C301F3 /* SingleHopEphemeralPeerExchanger.swift */; }; + F08B6B7D2C528C6300D0A121 /* EphemeralPeerExchangingPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919762C453FAF00C301F3 /* EphemeralPeerExchangingPipeline.swift */; }; + F08B6B7E2C528C6300D0A121 /* MultiHopEphemeralPeerExchanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = F059197C2C454C9200C301F3 /* MultiHopEphemeralPeerExchanger.swift */; }; F08B6B822C52931600D0A121 /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = F08B6B812C52931600D0A121 /* WireGuardKitTypes */; }; F09084682C6E88ED001CD36E /* DaitaPromptAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09084672C6E88ED001CD36E /* DaitaPromptAlert.swift */; }; F09A297B2A9F8A9B00EA3B6F /* LogoutDialogueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09A29782A9F8A9B00EA3B6F /* LogoutDialogueView.swift */; }; @@ -1373,7 +1373,7 @@ 449872E32B7CB96300094DDC /* TunnelSettingsUpdateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsUpdateTests.swift; sourceTree = ""; }; 449EB9FC2B95F8AD00DFA4EB /* DeviceMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceMock.swift; sourceTree = ""; }; 449EB9FE2B95FF2500DFA4EB /* AccountMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountMock.swift; sourceTree = ""; }; - 449EBA252B975B9700DFA4EB /* PostQuantumKeyReceiving.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyReceiving.swift; sourceTree = ""; }; + 449EBA252B975B9700DFA4EB /* EphemeralPeerReceiving.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerReceiving.swift; sourceTree = ""; }; 44B02E3A2BC5732D008EDF34 /* LoggingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggingTests.swift; sourceTree = ""; }; 44B3C4392BFE2C800079782C /* PacketTunnelActorReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelActorReducer.swift; sourceTree = ""; }; 44B3C43C2C00CBBC0079782C /* PacketTunnelActorReducerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PacketTunnelActorReducerTests.swift; sourceTree = ""; }; @@ -1993,7 +1993,7 @@ A90763C22B2858630045ADF0 /* Socks5Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Socks5Configuration.swift; sourceTree = ""; }; A90763C42B2858B40045ADF0 /* AnyIPEndpoint+Socks5.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AnyIPEndpoint+Socks5.swift"; sourceTree = ""; }; A90763C62B2858DC0045ADF0 /* CancellableChain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CancellableChain.swift; sourceTree = ""; }; - A90C48662C36BC2600DCB94C /* PostQuantumKeyReceiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyReceiver.swift; sourceTree = ""; }; + A90C48662C36BC2600DCB94C /* EphemeralPeerReceiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerReceiver.swift; sourceTree = ""; }; A90C48682C36BF3900DCB94C /* TunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelProvider.swift; sourceTree = ""; }; A91614D02B108D1B00F416EB /* TransportLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransportLayer.swift; sourceTree = ""; }; A91614D52B10B26B00F416EB /* TunnelControlViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelControlViewModel.swift; sourceTree = ""; }; @@ -2012,7 +2012,7 @@ A935594D2B4E919F00D5D524 /* Api.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Api.xcconfig; sourceTree = ""; }; A944F2712B8E02E800473F4C /* libmullvad_ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmullvad_ios.a; path = "../target/aarch64-apple-ios/debug/libmullvad_ios.a"; sourceTree = ""; }; A9467E7E2A29DEFE000DC21F /* RelayCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayCacheTests.swift; sourceTree = ""; }; - A948809A2BC9308D0090A44C /* PostQuantumKeyExchangeActor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyExchangeActor.swift; sourceTree = ""; }; + A948809A2BC9308D0090A44C /* EphemeralPeerExchangeActor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerExchangeActor.swift; sourceTree = ""; }; A95EEE352B722CD600A8A39B /* TunnelMonitorState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelMonitorState.swift; sourceTree = ""; }; A95EEE372B722DFC00A8A39B /* PingStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PingStats.swift; sourceTree = ""; }; A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Socks5UsernamePasswordCommand.swift; sourceTree = ""; }; @@ -2026,7 +2026,7 @@ A98502022B627B120061901E /* LocalNetworkProbe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNetworkProbe.swift; sourceTree = ""; }; A988DF252ADE86ED00D807EF /* WireGuardObfuscationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireGuardObfuscationSettings.swift; sourceTree = ""; }; A988DF282ADE880300D807EF /* TunnelSettingsV3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsV3.swift; sourceTree = ""; }; - A98F1B502C19C48D003C869E /* MullvadPostQuantumTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MullvadPostQuantumTests.swift; sourceTree = ""; }; + A98F1B502C19C48D003C869E /* EphemeralPeerExchangeActorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerExchangeActorTests.swift; sourceTree = ""; }; A992DA1D2C24709F00DE7CE5 /* MullvadRustRuntime.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MullvadRustRuntime.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A992DA1F2C24709F00DE7CE5 /* MullvadRustRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MullvadRustRuntime.h; sourceTree = ""; }; A998DA802BD147AD001D61A2 /* ListCustomListsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListCustomListsPage.swift; sourceTree = ""; }; @@ -2052,7 +2052,7 @@ A9E031792ACB0AE70095D843 /* UIApplication+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Stubs.swift"; sourceTree = ""; }; A9E0317D2ACC32920095D843 /* TunnelStatusBlockObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelStatusBlockObserver.swift; sourceTree = ""; }; A9E034632ABB302000E59A5A /* UIEdgeInsets+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIEdgeInsets+Extensions.swift"; sourceTree = ""; }; - A9EB4F9C2B7FAB21002A2D7A /* PostQuantumKeyNegotiator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyNegotiator.swift; sourceTree = ""; }; + A9EB4F9C2B7FAB21002A2D7A /* EphemeralPeerNegotiator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerNegotiator.swift; sourceTree = ""; }; A9EC20E72A5D3A8C0040D56E /* CoordinatesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatesTests.swift; sourceTree = ""; }; A9F360332AAB626300F53531 /* VPNConnectionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNConnectionProtocol.swift; sourceTree = ""; }; E1187ABA289BBB850024E748 /* OutOfTimeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutOfTimeViewController.swift; sourceTree = ""; }; @@ -2076,7 +2076,7 @@ F03A69F62C2AD2D5000E2E7E /* TimeInterval+Timeout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TimeInterval+Timeout.swift"; sourceTree = ""; }; F03A69F82C2AD413000E2E7E /* FormsheetPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormsheetPresentationController.swift; sourceTree = ""; }; F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomListLocationNodeBuilder.swift; sourceTree = ""; }; - F04AF92C2C466013004A8314 /* PostQuantumNegotiationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumNegotiationState.swift; sourceTree = ""; }; + F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerNegotiationState.swift; sourceTree = ""; }; F04DD3D72C130DF600E03E28 /* TunnelSettingsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelSettingsManager.swift; sourceTree = ""; }; F04FBE602A8379EE009278D7 /* AppPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPreferences.swift; sourceTree = ""; }; F050AE4D2B70D7F8003F4EDB /* LocationCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationCellViewModel.swift; sourceTree = ""; }; @@ -2088,14 +2088,14 @@ F050AE5D2B739A73003F4EDB /* LocationDataSourceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationDataSourceProtocol.swift; sourceTree = ""; }; F050AE5F2B73A41E003F4EDB /* AllLocationDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllLocationDataSource.swift; sourceTree = ""; }; F050AE612B74DBAC003F4EDB /* CustomListsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomListsDataSource.swift; sourceTree = ""; }; - F053F4B92C4A94D300FBD937 /* PostQuantumKeyExchangingPipelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyExchangingPipelineTests.swift; sourceTree = ""; }; + F053F4B92C4A94D300FBD937 /* EphemeralPeerExchangingPipelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerExchangingPipelineTests.swift; sourceTree = ""; }; F05769B82C6656E400D9778B /* TunnelSettingsPropagator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsPropagator.swift; sourceTree = ""; }; F05769BA2C6661EE00D9778B /* TunnelSettingsStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsStrategy.swift; sourceTree = ""; }; - F05919742C45194B00C301F3 /* PostQuantumKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKey.swift; sourceTree = ""; }; - F05919762C453FAF00C301F3 /* PostQuantumKeyExchangingPipeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyExchangingPipeline.swift; sourceTree = ""; }; - F05919782C45402E00C301F3 /* SingleHopPostQuantumKeyExchanging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleHopPostQuantumKeyExchanging.swift; sourceTree = ""; }; - F059197C2C454C9200C301F3 /* MultiHopPostQuantumKeyExchanging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiHopPostQuantumKeyExchanging.swift; sourceTree = ""; }; - F059197E2C454CE000C301F3 /* PostQuantumKeyExchangingProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyExchangingProtocol.swift; sourceTree = ""; }; + F05919742C45194B00C301F3 /* EphemeralPeerKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerKey.swift; sourceTree = ""; }; + F05919762C453FAF00C301F3 /* EphemeralPeerExchangingPipeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerExchangingPipeline.swift; sourceTree = ""; }; + F05919782C45402E00C301F3 /* SingleHopEphemeralPeerExchanger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleHopEphemeralPeerExchanger.swift; sourceTree = ""; }; + F059197C2C454C9200C301F3 /* MultiHopEphemeralPeerExchanger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiHopEphemeralPeerExchanger.swift; sourceTree = ""; }; + F059197E2C454CE000C301F3 /* EphemeralPeerExchangingProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerExchangingProtocol.swift; sourceTree = ""; }; F06045E52B231EB700B2D37A /* URLSessionTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionTransport.swift; sourceTree = ""; }; F06045E92B23217E00B2D37A /* ShadowsocksTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShadowsocksTransport.swift; sourceTree = ""; }; F06045EB2B2322A500B2D37A /* Jittered.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Jittered.swift; sourceTree = ""; }; @@ -2119,7 +2119,7 @@ F09D04BC2AEBB7C5003D4F89 /* OutgoingConnectionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingConnectionService.swift; sourceTree = ""; }; F09D04BF2AF39D63003D4F89 /* OutgoingConnectionServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingConnectionServiceTests.swift; sourceTree = ""; }; F0A0868F2C22D6A700BF83E7 /* TunnelSettingsStrategyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsStrategyTests.swift; sourceTree = ""; }; - F0A163882C47B46300592300 /* SingleHopPostQuantumKeyExchangingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleHopPostQuantumKeyExchangingTests.swift; sourceTree = ""; }; + F0A163882C47B46300592300 /* SingleHopEphemeralPeerExchangerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleHopEphemeralPeerExchangerTests.swift; sourceTree = ""; }; F0ACE3082BE4E478006D5333 /* MullvadMockData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MullvadMockData.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F0ACE30A2BE4E478006D5333 /* MullvadMockData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MullvadMockData.h; sourceTree = ""; }; F0ACE32E2BE4EA8B006D5333 /* MockProxyFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProxyFactory.swift; sourceTree = ""; }; @@ -2133,8 +2133,8 @@ F0C13FE32C64F7CB00BD087D /* DAITASettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAITASettings.swift; sourceTree = ""; }; F0C13FE52C64FB3400BD087D /* TunnelSettingsV6.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsV6.swift; sourceTree = ""; }; F0C2AEFC2A0BB5CC00986207 /* NotificationProviderIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationProviderIdentifier.swift; sourceTree = ""; }; - F0C4C9BD2C49477B00A79006 /* MultiHopPostQuantumKeyExchangingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiHopPostQuantumKeyExchangingTests.swift; sourceTree = ""; }; - F0C4C9BF2C495E7500A79006 /* PostQuantumKeyExchangeActorStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyExchangeActorStub.swift; sourceTree = ""; }; + F0C4C9BD2C49477B00A79006 /* MultiHopEphemeralPeerExchangerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiHopEphemeralPeerExchangerTests.swift; sourceTree = ""; }; + F0C4C9BF2C495E7500A79006 /* EphemeralPeerExchangeActorStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerExchangeActorStub.swift; sourceTree = ""; }; F0C6A8422AB08E54000777A8 /* RedeemVoucherViewConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedeemVoucherViewConfiguration.swift; sourceTree = ""; }; F0C6FA842A6A733700F521F0 /* InAppPurchaseInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppPurchaseInteractor.swift; sourceTree = ""; }; F0D8825A2B04F53600D3EF9A /* OutgoingConnectionData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingConnectionData.swift; sourceTree = ""; }; @@ -2569,8 +2569,8 @@ 449EBA242B975B7C00DFA4EB /* Protocols */ = { isa = PBXGroup; children = ( - 449EBA252B975B9700DFA4EB /* PostQuantumKeyReceiving.swift */, - A90C48662C36BC2600DCB94C /* PostQuantumKeyReceiver.swift */, + 449EBA252B975B9700DFA4EB /* EphemeralPeerReceiving.swift */, + A90C48662C36BC2600DCB94C /* EphemeralPeerReceiver.swift */, A90C48682C36BF3900DCB94C /* TunnelProvider.swift */, ); path = Protocols; @@ -3098,8 +3098,8 @@ 583832282AC3DF1300EA2071 /* PacketTunnelActorCommand.swift */, 7AD0AA192AD69B6E00119E10 /* PacketTunnelActorProtocol.swift */, 44B3C4392BFE2C800079782C /* PacketTunnelActorReducer.swift */, - F05919742C45194B00C301F3 /* PostQuantumKey.swift */, - F04AF92C2C466013004A8314 /* PostQuantumNegotiationState.swift */, + F05919742C45194B00C301F3 /* EphemeralPeerKey.swift */, + F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */, A97D25AD2B0BB18100946B2D /* ProtocolObfuscator.swift */, 58E7A0312AA0715100C57861 /* Protocols */, 58ED3A132A7C199C0085CE65 /* StartOptions.swift */, @@ -3364,16 +3364,14 @@ isa = PBXGroup; children = ( 7A3FD1B42AD4465A0042BEA6 /* AppMessageHandlerTests.swift */, + F053F4B92C4A94D300FBD937 /* EphemeralPeerExchangingPipelineTests.swift */, 586C14572AC463BB00245C01 /* EventChannelTests.swift */, - F0FBD98E2C4A60CC00EE5323 /* KeyExchangingResultStub.swift */, 58EC067D2A8D2B0700BEB973 /* Mocks */, - F0C4C9BD2C49477B00A79006 /* MultiHopPostQuantumKeyExchangingTests.swift */, + F0C4C9BD2C49477B00A79006 /* MultiHopEphemeralPeerExchangerTests.swift */, 58FE25D32AA729B5003D1918 /* PacketTunnelActorTests.swift */, 58C7A46F2A8649ED0060C66F /* PingerTests.swift */, - F0C4C9BF2C495E7500A79006 /* PostQuantumKeyExchangeActorStub.swift */, - F053F4B92C4A94D300FBD937 /* PostQuantumKeyExchangingPipelineTests.swift */, A97D25B12B0CB02D00946B2D /* ProtocolObfuscatorTests.swift */, - F0A163882C47B46300592300 /* SingleHopPostQuantumKeyExchangingTests.swift */, + F0A163882C47B46300592300 /* SingleHopEphemeralPeerExchangerTests.swift */, 5838321C2AC1C54600EA2071 /* TaskSleepTests.swift */, 58092E532A8B832E00C3CC72 /* TunnelMonitorTests.swift */, F062B94C2C16E09700B6D47A /* TunnelSettingsManagerTests.swift */, @@ -3649,7 +3647,7 @@ isa = PBXGroup; children = ( 580D6B8B2AB3369300B2D6E0 /* BlockedStateErrorMapperProtocol.swift */, - F059197E2C454CE000C301F3 /* PostQuantumKeyExchangingProtocol.swift */, + F059197E2C454CE000C301F3 /* EphemeralPeerExchangingProtocol.swift */, 586E7A2C2A987689006DAB1B /* SettingsReaderProtocol.swift */, 5819ABC22A8CF02C007B59A6 /* TunnelAdapterProtocol.swift */, ); @@ -3661,6 +3659,8 @@ children = ( 58F7753C2AB8473200425B47 /* BlockedStateErrorMapperStub.swift */, 581F23AC2A8CF92100788AB6 /* DefaultPathObserverFake.swift */, + F0C4C9BF2C495E7500A79006 /* EphemeralPeerExchangeActorStub.swift */, + F0FBD98E2C4A60CC00EE5323 /* KeyExchangingResultStub.swift */, 58EC067B2A8D2A0B00BEB973 /* NetworkCounters.swift */, 5838321A2AC1B18400EA2071 /* PacketTunnelActor+Mocks.swift */, 7AD0AA1B2AD6A63F00119E10 /* PacketTunnelActorStub.swift */, @@ -4012,8 +4012,8 @@ A9D9A4D32C36E1EA004088DD /* mullvad_rust_runtime.h */, A992DA1F2C24709F00DE7CE5 /* MullvadRustRuntime.h */, A9A557F42B7E3E5C0017ADA8 /* PacketTunnelProvider+TCPConnection.swift */, - A948809A2BC9308D0090A44C /* PostQuantumKeyExchangeActor.swift */, - A9EB4F9C2B7FAB21002A2D7A /* PostQuantumKeyNegotiator.swift */, + A948809A2BC9308D0090A44C /* EphemeralPeerExchangeActor.swift */, + A9EB4F9C2B7FAB21002A2D7A /* EphemeralPeerNegotiator.swift */, F0DDE40F2B220458006B57A7 /* ShadowSocksProxy.swift */, 584023212A406BF5007B27AC /* UDPOverTCPObfuscator.swift */, ); @@ -4024,7 +4024,7 @@ isa = PBXGroup; children = ( A9C308392C19DDA7008715F1 /* MullvadPostQuantum+Stubs.swift */, - A98F1B502C19C48D003C869E /* MullvadPostQuantumTests.swift */, + A98F1B502C19C48D003C869E /* EphemeralPeerExchangeActorTests.swift */, 585A02EC2A4B28F300C6CAFF /* TCPConnection.swift */, 585A02E82A4B283000C6CAFF /* TCPUnsafeListener.swift */, 58695A9F2A4ADA9200328DB3 /* TunnelObfuscationTests.swift */, @@ -4050,9 +4050,9 @@ F059197A2C45404500C301F3 /* PostQuantum */ = { isa = PBXGroup; children = ( - F059197C2C454C9200C301F3 /* MultiHopPostQuantumKeyExchanging.swift */, - F05919762C453FAF00C301F3 /* PostQuantumKeyExchangingPipeline.swift */, - F05919782C45402E00C301F3 /* SingleHopPostQuantumKeyExchanging.swift */, + F05919762C453FAF00C301F3 /* EphemeralPeerExchangingPipeline.swift */, + F059197C2C454C9200C301F3 /* MultiHopEphemeralPeerExchanger.swift */, + F05919782C45402E00C301F3 /* SingleHopEphemeralPeerExchanger.swift */, ); path = PostQuantum; sourceTree = ""; @@ -5457,13 +5457,13 @@ 58C7AF122ABD8480007EDD7A /* TunnelProviderReply.swift in Sources */, 58C7A4572A863FB90060C66F /* TunnelDeviceInfoProtocol.swift in Sources */, 58C7A4562A863FB90060C66F /* DefaultPathObserverProtocol.swift in Sources */, - F08B6B782C528B8A00D0A121 /* PostQuantumKeyExchangingProtocol.swift in Sources */, + F08B6B782C528B8A00D0A121 /* EphemeralPeerExchangingProtocol.swift in Sources */, 58FE25DA2AA72A8F003D1918 /* PacketTunnelActor.swift in Sources */, 587A5E522ADD7569003A70F1 /* ObservedState+Extensions.swift in Sources */, 58FE25E62AA738E8003D1918 /* TunnelAdapterProtocol.swift in Sources */, 44DF8AC42BF20BD200869CA4 /* PacketTunnelActor+PostQuantum.swift in Sources */, 583832252AC318A100EA2071 /* PacketTunnelActor+ConnectionMonitoring.swift in Sources */, - F05919752C45194B00C301F3 /* PostQuantumKey.swift in Sources */, + F05919752C45194B00C301F3 /* EphemeralPeerKey.swift in Sources */, 58C7A4552A863FB90060C66F /* TunnelMonitor.swift in Sources */, 58C7AF182ABD84AB007EDD7A /* ProxyURLResponse.swift in Sources */, 58C7A4512A863FB50060C66F /* PingerProtocol.swift in Sources */, @@ -5495,7 +5495,7 @@ A95EEE382B722DFC00A8A39B /* PingStats.swift in Sources */, 583832272AC3193600EA2071 /* PacketTunnelActor+SleepCycle.swift in Sources */, 58FE25DC2AA72A8F003D1918 /* AnyTask.swift in Sources */, - F04AF92D2C466013004A8314 /* PostQuantumNegotiationState.swift in Sources */, + F04AF92D2C466013004A8314 /* EphemeralPeerNegotiationState.swift in Sources */, A9840BB42C69F78A0030F05E /* Maybenot.swift in Sources */, 58FE25D92AA72A8F003D1918 /* AutoCancellingTask.swift in Sources */, 58FE25E12AA72A9B003D1918 /* SettingsReaderProtocol.swift in Sources */, @@ -5511,30 +5511,30 @@ 58EC067A2A8D208D00BEB973 /* TunnelDeviceInfoStub.swift in Sources */, 586C14582AC463BB00245C01 /* EventChannelTests.swift in Sources */, 58EC067C2A8D2A0B00BEB973 /* NetworkCounters.swift in Sources */, - F07751552C50F149006E6A12 /* PostQuantumKeyExchangeActorStub.swift in Sources */, + F07751552C50F149006E6A12 /* EphemeralPeerExchangeActorStub.swift in Sources */, 58FE25EC2AA77639003D1918 /* TunnelMonitorStub.swift in Sources */, 7A3FD1B82AD54AE60042BEA6 /* TimeServerProxy.swift in Sources */, 58FE25EE2AA7764E003D1918 /* TunnelAdapterDummy.swift in Sources */, 581F23AD2A8CF92100788AB6 /* DefaultPathObserverFake.swift in Sources */, - F07751582C50F149006E6A12 /* MultiHopPostQuantumKeyExchangingTests.swift in Sources */, + F07751582C50F149006E6A12 /* MultiHopEphemeralPeerExchangerTests.swift in Sources */, 5838321B2AC1B18400EA2071 /* PacketTunnelActor+Mocks.swift in Sources */, 5838321D2AC1C54600EA2071 /* TaskSleepTests.swift in Sources */, 58092E542A8B832E00C3CC72 /* TunnelMonitorTests.swift in Sources */, 7AD0AA212AD6CB0000119E10 /* URLRequestProxyStub.swift in Sources */, 581F23AF2A8CF94D00788AB6 /* PingerMock.swift in Sources */, - F07751592C50F149006E6A12 /* SingleHopPostQuantumKeyExchangingTests.swift in Sources */, + F07751592C50F149006E6A12 /* SingleHopEphemeralPeerExchangerTests.swift in Sources */, A97D25B42B0CB59300946B2D /* TunnelObfuscationStub.swift in Sources */, F0077EEE2C52844800DAB2AA /* KeyExchangingResultStub.swift in Sources */, A97D25B02B0BB5C400946B2D /* ProtocolObfuscationStub.swift in Sources */, 7A3FD1B72AD54ABD0042BEA6 /* AnyTransport.swift in Sources */, 58FE25F22AA77674003D1918 /* SettingsReaderStub.swift in Sources */, - F08B6B7C2C528C6300D0A121 /* SingleHopPostQuantumKeyExchanging.swift in Sources */, - F08B6B7D2C528C6300D0A121 /* PostQuantumKeyExchangingPipeline.swift in Sources */, - F08B6B7E2C528C6300D0A121 /* MultiHopPostQuantumKeyExchanging.swift in Sources */, + F08B6B7C2C528C6300D0A121 /* SingleHopEphemeralPeerExchanger.swift in Sources */, + F08B6B7D2C528C6300D0A121 /* EphemeralPeerExchangingPipeline.swift in Sources */, + F08B6B7E2C528C6300D0A121 /* MultiHopEphemeralPeerExchanger.swift in Sources */, F0ACE3372BE517F1006D5333 /* ServerRelaysResponse+Stubs.swift in Sources */, 58F7753D2AB8473200425B47 /* BlockedStateErrorMapperStub.swift in Sources */, 58FE25D42AA729B5003D1918 /* PacketTunnelActorTests.swift in Sources */, - F07751572C50F149006E6A12 /* PostQuantumKeyExchangingPipelineTests.swift in Sources */, + F07751572C50F149006E6A12 /* EphemeralPeerExchangingPipelineTests.swift in Sources */, 7A3FD1B52AD4465A0042BEA6 /* AppMessageHandlerTests.swift in Sources */, 58C7A4702A8649ED0060C66F /* PingerTests.swift in Sources */, A97D25B22B0CB02D00946B2D /* ProtocolObfuscatorTests.swift in Sources */, @@ -5927,9 +5927,9 @@ 583D86482A2678DC0060D63B /* DeviceStateAccessor.swift in Sources */, 58F3F36A2AA08E3C00D3B0A4 /* PacketTunnelProvider.swift in Sources */, 58906DE02445C7A5002F0673 /* NEProviderStopReason+Debug.swift in Sources */, - F0570CD12C4FB8E1007BDF2D /* PostQuantumKeyExchangingPipeline.swift in Sources */, - F0570CD22C4FB8E1007BDF2D /* SingleHopPostQuantumKeyExchanging.swift in Sources */, - F0570CD42C4FB8E1007BDF2D /* MultiHopPostQuantumKeyExchanging.swift in Sources */, + F0570CD12C4FB8E1007BDF2D /* EphemeralPeerExchangingPipeline.swift in Sources */, + F0570CD22C4FB8E1007BDF2D /* SingleHopEphemeralPeerExchanger.swift in Sources */, + F0570CD42C4FB8E1007BDF2D /* MultiHopEphemeralPeerExchanger.swift in Sources */, 58C7A45B2A8640030060C66F /* PacketTunnelPathObserver.swift in Sources */, 580D6B8E2AB33BBF00B2D6E0 /* BlockedStateErrorMapper.swift in Sources */, 06AC116228F94C450037AF9A /* ApplicationConfiguration.swift in Sources */, @@ -5979,7 +5979,7 @@ 7A307AD92A8CD8DA0017618B /* Duration.swift in Sources */, 58D2240A294C90210029F5F8 /* IPAddress+Codable.swift in Sources */, 58E45A5729F12C5100281ECF /* Result+Extensions.swift in Sources */, - A90C48672C36BC2600DCB94C /* PostQuantumKeyReceiver.swift in Sources */, + A90C48672C36BC2600DCB94C /* EphemeralPeerReceiver.swift in Sources */, A9E031782ACB09930095D843 /* UIApplication+Extensions.swift in Sources */, 58D2240B294C90210029F5F8 /* Cancellable.swift in Sources */, 58D2240C294C90210029F5F8 /* WrappingError.swift in Sources */, @@ -5997,7 +5997,7 @@ 7AF9BE8C2A321D1F00DBFEDB /* RelayFilter.swift in Sources */, 58D22414294C90210029F5F8 /* RelayLocation.swift in Sources */, 581DA2732A1E227D0046ED47 /* RESTTypes.swift in Sources */, - 449EBA262B975B9700DFA4EB /* PostQuantumKeyReceiving.swift in Sources */, + 449EBA262B975B9700DFA4EB /* EphemeralPeerReceiving.swift in Sources */, 58D22417294C90210029F5F8 /* FixedWidthInteger+Arithmetics.swift in Sources */, F0F56B092C0E058A009D676B /* ObserverList.swift in Sources */, ); @@ -6122,10 +6122,10 @@ buildActionMask = 2147483647; files = ( A9D9A4B12C36D10E004088DD /* ShadowSocksProxy.swift in Sources */, - A9D9A4BB2C36D397004088DD /* PostQuantumKeyNegotiator.swift in Sources */, + A9D9A4BB2C36D397004088DD /* EphemeralPeerNegotiator.swift in Sources */, A9D9A4B22C36D12D004088DD /* UDPOverTCPObfuscator.swift in Sources */, A9173C322C36CCDD00F6A08C /* PacketTunnelProvider+TCPConnection.swift in Sources */, - F05919802C45515200C301F3 /* PostQuantumKeyExchangeActor.swift in Sources */, + F05919802C45515200C301F3 /* EphemeralPeerExchangeActor.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6134,7 +6134,7 @@ buildActionMask = 2147483647; files = ( A9D9A4D22C36DBAF004088DD /* MullvadPostQuantum+Stubs.swift in Sources */, - F08B6B772C52878400D0A121 /* MullvadPostQuantumTests.swift in Sources */, + F08B6B772C52878400D0A121 /* EphemeralPeerExchangeActorTests.swift in Sources */, A9D9A4CF2C36D54E004088DD /* TCPConnection.swift in Sources */, A9D9A4CE2C36D54E004088DD /* TunnelObfuscationTests.swift in Sources */, A9D9A4CC2C36D54E004088DD /* TCPUnsafeListener.swift in Sources */, diff --git a/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift b/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift index 066ca9f00629..3df50a323c04 100644 --- a/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift @@ -759,7 +759,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo switch tunnelManager.tunnelStatus.state { case .connected, .connecting, .reconnecting, .waitingForConnectivity(.noConnection), .error, - .negotiatingPostQuantumKey: + .negotiatingEphemeralPeer: tunnelManager.reconnectTunnel(selectNewRelay: true) case .disconnecting, .disconnected: diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift index c008e0903c8f..561039f1a098 100644 --- a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift +++ b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift @@ -181,7 +181,8 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { transportLayer: .udp, remotePort: selectedRelays.entry?.endpoint.ipv4Relay.port ?? selectedRelays.exit.endpoint.ipv4Relay .port, - isPostQuantum: settings.tunnelQuantumResistance.isEnabled + isPostQuantum: settings.tunnelQuantumResistance.isEnabled, + isDaitaEnabled: settings.daita.state.isEnabled ) ) } catch { diff --git a/ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift b/ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift index a93e33b0b116..53a3e089ad7b 100644 --- a/ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift +++ b/ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift @@ -57,9 +57,9 @@ class MapConnectionStatusOperation: AsyncOperation { return connectionState.isNetworkReachable ? .connecting(connectionState.selectedRelays, isPostQuantum: connectionState.isPostQuantum) : .waitingForConnectivity(.noConnection) - case let .negotiatingPostQuantumKey(connectionState, privateKey): + case let .negotiatingEphemeralPeer(connectionState, privateKey): return connectionState.isNetworkReachable - ? .negotiatingPostQuantumKey(connectionState.selectedRelays, privateKey) + ? .negotiatingEphemeralPeer(connectionState.selectedRelays, privateKey) : .waitingForConnectivity(.noConnection) case let .reconnecting(connectionState): return connectionState.isNetworkReachable diff --git a/ios/MullvadVPN/TunnelManager/StopTunnelOperation.swift b/ios/MullvadVPN/TunnelManager/StopTunnelOperation.swift index 1bd7a4f9c783..1e8362c2ca7b 100644 --- a/ios/MullvadVPN/TunnelManager/StopTunnelOperation.swift +++ b/ios/MullvadVPN/TunnelManager/StopTunnelOperation.swift @@ -36,7 +36,7 @@ class StopTunnelOperation: ResultOperation { finish(result: .success(())) case .connected, .connecting, .reconnecting, .waitingForConnectivity(.noConnection), .error, - .negotiatingPostQuantumKey: + .negotiatingEphemeralPeer: doShutDownTunnel() case .disconnected, .disconnecting, .pendingReconnect, .waitingForConnectivity(.noNetwork): diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index 612b1c5ea6c7..8850cb477f46 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -673,7 +673,7 @@ final class TunnelManager: StorePaymentObserver { refreshDeviceState() } switch newTunnelStatus.state { - case .connecting, .reconnecting, .negotiatingPostQuantumKey: + case .connecting, .reconnecting, .negotiatingEphemeralPeer: // Start polling tunnel status to keep the relay information up to date // while the tunnel process is trying to connect. startPollingTunnelStatus(interval: establishingTunnelStatusPollInterval) diff --git a/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift b/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift index 1f524f56e8ad..90dde124ca76 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift @@ -11,7 +11,7 @@ import UIKit extension TunnelState { var textColorForSecureLabel: UIColor { switch self { - case .connecting, .reconnecting, .waitingForConnectivity(.noConnection), .negotiatingPostQuantumKey: + case .connecting, .reconnecting, .waitingForConnectivity(.noConnection), .negotiatingEphemeralPeer: .white case .connected: @@ -49,7 +49,8 @@ extension TunnelState { ) } - case .negotiatingPostQuantumKey: + // TODO: Handle Daita here in an upcoming PR for the UI + case .negotiatingEphemeralPeer: NSLocalizedString( "TUNNEL_STATE_NEGOTIATING_KEY", tableName: "Main", @@ -141,7 +142,7 @@ extension TunnelState { comment: "" ) - case .negotiatingPostQuantumKey: + case .negotiatingEphemeralPeer: NSLocalizedString( "SWITCH_LOCATION_BUTTON_TITLE", tableName: "Main", @@ -170,7 +171,7 @@ extension TunnelState { ) } - case .negotiatingPostQuantumKey: + case .negotiatingEphemeralPeer: NSLocalizedString( "TUNNEL_STATE_CONNECTING_ACCESSIBILITY_LABEL", tableName: "Main", diff --git a/ios/MullvadVPN/TunnelManager/TunnelState.swift b/ios/MullvadVPN/TunnelManager/TunnelState.swift index 7d76a53bc404..9127b2d29ec6 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelState.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelState.swift @@ -52,8 +52,8 @@ enum TunnelState: Equatable, CustomStringConvertible { /// Connecting the tunnel. case connecting(SelectedRelays?, isPostQuantum: Bool) - /// Negotiating a key for post-quantum resistance - case negotiatingPostQuantumKey(SelectedRelays, PrivateKey) + /// Negotiating an ephemeral peer either for post-quantum resistance or Daita + case negotiatingEphemeralPeer(SelectedRelays, PrivateKey) /// Connected the tunnel case connected(SelectedRelays, isPostQuantum: Bool) @@ -111,7 +111,8 @@ enum TunnelState: Equatable, CustomStringConvertible { "waiting for connectivity" case let .error(blockedStateReason): "error state: \(blockedStateReason)" - case let .negotiatingPostQuantumKey(tunnelRelays, _): + case let .negotiatingEphemeralPeer(tunnelRelays, _): + // TODO: Handle Daita and PQ here in an upcoming PR for the UI """ negotiating key with exit relay: \(tunnelRelays.exit.hostname)\ \(tunnelRelays.entry.flatMap { " via \($0.hostname)" } ?? "") @@ -122,7 +123,7 @@ enum TunnelState: Equatable, CustomStringConvertible { var isSecured: Bool { switch self { case .reconnecting, .connecting, .connected, .waitingForConnectivity(.noConnection), .error(.accountExpired), - .error(.deviceRevoked), .negotiatingPostQuantumKey: + .error(.deviceRevoked), .negotiatingEphemeralPeer: true case .pendingReconnect, .disconnecting, .disconnected, .waitingForConnectivity(.noNetwork), .error: false @@ -131,7 +132,7 @@ enum TunnelState: Equatable, CustomStringConvertible { var relays: SelectedRelays? { switch self { - case let .connected(relays, _), let .reconnecting(relays, _), let .negotiatingPostQuantumKey(relays, _): + case let .connected(relays, _), let .reconnecting(relays, _), let .negotiatingEphemeralPeer(relays, _): relays case let .connecting(relays, _): relays diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift index c59679e0ba04..2a8d5fccc8eb 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift @@ -394,7 +394,7 @@ private extension TunnelState { .waitingForConnectivity(.noConnection): [.selectLocation, .cancel] - case .negotiatingPostQuantumKey: + case .negotiatingEphemeralPeer: [.selectLocation, .cancel] case .connected, .reconnecting, .error: diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift index 95e9260d207f..765761f336cf 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift @@ -152,7 +152,7 @@ class TunnelViewController: UIViewController, RootContainment { contentView.setAnimatingActivity(true) mapViewController.setCenter(tunnelRelays?.exit.location.geoCoordinate, animated: animated) - case let .reconnecting(tunnelRelays, _), let .negotiatingPostQuantumKey(tunnelRelays, _): + case let .reconnecting(tunnelRelays, _), let .negotiatingEphemeralPeer(tunnelRelays, _): mapViewController.removeLocationMarker() contentView.setAnimatingActivity(true) mapViewController.setCenter(tunnelRelays.exit.location.geoCoordinate, animated: animated) diff --git a/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift b/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift index 49cbc5766f1a..d2337122181b 100644 --- a/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift +++ b/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift @@ -35,7 +35,8 @@ final class PacketTunnelActorReducerTests: XCTestCase { connectedEndpoint: selectedRelays.entry?.endpoint ?? selectedRelays.exit.endpoint, transportLayer: .udp, remotePort: 12345, - isPostQuantum: false + isPostQuantum: false, + isDaitaEnabled: false ) } @@ -196,7 +197,7 @@ final class PacketTunnelActorReducerTests: XCTestCase { func testHandleConnectionLossReconnectFromPQKeyNegotiation() { // Given - var state = State.negotiatingPostQuantumKey(makeConnectionData(), PrivateKey()) + var state = State.negotiatingEphemeralPeer(makeConnectionData(), PrivateKey()) // When let effects = PacketTunnelActor.Reducer.reduce(&state, .reconnect(.random, reason: .connectionLoss)) @@ -207,7 +208,7 @@ final class PacketTunnelActorReducerTests: XCTestCase { func testHandleUserReconnectFromPQKeyNegotiation() { // Given - var state = State.negotiatingPostQuantumKey(makeConnectionData(), PrivateKey()) + var state = State.negotiatingEphemeralPeer(makeConnectionData(), PrivateKey()) // When let effects = PacketTunnelActor.Reducer.reduce(&state, .reconnect(.random, reason: .userInitiated)) diff --git a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift index d9fd9b7f2f52..5062076688b3 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift @@ -26,12 +26,12 @@ class PacketTunnelProvider: NEPacketTunnelProvider { private var deviceChecker: DeviceChecker! private var adapter: WgAdapter! private var relaySelector: RelaySelectorWrapper! - private var postQuantumKeyExchangingPipeline: PostQuantumKeyExchangingPipeline! + private var ephemeralPeerExchangingPipeline: EphemeralPeerExchangingPipeline! private let tunnelSettingsUpdater: SettingsUpdater! private let tunnelSettingsListener = TunnelSettingsListener() - private lazy var postQuantumReceiver = { - PostQuantumKeyReceiver(tunnelProvider: self) + private lazy var ephemeralPeerReceiver = { + EphemeralPeerReceiver(tunnelProvider: self) }() // swiftlint:disable:next function_body_length @@ -95,16 +95,16 @@ class PacketTunnelProvider: NEPacketTunnelProvider { let urlRequestProxy = URLRequestProxy(dispatchQueue: internalQueue, transportProvider: transportProvider) appMessageHandler = AppMessageHandler(packetTunnelActor: actor, urlRequestProxy: urlRequestProxy) - postQuantumKeyExchangingPipeline = PostQuantumKeyExchangingPipeline( - PostQuantumKeyExchangeActor( - packetTunnel: postQuantumReceiver, - onFailure: self.keyExchangeFailed, + ephemeralPeerExchangingPipeline = EphemeralPeerExchangingPipeline( + EphemeralPeerExchangeActor( + packetTunnel: ephemeralPeerReceiver, + onFailure: self.ephemeralPeerExchangeFailed, iteratorProvider: { REST.RetryStrategy.postQuantumKeyExchange.makeDelayIterator() } ), onUpdateConfiguration: { [unowned self] configuration in - actor.replaceKeyWithPQ(configuration: configuration) + actor.changeEphemeralPeerNegotiationState(configuration: configuration) }, onFinish: { [unowned self] in - actor.notifyPostQuantumKeyExchanged() + actor.notifyEphemeralPeerNegotiated() } ) } @@ -131,10 +131,10 @@ class PacketTunnelProvider: NEPacketTunnelProvider { if connectionState.connectionAttemptCount > 1 { return } - case .negotiatingPostQuantumKey: - // When negotiating post quantum keys, allow the connection to go through immediately. + case .negotiatingEphemeralPeer: + // When negotiating ephemeral peers, allow the connection to go through immediately. // Otherwise, the in-tunnel TCP connection will never become ready as the OS doesn't let - // any traffic through until this function returns, which would prevent negotiating keys + // any traffic through until this function returns, which would prevent negotiating ephemeral peers // from an unconnected state. return default: @@ -267,8 +267,8 @@ extension PacketTunnelProvider { // Cache last connection attempt to filter out repeating calls. lastConnectionAttempt = connectionAttempt - case let .negotiatingPostQuantumKey(observedConnectionState, privateKey): - postQuantumKeyExchangingPipeline.startNegotiation(observedConnectionState, privateKey: privateKey) + case let .negotiatingEphemeralPeer(observedConnectionState, privateKey): + ephemeralPeerExchangingPipeline.startNegotiation(observedConnectionState, privateKey: privateKey) case .initial, .connected, .disconnecting, .disconnected, .error: break } @@ -311,12 +311,16 @@ extension PacketTunnelProvider { } } -extension PacketTunnelProvider: PostQuantumKeyReceiving { +extension PacketTunnelProvider: EphemeralPeerReceiving { func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) { - postQuantumKeyExchangingPipeline.receivePostQuantumKey(key, ephemeralKey: ephemeralKey) + ephemeralPeerExchangingPipeline.receivePostQuantumKey(key, ephemeralKey: ephemeralKey) } - func keyExchangeFailed() { + public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey) { + ephemeralPeerExchangingPipeline.receiveEphemeralPeerPrivateKey(ephemeralPeerPrivateKey) + } + + func ephemeralPeerExchangeFailed() { // Do not try reconnecting to the `.current` relay, else the actor's `State` equality check will fail // and it will not try to reconnect actor.reconnect(to: .random, reconnectReason: .connectionLoss) diff --git a/ios/PacketTunnel/PostQuantum/PostQuantumKeyExchangingPipeline.swift b/ios/PacketTunnel/PostQuantum/EphemeralPeerExchangingPipeline.swift similarity index 55% rename from ios/PacketTunnel/PostQuantum/PostQuantumKeyExchangingPipeline.swift rename to ios/PacketTunnel/PostQuantum/EphemeralPeerExchangingPipeline.swift index 1e9dc1d3c583..0d0da931f0c8 100644 --- a/ios/PacketTunnel/PostQuantum/PostQuantumKeyExchangingPipeline.swift +++ b/ios/PacketTunnel/PostQuantum/EphemeralPeerExchangingPipeline.swift @@ -11,16 +11,16 @@ import MullvadSettings import PacketTunnelCore import WireGuardKitTypes -final public class PostQuantumKeyExchangingPipeline { - let keyExchanger: PostQuantumKeyExchangeActorProtocol - let onUpdateConfiguration: (PostQuantumNegotiationState) -> Void +final public class EphemeralPeerExchangingPipeline { + let keyExchanger: EphemeralPeerExchangeActorProtocol + let onUpdateConfiguration: (EphemeralPeerNegotiationState) -> Void let onFinish: () -> Void - private var postQuantumKeyExchanging: PostQuantumKeyExchangingProtocol! + private var ephemeralPeerExchanger: EphemeralPeerExchangingProtocol! public init( - _ keyExchanger: PostQuantumKeyExchangeActorProtocol, - onUpdateConfiguration: @escaping (PostQuantumNegotiationState) -> Void, + _ keyExchanger: EphemeralPeerExchangeActorProtocol, + onUpdateConfiguration: @escaping (EphemeralPeerNegotiationState) -> Void, onFinish: @escaping () -> Void ) { self.keyExchanger = keyExchanger @@ -32,28 +32,38 @@ final public class PostQuantumKeyExchangingPipeline { keyExchanger.reset() let entryPeer = connectionState.selectedRelays.entry let exitPeer = connectionState.selectedRelays.exit + let enablePostQuantum = connectionState.isPostQuantum + let enableDaita = connectionState.isDaitaEnabled if let entryPeer { - postQuantumKeyExchanging = MultiHopPostQuantumKeyExchanging( + ephemeralPeerExchanger = MultiHopEphemeralPeerExchanger( entry: entryPeer, exit: exitPeer, devicePrivateKey: privateKey, keyExchanger: keyExchanger, + enablePostQuantum: enablePostQuantum, + enableDaita: enableDaita, onUpdateConfiguration: self.onUpdateConfiguration, onFinish: onFinish ) } else { - postQuantumKeyExchanging = SingleHopPostQuantumKeyExchanging( + ephemeralPeerExchanger = SingleHopEphemeralPeerExchanger( exit: exitPeer, devicePrivateKey: privateKey, keyExchanger: keyExchanger, + enablePostQuantum: enablePostQuantum, + enableDaita: enableDaita, onUpdateConfiguration: self.onUpdateConfiguration, onFinish: onFinish ) } - postQuantumKeyExchanging.start() + ephemeralPeerExchanger.start() } public func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) { - postQuantumKeyExchanging.receivePostQuantumKey(key, ephemeralKey: ephemeralKey) + ephemeralPeerExchanger.receivePostQuantumKey(key, ephemeralKey: ephemeralKey) + } + + public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey) { + ephemeralPeerExchanger.receiveEphemeralPeerPrivateKey(ephemeralPeerPrivateKey) } } diff --git a/ios/PacketTunnel/PostQuantum/MultiHopPostQuantumKeyExchanging.swift b/ios/PacketTunnel/PostQuantum/MultiHopEphemeralPeerExchanger.swift similarity index 52% rename from ios/PacketTunnel/PostQuantum/MultiHopPostQuantumKeyExchanging.swift rename to ios/PacketTunnel/PostQuantum/MultiHopEphemeralPeerExchanger.swift index ed602de976b9..ee1a3afe6c42 100644 --- a/ios/PacketTunnel/PostQuantum/MultiHopPostQuantumKeyExchanging.swift +++ b/ios/PacketTunnel/PostQuantum/MultiHopEphemeralPeerExchanger.swift @@ -13,16 +13,18 @@ import MullvadTypes import PacketTunnelCore import WireGuardKitTypes -final class MultiHopPostQuantumKeyExchanging: PostQuantumKeyExchangingProtocol { +final class MultiHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol { let entry: SelectedRelay let exit: SelectedRelay - let keyExchanger: PostQuantumKeyExchangeActorProtocol + let keyExchanger: EphemeralPeerExchangeActorProtocol let devicePrivateKey: PrivateKey let onFinish: () -> Void - let onUpdateConfiguration: (PostQuantumNegotiationState) -> Void + let onUpdateConfiguration: (EphemeralPeerNegotiationState) -> Void + let enablePostQuantum: Bool + let enableDaita: Bool - private var entryPostQuantumKey: PostQuantumKey! - private var exitPostQuantumKey: PostQuantumKey! + private var entryPeerKey: EphemeralPeerKey! + private var exitPeerKey: EphemeralPeerKey! private let defaultGatewayAddressRange = [IPAddressRange(from: "\(LocalNetworkIPs.gatewayAddress.rawValue)/32")!] private let allTrafficRange = [ @@ -43,14 +45,18 @@ final class MultiHopPostQuantumKeyExchanging: PostQuantumKeyExchangingProtocol { entry: SelectedRelay, exit: SelectedRelay, devicePrivateKey: PrivateKey, - keyExchanger: PostQuantumKeyExchangeActorProtocol, - onUpdateConfiguration: @escaping (PostQuantumNegotiationState) -> Void, + keyExchanger: EphemeralPeerExchangeActorProtocol, + enablePostQuantum: Bool, + enableDaita: Bool, + onUpdateConfiguration: @escaping (EphemeralPeerNegotiationState) -> Void, onFinish: @escaping () -> Void ) { self.entry = entry self.exit = exit self.devicePrivateKey = devicePrivateKey self.keyExchanger = keyExchanger + self.enablePostQuantum = enablePostQuantum + self.enableDaita = enableDaita self.onUpdateConfiguration = onUpdateConfiguration self.onFinish = onFinish } @@ -60,69 +66,88 @@ final class MultiHopPostQuantumKeyExchanging: PostQuantumKeyExchangingProtocol { negotiateWithEntry() } + public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey) { + if state == .negotiatingWithEntry { + entryPeerKey = EphemeralPeerKey(ephemeralKey: ephemeralPeerPrivateKey) + negotiateBetweenEntryAndExit() + } else if state == .negotiatingBetweenEntryAndExit { + exitPeerKey = EphemeralPeerKey(ephemeralKey: ephemeralPeerPrivateKey) + makeConnection() + } + } + func receivePostQuantumKey( _ preSharedKey: PreSharedKey, ephemeralKey: PrivateKey ) { if state == .negotiatingWithEntry { - entryPostQuantumKey = PostQuantumKey(preSharedKey: preSharedKey, ephemeralKey: ephemeralKey) + entryPeerKey = EphemeralPeerKey(preSharedKey: preSharedKey, ephemeralKey: ephemeralKey) negotiateBetweenEntryAndExit() } else if state == .negotiatingBetweenEntryAndExit { - exitPostQuantumKey = PostQuantumKey(preSharedKey: preSharedKey, ephemeralKey: ephemeralKey) + exitPeerKey = EphemeralPeerKey(preSharedKey: preSharedKey, ephemeralKey: ephemeralKey) makeConnection() } } private func negotiateWithEntry() { state = .negotiatingWithEntry - onUpdateConfiguration(.single(PostQuantumConfigurationRelay( + onUpdateConfiguration(.single(EphemeralPeerRelayConfiguration( relay: entry, - configuration: PostQuantumConfiguration( + configuration: EphemeralPeerConfiguration( privateKey: devicePrivateKey, allowedIPs: defaultGatewayAddressRange ) ))) - keyExchanger.startNegotiation(with: devicePrivateKey) + keyExchanger.startNegotiation( + with: devicePrivateKey, + enablePostQuantum: enablePostQuantum, + enableDaita: enableDaita + ) } private func negotiateBetweenEntryAndExit() { state = .negotiatingBetweenEntryAndExit onUpdateConfiguration(.multi( - entry: PostQuantumConfigurationRelay( + entry: EphemeralPeerRelayConfiguration( relay: entry, - configuration: PostQuantumConfiguration( - privateKey: entryPostQuantumKey.ephemeralKey, - preSharedKey: entryPostQuantumKey.preSharedKey, + configuration: EphemeralPeerConfiguration( + privateKey: entryPeerKey.ephemeralKey, + preSharedKey: entryPeerKey.preSharedKey, allowedIPs: [IPAddressRange(from: "\(exit.endpoint.ipv4Relay.ip)/32")!] ) ), - exit: PostQuantumConfigurationRelay( + exit: EphemeralPeerRelayConfiguration( relay: exit, - configuration: PostQuantumConfiguration( + configuration: EphemeralPeerConfiguration( privateKey: devicePrivateKey, allowedIPs: defaultGatewayAddressRange ) ) )) - keyExchanger.startNegotiation(with: devicePrivateKey) + // Daita is always disabled when negotiating with the exit peer in the multihop scenarios + keyExchanger.startNegotiation( + with: devicePrivateKey, + enablePostQuantum: enablePostQuantum, + enableDaita: false + ) } private func makeConnection() { state = .makeConnection onUpdateConfiguration(.multi( - entry: PostQuantumConfigurationRelay( + entry: EphemeralPeerRelayConfiguration( relay: entry, - configuration: PostQuantumConfiguration( - privateKey: entryPostQuantumKey.ephemeralKey, - preSharedKey: entryPostQuantumKey.preSharedKey, + configuration: EphemeralPeerConfiguration( + privateKey: entryPeerKey.ephemeralKey, + preSharedKey: entryPeerKey.preSharedKey, allowedIPs: [IPAddressRange(from: "\(exit.endpoint.ipv4Relay.ip)/32")!] ) ), - exit: PostQuantumConfigurationRelay( + exit: EphemeralPeerRelayConfiguration( relay: exit, - configuration: PostQuantumConfiguration( - privateKey: exitPostQuantumKey.ephemeralKey, - preSharedKey: exitPostQuantumKey.preSharedKey, + configuration: EphemeralPeerConfiguration( + privateKey: exitPeerKey.ephemeralKey, + preSharedKey: exitPeerKey.preSharedKey, allowedIPs: allTrafficRange ) ) diff --git a/ios/PacketTunnel/PostQuantum/SingleHopEphemeralPeerExchanger.swift b/ios/PacketTunnel/PostQuantum/SingleHopEphemeralPeerExchanger.swift new file mode 100644 index 000000000000..f959a335efec --- /dev/null +++ b/ios/PacketTunnel/PostQuantum/SingleHopEphemeralPeerExchanger.swift @@ -0,0 +1,90 @@ +// +// SingleHopPostQuantumKeyExchanging.swift +// PacketTunnel +// +// Created by Mojgan on 2024-07-15. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import MullvadREST +import MullvadRustRuntime +import MullvadSettings +import MullvadTypes +import PacketTunnelCore +import WireGuardKitTypes + +struct SingleHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol { + let exit: SelectedRelay + let keyExchanger: EphemeralPeerExchangeActorProtocol + let devicePrivateKey: PrivateKey + let onFinish: () -> Void + let onUpdateConfiguration: (EphemeralPeerNegotiationState) -> Void + let enablePostQuantum: Bool + let enableDaita: Bool + + init( + exit: SelectedRelay, + devicePrivateKey: PrivateKey, + keyExchanger: EphemeralPeerExchangeActorProtocol, + enablePostQuantum: Bool, + enableDaita: Bool, + onUpdateConfiguration: @escaping (EphemeralPeerNegotiationState) -> Void, + onFinish: @escaping () -> Void + ) { + self.devicePrivateKey = devicePrivateKey + self.exit = exit + self.keyExchanger = keyExchanger + self.enablePostQuantum = enablePostQuantum + self.enableDaita = enableDaita + self.onUpdateConfiguration = onUpdateConfiguration + self.onFinish = onFinish + } + + func start() { + onUpdateConfiguration(.single(EphemeralPeerRelayConfiguration( + relay: exit, + configuration: EphemeralPeerConfiguration( + privateKey: devicePrivateKey, + allowedIPs: [IPAddressRange(from: "\(LocalNetworkIPs.gatewayAddress.rawValue)/32")!] + ) + ))) + keyExchanger.startNegotiation( + with: devicePrivateKey, + enablePostQuantum: enablePostQuantum, + enableDaita: enableDaita + ) + } + + public func receiveEphemeralPeerPrivateKey(_ ephemeralKey: PrivateKey) { + onUpdateConfiguration(.single(EphemeralPeerRelayConfiguration( + relay: exit, + configuration: EphemeralPeerConfiguration( + privateKey: ephemeralKey, + preSharedKey: nil, + allowedIPs: [ + IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV4.rawValue)/0")!, + IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV6.rawValue)/0")!, + ] + ) + ))) + self.onFinish() + } + + func receivePostQuantumKey( + _ preSharedKey: WireGuardKitTypes.PreSharedKey, + ephemeralKey: WireGuardKitTypes.PrivateKey + ) { + onUpdateConfiguration(.single(EphemeralPeerRelayConfiguration( + relay: exit, + configuration: EphemeralPeerConfiguration( + privateKey: ephemeralKey, + preSharedKey: preSharedKey, + allowedIPs: [ + IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV4.rawValue)/0")!, + IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV6.rawValue)/0")!, + ] + ) + ))) + self.onFinish() + } +} diff --git a/ios/PacketTunnel/PostQuantum/SingleHopPostQuantumKeyExchanging.swift b/ios/PacketTunnel/PostQuantum/SingleHopPostQuantumKeyExchanging.swift deleted file mode 100644 index b05a819fb9fd..000000000000 --- a/ios/PacketTunnel/PostQuantum/SingleHopPostQuantumKeyExchanging.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// SingleHopPostQuantumKeyExchanging.swift -// PacketTunnel -// -// Created by Mojgan on 2024-07-15. -// Copyright © 2024 Mullvad VPN AB. All rights reserved. -// - -import MullvadREST -import MullvadRustRuntime -import MullvadSettings -import MullvadTypes -import PacketTunnelCore -import WireGuardKitTypes - -struct SingleHopPostQuantumKeyExchanging: PostQuantumKeyExchangingProtocol { - let exit: SelectedRelay - let keyExchanger: PostQuantumKeyExchangeActorProtocol - let devicePrivateKey: PrivateKey - let onFinish: () -> Void - let onUpdateConfiguration: (PostQuantumNegotiationState) -> Void - - init( - exit: SelectedRelay, - devicePrivateKey: PrivateKey, - keyExchanger: PostQuantumKeyExchangeActorProtocol, - onUpdateConfiguration: @escaping (PostQuantumNegotiationState) -> Void, - onFinish: @escaping () -> Void - ) { - self.devicePrivateKey = devicePrivateKey - self.exit = exit - self.keyExchanger = keyExchanger - self.onUpdateConfiguration = onUpdateConfiguration - self.onFinish = onFinish - } - - func start() { - onUpdateConfiguration(.single(PostQuantumConfigurationRelay( - relay: exit, - configuration: PostQuantumConfiguration( - privateKey: devicePrivateKey, - allowedIPs: [IPAddressRange(from: "\(LocalNetworkIPs.gatewayAddress.rawValue)/32")!] - ) - ))) - keyExchanger.startNegotiation(with: devicePrivateKey) - } - - func receivePostQuantumKey( - _ preSharedKey: WireGuardKitTypes.PreSharedKey, - ephemeralKey: WireGuardKitTypes.PrivateKey - ) { - onUpdateConfiguration(.single(PostQuantumConfigurationRelay( - relay: exit, - configuration: PostQuantumConfiguration( - privateKey: ephemeralKey, - preSharedKey: preSharedKey, - allowedIPs: [ - IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV4.rawValue)/0")!, - IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV6.rawValue)/0")!, - ] - ) - ))) - self.onFinish() - } -} diff --git a/ios/PacketTunnel/WireGuardAdapter/WgAdapter.swift b/ios/PacketTunnel/WireGuardAdapter/WgAdapter.swift index 3351fcb554b7..cf52553a5ee8 100644 --- a/ios/PacketTunnel/WireGuardAdapter/WgAdapter.swift +++ b/ios/PacketTunnel/WireGuardAdapter/WgAdapter.swift @@ -29,13 +29,13 @@ struct WgAdapter: TunnelAdapterProtocol { ) } - func start(configuration: TunnelAdapterConfiguration) async throws { + func start(configuration: TunnelAdapterConfiguration, daita: DaitaConfiguration?) async throws { let wgConfig = configuration.asWgConfig do { try await adapter.stop() - try await adapter.start(tunnelConfiguration: wgConfig) + try await adapter.start(tunnelConfiguration: wgConfig, daita: daita) } catch WireGuardAdapterError.invalidState { - try await adapter.start(tunnelConfiguration: wgConfig) + try await adapter.start(tunnelConfiguration: wgConfig, daita: daita) } let tunAddresses = wgConfig.interface.addresses.map { $0.address } @@ -47,7 +47,8 @@ struct WgAdapter: TunnelAdapterProtocol { func startMultihop( entryConfiguration: TunnelAdapterConfiguration? = nil, - exitConfiguration: TunnelAdapterConfiguration + exitConfiguration: TunnelAdapterConfiguration, + daita: DaitaConfiguration? ) async throws { let exitConfiguration = exitConfiguration.asWgConfig let entryConfiguration = entryConfiguration?.asWgConfig @@ -62,12 +63,14 @@ struct WgAdapter: TunnelAdapterProtocol { try await adapter.stop() try await adapter.startMultihop( entryConfiguration: entryConfiguration, - exitConfiguration: exitConfiguration + exitConfiguration: exitConfiguration, + daita: daita ) } catch WireGuardAdapterError.invalidState { try await adapter.startMultihop( entryConfiguration: entryConfiguration, - exitConfiguration: exitConfiguration + exitConfiguration: exitConfiguration, + daita: daita ) } diff --git a/ios/PacketTunnel/WireGuardAdapter/WireGuardAdapter+Async.swift b/ios/PacketTunnel/WireGuardAdapter/WireGuardAdapter+Async.swift index 9c2322a71f0e..dba3c8f8e5d1 100644 --- a/ios/PacketTunnel/WireGuardAdapter/WireGuardAdapter+Async.swift +++ b/ios/PacketTunnel/WireGuardAdapter/WireGuardAdapter+Async.swift @@ -10,9 +10,9 @@ import Foundation import WireGuardKit extension WireGuardAdapter { - func start(tunnelConfiguration: TunnelConfiguration) async throws { + func start(tunnelConfiguration: TunnelConfiguration, daita: DaitaConfiguration?) async throws { return try await withCheckedThrowingContinuation { continuation in - start(tunnelConfiguration: tunnelConfiguration) { error in + start(tunnelConfiguration: tunnelConfiguration, daita: daita) { error in if let error { continuation.resume(throwing: error) } else { @@ -22,9 +22,17 @@ extension WireGuardAdapter { } } - func startMultihop(entryConfiguration: TunnelConfiguration?, exitConfiguration: TunnelConfiguration) async throws { + func startMultihop( + entryConfiguration: TunnelConfiguration?, + exitConfiguration: TunnelConfiguration, + daita: DaitaConfiguration? + ) async throws { return try await withCheckedThrowingContinuation { continuation in - startMultihop(exitConfiguration: exitConfiguration, entryConfiguration: entryConfiguration) { error in + startMultihop( + exitConfiguration: exitConfiguration, + entryConfiguration: entryConfiguration, + daita: daita + ) { error in if let error { continuation.resume(throwing: error) } else { diff --git a/ios/PacketTunnelCore/Actor/PostQuantumKey.swift b/ios/PacketTunnelCore/Actor/EphemeralPeerKey.swift similarity index 53% rename from ios/PacketTunnelCore/Actor/PostQuantumKey.swift rename to ios/PacketTunnelCore/Actor/EphemeralPeerKey.swift index bb5cf7f43815..d411965c6299 100644 --- a/ios/PacketTunnelCore/Actor/PostQuantumKey.swift +++ b/ios/PacketTunnelCore/Actor/EphemeralPeerKey.swift @@ -1,5 +1,5 @@ // -// PostQuantumKey.swift +// EphemeralPeerKey.swift // PacketTunnelCore // // Created by Mojgan on 2024-07-15. @@ -8,11 +8,12 @@ import WireGuardKitTypes -public struct PostQuantumKey: Equatable { - public let preSharedKey: PreSharedKey +/// The preshared / private key used by ephemeral peers +public struct EphemeralPeerKey: Equatable { + public let preSharedKey: PreSharedKey? public let ephemeralKey: PrivateKey - public init(preSharedKey: PreSharedKey, ephemeralKey: PrivateKey) { + public init(preSharedKey: PreSharedKey? = nil, ephemeralKey: PrivateKey) { self.preSharedKey = preSharedKey self.ephemeralKey = ephemeralKey } diff --git a/ios/PacketTunnelCore/Actor/PostQuantumNegotiationState.swift b/ios/PacketTunnelCore/Actor/EphemeralPeerNegotiationState.swift similarity index 67% rename from ios/PacketTunnelCore/Actor/PostQuantumNegotiationState.swift rename to ios/PacketTunnelCore/Actor/EphemeralPeerNegotiationState.swift index bb3b34c450b2..339e458ce266 100644 --- a/ios/PacketTunnelCore/Actor/PostQuantumNegotiationState.swift +++ b/ios/PacketTunnelCore/Actor/EphemeralPeerNegotiationState.swift @@ -1,5 +1,5 @@ // -// PostQuantumConfiguration.swift +// EphemeralPeerNegotiationState.swift // PacketTunnelCore // // Created by Mojgan on 2024-07-16. @@ -9,11 +9,11 @@ import MullvadREST import WireGuardKitTypes -public enum PostQuantumNegotiationState: Equatable { - case single(PostQuantumConfigurationRelay) - case multi(entry: PostQuantumConfigurationRelay, exit: PostQuantumConfigurationRelay) +public enum EphemeralPeerNegotiationState: Equatable { + case single(EphemeralPeerRelayConfiguration) + case multi(entry: EphemeralPeerRelayConfiguration, exit: EphemeralPeerRelayConfiguration) - public static func == (lhs: PostQuantumNegotiationState, rhs: PostQuantumNegotiationState) -> Bool { + public static func == (lhs: EphemeralPeerNegotiationState, rhs: EphemeralPeerNegotiationState) -> Bool { return switch (lhs, rhs) { case let (.single(hop1), .single(hop2)): hop1 == hop2 @@ -25,11 +25,11 @@ public enum PostQuantumNegotiationState: Equatable { } } -public struct PostQuantumConfigurationRelay: Equatable, CustomDebugStringConvertible { +public struct EphemeralPeerRelayConfiguration: Equatable, CustomDebugStringConvertible { public let relay: SelectedRelay - public let configuration: PostQuantumConfiguration + public let configuration: EphemeralPeerConfiguration - public init(relay: SelectedRelay, configuration: PostQuantumConfiguration) { + public init(relay: SelectedRelay, configuration: EphemeralPeerConfiguration) { self.relay = relay self.configuration = configuration } @@ -39,7 +39,7 @@ public struct PostQuantumConfigurationRelay: Equatable, CustomDebugStringConvert } } -public struct PostQuantumConfiguration: Equatable, CustomDebugStringConvertible { +public struct EphemeralPeerConfiguration: Equatable, CustomDebugStringConvertible { public let privateKey: PrivateKey public let preSharedKey: PreSharedKey? public let allowedIPs: [IPAddressRange] diff --git a/ios/PacketTunnelCore/Actor/ObservedState+Extensions.swift b/ios/PacketTunnelCore/Actor/ObservedState+Extensions.swift index f43c937e943a..f809fa0d9fc7 100644 --- a/ios/PacketTunnelCore/Actor/ObservedState+Extensions.swift +++ b/ios/PacketTunnelCore/Actor/ObservedState+Extensions.swift @@ -16,7 +16,7 @@ extension ObservedState { "Connected" case .connecting: "Connecting" - case .negotiatingPostQuantumKey: + case .negotiatingEphemeralPeer: "Negotiating Post Quantum Secure Key" case .reconnecting: "Reconnecting" @@ -37,7 +37,7 @@ extension ObservedState { let .connecting(connectionState), let .reconnecting(connectionState), let .connected(connectionState), - let .negotiatingPostQuantumKey(connectionState, _), + let .negotiatingEphemeralPeer(connectionState, _), let .disconnecting(connectionState): connectionState default: diff --git a/ios/PacketTunnelCore/Actor/ObservedState.swift b/ios/PacketTunnelCore/Actor/ObservedState.swift index f81602019aa4..8b3779284e85 100644 --- a/ios/PacketTunnelCore/Actor/ObservedState.swift +++ b/ios/PacketTunnelCore/Actor/ObservedState.swift @@ -18,7 +18,7 @@ public enum ObservedState: Equatable, Codable { case initial case connecting(ObservedConnectionState) case reconnecting(ObservedConnectionState) - case negotiatingPostQuantumKey(ObservedConnectionState, PrivateKey) + case negotiatingEphemeralPeer(ObservedConnectionState, PrivateKey) case connected(ObservedConnectionState) case disconnecting(ObservedConnectionState) case disconnected @@ -35,6 +35,7 @@ public struct ObservedConnectionState: Equatable, Codable { public var remotePort: UInt16 public var lastKeyRotation: Date? public let isPostQuantum: Bool + public let isDaitaEnabled: Bool public var isNetworkReachable: Bool { networkReachability != .unreachable @@ -48,7 +49,8 @@ public struct ObservedConnectionState: Equatable, Codable { transportLayer: TransportLayer, remotePort: UInt16, lastKeyRotation: Date? = nil, - isPostQuantum: Bool + isPostQuantum: Bool, + isDaitaEnabled: Bool ) { self.selectedRelays = selectedRelays self.relayConstraints = relayConstraints @@ -58,6 +60,7 @@ public struct ObservedConnectionState: Equatable, Codable { self.remotePort = remotePort self.lastKeyRotation = lastKeyRotation self.isPostQuantum = isPostQuantum + self.isDaitaEnabled = isDaitaEnabled } } @@ -86,8 +89,8 @@ extension State { return .reconnecting(connState.observedConnectionState) case let .disconnecting(connState): return .disconnecting(connState.observedConnectionState) - case let .negotiatingPostQuantumKey(connState, privateKey): - return .negotiatingPostQuantumKey(connState.observedConnectionState, privateKey) + case let .negotiatingEphemeralPeer(connState, privateKey): + return .negotiatingEphemeralPeer(connState.observedConnectionState, privateKey) case .disconnected: return .disconnected case let .error(blockedState): @@ -107,7 +110,8 @@ extension State.ConnectionData { transportLayer: transportLayer, remotePort: remotePort, lastKeyRotation: lastKeyRotation, - isPostQuantum: isPostQuantum + isPostQuantum: isPostQuantum, + isDaitaEnabled: isDaitaEnabled ) } } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+ConnectionMonitoring.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+ConnectionMonitoring.swift index aec5b94dec04..4c53a977b361 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+ConnectionMonitoring.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+ConnectionMonitoring.swift @@ -42,7 +42,7 @@ extension PacketTunnelActor { connState.connectionAttemptCount = 0 state = .connected(connState) - case .initial, .connected, .disconnecting, .disconnected, .error, .negotiatingPostQuantumKey: + case .initial, .connected, .disconnecting, .disconnected, .error, .negotiatingEphemeralPeer: break } } @@ -53,7 +53,7 @@ extension PacketTunnelActor { case .connecting, .reconnecting, .connected: eventChannel.send(.reconnect(.random, reason: .connectionLoss)) - case .initial, .disconnected, .disconnecting, .error, .negotiatingPostQuantumKey: + case .initial, .disconnected, .disconnecting, .error, .negotiatingEphemeralPeer: break } } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+ErrorState.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+ErrorState.swift index 4b4a95c40634..064445ff1ea6 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+ErrorState.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+ErrorState.swift @@ -84,8 +84,8 @@ extension PacketTunnelActor { return nil } - // Post quantum key exchange cannot enter the blocked state - case .disconnecting, .disconnected, .negotiatingPostQuantumKey: + // Ephemeral peer exchange cannot enter the blocked state + case .disconnecting, .disconnected, .negotiatingEphemeralPeer: return nil } } @@ -127,7 +127,7 @@ extension PacketTunnelActor { publicKey: PrivateKey().publicKey ) try? await tunnelAdapter.stop() - try await tunnelAdapter.start(configuration: config) + try await tunnelAdapter.start(configuration: config, daita: nil) } catch { logger.error(error: error, message: "Unable to configure the tunnel for error state.") } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift index 9f996904146a..4bebc5c32446 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift @@ -14,21 +14,21 @@ extension PacketTunnelActor { Attempt to start the process of negotiating a post-quantum secure key, setting up an initial connection restricted to the negotiation host and entering the negotiating state. */ - internal func tryStartPostQuantumNegotiation( + internal func tryStartEphemeralPeerNegotiation( withSettings settings: Settings, nextRelays: NextRelays, reason: ActorReconnectReason ) async throws { if let connectionState = try obfuscateConnection(nextRelays: nextRelays, settings: settings, reason: reason) { let activeKey = activeKey(from: connectionState, in: settings) - state = .negotiatingPostQuantumKey(connectionState, activeKey) + state = .negotiatingEphemeralPeer(connectionState, activeKey) } } /** Called on receipt of the new PQ-negotiated key, to reconnect to the relay, in PQ-secure mode. */ - internal func postQuantumConnect() async { + internal func connectWithEphemeralPeer() async { guard let connectionData = state.connectionData else { logger.error("Could not create connection state in PostQuantumConnect") eventChannel.send(.reconnect(.current)) @@ -47,9 +47,9 @@ extension PacketTunnelActor { } /** - Called to reconfigure the tunnel after each key negotiation. + Called to reconfigure the tunnel after each ephemeral peer negotiation. */ - internal func updatePostQuantumNegotiationState(configuration: PostQuantumNegotiationState) async throws { + internal func updateEphemeralPeerNegotiationState(configuration: EphemeralPeerNegotiationState) async throws { /** The obfuscater needs to be restarted every time a new tunnel configuration is being used, because the obfuscation may be tied to a specific UDP session, as is the case for udp2tcp. @@ -60,10 +60,20 @@ extension PacketTunnelActor { settings: settings, reason: .userInitiated ) else { - logger.error("Tried to replace post quantum configuration in invalid state: \(state.name)") + logger.error("Tried to update ephemeral peer negotiation in invalid state: \(state.name)") return } + var daitaConfiguration: DaitaConfiguration? + if settings.daita.state.isEnabled { + let maybeNot = Maybenot() + daitaConfiguration = DaitaConfiguration( + machines: maybeNot.machines, + maxEvents: maybeNot.maximumEvents, + maxActions: maybeNot.maximumActions + ) + } + switch configuration { case let .single(hop): let exitConfiguration = try ConfigurationBuilder( @@ -75,7 +85,7 @@ extension PacketTunnelActor { preSharedKey: hop.configuration.preSharedKey ).makeConfiguration() - try await tunnelAdapter.start(configuration: exitConfiguration) + try await tunnelAdapter.start(configuration: exitConfiguration, daita: daitaConfiguration) case let .multi(firstHop, secondHop): let entryConfiguration = try ConfigurationBuilder( @@ -97,7 +107,7 @@ extension PacketTunnelActor { ).makeConfiguration() try await tunnelAdapter.startMultihop( - entryConfiguration: entryConfiguration, exitConfiguration: exitConfiguration + entryConfiguration: entryConfiguration, exitConfiguration: exitConfiguration, daita: daitaConfiguration ) } } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+Public.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+Public.swift index 625b69319e17..05b69deb35d2 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+Public.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+Public.swift @@ -52,20 +52,20 @@ extension PacketTunnelActor { } /** - Tell actor that post quantum key exchanging took place. + Tell actor that the ephemeral peer exchanging took place. */ - nonisolated public func notifyPostQuantumKeyExchanged() { - eventChannel.send(.notifyPostQuantumKeyExchanged) + nonisolated public func notifyEphemeralPeerNegotiated() { + eventChannel.send(.notifyEphemeralPeerNegotiated) } /** - Issue a new preshared key to the Actor. + Tell actor that the ephemeral peer negotiation state changed. - Parameter key: the new key */ - nonisolated public func replaceKeyWithPQ(configuration: PostQuantumNegotiationState) { - eventChannel.send(.postQuantumNegotiationStateChanged(configuration)) + nonisolated public func changeEphemeralPeerNegotiationState(configuration: EphemeralPeerNegotiationState) { + eventChannel.send(.ephemeralPeerNegotiationStateChanged(configuration)) } /** diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift index 9e21e8550ee7..0a4b9dc493fc 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift @@ -139,15 +139,15 @@ public actor PacketTunnelActor { case let .cacheActiveKey(lastKeyRotation): cacheActiveKey(lastKeyRotation: lastKeyRotation) - case let .reconfigureForPostQuantum(configuration): + case let .reconfigureForEphemeralPeer(configuration): do { - try await updatePostQuantumNegotiationState(configuration: configuration) + try await updateEphemeralPeerNegotiationState(configuration: configuration) } catch { logger.error(error: error, message: "Failed to reconfigure tunnel after each hop negotiation.") await setErrorStateInternal(with: error) } - case .postQuantumConnect: - await postQuantumConnect() + case .connectWithEphemeralPeer: + await connectWithEphemeralPeer() case .setDisconnectedState: self.state = .disconnected } @@ -188,7 +188,7 @@ extension PacketTunnelActor { private func stop() async { switch state { case let .connected(connState), let .connecting(connState), let .reconnecting(connState), - let .negotiatingPostQuantumKey(connState, _): + let .negotiatingEphemeralPeer(connState, _): state = .disconnecting(connState) tunnelMonitor.stop() @@ -225,7 +225,7 @@ extension PacketTunnelActor { switch state { // There is no connection monitoring going on when exchanging keys. // The procedure starts from scratch for each reconnection attempts. - case .connecting, .connected, .reconnecting, .error, .negotiatingPostQuantumKey: + case .connecting, .connected, .reconnecting, .error, .negotiatingEphemeralPeer: switch reason { case .connectionLoss: // Tunnel monitor is already paused at this point. Avoid calling stop() to prevent the reset of @@ -259,8 +259,8 @@ extension PacketTunnelActor { ) async throws { let settings: Settings = try settingsReader.read() - if settings.quantumResistance.isEnabled { - try await tryStartPostQuantumNegotiation(withSettings: settings, nextRelays: nextRelays, reason: reason) + if settings.quantumResistance.isEnabled || settings.daita.state.isEnabled { + try await tryStartEphemeralPeerNegotiation(withSettings: settings, nextRelays: nextRelays, reason: reason) } else { try await tryStartConnection(withSettings: settings, nextRelays: nextRelays, reason: reason) } @@ -330,9 +330,20 @@ extension PacketTunnelActor { startDefaultPathObserver(notifyObserverWithCurrentPath: true) } + var daitaConfiguration: DaitaConfiguration? + if settings.daita.state.isEnabled { + let maybeNot = Maybenot() + daitaConfiguration = DaitaConfiguration( + machines: maybeNot.machines, + maxEvents: maybeNot.maximumEvents, + maxActions: maybeNot.maximumActions + ) + } + try await tunnelAdapter.startMultihop( entryConfiguration: entryConfiguration, - exitConfiguration: exitConfiguration + exitConfiguration: exitConfiguration, + daita: daitaConfiguration ) // Resume tunnel monitoring and use IPv4 gateway as a probe address. @@ -377,8 +388,8 @@ extension PacketTunnelActor { } switch state { - // Handle PQ PSK separately as it doesn't interfere with either the `.connecting` or `.reconnecting` states. - case var .negotiatingPostQuantumKey(connectionState, _): + // Handle ephemeral peers separately as they don't interfere with either the `.connecting` or `.reconnecting` states. + case var .negotiatingEphemeralPeer(connectionState, _): if reason == .connectionLoss { connectionState.incrementAttemptCount() } @@ -429,7 +440,8 @@ extension PacketTunnelActor { connectedEndpoint: connectedRelay.endpoint, transportLayer: .udp, remotePort: connectedRelay.endpoint.ipv4Relay.port, - isPostQuantum: settings.quantumResistance.isEnabled + isPostQuantum: settings.quantumResistance.isEnabled, + isDaitaEnabled: settings.daita.state.isEnabled ) case .disconnecting, .disconnected: return nil @@ -471,7 +483,8 @@ extension PacketTunnelActor { connectedEndpoint: obfuscatedEndpoint, transportLayer: transportLayer, remotePort: protocolObfuscator.remotePort, - isPostQuantum: settings.quantumResistance.isEnabled + isPostQuantum: settings.quantumResistance.isEnabled, + isDaitaEnabled: settings.daita.state.isEnabled ) } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift index 7ea1c785b584..b677986d041b 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift @@ -37,10 +37,10 @@ extension PacketTunnelActor { case networkReachability(NetworkPath) /// Update the device private key, as per post-quantum protocols - case postQuantumNegotiationStateChanged(PostQuantumNegotiationState) + case ephemeralPeerNegotiationStateChanged(EphemeralPeerNegotiationState) - /// Notify that post quantum key exchanging took place - case notifyPostQuantumKeyExchanged + /// Notify that an ephemeral peer exchanging took place + case notifyEphemeralPeerNegotiated /// Format command for log output. func logFormat() -> String { @@ -73,10 +73,10 @@ extension PacketTunnelActor { return "networkReachability" case .switchKey: return "switchKey" - case .postQuantumNegotiationStateChanged: - return "postQuantumNegotiationStateChanged" - case .notifyPostQuantumKeyExchanged: - return "notifyPostQuantumKeyExchanged" + case .ephemeralPeerNegotiationStateChanged: + return "ephemeralPeerNegotiationStateChanged" + case .notifyEphemeralPeerNegotiated: + return "notifyEphemeralPeerNegotiated" } } } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActorReducer.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActorReducer.swift index 7d18463f17f0..3382baf2092a 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActorReducer.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActorReducer.swift @@ -25,8 +25,8 @@ extension PacketTunnelActor { case stopTunnelAdapter case configureForErrorState(BlockedStateReason) case cacheActiveKey(Date?) - case reconfigureForPostQuantum(PostQuantumNegotiationState) - case postQuantumConnect + case reconfigureForEphemeralPeer(EphemeralPeerNegotiationState) + case connectWithEphemeralPeer // acknowledge that the disconnection process has concluded, go to .disconnected. case setDisconnectedState @@ -45,8 +45,8 @@ extension PacketTunnelActor { case (.stopTunnelAdapter, .stopTunnelAdapter): true case let (.configureForErrorState(r0), .configureForErrorState(r1)): r0 == r1 case let (.cacheActiveKey(d0), .cacheActiveKey(d1)): d0 == d1 - case let (.reconfigureForPostQuantum(pqns0), .reconfigureForPostQuantum(pqns1)): pqns0 == pqns1 - case (.postQuantumConnect, .postQuantumConnect): true + case let (.reconfigureForEphemeralPeer(eph0), .reconfigureForEphemeralPeer(eph1)): eph0 == eph1 + case (.connectWithEphemeralPeer, .connectWithEphemeralPeer): true case (.setDisconnectedState, .setDisconnectedState): true default: false } @@ -89,11 +89,11 @@ extension PacketTunnelActor { state.mutateAssociatedData { $0.networkReachability = newReachability } return [.updateTunnelMonitorPath(defaultPath)] - case let .postQuantumNegotiationStateChanged(configuration): - return [.reconfigureForPostQuantum(configuration)] + case let .ephemeralPeerNegotiationStateChanged(configuration): + return [.reconfigureForEphemeralPeer(configuration)] - case .notifyPostQuantumKeyExchanged: - return [.postQuantumConnect] + case .notifyEphemeralPeerNegotiated: + return [.connectWithEphemeralPeer] } } @@ -103,7 +103,7 @@ extension PacketTunnelActor { // a call of the reducer produces one state transition and a sequence of effects. In the app, a stop transitions to .disconnecting, shuts down various processes, and finally transitions to .disconnected. We currently do this by having an effect which acknowledges the completion of disconnection and just sets the state. This is a bit messy, and could possibly do with some rethinking. switch state { case let .connected(connState), let .connecting(connState), let .reconnecting(connState), - let .negotiatingPostQuantumKey(connState, _): + let .negotiatingEphemeralPeer(connState, _): state = .disconnecting(connState) return [ .stopTunnelMonitor, @@ -137,7 +137,7 @@ extension PacketTunnelActor { // There is no connection monitoring going on when exchanging keys. // The procedure starts from scratch for each reconnection attempts. return [] - case .connecting, .connected, .reconnecting, .error, .negotiatingPostQuantumKey: + case .connecting, .connected, .reconnecting, .error, .negotiatingEphemeralPeer: if reason == .userInitiated { return [.stopTunnelMonitor, .restartConnection(nextRelays, reason)] } else { @@ -169,7 +169,7 @@ extension PacketTunnelActor { connState.connectionAttemptCount = 0 state = .connected(connState) - case .initial, .connected, .disconnecting, .disconnected, .error, .negotiatingPostQuantumKey: + case .initial, .connected, .disconnecting, .disconnected, .error, .negotiatingEphemeralPeer: break } return [] @@ -177,7 +177,7 @@ extension PacketTunnelActor { switch state { case .connecting, .reconnecting, .connected: return [.restartConnection(.random, .connectionLoss)] - case .initial, .disconnected, .disconnecting, .error, .negotiatingPostQuantumKey: + case .initial, .disconnected, .disconnecting, .error, .negotiatingEphemeralPeer: return [] } } diff --git a/ios/PacketTunnelCore/Actor/Protocols/PostQuantumKeyExchangingProtocol.swift b/ios/PacketTunnelCore/Actor/Protocols/EphemeralPeerExchangingProtocol.swift similarity index 73% rename from ios/PacketTunnelCore/Actor/Protocols/PostQuantumKeyExchangingProtocol.swift rename to ios/PacketTunnelCore/Actor/Protocols/EphemeralPeerExchangingProtocol.swift index 1df27c7176c7..bffc4f7a2111 100644 --- a/ios/PacketTunnelCore/Actor/Protocols/PostQuantumKeyExchangingProtocol.swift +++ b/ios/PacketTunnelCore/Actor/Protocols/EphemeralPeerExchangingProtocol.swift @@ -8,7 +8,8 @@ import WireGuardKitTypes -public protocol PostQuantumKeyExchangingProtocol { +public protocol EphemeralPeerExchangingProtocol { func start() func receivePostQuantumKey(_ preSharedKey: PreSharedKey, ephemeralKey: PrivateKey) + func receiveEphemeralPeerPrivateKey(_: PrivateKey) } diff --git a/ios/PacketTunnelCore/Actor/Protocols/TunnelAdapterProtocol.swift b/ios/PacketTunnelCore/Actor/Protocols/TunnelAdapterProtocol.swift index e07ba4664e1e..ac992c76c99e 100644 --- a/ios/PacketTunnelCore/Actor/Protocols/TunnelAdapterProtocol.swift +++ b/ios/PacketTunnelCore/Actor/Protocols/TunnelAdapterProtocol.swift @@ -15,12 +15,13 @@ import WireGuardKitTypes /// Protocol describing interface for any kind of adapter implementing a VPN tunnel. public protocol TunnelAdapterProtocol { /// Start tunnel adapter or update active configuration. - func start(configuration: TunnelAdapterConfiguration) async throws + func start(configuration: TunnelAdapterConfiguration, daita: DaitaConfiguration?) async throws /// Start tunnel adapter or update active configuration. func startMultihop( entryConfiguration: TunnelAdapterConfiguration?, - exitConfiguration: TunnelAdapterConfiguration + exitConfiguration: TunnelAdapterConfiguration, + daita: DaitaConfiguration? ) async throws /// Stop tunnel adapter with the given configuration. diff --git a/ios/PacketTunnelCore/Actor/State+Extensions.swift b/ios/PacketTunnelCore/Actor/State+Extensions.swift index d784b4645197..a1e2c18d11bd 100644 --- a/ios/PacketTunnelCore/Actor/State+Extensions.swift +++ b/ios/PacketTunnelCore/Actor/State+Extensions.swift @@ -23,7 +23,7 @@ extension State { case .initial: return .connecting - case .connecting, .negotiatingPostQuantumKey: + case .connecting, .negotiatingEphemeralPeer: return .connecting case .connected, .reconnecting: @@ -58,15 +58,24 @@ extension State { case let .error(blockedState): "\(name): \(blockedState.reason)" - case .initial, .disconnecting, .disconnected, .negotiatingPostQuantumKey: + case .initial, .disconnecting, .disconnected, .negotiatingEphemeralPeer: name } } var name: String { switch self { - case .negotiatingPostQuantumKey: - "Negotiating Post Quantum Key" + case let .negotiatingEphemeralPeer(connectionData, _): + switch (connectionData.isPostQuantum, connectionData.isDaitaEnabled) { + case (true, true): + "Negotiating Post Quantum Key with Daita" + case (true, false): + "Negotiating Post Quantum Key" + case (false, true): + "Negotiating Daita peer without Post Quantum Key" + case (false, false): + "Negotiating ephemeral peer without Post Quantum Key or Daita -- Multihop exit relay probably" + } case .connected: "Connected" case .connecting: @@ -90,7 +99,7 @@ extension State { let .connecting(connState), let .connected(connState), let .reconnecting(connState), - let .negotiatingPostQuantumKey(connState, _), + let .negotiatingEphemeralPeer(connState, _), let .disconnecting(connState): connState default: nil } @@ -120,7 +129,7 @@ extension State { case .connected: .connected(newValue) case .reconnecting: .reconnecting(newValue) case .disconnecting: .disconnecting(newValue) - case let .negotiatingPostQuantumKey(_, privateKey): .negotiatingPostQuantumKey(newValue, privateKey) + case let .negotiatingEphemeralPeer(_, privateKey): .negotiatingEphemeralPeer(newValue, privateKey) default: self } } @@ -133,7 +142,7 @@ extension State { case let .connecting(connState), let .connected(connState), let .reconnecting(connState), - let .negotiatingPostQuantumKey(connState, _), + let .negotiatingEphemeralPeer(connState, _), let .disconnecting(connState): var associatedData: StateAssociatedData = connState modifier(&associatedData) diff --git a/ios/PacketTunnelCore/Actor/State.swift b/ios/PacketTunnelCore/Actor/State.swift index f3c1b012b29e..10a28b5a2486 100644 --- a/ios/PacketTunnelCore/Actor/State.swift +++ b/ios/PacketTunnelCore/Actor/State.swift @@ -59,8 +59,8 @@ enum State: Equatable { /// Initial state at the time when actor is initialized but before the first connection attempt. case initial - /// Establish a connection to the gateway, and exchange a post quantum key with the GRPC service that resides there. - case negotiatingPostQuantumKey(ConnectionData, PrivateKey) + /// Establish a connection to the gateway, and exchange an ephemeral wireguard peer with the GRPC service that resides there. + case negotiatingEphemeralPeer(ConnectionData, PrivateKey) /// Tunnel is attempting to connect. /// The actor should remain in this state until the very first connection is established, i.e determined by tunnel monitor. @@ -150,6 +150,9 @@ extension State { /// True if post-quantum key exchange is enabled public let isPostQuantum: Bool + + /// True if Daita is enabled + public let isDaitaEnabled: Bool } /// Data associated with error state. @@ -254,7 +257,7 @@ public enum ActorReconnectReason: Equatable { /// Initiated by user. case userInitiated - /// Initiated by tunnel monitor due to loss of connectivity, or if post quantum key negotiation times out. + /// Initiated by tunnel monitor due to loss of connectivity, or if ephemeral peer negotiation times out. /// Actor will increment the connection attempt counter before picking next relay. case connectionLoss } diff --git a/ios/PacketTunnelCoreTests/PostQuantumKeyExchangingPipelineTests.swift b/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift similarity index 53% rename from ios/PacketTunnelCoreTests/PostQuantumKeyExchangingPipelineTests.swift rename to ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift index f0725be312cd..e5a679ec58c8 100644 --- a/ios/PacketTunnelCoreTests/PostQuantumKeyExchangingPipelineTests.swift +++ b/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift @@ -1,5 +1,5 @@ // -// PostQuantumKeyExchangingPipelineTests.swift +// EphemeralPeerExchangingPipelineTests.swift // MullvadPostQuantumTests // // Created by Mojgan on 2024-07-19. @@ -13,7 +13,7 @@ @testable import WireGuardKitTypes import XCTest -final class PostQuantumKeyExchangingPipelineTests: XCTestCase { +final class EphemeralPeerExchangingPipelineTests: XCTestCase { var entryRelay: SelectedRelay! var exitRelay: SelectedRelay! var relayConstraints: RelayConstraints! @@ -60,18 +60,18 @@ final class PostQuantumKeyExchangingPipelineTests: XCTestCase { ) } - func testSingleHopKeyExchange() throws { + func testSingleHopPostQuantumKeyExchange() throws { let reconfigurationExpectation = expectation(description: "Tunnel reconfiguration took place") reconfigurationExpectation.expectedFulfillmentCount = 2 let negotiationSuccessful = expectation(description: "Negotiation succeeded.") negotiationSuccessful.expectedFulfillmentCount = 1 - let keyExchangeActor = PostQuantumKeyExchangeActorStub() + let keyExchangeActor = EphemeralPeerExchangeActorStub() let preSharedKey = try XCTUnwrap(PreSharedKey(hexKey: PrivateKey().hexKey)) keyExchangeActor.result = .success((preSharedKey, PrivateKey())) - let postQuantumKeyExchangingPipeline = PostQuantumKeyExchangingPipeline(keyExchangeActor) { _ in + let postQuantumKeyExchangingPipeline = EphemeralPeerExchangingPipeline(keyExchangeActor) { _ in reconfigurationExpectation.fulfill() } onFinish: { negotiationSuccessful.fulfill() @@ -81,16 +81,37 @@ final class PostQuantumKeyExchangingPipelineTests: XCTestCase { postQuantumKeyExchangingPipeline.receivePostQuantumKey(preSharedKey, ephemeralKey: privateKey) }) - let connectionState = ObservedConnectionState( - selectedRelays: SelectedRelays(entry: nil, exit: exitRelay, retryAttempt: 0), - relayConstraints: relayConstraints, - networkReachability: NetworkReachability.reachable, - connectionAttemptCount: 0, - transportLayer: .udp, - remotePort: 1234, - isPostQuantum: true + let connectionState = stubConnectionState(enableMultiHop: false, enablePostQuantum: true, enableDaita: false) + postQuantumKeyExchangingPipeline.startNegotiation(connectionState, privateKey: PrivateKey()) + + wait( + for: [reconfigurationExpectation, negotiationSuccessful], + timeout: .UnitTest.invertedTimeout ) + } + + func testSingleHopDaitaPeerExchange() throws { + let reconfigurationExpectation = expectation(description: "Tunnel reconfiguration took place") + reconfigurationExpectation.expectedFulfillmentCount = 2 + let negotiationSuccessful = expectation(description: "Negotiation succeeded.") + negotiationSuccessful.expectedFulfillmentCount = 1 + + let keyExchangeActor = EphemeralPeerExchangeActorStub() + let preSharedKey = try XCTUnwrap(PreSharedKey(hexKey: PrivateKey().hexKey)) + keyExchangeActor.result = .success((preSharedKey, PrivateKey())) + + let postQuantumKeyExchangingPipeline = EphemeralPeerExchangingPipeline(keyExchangeActor) { _ in + reconfigurationExpectation.fulfill() + } onFinish: { + negotiationSuccessful.fulfill() + } + + keyExchangeActor.delegate = KeyExchangingResultStub(onReceiveEphemeralPeerPrivateKey: { privateKey in + postQuantumKeyExchangingPipeline.receiveEphemeralPeerPrivateKey(privateKey) + }) + + let connectionState = stubConnectionState(enableMultiHop: false, enablePostQuantum: false, enableDaita: true) postQuantumKeyExchangingPipeline.startNegotiation(connectionState, privateKey: PrivateKey()) wait( @@ -99,18 +120,18 @@ final class PostQuantumKeyExchangingPipelineTests: XCTestCase { ) } - func testMultiHopKeyExchange() throws { + func testMultiHopPostQuantumKeyExchange() throws { let reconfigurationExpectation = expectation(description: "Tunnel reconfiguration took place") reconfigurationExpectation.expectedFulfillmentCount = 3 let negotiationSuccessful = expectation(description: "Negotiation succeeded.") negotiationSuccessful.expectedFulfillmentCount = 1 - let keyExchangeActor = PostQuantumKeyExchangeActorStub() + let keyExchangeActor = EphemeralPeerExchangeActorStub() let preSharedKey = try XCTUnwrap(PreSharedKey(hexKey: PrivateKey().hexKey)) keyExchangeActor.result = .success((preSharedKey, PrivateKey())) - let postQuantumKeyExchangingPipeline = PostQuantumKeyExchangingPipeline(keyExchangeActor) { _ in + let postQuantumKeyExchangingPipeline = EphemeralPeerExchangingPipeline(keyExchangeActor) { _ in reconfigurationExpectation.fulfill() } onFinish: { negotiationSuccessful.fulfill() @@ -120,16 +141,37 @@ final class PostQuantumKeyExchangingPipelineTests: XCTestCase { postQuantumKeyExchangingPipeline.receivePostQuantumKey(preSharedKey, ephemeralKey: privateKey) }) - let connectionState = ObservedConnectionState( - selectedRelays: SelectedRelays(entry: entryRelay, exit: exitRelay, retryAttempt: 0), - relayConstraints: relayConstraints, - networkReachability: NetworkReachability.reachable, - connectionAttemptCount: 0, - transportLayer: .udp, - remotePort: 1234, - isPostQuantum: true + let connectionState = stubConnectionState(enableMultiHop: true, enablePostQuantum: true, enableDaita: false) + postQuantumKeyExchangingPipeline.startNegotiation(connectionState, privateKey: PrivateKey()) + + wait( + for: [reconfigurationExpectation, negotiationSuccessful], + timeout: .UnitTest.invertedTimeout ) + } + + func testMultiHopDaitaExchange() throws { + let reconfigurationExpectation = expectation(description: "Tunnel reconfiguration took place") + reconfigurationExpectation.expectedFulfillmentCount = 3 + + let negotiationSuccessful = expectation(description: "Negotiation succeeded.") + negotiationSuccessful.expectedFulfillmentCount = 1 + + let keyExchangeActor = EphemeralPeerExchangeActorStub() + let preSharedKey = try XCTUnwrap(PreSharedKey(hexKey: PrivateKey().hexKey)) + keyExchangeActor.result = .success((preSharedKey, PrivateKey())) + let postQuantumKeyExchangingPipeline = EphemeralPeerExchangingPipeline(keyExchangeActor) { _ in + reconfigurationExpectation.fulfill() + } onFinish: { + negotiationSuccessful.fulfill() + } + + keyExchangeActor.delegate = KeyExchangingResultStub(onReceiveEphemeralPeerPrivateKey: { privateKey in + postQuantumKeyExchangingPipeline.receiveEphemeralPeerPrivateKey(privateKey) + }) + + let connectionState = stubConnectionState(enableMultiHop: true, enablePostQuantum: false, enableDaita: true) postQuantumKeyExchangingPipeline.startNegotiation(connectionState, privateKey: PrivateKey()) wait( @@ -137,4 +179,21 @@ final class PostQuantumKeyExchangingPipelineTests: XCTestCase { timeout: .UnitTest.invertedTimeout ) } + + func stubConnectionState( + enableMultiHop: Bool, + enablePostQuantum: Bool, + enableDaita: Bool + ) -> ObservedConnectionState { + ObservedConnectionState( + selectedRelays: SelectedRelays(entry: enableMultiHop ? entryRelay : nil, exit: exitRelay, retryAttempt: 0), + relayConstraints: relayConstraints, + networkReachability: NetworkReachability.reachable, + connectionAttemptCount: 0, + transportLayer: .udp, + remotePort: 1234, + isPostQuantum: enablePostQuantum, + isDaitaEnabled: enableDaita + ) + } } diff --git a/ios/PacketTunnelCoreTests/PostQuantumKeyExchangeActorStub.swift b/ios/PacketTunnelCoreTests/Mocks/EphemeralPeerExchangeActorStub.swift similarity index 50% rename from ios/PacketTunnelCoreTests/PostQuantumKeyExchangeActorStub.swift rename to ios/PacketTunnelCoreTests/Mocks/EphemeralPeerExchangeActorStub.swift index 9ea468f54786..7f17af56bec8 100644 --- a/ios/PacketTunnelCoreTests/PostQuantumKeyExchangeActorStub.swift +++ b/ios/PacketTunnelCoreTests/Mocks/EphemeralPeerExchangeActorStub.swift @@ -1,5 +1,5 @@ // -// PostQuantumKeyExchangeActorStub.swift +// EphemeralPeerExchangeActorStub.swift // MullvadPostQuantumTests // // Created by Mojgan on 2024-07-18. @@ -12,18 +12,22 @@ import NetworkExtension @testable import PacketTunnelCore @testable import WireGuardKitTypes -final class PostQuantumKeyExchangeActorStub: PostQuantumKeyExchangeActorProtocol { - typealias KeyNegotiationResult = Result<(PreSharedKey, PrivateKey), PostQuantumKeyExchangeErrorStub> +final class EphemeralPeerExchangeActorStub: EphemeralPeerExchangeActorProtocol { + typealias KeyNegotiationResult = Result<(PreSharedKey, PrivateKey), EphemeralPeerExchangeErrorStub> var result: KeyNegotiationResult = .failure(.unknown) - var delegate: PostQuantumKeyReceiving? + var delegate: EphemeralPeerReceiving? - func startNegotiation(with privateKey: PrivateKey) { + func startNegotiation(with privateKey: PrivateKey, enablePostQuantum: Bool, enableDaita: Bool) { switch result { case let .success((preSharedKey, ephemeralKey)): - delegate?.receivePostQuantumKey(preSharedKey, ephemeralKey: ephemeralKey) + if enablePostQuantum { + delegate?.receivePostQuantumKey(preSharedKey, ephemeralKey: ephemeralKey) + } else { + delegate?.receiveEphemeralPeerPrivateKey(ephemeralKey) + } case .failure: - delegate?.keyExchangeFailed() + delegate?.ephemeralPeerExchangeFailed() } } @@ -32,7 +36,7 @@ final class PostQuantumKeyExchangeActorStub: PostQuantumKeyExchangeActorProtocol func reset() {} } -enum PostQuantumKeyExchangeErrorStub: Error { +enum EphemeralPeerExchangeErrorStub: Error { case unknown case canceled } diff --git a/ios/PacketTunnelCoreTests/KeyExchangingResultStub.swift b/ios/PacketTunnelCoreTests/Mocks/KeyExchangingResultStub.swift similarity index 62% rename from ios/PacketTunnelCoreTests/KeyExchangingResultStub.swift rename to ios/PacketTunnelCoreTests/Mocks/KeyExchangingResultStub.swift index 3d6b747a97be..9dc9dca58c82 100644 --- a/ios/PacketTunnelCoreTests/KeyExchangingResultStub.swift +++ b/ios/PacketTunnelCoreTests/Mocks/KeyExchangingResultStub.swift @@ -10,15 +10,20 @@ @testable import MullvadTypes @testable import WireGuardKitTypes -struct KeyExchangingResultStub: PostQuantumKeyReceiving { +struct KeyExchangingResultStub: EphemeralPeerReceiving { var onFailure: (() -> Void)? var onReceivePostQuantumKey: ((PreSharedKey, PrivateKey) -> Void)? + var onReceiveEphemeralPeerPrivateKey: ((PrivateKey) -> Void)? func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) { onReceivePostQuantumKey?(key, ephemeralKey) } - func keyExchangeFailed() { + public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey) { + onReceiveEphemeralPeerPrivateKey?(ephemeralPeerPrivateKey) + } + + func ephemeralPeerExchangeFailed() { onFailure?() } } diff --git a/ios/PacketTunnelCoreTests/Mocks/TunnelAdapterDummy.swift b/ios/PacketTunnelCoreTests/Mocks/TunnelAdapterDummy.swift index 79b75a002d70..3c8e9552e711 100644 --- a/ios/PacketTunnelCoreTests/Mocks/TunnelAdapterDummy.swift +++ b/ios/PacketTunnelCoreTests/Mocks/TunnelAdapterDummy.swift @@ -8,15 +8,17 @@ import Foundation import PacketTunnelCore +@testable import WireGuardKitTypes /// Dummy tunnel adapter that does nothing and reports no errors. class TunnelAdapterDummy: TunnelAdapterProtocol { func startMultihop( entryConfiguration: TunnelAdapterConfiguration?, - exitConfiguration: TunnelAdapterConfiguration + exitConfiguration: TunnelAdapterConfiguration, + daita: DaitaConfiguration? ) async throws {} - func start(configuration: TunnelAdapterConfiguration) async throws {} + func start(configuration: TunnelAdapterConfiguration, daita: DaitaConfiguration?) async throws {} func stop() async throws {} diff --git a/ios/PacketTunnelCoreTests/MultiHopPostQuantumKeyExchangingTests.swift b/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift similarity index 57% rename from ios/PacketTunnelCoreTests/MultiHopPostQuantumKeyExchangingTests.swift rename to ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift index 5b8968b1ea64..95436edb4c9c 100644 --- a/ios/PacketTunnelCoreTests/MultiHopPostQuantumKeyExchangingTests.swift +++ b/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift @@ -1,5 +1,5 @@ // -// MultiHopPostQuantumKeyExchangingTests.swift +// MultiHopEphemeralPeerExchangerTests.swift // MullvadPostQuantumTests // // Created by Mojgan on 2024-07-18. @@ -13,7 +13,7 @@ @testable import WireGuardKitTypes import XCTest -final class MultiHopPostQuantumKeyExchangingTests: XCTestCase { +final class MultiHopEphemeralPeerExchangerTests: XCTestCase { var exitRelay: SelectedRelay! var entryRelay: SelectedRelay! @@ -59,7 +59,7 @@ final class MultiHopPostQuantumKeyExchangingTests: XCTestCase { ) } - func testKeyExchangeFailsWhenNegotiationCannotStart() { + func testEphemeralPeerExchangeFailsWhenNegotiationCannotStart() { let expectedNegotiationFailure = expectation(description: "Negotiation failed.") let reconfigurationExpectation = expectation(description: "Tunnel reconfiguration took place") @@ -68,25 +68,27 @@ final class MultiHopPostQuantumKeyExchangingTests: XCTestCase { let negotiationSuccessful = expectation(description: "Negotiation succeeded.") negotiationSuccessful.isInverted = true - let keyExchangeActor = PostQuantumKeyExchangeActorStub() - keyExchangeActor.result = .failure(PostQuantumKeyExchangeErrorStub.canceled) + let peerExchangeActor = EphemeralPeerExchangeActorStub() + peerExchangeActor.result = .failure(EphemeralPeerExchangeErrorStub.canceled) - let multiHopPostQuantumKeyExchanging = MultiHopPostQuantumKeyExchanging( + let multiHopExchanger = MultiHopEphemeralPeerExchanger( entry: entryRelay, exit: exitRelay, devicePrivateKey: PrivateKey(), - keyExchanger: keyExchangeActor + keyExchanger: peerExchangeActor, + enablePostQuantum: true, + enableDaita: false ) { _ in reconfigurationExpectation.fulfill() } onFinish: { negotiationSuccessful.fulfill() } - keyExchangeActor.delegate = KeyExchangingResultStub { + peerExchangeActor.delegate = KeyExchangingResultStub { expectedNegotiationFailure.fulfill() } - multiHopPostQuantumKeyExchanging.start() + multiHopExchanger.start() wait( for: [expectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], @@ -94,7 +96,7 @@ final class MultiHopPostQuantumKeyExchangingTests: XCTestCase { ) } - func testKeyExchangeSuccessWhenNegotiationStart() throws { + func testEphemeralPeerExchangeSuccessWhenPostQuantumNegotiationStarts() throws { let unexpectedNegotiationFailure = expectation(description: "Negotiation failed.") unexpectedNegotiationFailure.isInverted = true @@ -104,25 +106,65 @@ final class MultiHopPostQuantumKeyExchangingTests: XCTestCase { let negotiationSuccessful = expectation(description: "Negotiation succeeded.") negotiationSuccessful.expectedFulfillmentCount = 1 - let keyExchangeActor = PostQuantumKeyExchangeActorStub() + let peerExchangeActor = EphemeralPeerExchangeActorStub() let preSharedKey = try XCTUnwrap(PreSharedKey(hexKey: PrivateKey().hexKey)) - keyExchangeActor.result = .success((preSharedKey, PrivateKey())) + peerExchangeActor.result = .success((preSharedKey, PrivateKey())) - let multiHopPostQuantumKeyExchanging = MultiHopPostQuantumKeyExchanging( + let multiHopPeerExchanger = MultiHopEphemeralPeerExchanger( entry: entryRelay, exit: exitRelay, devicePrivateKey: PrivateKey(), - keyExchanger: keyExchangeActor + keyExchanger: peerExchangeActor, + enablePostQuantum: true, + enableDaita: false ) { _ in reconfigurationExpectation.fulfill() } onFinish: { negotiationSuccessful.fulfill() } - keyExchangeActor.delegate = KeyExchangingResultStub(onReceivePostQuantumKey: { preSharedKey, ephemeralKey in - multiHopPostQuantumKeyExchanging.receivePostQuantumKey(preSharedKey, ephemeralKey: ephemeralKey) + peerExchangeActor.delegate = KeyExchangingResultStub(onReceivePostQuantumKey: { preSharedKey, ephemeralKey in + multiHopPeerExchanger.receivePostQuantumKey(preSharedKey, ephemeralKey: ephemeralKey) }) - multiHopPostQuantumKeyExchanging.start() + multiHopPeerExchanger.start() + + wait( + for: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], + timeout: .UnitTest.invertedTimeout + ) + } + + func testEphemeralPeerExchangeSuccessWhenDaitaNegotiationStarts() throws { + let unexpectedNegotiationFailure = expectation(description: "Negotiation failed.") + unexpectedNegotiationFailure.isInverted = true + + let reconfigurationExpectation = expectation(description: "Tunnel reconfiguration took place") + reconfigurationExpectation.expectedFulfillmentCount = 3 + + let negotiationSuccessful = expectation(description: "Negotiation succeeded.") + negotiationSuccessful.expectedFulfillmentCount = 1 + + let peerExchangeActor = EphemeralPeerExchangeActorStub() + let preSharedKey = try XCTUnwrap(PreSharedKey(hexKey: PrivateKey().hexKey)) + peerExchangeActor.result = .success((preSharedKey, PrivateKey())) + + let multiHopPeerExchanger = MultiHopEphemeralPeerExchanger( + entry: entryRelay, + exit: exitRelay, + devicePrivateKey: PrivateKey(), + keyExchanger: peerExchangeActor, + enablePostQuantum: false, + enableDaita: true + ) { _ in + reconfigurationExpectation.fulfill() + } onFinish: { + negotiationSuccessful.fulfill() + } + + peerExchangeActor.delegate = KeyExchangingResultStub(onReceiveEphemeralPeerPrivateKey: { ephemeralKey in + multiHopPeerExchanger.receiveEphemeralPeerPrivateKey(ephemeralKey) + }) + multiHopPeerExchanger.start() wait( for: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], diff --git a/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift b/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift index cdea29460d12..f266a602a122 100644 --- a/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift +++ b/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift @@ -140,7 +140,7 @@ final class PacketTunnelActorTests: XCTestCase { switch newState { case .initial: break - case let .negotiatingPostQuantumKey(connState, _): + case let .negotiatingEphemeralPeer(connState, _): XCTAssertEqual(connState.connectionAttemptCount, nextAttemptCount) nextAttemptCount += 1 negotiatingPostQuantumKeyStateExpectation.fulfill() diff --git a/ios/PacketTunnelCoreTests/SingleHopPostQuantumKeyExchangingTests.swift b/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift similarity index 58% rename from ios/PacketTunnelCoreTests/SingleHopPostQuantumKeyExchangingTests.swift rename to ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift index b052ad7762c5..e94ca0889e06 100644 --- a/ios/PacketTunnelCoreTests/SingleHopPostQuantumKeyExchangingTests.swift +++ b/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift @@ -1,5 +1,5 @@ // -// SingleHopPostQuantumKeyExchangingTests.swift +// SingleHopEphemeralPeerExchangerTests.swift // MullvadPostQuantumTests // // Created by Mojgan on 2024-07-17. @@ -13,7 +13,7 @@ @testable import WireGuardKitTypes import XCTest -final class SingleHopPostQuantumKeyExchangingTests: XCTestCase { +final class SingleHopEphemeralPeerExchangerTests: XCTestCase { var exitRelay: SelectedRelay! override func setUpWithError() throws { @@ -38,7 +38,7 @@ final class SingleHopPostQuantumKeyExchangingTests: XCTestCase { exitRelay = SelectedRelay(endpoint: match.endpoint, hostname: match.relay.hostname, location: match.location) } - func testKeyExchangeFailsWhenNegotiationCannotStart() { + func testEphemeralPeerExchangeFailsWhenNegotiationCannotStart() { let expectedNegotiationFailure = expectation(description: "Negotiation failed.") let reconfigurationExpectation = expectation(description: "Tunnel reconfiguration took place") @@ -47,13 +47,15 @@ final class SingleHopPostQuantumKeyExchangingTests: XCTestCase { let negotiationSuccessful = expectation(description: "Negotiation succeeded.") negotiationSuccessful.isInverted = true - let keyExchangeActor = PostQuantumKeyExchangeActorStub() - keyExchangeActor.result = .failure(PostQuantumKeyExchangeErrorStub.canceled) + let keyExchangeActor = EphemeralPeerExchangeActorStub() + keyExchangeActor.result = .failure(EphemeralPeerExchangeErrorStub.canceled) - let singleHopPostQuantumKeyExchanging = SingleHopPostQuantumKeyExchanging( + let singleHopPostQuantumKeyExchanging = SingleHopEphemeralPeerExchanger( exit: exitRelay, devicePrivateKey: PrivateKey(), - keyExchanger: keyExchangeActor + keyExchanger: keyExchangeActor, + enablePostQuantum: true, + enableDaita: false ) { _ in reconfigurationExpectation.fulfill() } onFinish: { @@ -72,7 +74,7 @@ final class SingleHopPostQuantumKeyExchangingTests: XCTestCase { ) } - func testKeyExchangeSuccessWhenNegotiationStart() throws { + func testEphemeralPeerExchangeSuccessWhenPostQuantumNegotiationStarts() throws { let unexpectedNegotiationFailure = expectation(description: "Negotiation failed.") unexpectedNegotiationFailure.isInverted = true @@ -82,14 +84,16 @@ final class SingleHopPostQuantumKeyExchangingTests: XCTestCase { let negotiationSuccessful = expectation(description: "Negotiation succeeded.") negotiationSuccessful.expectedFulfillmentCount = 1 - let keyExchangeActor = PostQuantumKeyExchangeActorStub() + let keyExchangeActor = EphemeralPeerExchangeActorStub() let preSharedKey = try XCTUnwrap(PreSharedKey(hexKey: PrivateKey().hexKey)) keyExchangeActor.result = .success((preSharedKey, PrivateKey())) - let singleHopPostQuantumKeyExchanging = SingleHopPostQuantumKeyExchanging( + let singleHopPostQuantumKeyExchanging = SingleHopEphemeralPeerExchanger( exit: exitRelay, devicePrivateKey: PrivateKey(), - keyExchanger: keyExchangeActor + keyExchanger: keyExchangeActor, + enablePostQuantum: true, + enableDaita: false ) { _ in reconfigurationExpectation.fulfill() } onFinish: { @@ -106,4 +110,41 @@ final class SingleHopPostQuantumKeyExchangingTests: XCTestCase { timeout: .UnitTest.invertedTimeout ) } + + func testEphemeralPeerExchangeSuccessWhenDaitaNegotiationStarts() throws { + let unexpectedNegotiationFailure = expectation(description: "Negotiation failed.") + unexpectedNegotiationFailure.isInverted = true + + let reconfigurationExpectation = expectation(description: "Tunnel reconfiguration took place") + reconfigurationExpectation.expectedFulfillmentCount = 2 + + let negotiationSuccessful = expectation(description: "Negotiation succeeded.") + negotiationSuccessful.expectedFulfillmentCount = 1 + + let peerExchangeActor = EphemeralPeerExchangeActorStub() + let preSharedKey = try XCTUnwrap(PreSharedKey(hexKey: PrivateKey().hexKey)) + peerExchangeActor.result = .success((preSharedKey, PrivateKey())) + + let multiHopPeerExchanger = SingleHopEphemeralPeerExchanger( + exit: exitRelay, + devicePrivateKey: PrivateKey(), + keyExchanger: peerExchangeActor, + enablePostQuantum: false, + enableDaita: true + ) { _ in + reconfigurationExpectation.fulfill() + } onFinish: { + negotiationSuccessful.fulfill() + } + + peerExchangeActor.delegate = KeyExchangingResultStub(onReceiveEphemeralPeerPrivateKey: { ephemeralKey in + multiHopPeerExchanger.receiveEphemeralPeerPrivateKey(ephemeralKey) + }) + multiHopPeerExchanger.start() + + wait( + for: [unexpectedNegotiationFailure, reconfigurationExpectation, negotiationSuccessful], + timeout: .UnitTest.invertedTimeout + ) + } } diff --git a/mullvad-ios/src/post_quantum_proxy/ios_runtime.rs b/mullvad-ios/src/ephemeral_peer_proxy/ios_runtime.rs similarity index 70% rename from mullvad-ios/src/post_quantum_proxy/ios_runtime.rs rename to mullvad-ios/src/ephemeral_peer_proxy/ios_runtime.rs index 7da53a95cdad..7dbf5c21e1c4 100644 --- a/mullvad-ios/src/post_quantum_proxy/ios_runtime.rs +++ b/mullvad-ios/src/ephemeral_peer_proxy/ios_runtime.rs @@ -1,4 +1,6 @@ -use super::{ios_tcp_connection::*, PostQuantumCancelToken}; +use super::{ + ios_tcp_connection::*, EphemeralPeerCancelToken, EphemeralPeerParameters, PacketTunnelBridge, +}; use libc::c_void; use std::{ future::Future, @@ -16,28 +18,25 @@ use tower::util::service_fn; /// # Safety /// packet_tunnel and tcp_connection must be valid pointers to a packet tunnel and a TCP connection /// instances. -pub unsafe fn run_post_quantum_psk_exchange( +pub unsafe fn run_ephemeral_peer_exchange( pub_key: [u8; 32], ephemeral_key: [u8; 32], - packet_tunnel: *const c_void, - tcp_connection: *const c_void, - post_quantum_key_exchange_timeout: u64, + packet_tunnel_bridge: PacketTunnelBridge, + peer_parameters: EphemeralPeerParameters, tokio_handle: TokioHandle, -) -> Result { +) -> Result { match unsafe { IOSRuntime::new( pub_key, ephemeral_key, - packet_tunnel, - tcp_connection, - post_quantum_key_exchange_timeout, + packet_tunnel_bridge, + peer_parameters, ) } { Ok(runtime) => { let token = runtime.packet_tunnel.tcp_connection.clone(); - runtime.run(tokio_handle); - Ok(PostQuantumCancelToken { + Ok(EphemeralPeerCancelToken { context: Arc::into_raw(token) as *mut _, }) } @@ -61,27 +60,28 @@ struct IOSRuntime { pub_key: [u8; 32], ephemeral_key: [u8; 32], packet_tunnel: SwiftContext, - post_quantum_key_exchange_timeout: u64, + peer_parameters: EphemeralPeerParameters, } impl IOSRuntime { pub unsafe fn new( pub_key: [u8; 32], ephemeral_key: [u8; 32], - packet_tunnel: *const libc::c_void, - tcp_connection: *const c_void, - post_quantum_key_exchange_timeout: u64, + packet_tunnel_bridge: PacketTunnelBridge, + peer_parameters: EphemeralPeerParameters, ) -> io::Result { let context = SwiftContext { - packet_tunnel, - tcp_connection: Arc::new(Mutex::new(ConnectionContext::new(tcp_connection))), + packet_tunnel: packet_tunnel_bridge.packet_tunnel, + tcp_connection: Arc::new(Mutex::new(ConnectionContext::new( + packet_tunnel_bridge.tcp_connection, + ))), }; Ok(Self { pub_key, ephemeral_key, packet_tunnel: context, - post_quantum_key_exchange_timeout, + peer_parameters, }) } @@ -124,7 +124,7 @@ impl IOSRuntime { Ok(result) => result, Err(error) => { log::error!("Failed to create iOS TCP client: {error}"); - swift_post_quantum_key_ready( + swift_ephemeral_peer_ready( self.packet_tunnel.packet_tunnel, ptr::null(), ptr::null(), @@ -133,6 +133,7 @@ impl IOSRuntime { } } }; + // Use `self.ephemeral_key` as the new private key when no PQ but yes DAITA let ephemeral_pub_key = PrivateKey::from(self.ephemeral_key).public_key(); tokio::select! { @@ -140,51 +141,51 @@ impl IOSRuntime { async_provider, PublicKey::from(self.pub_key), ephemeral_pub_key, - true, - false, + self.peer_parameters.enable_post_quantum, + self.peer_parameters.enable_daita, ) => { shutdown_handle.shutdown(); + if let Ok(mut connection) = self.packet_tunnel.tcp_connection.lock() { + connection.shutdown(); + } match ephemeral_peer { Ok(peer) => { match peer.psk { Some(preshared_key) => unsafe { - if let Ok(mut connection) = self.packet_tunnel.tcp_connection.lock() { - connection.shutdown(); - }; let preshared_key_bytes = preshared_key.as_bytes(); - swift_post_quantum_key_ready(self.packet_tunnel.packet_tunnel, preshared_key_bytes.as_ptr(), self.ephemeral_key.as_ptr()); + swift_ephemeral_peer_ready(self.packet_tunnel.packet_tunnel, + preshared_key_bytes.as_ptr(), + self.ephemeral_key.as_ptr()); }, None => { - log::error!("No suitable peer was found"); - - if let Ok(mut connection) = self.packet_tunnel.tcp_connection.lock() { - connection.shutdown(); - }; + // Daita peer was requested, but without enabling post quantum keys unsafe { - swift_post_quantum_key_ready(self.packet_tunnel.packet_tunnel, ptr::null(), ptr::null()); + swift_ephemeral_peer_ready(self.packet_tunnel.packet_tunnel, + ptr::null(), + self.ephemeral_key.as_ptr()); } } - } }, Err(error) => { log::error!("Key exchange failed {}", error); - if let Ok(mut connection) = self.packet_tunnel.tcp_connection.lock() { - connection.shutdown(); - }; unsafe { - swift_post_quantum_key_ready(self.packet_tunnel.packet_tunnel, ptr::null(), ptr::null()); + swift_ephemeral_peer_ready(self.packet_tunnel.packet_tunnel, + ptr::null(), + ptr::null()); } } } } - _ = tokio::time::sleep(std::time::Duration::from_secs(self.post_quantum_key_exchange_timeout)) => { + _ = tokio::time::sleep(std::time::Duration::from_secs(self.peer_parameters.peer_exchange_timeout)) => { if let Ok(mut connection) = self.packet_tunnel.tcp_connection.lock() { connection.shutdown(); }; shutdown_handle.shutdown(); - unsafe { swift_post_quantum_key_ready(self.packet_tunnel.packet_tunnel, ptr::null(), ptr::null()); } + unsafe { swift_ephemeral_peer_ready(self.packet_tunnel.packet_tunnel, + ptr::null(), + ptr::null()); } } } } diff --git a/mullvad-ios/src/post_quantum_proxy/ios_tcp_connection.rs b/mullvad-ios/src/ephemeral_peer_proxy/ios_tcp_connection.rs similarity index 95% rename from mullvad-ios/src/post_quantum_proxy/ios_tcp_connection.rs rename to mullvad-ios/src/ephemeral_peer_proxy/ios_tcp_connection.rs index b550cc69b3e0..d91081fe576d 100644 --- a/mullvad-ios/src/post_quantum_proxy/ios_tcp_connection.rs +++ b/mullvad-ios/src/ephemeral_peer_proxy/ios_tcp_connection.rs @@ -30,9 +30,12 @@ extern "C" { sender: *const libc::c_void, ); - /// Called when the preshared post quantum key is ready. - /// `raw_preshared_key` might be NULL if the key negotiation failed. - pub fn swift_post_quantum_key_ready( + /// Called when the preshared post quantum key is ready, + /// or when a Daita peer has been successfully requested. + /// `raw_preshared_key` will be NULL if: + /// - The post quantum key negotiation failed + /// - A Daita peer has been requested without enabling post quantum keys. + pub fn swift_ephemeral_peer_ready( raw_packet_tunnel: *const c_void, raw_preshared_key: *const u8, raw_ephemeral_private_key: *const u8, diff --git a/mullvad-ios/src/post_quantum_proxy/mod.rs b/mullvad-ios/src/ephemeral_peer_proxy/mod.rs similarity index 71% rename from mullvad-ios/src/post_quantum_proxy/mod.rs rename to mullvad-ios/src/ephemeral_peer_proxy/mod.rs index 9863e58582f1..0cb85f2177b2 100644 --- a/mullvad-ios/src/post_quantum_proxy/mod.rs +++ b/mullvad-ios/src/ephemeral_peer_proxy/mod.rs @@ -1,7 +1,7 @@ pub mod ios_runtime; pub mod ios_tcp_connection; -use ios_runtime::run_post_quantum_psk_exchange; +use ios_runtime::run_ephemeral_peer_exchange; use ios_tcp_connection::ConnectionContext; use libc::c_void; use std::sync::{Arc, Mutex, Weak}; @@ -11,12 +11,23 @@ use std::sync::Once; static INIT_LOGGING: Once = Once::new(); #[repr(C)] -pub struct PostQuantumCancelToken { +pub struct EphemeralPeerCancelToken { // Must keep a pointer to a valid std::sync::Arc pub context: *mut c_void, } -impl PostQuantumCancelToken { +pub struct PacketTunnelBridge { + pub packet_tunnel: *const c_void, + pub tcp_connection: *const c_void, +} + +pub struct EphemeralPeerParameters { + pub peer_exchange_timeout: u64, + pub enable_post_quantum: bool, + pub enable_daita: bool, +} + +impl EphemeralPeerCancelToken { /// # Safety /// This function can only be called when the context pointer is valid. unsafe fn cancel(&self) { @@ -34,41 +45,41 @@ impl PostQuantumCancelToken { } } -impl Drop for PostQuantumCancelToken { +impl Drop for EphemeralPeerCancelToken { fn drop(&mut self) { let _: Arc> = unsafe { Arc::from_raw(self.context as _) }; } } -unsafe impl Send for PostQuantumCancelToken {} +unsafe impl Send for EphemeralPeerCancelToken {} -/// Called by the Swift side to signal that the quantum-secure key exchange should be cancelled. +/// Called by the Swift side to signal that the ephemeral peer exchange should be cancelled. /// After this call, the cancel token is no longer valid. /// /// # Safety -/// `sender` must be pointing to a valid instance of a `PostQuantumCancelToken` created by the +/// `sender` must be pointing to a valid instance of a `EphemeralPeerCancelToken` created by the /// `PacketTunnelProvider`. #[no_mangle] -pub unsafe extern "C" fn cancel_post_quantum_key_exchange(sender: *const PostQuantumCancelToken) { +pub unsafe extern "C" fn cancel_ephemeral_peer_exchange(sender: *const EphemeralPeerCancelToken) { let sender = unsafe { &*sender }; sender.cancel(); } -/// Called by the Swift side to signal that the Rust `PostQuantumCancelToken` can be safely dropped +/// Called by the Swift side to signal that the Rust `EphemeralPeerCancelToken` can be safely dropped /// from memory. /// /// # Safety -/// `sender` must be pointing to a valid instance of a `PostQuantumCancelToken` created by the +/// `sender` must be pointing to a valid instance of a `EphemeralPeerCancelToken` created by the /// `PacketTunnelProvider`. #[no_mangle] -pub unsafe extern "C" fn drop_post_quantum_key_exchange_token( - sender: *const PostQuantumCancelToken, +pub unsafe extern "C" fn drop_ephemeral_peer_exchange_token( + sender: *const EphemeralPeerCancelToken, ) { let _sender = unsafe { std::ptr::read(sender) }; } /// Called by Swift whenever data has been written to the in-tunnel TCP connection when exchanging -/// quantum-resistant pre shared keys. +/// quantum-resistant pre shared keys, or ephemeral peers. /// /// If `bytes_sent` is 0, this indicates that the connection was closed or that an error occurred. /// @@ -84,7 +95,7 @@ pub unsafe extern "C" fn handle_sent(bytes_sent: usize, sender: *const c_void) { } /// Called by Swift whenever data has been read from the in-tunnel TCP connection when exchanging -/// quantum-resistant pre shared keys. +/// quantum-resistant pre shared keys, or ephemeral peers. /// /// If `data` is null or empty, this indicates that the connection was closed or that an error /// occurred. An empty buffer is sent to the underlying reader to signal EOF. @@ -109,7 +120,7 @@ pub unsafe extern "C" fn handle_recv(data: *const u8, mut data_len: usize, sende } } -/// Entry point for exchanging post quantum keys on iOS. +/// Entry point for requesting ephemeral peers on iOS. /// The TCP connection must be created to go through the tunnel. /// # Safety /// `public_key` and `ephemeral_key` must be valid respective `PublicKey` and `PrivateKey` types. @@ -118,13 +129,15 @@ pub unsafe extern "C" fn handle_recv(data: *const u8, mut data_len: usize, sende /// connection instances. /// `cancel_token` should be owned by the caller of this function. #[no_mangle] -pub unsafe extern "C" fn negotiate_post_quantum_key( +pub unsafe extern "C" fn request_ephemeral_peer( public_key: *const u8, ephemeral_key: *const u8, packet_tunnel: *const c_void, tcp_connection: *const c_void, - cancel_token: *mut PostQuantumCancelToken, - post_quantum_key_exchange_timeout: u64, + cancel_token: *mut EphemeralPeerCancelToken, + peer_exchange_timeout: u64, + enable_post_quantum: bool, + enable_daita: bool, ) -> i32 { INIT_LOGGING.call_once(|| { let _ = oslog::OsLogger::new("net.mullvad.MullvadVPN.TTCC") @@ -144,13 +157,22 @@ pub unsafe extern "C" fn negotiate_post_quantum_key( } }; + let packet_tunnel_bridge = PacketTunnelBridge { + packet_tunnel, + tcp_connection, + }; + let peer_parameters = EphemeralPeerParameters { + peer_exchange_timeout, + enable_post_quantum, + enable_daita, + }; + match unsafe { - run_post_quantum_psk_exchange( + run_ephemeral_peer_exchange( pub_key, eph_key, - packet_tunnel, - tcp_connection, - post_quantum_key_exchange_timeout, + packet_tunnel_bridge, + peer_parameters, handle, ) } { diff --git a/mullvad-ios/src/lib.rs b/mullvad-ios/src/lib.rs index 663284ca07bd..d36a925788d0 100644 --- a/mullvad-ios/src/lib.rs +++ b/mullvad-ios/src/lib.rs @@ -1,5 +1,5 @@ #![cfg(target_os = "ios")] -mod post_quantum_proxy; +mod ephemeral_peer_proxy; mod shadowsocks_proxy; mod tunnel_obfuscator_proxy;