Skip to content

Commit

Permalink
Talk about ephemeral peers instead of just saying post quantum
Browse files Browse the repository at this point in the history
  • Loading branch information
buggmagnet committed Sep 3, 2024
1 parent 50ae9e8 commit 4ef839f
Show file tree
Hide file tree
Showing 29 changed files with 311 additions and 184 deletions.
6 changes: 3 additions & 3 deletions ios/MullvadRustRuntime/EphemeralPeerExchangeActor.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// PostQuantumKeyExchangeActor.swift
// EphemeralPeerExchangeActor.swift
// PacketTunnel
//
// Created by Marco Nikic on 2024-04-12.
Expand Down Expand Up @@ -99,9 +99,9 @@ public class EphemeralPeerExchangeActor: EphemeralPeerExchangeActorProtocol {
gatewayIP: IPv4Gateway,
devicePublicKey: privateKey.publicKey,
presharedKey: ephemeralSharedKey,
postQuantumKeyReceiver: packetTunnel,
peerReceiver: packetTunnel,
tcpConnection: inTunnelTCPConnection,
postQuantumKeyExchangeTimeout: tcpConnectionTimeout,
peerExchangeTimeout: tcpConnectionTimeout,
enablePostQuantum: enablePostQuantum,
enableDaita: enableDaita
) {
Expand Down
22 changes: 10 additions & 12 deletions ios/MullvadRustRuntime/EphemeralPeerNegotiator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public protocol EphemeralPeerNegotiating {
gatewayIP: IPv4Address,
devicePublicKey: PublicKey,
presharedKey: PrivateKey,
postQuantumKeyReceiver: any TunnelProvider,
peerReceiver: any TunnelProvider,
tcpConnection: NWTCPConnection,
postQuantumKeyExchangeTimeout: Duration,
peerExchangeTimeout: Duration,
enablePostQuantum: Bool,
enableDaita: Bool
) -> Bool
Expand All @@ -29,9 +29,7 @@ public protocol EphemeralPeerNegotiating {
init()
}

/**
Attempt to start the asynchronous process of key negotiation. Returns true if successfully started, false if failed.
*/
/// Requests an ephemeral peer asynchronously.
public class EphemeralPeerNegotiator: EphemeralPeerNegotiating {
required public init() {}

Expand All @@ -41,25 +39,25 @@ public class EphemeralPeerNegotiator: EphemeralPeerNegotiating {
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 = EphemeralPeerCancelToken()

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
)
Expand All @@ -72,12 +70,12 @@ public class EphemeralPeerNegotiator: EphemeralPeerNegotiating {

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)
}
}

Expand Down
22 changes: 12 additions & 10 deletions ios/MullvadRustRuntime/PacketTunnelProvider+TCPConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,37 +80,39 @@ func tcpConnectionReceive(

/// End sequence of a quantum-secure pre shared key 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<PostQuantumKeyReceiver>.fromOpaque(rawPostQuantumKeyReceiver)
guard let rawEphemeralPeerReceiver else { return }
let ephemeralPeerReceiver = Unmanaged<EphemeralPeerReceiver>.fromOpaque(rawEphemeralPeerReceiver)
.takeUnretainedValue()

// 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 {
postQuantumKeyReceiver.ephemeralPeerExchangeFailed()
ephemeralPeerReceiver.ephemeralPeerExchangeFailed()
return
}

// 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)) {
postQuantumKeyReceiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey)
ephemeralPeerReceiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey)
} else {
postQuantumKeyReceiver.receiveEphemeralPeerPrivateKey(ephemeralKey)
ephemeralPeerReceiver.receiveEphemeralPeerPrivateKey(ephemeralKey)
}
return
}
29 changes: 14 additions & 15 deletions ios/MullvadRustRuntime/include/mullvad_rust_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 EphemeralPeerCancelToken *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 EphemeralPeerCancelToken *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.
*
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -77,7 +77,7 @@ int32_t request_ephemeral_peer(const uint8_t *public_key,
const void *packet_tunnel,
const void *tcp_connection,
struct EphemeralPeerCancelToken *cancel_token,
uint64_t post_quantum_key_exchange_timeout,
uint64_t peer_exchange_timeout,
bool enable_post_quantum,
bool enable_daita);

Expand All @@ -100,13 +100,12 @@ extern void swift_nw_tcp_connection_read(const void *connection, const void *sen
* 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 qunatum key negotiation failed
* - 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,
bool daita_enabled);
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
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -14,7 +14,7 @@ import NetworkExtension
@testable import WireGuardKitTypes
import XCTest

class MullvadPostQuantumTests: XCTestCase {
class EphemeralPeerExchangeActorTests: XCTestCase {
var tcpConnection: NWTCPConnectionStub!
var tunnelProvider: TunnelProviderStub!

Expand Down
10 changes: 5 additions & 5 deletions ios/MullvadRustRuntimeTests/MullvadPostQuantum+Stubs.swift
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -58,9 +58,9 @@ class FailedNegotiatorStub: EphemeralPeerNegotiating {
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 }
Expand All @@ -84,9 +84,9 @@ class SuccessfulNegotiatorStub: EphemeralPeerNegotiating {
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 }
Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadRustRuntimeTests/TCPConnection.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// TCPConnection.swift
// TunnelObfuscationTests
// MullvadRustRuntimeTests
//
// Created by pronebird on 27/06/2023.
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadRustRuntimeTests/TCPUnsafeListener.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// TCPUnsafeListener.swift
// TunnelObfuscationTests
// MullvadRustRuntimeTests
//
// Created by pronebird on 27/06/2023.
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadRustRuntimeTests/TunnelObfuscationTests.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// TunnelObfuscationTests.swift
// TunnelObfuscationTests
// MullvadRustRuntimeTests
//
// Created by pronebird on 27/06/2023.
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadRustRuntimeTests/UDPConnection.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// UDPConnection.swift
// TunnelObfuscationTests
// MullvadRustRuntimeTests
//
// Created by pronebird on 27/06/2023.
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import Foundation
import NetworkExtension
import WireGuardKitTypes

public class PostQuantumKeyReceiver: EphemeralPeerReceiving, 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? EphemeralPeerReceiving else { return }
Expand Down
8 changes: 5 additions & 3 deletions ios/MullvadTypes/Protocols/EphemeralPeerReceiving.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// PostQuantumKeyReceiving.swift
// EphemeralPeerReceiving.swift
// MullvadTypes
//
// Created by Andrew Bulhak on 2024-03-05.
Expand All @@ -13,10 +13,12 @@ public protocol EphemeralPeerReceiving {
/// Called when successfully requesting an ephemeral peer with Post Quantum PSK enabled
///
/// - Parameters:
/// - key: The preshared key used by the Post Quantum Peer
/// - ephemeralKey: The private key used by the Post Quantum Peer
/// - 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
Expand Down
Loading

0 comments on commit 4ef839f

Please sign in to comment.