Skip to content

Commit

Permalink
Use DAITAv2 on iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
pinkisemils committed Dec 20, 2024
1 parent fa2de6a commit f3529f5
Show file tree
Hide file tree
Showing 18 changed files with 260 additions and 114 deletions.
27 changes: 23 additions & 4 deletions ios/MullvadRustRuntime/EphemeralPeerReceiver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ import WireGuardKitTypes
/// - 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_ephemeral_peer_ready")
/// - rawDaitaParameters: A raw pointer to negotiated DAITA parameters
@_silgen_name("swift_ephemeral_peer_ready")
func receivePostQuantumKey(
rawEphemeralPeerReceiver: UnsafeMutableRawPointer?,
rawPresharedKey: UnsafeMutableRawPointer?,
rawEphemeralKey: UnsafeMutableRawPointer?
rawEphemeralKey: UnsafeMutableRawPointer?,
rawDaitaParameters: UnsafePointer<DaitaV2Parameters>?
) {
guard let rawEphemeralPeerReceiver else { return }
let ephemeralPeerReceiver = Unmanaged<EphemeralPeerReceiver>.fromOpaque(rawEphemeralPeerReceiver)
Expand All @@ -41,12 +43,29 @@ func receivePostQuantumKey(
return
}

let maybeNot = Maybenot()
let daitaParameters: DaitaV2Parameters? = rawDaitaParameters?.withMemoryRebound(
to: DaitaParameters.self,
capacity: 1
) { body in
let params = body.pointee
guard params.machines != nil else { return nil }
let machines = String(cString: params.machines)
return DaitaV2Parameters(
machines: machines,
maximumEvents: maybeNot.maximumEvents,
maximumActions: maybeNot.maximumActions,
maximumPadding: params.max_padding_frac,
maximumBlocking: params.max_blocking_frac
)
}

// 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)
ephemeralPeerReceiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey, daitaParameters: daitaParameters)
} else {
ephemeralPeerReceiver.receiveEphemeralPeerPrivateKey(ephemeralKey)
ephemeralPeerReceiver.receiveEphemeralPeerPrivateKey(ephemeralKey, daitaParameters: daitaParameters)
}
return
}
29 changes: 18 additions & 11 deletions ios/MullvadRustRuntime/include/mullvad_rust_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ typedef struct ProxyHandle {
uint16_t port;
} ProxyHandle;

typedef struct DaitaParameters {
uint8_t *machines;
double max_padding_frac;
double max_blocking_frac;
} DaitaParameters;

typedef struct WgTcpConnectionFunctions {
int32_t (*open_fn)(int32_t tunnelHandle, const char *address, uint64_t timeout);
int32_t (*close_fn)(int32_t tunnelHandle, int32_t socketHandle);
Expand Down Expand Up @@ -88,6 +94,18 @@ int32_t encrypted_dns_proxy_start(struct EncryptedDnsProxyState *encrypted_dns_p
*/
int32_t encrypted_dns_proxy_stop(struct ProxyHandle *proxy_config);

/**
* 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_ephemeral_peer_ready(const void *raw_packet_tunnel,
const uint8_t *raw_preshared_key,
const uint8_t *raw_ephemeral_private_key,
const struct DaitaParameters *daita_parameters);

/**
* 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.
Expand Down Expand Up @@ -124,17 +142,6 @@ struct ExchangeCancelToken *request_ephemeral_peer(const uint8_t *public_key,
int32_t tunnel_handle,
struct EphemeralPeerParameters peer_parameters);

/**
* 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_ephemeral_peer_ready(const void *raw_packet_tunnel,
const uint8_t *raw_preshared_key,
const uint8_t *raw_ephemeral_private_key);

/**
* # Safety
* `addr`, `password`, `cipher` must be valid for the lifetime of this function call and they must
Expand Down
31 changes: 31 additions & 0 deletions ios/MullvadTypes/Protocols/DaitaV2Parameters.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// DaitaV2Parameters.swift
// MullvadTypes
//
// Created by Marco Nikic on 2024-11-12.
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

import Foundation

public struct DaitaV2Parameters: Equatable {
public let machines: String
public let maximumEvents: UInt32
public let maximumActions: UInt32
public let maximumPadding: Double
public let maximumBlocking: Double

public init(
machines: String,
maximumEvents: UInt32,
maximumActions: UInt32,
maximumPadding: Double,
maximumBlocking: Double
) {
self.machines = machines
self.maximumEvents = maximumEvents
self.maximumActions = maximumActions
self.maximumPadding = maximumPadding
self.maximumBlocking = maximumBlocking
}
}
15 changes: 11 additions & 4 deletions ios/MullvadTypes/Protocols/EphemeralPeerReceiver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,26 @@ public class EphemeralPeerReceiver: EphemeralPeerReceiving, TunnelProvider {

// MARK: - EphemeralPeerReceiving

public func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) {
public func receivePostQuantumKey(
_ key: PreSharedKey,
ephemeralKey: PrivateKey,
daitaParameters: DaitaV2Parameters?
) {
let semaphore = DispatchSemaphore(value: 0)
Task {
await keyReceiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey)
await keyReceiver.receivePostQuantumKey(key, ephemeralKey: ephemeralKey, daitaParameters: daitaParameters)
semaphore.signal()
}
semaphore.wait()
}

public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey) {
public func receiveEphemeralPeerPrivateKey(
_ ephemeralPeerPrivateKey: PrivateKey,
daitaParameters: DaitaV2Parameters?
) {
let semaphore = DispatchSemaphore(value: 0)
Task {
await keyReceiver.receiveEphemeralPeerPrivateKey(ephemeralPeerPrivateKey)
await keyReceiver.receiveEphemeralPeerPrivateKey(ephemeralPeerPrivateKey, daitaParameters: daitaParameters)
semaphore.signal()
}
semaphore.wait()
Expand Down
9 changes: 6 additions & 3 deletions ios/MullvadTypes/Protocols/EphemeralPeerReceiving.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ public protocol EphemeralPeerReceiving {
/// - 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) async
/// - daitaParameters: DAITA parameters
func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey, daitaParameters: DaitaV2Parameters?) async

/// 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) async
/// - Parameters:
/// - _: The private key used by the Ephemeral Peer
/// - daitaParameters: DAITA parameters
func receiveEphemeralPeerPrivateKey(_: PrivateKey, daitaParameters: DaitaV2Parameters?) async

/// Called when an ephemeral peer could not be successfully negotiated
func ephemeralPeerExchangeFailed()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,12 +376,12 @@ extension PacketTunnelProvider {
}

extension PacketTunnelProvider: EphemeralPeerReceiving {
func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) async {
await ephemeralPeerExchangingPipeline.receivePostQuantumKey(key, ephemeralKey: ephemeralKey)
func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey, daitaParameters: MullvadTypes.DaitaV2Parameters?) async {
await ephemeralPeerExchangingPipeline.receivePostQuantumKey(key, ephemeralKey: ephemeralKey, daitaParameters: daitaParameters)
}

public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey) async {
await ephemeralPeerExchangingPipeline.receiveEphemeralPeerPrivateKey(ephemeralPeerPrivateKey)
public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey, daitaParameters: MullvadTypes.DaitaV2Parameters?) async {
await ephemeralPeerExchangingPipeline.receiveEphemeralPeerPrivateKey(ephemeralPeerPrivateKey, daitaParameters: daitaParameters)
}

func ephemeralPeerExchangeFailed() {
Expand Down
16 changes: 12 additions & 4 deletions ios/PacketTunnel/PostQuantum/EphemeralPeerExchangingPipeline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import MullvadRustRuntime
import MullvadSettings
import MullvadTypes
import PacketTunnelCore
import WireGuardKitTypes

Expand Down Expand Up @@ -59,11 +60,18 @@ final public class EphemeralPeerExchangingPipeline {
await ephemeralPeerExchanger.start()
}

public func receivePostQuantumKey(_ key: PreSharedKey, ephemeralKey: PrivateKey) async {
await ephemeralPeerExchanger.receivePostQuantumKey(key, ephemeralKey: ephemeralKey)
public func receivePostQuantumKey(
_ key: PreSharedKey,
ephemeralKey: PrivateKey,
daitaParameters: DaitaV2Parameters?
) async {
await ephemeralPeerExchanger.receivePostQuantumKey(key, ephemeralKey: ephemeralKey, daitaParameters: daitaParameters)
}

public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey) async {
await ephemeralPeerExchanger.receiveEphemeralPeerPrivateKey(ephemeralPeerPrivateKey)
public func receiveEphemeralPeerPrivateKey(
_ ephemeralPeerPrivateKey: PrivateKey,
daitaParameters: DaitaV2Parameters?
) async {
await ephemeralPeerExchanger.receiveEphemeralPeerPrivateKey(ephemeralPeerPrivateKey, daitaParameters: daitaParameters)
}
}
26 changes: 19 additions & 7 deletions ios/PacketTunnel/PostQuantum/MultiHopEphemeralPeerExchanger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ final class MultiHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {

private var entryPeerKey: EphemeralPeerKey!
private var exitPeerKey: EphemeralPeerKey!
private var daitaParameters: DaitaV2Parameters?

private let defaultGatewayAddressRange = [IPAddressRange(from: "\(LocalNetworkIPs.gatewayAddress.rawValue)/32")!]
private let allTrafficRange = [
Expand Down Expand Up @@ -66,7 +67,11 @@ final class MultiHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {
await negotiateWithEntry()
}

public func receiveEphemeralPeerPrivateKey(_ ephemeralPeerPrivateKey: PrivateKey) async {
public func receiveEphemeralPeerPrivateKey(
_ ephemeralPeerPrivateKey: PrivateKey,
daitaParameters: DaitaV2Parameters?
) async {
self.daitaParameters = daitaParameters
if state == .negotiatingWithEntry {
entryPeerKey = EphemeralPeerKey(ephemeralKey: ephemeralPeerPrivateKey)
await negotiateBetweenEntryAndExit()
Expand All @@ -78,8 +83,10 @@ final class MultiHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {

func receivePostQuantumKey(
_ preSharedKey: PreSharedKey,
ephemeralKey: PrivateKey
ephemeralKey: PrivateKey,
daitaParameters: DaitaV2Parameters?
) async {
self.daitaParameters = daitaParameters
if state == .negotiatingWithEntry {
entryPeerKey = EphemeralPeerKey(preSharedKey: preSharedKey, ephemeralKey: ephemeralKey)
await negotiateBetweenEntryAndExit()
Expand All @@ -95,7 +102,8 @@ final class MultiHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {
relay: entry,
configuration: EphemeralPeerConfiguration(
privateKey: devicePrivateKey,
allowedIPs: defaultGatewayAddressRange
allowedIPs: defaultGatewayAddressRange,
daitaParameters: daitaParameters
)
)))
keyExchanger.startNegotiation(
Expand All @@ -113,14 +121,16 @@ final class MultiHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {
configuration: EphemeralPeerConfiguration(
privateKey: entryPeerKey.ephemeralKey,
preSharedKey: entryPeerKey.preSharedKey,
allowedIPs: [IPAddressRange(from: "\(exit.endpoint.ipv4Relay.ip)/32")!]
allowedIPs: [IPAddressRange(from: "\(exit.endpoint.ipv4Relay.ip)/32")!],
daitaParameters: self.daitaParameters
)
),
exit: EphemeralPeerRelayConfiguration(
relay: exit,
configuration: EphemeralPeerConfiguration(
privateKey: devicePrivateKey,
allowedIPs: defaultGatewayAddressRange
allowedIPs: defaultGatewayAddressRange,
daitaParameters: self.daitaParameters
)
)
))
Expand All @@ -140,15 +150,17 @@ final class MultiHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {
configuration: EphemeralPeerConfiguration(
privateKey: entryPeerKey.ephemeralKey,
preSharedKey: entryPeerKey.preSharedKey,
allowedIPs: [IPAddressRange(from: "\(exit.endpoint.ipv4Relay.ip)/32")!]
allowedIPs: [IPAddressRange(from: "\(exit.endpoint.ipv4Relay.ip)/32")!],
daitaParameters: self.daitaParameters
)
),
exit: EphemeralPeerRelayConfiguration(
relay: exit,
configuration: EphemeralPeerConfiguration(
privateKey: exitPeerKey.ephemeralKey,
preSharedKey: exitPeerKey.preSharedKey,
allowedIPs: allTrafficRange
allowedIPs: allTrafficRange,
daitaParameters: self.daitaParameters
)
)
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ struct SingleHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {
relay: exit,
configuration: EphemeralPeerConfiguration(
privateKey: devicePrivateKey,
allowedIPs: [IPAddressRange(from: "\(LocalNetworkIPs.gatewayAddress.rawValue)/32")!]
allowedIPs: [IPAddressRange(from: "\(LocalNetworkIPs.gatewayAddress.rawValue)/32")!],
daitaParameters: nil
)
)))
keyExchanger.startNegotiation(
Expand All @@ -55,7 +56,7 @@ struct SingleHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {
)
}

public func receiveEphemeralPeerPrivateKey(_ ephemeralKey: PrivateKey) async {
public func receiveEphemeralPeerPrivateKey(_ ephemeralKey: PrivateKey, daitaParameters: DaitaV2Parameters?) async {
await onUpdateConfiguration(.single(EphemeralPeerRelayConfiguration(
relay: exit,
configuration: EphemeralPeerConfiguration(
Expand All @@ -64,15 +65,17 @@ struct SingleHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {
allowedIPs: [
IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV4.rawValue)/0")!,
IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV6.rawValue)/0")!,
]
],
daitaParameters: daitaParameters
)
)))
self.onFinish()
}

func receivePostQuantumKey(
_ preSharedKey: WireGuardKitTypes.PreSharedKey,
ephemeralKey: WireGuardKitTypes.PrivateKey
ephemeralKey: WireGuardKitTypes.PrivateKey,
daitaParameters: DaitaV2Parameters?
) async {
await onUpdateConfiguration(.single(EphemeralPeerRelayConfiguration(
relay: exit,
Expand All @@ -82,7 +85,8 @@ struct SingleHopEphemeralPeerExchanger: EphemeralPeerExchangingProtocol {
allowedIPs: [
IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV4.rawValue)/0")!,
IPAddressRange(from: "\(LocalNetworkIPs.defaultRouteIpV6.rawValue)/0")!,
]
],
daitaParameters: daitaParameters
)
)))
self.onFinish()
Expand Down
10 changes: 9 additions & 1 deletion ios/PacketTunnelCore/Actor/EphemeralPeerNegotiationState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import MullvadREST
import MullvadTypes
import WireGuardKitTypes

public enum EphemeralPeerNegotiationState: Equatable {
Expand Down Expand Up @@ -43,11 +44,18 @@ public struct EphemeralPeerConfiguration: Equatable, CustomDebugStringConvertibl
public let privateKey: PrivateKey
public let preSharedKey: PreSharedKey?
public let allowedIPs: [IPAddressRange]
public let daitaParameters: DaitaV2Parameters?

public init(privateKey: PrivateKey, preSharedKey: PreSharedKey? = nil, allowedIPs: [IPAddressRange]) {
public init(
privateKey: PrivateKey,
preSharedKey: PreSharedKey? = nil,
allowedIPs: [IPAddressRange],
daitaParameters: DaitaV2Parameters?
) {
self.privateKey = privateKey
self.preSharedKey = preSharedKey
self.allowedIPs = allowedIPs
self.daitaParameters = daitaParameters
}

public var debugDescription: String {
Expand Down
Loading

0 comments on commit f3529f5

Please sign in to comment.