Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DAITAv2 on iOS #7387

Merged
merged 2 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ios/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ Line wrap the file at 100 chars. Th
* **Fixed**: for any bug fixes.
* **Security**: in case of vulnerabilities.

## Unreleased
### Added
- Update to DAITA v2 - now machines are provided by relays dynamically instead
of using bundled ones.

## [2024.11 - 2024-12-12]
### Added
- Add WireGuard over Shadowsocks obfuscation. It can be enabled in "VPN settings". This will
Expand Down
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
}
43 changes: 27 additions & 16 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,22 @@ int32_t encrypted_dns_proxy_start(struct EncryptedDnsProxyState *encrypted_dns_p
*/
int32_t encrypted_dns_proxy_stop(struct ProxyHandle *proxy_config);

/**
* To be called when ephemeral peer exchange has finished. All parameters except
* `raw_packet_tunnel` are optional.
*
* # Safety:
* If the key exchange failed, all pointers except `raw_packet_tunnel` must be null. If the
* key exchange was successful, `raw_ephemeral_private_key` must be a valid pointer to 32
* bytes for the lifetime of this call. If PQ was enabled, `raw_preshared_key` must be a valid
* pointer to 32 bytes for the lifetime of this call. If DAITA was requested, the
* `daita_prameters` must point to a valid instance of `DaitaParameters`.
*/
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 All @@ -112,29 +134,18 @@ void drop_ephemeral_peer_exchange_token(struct ExchangeCancelToken *sender);
* 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.
* They will not be valid after this function is called, and thus must be copied here.
* `packet_tunnel` must be valid pointers to a packet tunnel, the packet tunnel pointer must
* outlive the ephemeral peer exchange. `cancel_token` should be owned by the caller of this
* function.
* `public_key` and `ephemeral_key` must be valid respective `PublicKey` and `PrivateKey` types,
* specifically, they must be valid pointers to 32 bytes. They will not be valid after this
* function is called, and thus must be copied here. `packet_tunnel` must be valid pointers to a
* packet tunnel, the packet tunnel pointer must outlive the ephemeral peer exchange.
* `cancel_token` should be owned by the caller of this function.
*/
struct ExchangeCancelToken *request_ephemeral_peer(const uint8_t *public_key,
const uint8_t *ephemeral_key,
const void *packet_tunnel,
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
16 changes: 10 additions & 6 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -739,18 +739,19 @@
A932D9F52B5EBB9D00999395 /* RESTTransportStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = A932D9F42B5EBB9D00999395 /* RESTTransportStub.swift */; };
A935594C2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935594B2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift */; };
A939661B2CAE6CE1008128CA /* MigrationManagerMultiProcessUpgradeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A939661A2CAE6CE1008128CA /* MigrationManagerMultiProcessUpgradeTests.swift */; };
A93969812CE606190032A7A0 /* Maybenot.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9840BB32C69F78A0030F05E /* Maybenot.swift */; };
A94D691A2ABAD66700413DD4 /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = 58FE25E22AA72AE9003D1918 /* WireGuardKitTypes */; };
A94D691B2ABAD66700413DD4 /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = 58FE25E72AA7399D003D1918 /* WireGuardKitTypes */; };
A95EEE362B722CD600A8A39B /* TunnelMonitorState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95EEE352B722CD600A8A39B /* TunnelMonitorState.swift */; };
A95EEE382B722DFC00A8A39B /* PingStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95EEE372B722DFC00A8A39B /* PingStats.swift */; };
A970C89D2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */; };
A97275562CE36CAE00029F15 /* DaitaV2Parameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97275552CE36CAE00029F15 /* DaitaV2Parameters.swift */; };
A97D25AE2B0BB18100946B2D /* ProtocolObfuscator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D25AD2B0BB18100946B2D /* ProtocolObfuscator.swift */; };
A97D25B02B0BB5C400946B2D /* ProtocolObfuscationStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D25AF2B0BB5C400946B2D /* ProtocolObfuscationStub.swift */; };
A97D25B22B0CB02D00946B2D /* ProtocolObfuscatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D25B12B0CB02D00946B2D /* ProtocolObfuscatorTests.swift */; };
A97D25B42B0CB59300946B2D /* TunnelObfuscationStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D25B32B0CB59300946B2D /* TunnelObfuscationStub.swift */; };
A97D30172AE6B5E90045C0E4 /* StoredWgKeyData.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D30162AE6B5E90045C0E4 /* StoredWgKeyData.swift */; };
A97FF5502A0D2FFC00900996 /* NSFileCoordinator+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97FF54F2A0D2FFC00900996 /* NSFileCoordinator+Extensions.swift */; };
A9840BB42C69F78A0030F05E /* Maybenot.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9840BB32C69F78A0030F05E /* Maybenot.swift */; };
A98502032B627B120061901E /* LocalNetworkProbe.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98502022B627B120061901E /* LocalNetworkProbe.swift */; };
A988A3E22AFE54AC0008D2C7 /* AccountExpiry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6F2FA62AFBB9AE006D0856 /* AccountExpiry.swift */; };
A988DF272ADE86ED00D807EF /* WireGuardObfuscationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A988DF252ADE86ED00D807EF /* WireGuardObfuscationSettings.swift */; };
Expand Down Expand Up @@ -2120,6 +2121,7 @@
A95EEE352B722CD600A8A39B /* TunnelMonitorState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelMonitorState.swift; sourceTree = "<group>"; };
A95EEE372B722DFC00A8A39B /* PingStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PingStats.swift; sourceTree = "<group>"; };
A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Socks5UsernamePasswordCommand.swift; sourceTree = "<group>"; };
A97275552CE36CAE00029F15 /* DaitaV2Parameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaitaV2Parameters.swift; sourceTree = "<group>"; };
A97D25AD2B0BB18100946B2D /* ProtocolObfuscator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolObfuscator.swift; sourceTree = "<group>"; };
A97D25AF2B0BB5C400946B2D /* ProtocolObfuscationStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolObfuscationStub.swift; sourceTree = "<group>"; };
A97D25B12B0CB02D00946B2D /* ProtocolObfuscatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolObfuscatorTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2714,6 +2716,7 @@
449EBA252B975B9700DFA4EB /* EphemeralPeerReceiving.swift */,
A90C48662C36BC2600DCB94C /* EphemeralPeerReceiver.swift */,
A90C48682C36BF3900DCB94C /* TunnelProvider.swift */,
A97275552CE36CAE00029F15 /* DaitaV2Parameters.swift */,
);
path = Protocols;
sourceTree = "<group>";
Expand Down Expand Up @@ -4721,7 +4724,6 @@
isa = PBXNativeTarget;
buildConfigurationList = 58C7A44B2A863F4A0060C66F /* Build configuration list for PBXNativeTarget "PacketTunnelCore" */;
buildPhases = (
A9840BB22C69F7290030F05E /* Import maybenot_machines */,
58C7A4312A863F440060C66F /* Headers */,
58C7A4322A863F440060C66F /* Sources */,
58C7A4332A863F440060C66F /* Frameworks */,
Expand Down Expand Up @@ -4973,6 +4975,7 @@
isa = PBXNativeTarget;
buildConfigurationList = A992DA252C24709F00DE7CE5 /* Build configuration list for PBXNativeTarget "MullvadRustRuntime" */;
buildPhases = (
A93969802CE603110032A7A0 /* Import maybenot_machines */,
A992DA2A2C2470B300DE7CE5 /* Build MullvadRustRuntime */,
A992DA182C24709F00DE7CE5 /* Headers */,
A992DA192C24709F00DE7CE5 /* Sources */,
Expand Down Expand Up @@ -5351,7 +5354,7 @@
shellPath = /bin/sh;
shellScript = "if [[ \"$(uname -m)\" == arm64 ]]; then\n export PATH=\"/opt/homebrew/bin:$PATH\"\nfi\n\nif which swiftlint > /dev/null; then\n swiftlint PacketTunnel/**/*.swift\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
};
A9840BB22C69F7290030F05E /* Import maybenot_machines */ = {
A93969802CE603110032A7A0 /* Import maybenot_machines */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
Expand All @@ -5367,7 +5370,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "MAYBENOT_MACHINES=`cat ${SRCROOT}/../dist-assets/maybenot_machines`\ncat > ${SRCROOT}/PacketTunnelCore/Daita/Maybenot.swift << EOF\n// swiftlint:disable line_length\n// This is an autogenerated file, do not edit\npublic struct Maybenot {\n public let machines=\"\"\"\n$MAYBENOT_MACHINES\n\"\"\"\n public let maximumEvents: UInt32 = 1000\n public let maximumActions: UInt32 = 1000\n}\n// swiftlint:enable line_length\nEOF\n";
shellScript = "MAYBENOT_MACHINES=`cat ${SRCROOT}/../dist-assets/maybenot_machines`\ncat > ${SRCROOT}/PacketTunnelCore/Daita/Maybenot.swift << EOF\n// swiftlint:disable line_length\n// This is an autogenerated file, do not edit\npublic struct Maybenot {\n public let machines=\"\"\"\n$MAYBENOT_MACHINES\n\"\"\"\n public let maximumEvents: UInt32 = 2048\n public let maximumActions: UInt32 = 1024\n public let maximumPadding: Double = 1.0\n public let maximumBlocking: Double = 1.0\n}\n// swiftlint:enable line_length\nEOF\n";
};
A992DA2A2C2470B300DE7CE5 /* Build MullvadRustRuntime */ = {
isa = PBXShellScriptBuildPhase;
Expand Down Expand Up @@ -5775,7 +5778,6 @@
583832272AC3193600EA2071 /* PacketTunnelActor+SleepCycle.swift in Sources */,
58FE25DC2AA72A8F003D1918 /* AnyTask.swift in Sources */,
F04AF92D2C466013004A8314 /* EphemeralPeerNegotiationState.swift in Sources */,
A9840BB42C69F78A0030F05E /* Maybenot.swift in Sources */,
58FE25D92AA72A8F003D1918 /* AutoCancellingTask.swift in Sources */,
58FE25E12AA72A9B003D1918 /* SettingsReaderProtocol.swift in Sources */,
58C7A4582A863FB90060C66F /* TunnelMonitorProtocol.swift in Sources */,
Expand Down Expand Up @@ -6313,6 +6315,7 @@
58D22412294C90210029F5F8 /* RelayConstraint.swift in Sources */,
7A7AD14F2BF21EF200B30B3C /* NameInputFormatter.swift in Sources */,
58D22413294C90210029F5F8 /* RelayConstraints.swift in Sources */,
A97275562CE36CAE00029F15 /* DaitaV2Parameters.swift in Sources */,
7AF9BE8C2A321D1F00DBFEDB /* RelayFilter.swift in Sources */,
58D22414294C90210029F5F8 /* RelayLocation.swift in Sources */,
581DA2732A1E227D0046ED47 /* RESTTypes.swift in Sources */,
Expand Down Expand Up @@ -6447,6 +6450,7 @@
A9D9A4BB2C36D397004088DD /* EphemeralPeerNegotiator.swift in Sources */,
A9D9A4B22C36D12D004088DD /* TunnelObfuscator.swift in Sources */,
A9173C322C36CCDD00F6A08C /* EphemeralPeerReceiver.swift in Sources */,
A93969812CE606190032A7A0 /* Maybenot.swift in Sources */,
F05919802C45515200C301F3 /* EphemeralPeerExchangeActor.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -9512,7 +9516,7 @@
repositoryURL = "https://github.com/mullvad/wireguard-apple.git";
requirement = {
kind = revision;
revision = 4499596651b4fe8a162e587c75a01615168f29a6;
revision = f6c6af02d3a9168589b8c109b4826b7f224fcf73;
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/mullvad/wireguard-apple.git",
"state" : {
"revision" : "4499596651b4fe8a162e587c75a01615168f29a6"
"revision" : "f6c6af02d3a9168589b8c109b4826b7f224fcf73"
}
}
],
Expand Down
Loading
Loading