Merge pull request #44 from keeshux/encapsulate-session-configuration
Encapsulate session configuration
This commit is contained in:
commit
2e31503877
|
@ -88,15 +88,16 @@ extension ViewController {
|
||||||
let port = UInt16(textPort.text!)!
|
let port = UInt16(textPort.text!)!
|
||||||
let credentials = SessionProxy.Credentials(textUsername.text!, textPassword.text!)
|
let credentials = SessionProxy.Credentials(textUsername.text!, textPassword.text!)
|
||||||
|
|
||||||
var builder = TunnelKitProvider.ConfigurationBuilder(ca: ca)
|
var sessionBuilder = SessionProxy.ConfigurationBuilder(ca: ca)
|
||||||
|
sessionBuilder.cipher = .aes256gcm
|
||||||
|
sessionBuilder.digest = .sha1
|
||||||
|
sessionBuilder.compressionFraming = .compLZO
|
||||||
|
sessionBuilder.renegotiatesAfter = nil
|
||||||
|
sessionBuilder.usesPIAPatches = true
|
||||||
|
var builder = TunnelKitProvider.ConfigurationBuilder(sessionConfiguration: sessionBuilder.build())
|
||||||
let socketType: TunnelKitProvider.SocketType = switchTCP.isOn ? .tcp : .udp
|
let socketType: TunnelKitProvider.SocketType = switchTCP.isOn ? .tcp : .udp
|
||||||
builder.endpointProtocols = [TunnelKitProvider.EndpointProtocol(socketType, port)]
|
builder.endpointProtocols = [TunnelKitProvider.EndpointProtocol(socketType, port)]
|
||||||
builder.cipher = .aes256gcm
|
|
||||||
builder.digest = .sha1
|
|
||||||
builder.mtu = 1350
|
builder.mtu = 1350
|
||||||
builder.compressionFraming = .compLZO
|
|
||||||
builder.renegotiatesAfterSeconds = nil
|
|
||||||
builder.usesPIAPatches = true
|
|
||||||
builder.shouldDebug = true
|
builder.shouldDebug = true
|
||||||
builder.debugLogKey = "Log"
|
builder.debugLogKey = "Log"
|
||||||
|
|
||||||
|
|
|
@ -88,15 +88,17 @@ extension ViewController {
|
||||||
let port = UInt16(textPort.stringValue)!
|
let port = UInt16(textPort.stringValue)!
|
||||||
let credentials = SessionProxy.Credentials(textUsername.stringValue, textPassword.stringValue)
|
let credentials = SessionProxy.Credentials(textUsername.stringValue, textPassword.stringValue)
|
||||||
|
|
||||||
var builder = TunnelKitProvider.ConfigurationBuilder(ca: ca)
|
var sessionBuilder = SessionProxy.ConfigurationBuilder(ca: ca)
|
||||||
|
sessionBuilder.cipher = .aes128cbc
|
||||||
|
sessionBuilder.digest = .sha1
|
||||||
|
sessionBuilder.compressionFraming = .compLZO
|
||||||
|
sessionBuilder.renegotiatesAfter = nil
|
||||||
|
sessionBuilder.usesPIAPatches = true
|
||||||
|
var builder = TunnelKitProvider.ConfigurationBuilder(sessionConfiguration: sessionBuilder.build())
|
||||||
// let socketType: TunnelKitProvider.SocketType = isTCP ? .tcp : .udp
|
// let socketType: TunnelKitProvider.SocketType = isTCP ? .tcp : .udp
|
||||||
let socketType: TunnelKitProvider.SocketType = .udp
|
let socketType: TunnelKitProvider.SocketType = .udp
|
||||||
builder.endpointProtocols = [TunnelKitProvider.EndpointProtocol(socketType, port)]
|
builder.endpointProtocols = [TunnelKitProvider.EndpointProtocol(socketType, port)]
|
||||||
builder.cipher = .aes128cbc
|
|
||||||
builder.digest = .sha1
|
|
||||||
builder.mtu = 1350
|
builder.mtu = 1350
|
||||||
builder.compressionFraming = .compLZO
|
|
||||||
builder.renegotiatesAfterSeconds = nil
|
|
||||||
builder.shouldDebug = true
|
builder.shouldDebug = true
|
||||||
builder.debugLogKey = "Log"
|
builder.debugLogKey = "Log"
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
PODS:
|
PODS:
|
||||||
- OpenSSL-Apple (1.1.0i-v2)
|
- OpenSSL-Apple (1.1.0i-v2)
|
||||||
- SwiftyBeaver (1.6.1)
|
- SwiftyBeaver (1.6.1)
|
||||||
- TunnelKit (1.2.2):
|
- TunnelKit (1.3.0):
|
||||||
- TunnelKit/AppExtension (= 1.2.2)
|
- TunnelKit/AppExtension (= 1.3.0)
|
||||||
- TunnelKit/Core (= 1.2.2)
|
- TunnelKit/Core (= 1.3.0)
|
||||||
- TunnelKit/AppExtension (1.2.2):
|
- TunnelKit/AppExtension (1.3.0):
|
||||||
- SwiftyBeaver
|
- SwiftyBeaver
|
||||||
- TunnelKit/Core
|
- TunnelKit/Core
|
||||||
- TunnelKit/Core (1.2.2):
|
- TunnelKit/Core (1.3.0):
|
||||||
- OpenSSL-Apple (~> 1.1.0h)
|
- OpenSSL-Apple (~> 1.1.0h)
|
||||||
- SwiftyBeaver
|
- SwiftyBeaver
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ EXTERNAL SOURCES:
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
OpenSSL-Apple: a93b8f2eec8783ff40d9a9304de180ab68bb647c
|
OpenSSL-Apple: a93b8f2eec8783ff40d9a9304de180ab68bb647c
|
||||||
SwiftyBeaver: ccfcdf85a04d429f1633f668650b0ce8020bda3a
|
SwiftyBeaver: ccfcdf85a04d429f1633f668650b0ce8020bda3a
|
||||||
TunnelKit: 15c88f0cef7b926883566a9455e912a1e55f4048
|
TunnelKit: 8e747cac28959ebfdfa4eeab589c933f1856c0fb
|
||||||
|
|
||||||
PODFILE CHECKSUM: f66dfaaa92a8d04ab2743f3caeab0ac9f9f25859
|
PODFILE CHECKSUM: f66dfaaa92a8d04ab2743f3caeab0ac9f9f25859
|
||||||
|
|
||||||
|
|
|
@ -53,9 +53,9 @@
|
||||||
0E3E0F222108A8CC00B371C1 /* SessionProxy+PushReply.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3E0F202108A8CC00B371C1 /* SessionProxy+PushReply.swift */; };
|
0E3E0F222108A8CC00B371C1 /* SessionProxy+PushReply.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3E0F202108A8CC00B371C1 /* SessionProxy+PushReply.swift */; };
|
||||||
0E50D57521634E0A00FC87A8 /* ControlChannelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E50D57421634E0A00FC87A8 /* ControlChannelTests.swift */; };
|
0E50D57521634E0A00FC87A8 /* ControlChannelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E50D57421634E0A00FC87A8 /* ControlChannelTests.swift */; };
|
||||||
0E58F1302138AC2F00A49F27 /* DNSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E58F12F2138AC2F00A49F27 /* DNSTests.swift */; };
|
0E58F1302138AC2F00A49F27 /* DNSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E58F12F2138AC2F00A49F27 /* DNSTests.swift */; };
|
||||||
0E749F622178911D00BB2701 /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; };
|
|
||||||
0E749F5F2178885500BB2701 /* SessionProxy+PIA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */; };
|
0E749F5F2178885500BB2701 /* SessionProxy+PIA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */; };
|
||||||
0E749F602178885500BB2701 /* SessionProxy+PIA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */; };
|
0E749F602178885500BB2701 /* SessionProxy+PIA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */; };
|
||||||
|
0E749F622178911D00BB2701 /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; };
|
||||||
0E85A25A202CC5AF0059E9F9 /* AppExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E85A259202CC5AE0059E9F9 /* AppExtensionTests.swift */; };
|
0E85A25A202CC5AF0059E9F9 /* AppExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E85A259202CC5AE0059E9F9 /* AppExtensionTests.swift */; };
|
||||||
0E9379C91F819A4300CE91B6 /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E17D7F91F730D9F009EE129 /* TunnelKit.framework */; };
|
0E9379C91F819A4300CE91B6 /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E17D7F91F730D9F009EE129 /* TunnelKit.framework */; };
|
||||||
0EB2B45320F0BB44004233D7 /* EncryptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB2B45220F0BB44004233D7 /* EncryptionTests.swift */; };
|
0EB2B45320F0BB44004233D7 /* EncryptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB2B45220F0BB44004233D7 /* EncryptionTests.swift */; };
|
||||||
|
@ -232,8 +232,8 @@
|
||||||
0E58F12F2138AC2F00A49F27 /* DNSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSTests.swift; sourceTree = "<group>"; };
|
0E58F12F2138AC2F00A49F27 /* DNSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSTests.swift; sourceTree = "<group>"; };
|
||||||
0E6479DD212EAC96008E6888 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
0E6479DD212EAC96008E6888 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
0E6479E0212EACD6008E6888 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
0E6479E0212EACD6008E6888 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
0E749F612178911C00BB2701 /* pia-2048.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = "pia-2048.pem"; sourceTree = "<group>"; };
|
|
||||||
0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionProxy+PIA.swift"; sourceTree = "<group>"; };
|
0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionProxy+PIA.swift"; sourceTree = "<group>"; };
|
||||||
|
0E749F612178911C00BB2701 /* pia-2048.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = "pia-2048.pem"; sourceTree = "<group>"; };
|
||||||
0E85A259202CC5AE0059E9F9 /* AppExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppExtensionTests.swift; sourceTree = "<group>"; };
|
0E85A259202CC5AE0059E9F9 /* AppExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppExtensionTests.swift; sourceTree = "<group>"; };
|
||||||
0E85A25B202CCA3D0059E9F9 /* TunnelKitHost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TunnelKitHost.entitlements; sourceTree = "<group>"; };
|
0E85A25B202CCA3D0059E9F9 /* TunnelKitHost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TunnelKitHost.entitlements; sourceTree = "<group>"; };
|
||||||
0EB2B45220F0BB44004233D7 /* EncryptionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionTests.swift; sourceTree = "<group>"; };
|
0EB2B45220F0BB44004233D7 /* EncryptionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionTests.swift; sourceTree = "<group>"; };
|
||||||
|
@ -471,6 +471,7 @@
|
||||||
0EFEB4322006D3C800F81029 /* CryptoBox.m */,
|
0EFEB4322006D3C800F81029 /* CryptoBox.m */,
|
||||||
0E07596D20EF79B400F38FD8 /* CryptoCBC.h */,
|
0E07596D20EF79B400F38FD8 /* CryptoCBC.h */,
|
||||||
0E07595C20EF6D1400F38FD8 /* CryptoCBC.m */,
|
0E07595C20EF6D1400F38FD8 /* CryptoCBC.m */,
|
||||||
|
0ECE3527212EB7770040F253 /* CryptoContainer.swift */,
|
||||||
0E3B15C52152B05E00984B17 /* CryptoCTR.h */,
|
0E3B15C52152B05E00984B17 /* CryptoCTR.h */,
|
||||||
0E3B15C62152B05E00984B17 /* CryptoCTR.m */,
|
0E3B15C62152B05E00984B17 /* CryptoCTR.m */,
|
||||||
0E07596120EF733F00F38FD8 /* CryptoMacros.h */,
|
0E07596120EF733F00F38FD8 /* CryptoMacros.h */,
|
||||||
|
@ -518,7 +519,6 @@
|
||||||
children = (
|
children = (
|
||||||
0EBBF2E32084FDF400E36B40 /* Transport */,
|
0EBBF2E32084FDF400E36B40 /* Transport */,
|
||||||
0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */,
|
0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */,
|
||||||
0ECE3527212EB7770040F253 /* CryptoContainer.swift */,
|
|
||||||
0EC1BBA420D71190007C4C7B /* DNSResolver.swift */,
|
0EC1BBA420D71190007C4C7B /* DNSResolver.swift */,
|
||||||
0EBBF2E42084FE6F00E36B40 /* GenericSocket.swift */,
|
0EBBF2E42084FE6F00E36B40 /* GenericSocket.swift */,
|
||||||
0EFEB4AA200760EC00F81029 /* InterfaceObserver.swift */,
|
0EFEB4AA200760EC00F81029 /* InterfaceObserver.swift */,
|
||||||
|
|
|
@ -121,38 +121,11 @@ extension TunnelKitProvider {
|
||||||
/// The accepted communication protocols. Must be non-empty.
|
/// The accepted communication protocols. Must be non-empty.
|
||||||
public var endpointProtocols: [EndpointProtocol]
|
public var endpointProtocols: [EndpointProtocol]
|
||||||
|
|
||||||
/// The encryption algorithm.
|
|
||||||
public var cipher: SessionProxy.Cipher
|
|
||||||
|
|
||||||
/// The message digest algorithm.
|
|
||||||
public var digest: SessionProxy.Digest
|
|
||||||
|
|
||||||
/// The CA certificate to validate server against.
|
|
||||||
public let ca: CryptoContainer
|
|
||||||
|
|
||||||
/// The optional client certificate to authenticate with. Set to `nil` to disable client authentication (default).
|
|
||||||
public var clientCertificate: CryptoContainer?
|
|
||||||
|
|
||||||
/// The optional key for `clientCertificate`. Set to `nil` if client authentication unused (default).
|
|
||||||
public var clientKey: CryptoContainer?
|
|
||||||
|
|
||||||
/// The MTU of the link.
|
/// The MTU of the link.
|
||||||
public var mtu: Int
|
public var mtu: Int
|
||||||
|
|
||||||
/// Sets compression framing, disabled by default.
|
/// The session configuration.
|
||||||
public var compressionFraming: SessionProxy.CompressionFraming
|
public var sessionConfiguration: SessionProxy.Configuration
|
||||||
|
|
||||||
/// The optional TLS wrapping. When `strategy == .auth`, uses `digest` as HMAC algorithm.
|
|
||||||
public var tlsWrap: SessionProxy.TLSWrap?
|
|
||||||
|
|
||||||
/// Sends periodical keep-alive packets (ping) if set. Useful with stateful firewalls.
|
|
||||||
public var keepAliveSeconds: Int?
|
|
||||||
|
|
||||||
/// The number of seconds after which a renegotiation is started. Set to `nil` to disable renegotiation (default).
|
|
||||||
public var renegotiatesAfterSeconds: Int?
|
|
||||||
|
|
||||||
/// Server is patched for the PIA VPN provider.
|
|
||||||
public var usesPIAPatches: Bool?
|
|
||||||
|
|
||||||
// MARK: Debugging
|
// MARK: Debugging
|
||||||
|
|
||||||
|
@ -175,21 +148,12 @@ extension TunnelKitProvider {
|
||||||
|
|
||||||
- Parameter ca: The CA certificate.
|
- Parameter ca: The CA certificate.
|
||||||
*/
|
*/
|
||||||
public init(ca: CryptoContainer) {
|
public init(sessionConfiguration: SessionProxy.Configuration) {
|
||||||
prefersResolvedAddresses = false
|
prefersResolvedAddresses = false
|
||||||
resolvedAddresses = nil
|
resolvedAddresses = nil
|
||||||
endpointProtocols = [EndpointProtocol(.udp, 1194)]
|
endpointProtocols = [EndpointProtocol(.udp, 1194)]
|
||||||
cipher = .aes128cbc
|
|
||||||
digest = .sha1
|
|
||||||
self.ca = ca
|
|
||||||
clientCertificate = nil
|
|
||||||
clientKey = nil
|
|
||||||
mtu = 1500
|
mtu = 1500
|
||||||
compressionFraming = .disabled
|
self.sessionConfiguration = sessionConfiguration
|
||||||
tlsWrap = nil
|
|
||||||
keepAliveSeconds = nil
|
|
||||||
renegotiatesAfterSeconds = nil
|
|
||||||
usesPIAPatches = false
|
|
||||||
shouldDebug = false
|
shouldDebug = false
|
||||||
debugLogKey = nil
|
debugLogKey = nil
|
||||||
debugLogFormat = nil
|
debugLogFormat = nil
|
||||||
|
@ -199,6 +163,21 @@ extension TunnelKitProvider {
|
||||||
fileprivate init(providerConfiguration: [String: Any]) throws {
|
fileprivate init(providerConfiguration: [String: Any]) throws {
|
||||||
let S = Configuration.Keys.self
|
let S = Configuration.Keys.self
|
||||||
|
|
||||||
|
prefersResolvedAddresses = providerConfiguration[S.prefersResolvedAddresses] as? Bool ?? false
|
||||||
|
resolvedAddresses = providerConfiguration[S.resolvedAddresses] as? [String]
|
||||||
|
guard let endpointProtocolsStrings = providerConfiguration[S.endpointProtocols] as? [String], !endpointProtocolsStrings.isEmpty else {
|
||||||
|
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.endpointProtocols)] is nil or empty")
|
||||||
|
}
|
||||||
|
endpointProtocols = try endpointProtocolsStrings.map {
|
||||||
|
guard let ep = EndpointProtocol(rawValue: $0) else {
|
||||||
|
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.endpointProtocols)] has a badly formed element")
|
||||||
|
}
|
||||||
|
return ep
|
||||||
|
}
|
||||||
|
mtu = providerConfiguration[S.mtu] as? Int ?? 1250
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
guard let cipherAlgorithm = providerConfiguration[S.cipherAlgorithm] as? String, let cipher = SessionProxy.Cipher(rawValue: cipherAlgorithm) else {
|
guard let cipherAlgorithm = providerConfiguration[S.cipherAlgorithm] as? String, let cipher = SessionProxy.Cipher(rawValue: cipherAlgorithm) else {
|
||||||
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.cipherAlgorithm)]")
|
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.cipherAlgorithm)]")
|
||||||
}
|
}
|
||||||
|
@ -224,41 +203,28 @@ extension TunnelKitProvider {
|
||||||
clientCertificate = nil
|
clientCertificate = nil
|
||||||
clientKey = nil
|
clientKey = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
prefersResolvedAddresses = providerConfiguration[S.prefersResolvedAddresses] as? Bool ?? false
|
var sessionConfigurationBuilder = SessionProxy.ConfigurationBuilder(ca: ca)
|
||||||
resolvedAddresses = providerConfiguration[S.resolvedAddresses] as? [String]
|
sessionConfigurationBuilder.cipher = cipher
|
||||||
|
sessionConfigurationBuilder.digest = digest
|
||||||
guard let endpointProtocolsStrings = providerConfiguration[S.endpointProtocols] as? [String], !endpointProtocolsStrings.isEmpty else {
|
sessionConfigurationBuilder.clientCertificate = clientCertificate
|
||||||
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.endpointProtocols)] is nil or empty")
|
sessionConfigurationBuilder.clientKey = clientKey
|
||||||
}
|
|
||||||
endpointProtocols = try endpointProtocolsStrings.map {
|
|
||||||
guard let ep = EndpointProtocol(rawValue: $0) else {
|
|
||||||
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.endpointProtocols)] has a badly formed element")
|
|
||||||
}
|
|
||||||
return ep
|
|
||||||
}
|
|
||||||
|
|
||||||
self.cipher = cipher
|
|
||||||
self.digest = digest
|
|
||||||
self.ca = ca
|
|
||||||
self.clientCertificate = clientCertificate
|
|
||||||
self.clientKey = clientKey
|
|
||||||
mtu = providerConfiguration[S.mtu] as? Int ?? 1250
|
|
||||||
if let compressionFramingValue = providerConfiguration[S.compressionFraming] as? Int, let compressionFraming = SessionProxy.CompressionFraming(rawValue: compressionFramingValue) {
|
if let compressionFramingValue = providerConfiguration[S.compressionFraming] as? Int, let compressionFraming = SessionProxy.CompressionFraming(rawValue: compressionFramingValue) {
|
||||||
self.compressionFraming = compressionFraming
|
sessionConfigurationBuilder.compressionFraming = compressionFraming
|
||||||
} else {
|
} else {
|
||||||
compressionFraming = .disabled
|
sessionConfigurationBuilder.compressionFraming = .disabled
|
||||||
}
|
}
|
||||||
if let tlsWrapData = providerConfiguration[S.tlsWrap] as? Data {
|
if let tlsWrapData = providerConfiguration[S.tlsWrap] as? Data {
|
||||||
do {
|
do {
|
||||||
tlsWrap = try SessionProxy.TLSWrap.deserialized(tlsWrapData)
|
sessionConfigurationBuilder.tlsWrap = try SessionProxy.TLSWrap.deserialized(tlsWrapData)
|
||||||
} catch {
|
} catch {
|
||||||
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.tlsWrap)]")
|
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.tlsWrap)]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keepAliveSeconds = providerConfiguration[S.keepAlive] as? Int
|
sessionConfigurationBuilder.keepAliveInterval = providerConfiguration[S.keepAlive] as? TimeInterval
|
||||||
renegotiatesAfterSeconds = providerConfiguration[S.renegotiatesAfter] as? Int
|
sessionConfigurationBuilder.renegotiatesAfter = providerConfiguration[S.renegotiatesAfter] as? TimeInterval
|
||||||
usesPIAPatches = providerConfiguration[S.usesPIAPatches] as? Bool ?? false
|
sessionConfigurationBuilder.usesPIAPatches = providerConfiguration[S.usesPIAPatches] as? Bool ?? false
|
||||||
|
sessionConfiguration = sessionConfigurationBuilder.build()
|
||||||
|
|
||||||
shouldDebug = providerConfiguration[S.debug] as? Bool ?? false
|
shouldDebug = providerConfiguration[S.debug] as? Bool ?? false
|
||||||
if shouldDebug {
|
if shouldDebug {
|
||||||
|
@ -287,17 +253,8 @@ extension TunnelKitProvider {
|
||||||
prefersResolvedAddresses: prefersResolvedAddresses,
|
prefersResolvedAddresses: prefersResolvedAddresses,
|
||||||
resolvedAddresses: resolvedAddresses,
|
resolvedAddresses: resolvedAddresses,
|
||||||
endpointProtocols: endpointProtocols,
|
endpointProtocols: endpointProtocols,
|
||||||
cipher: cipher,
|
|
||||||
digest: digest,
|
|
||||||
ca: ca,
|
|
||||||
clientCertificate: clientCertificate,
|
|
||||||
clientKey: clientKey,
|
|
||||||
mtu: mtu,
|
mtu: mtu,
|
||||||
compressionFraming: compressionFraming,
|
sessionConfiguration: sessionConfiguration,
|
||||||
tlsWrap: tlsWrap,
|
|
||||||
keepAliveSeconds: keepAliveSeconds,
|
|
||||||
renegotiatesAfterSeconds: renegotiatesAfterSeconds,
|
|
||||||
usesPIAPatches: usesPIAPatches,
|
|
||||||
shouldDebug: shouldDebug,
|
shouldDebug: shouldDebug,
|
||||||
debugLogKey: shouldDebug ? debugLogKey : nil,
|
debugLogKey: shouldDebug ? debugLogKey : nil,
|
||||||
debugLogFormat: shouldDebug ? debugLogFormat : nil,
|
debugLogFormat: shouldDebug ? debugLogFormat : nil,
|
||||||
|
@ -317,6 +274,10 @@ extension TunnelKitProvider {
|
||||||
|
|
||||||
static let endpointProtocols = "EndpointProtocols"
|
static let endpointProtocols = "EndpointProtocols"
|
||||||
|
|
||||||
|
static let mtu = "MTU"
|
||||||
|
|
||||||
|
// MARK: SessionConfiguration
|
||||||
|
|
||||||
static let cipherAlgorithm = "CipherAlgorithm"
|
static let cipherAlgorithm = "CipherAlgorithm"
|
||||||
|
|
||||||
static let digestAlgorithm = "DigestAlgorithm"
|
static let digestAlgorithm = "DigestAlgorithm"
|
||||||
|
@ -327,8 +288,6 @@ extension TunnelKitProvider {
|
||||||
|
|
||||||
static let clientKey = "ClientKey"
|
static let clientKey = "ClientKey"
|
||||||
|
|
||||||
static let mtu = "MTU"
|
|
||||||
|
|
||||||
static let compressionFraming = "CompressionFraming"
|
static let compressionFraming = "CompressionFraming"
|
||||||
|
|
||||||
static let tlsWrap = "TLSWrap"
|
static let tlsWrap = "TLSWrap"
|
||||||
|
@ -338,6 +297,8 @@ extension TunnelKitProvider {
|
||||||
static let renegotiatesAfter = "RenegotiatesAfter"
|
static let renegotiatesAfter = "RenegotiatesAfter"
|
||||||
|
|
||||||
static let usesPIAPatches = "UsesPIAPatches"
|
static let usesPIAPatches = "UsesPIAPatches"
|
||||||
|
|
||||||
|
// MARK: Debugging
|
||||||
|
|
||||||
static let debug = "Debug"
|
static let debug = "Debug"
|
||||||
|
|
||||||
|
@ -357,38 +318,11 @@ extension TunnelKitProvider {
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.endpointProtocols`
|
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.endpointProtocols`
|
||||||
public let endpointProtocols: [EndpointProtocol]
|
public let endpointProtocols: [EndpointProtocol]
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.cipher`
|
|
||||||
public let cipher: SessionProxy.Cipher
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.digest`
|
|
||||||
public let digest: SessionProxy.Digest
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.ca`
|
|
||||||
public let ca: CryptoContainer
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.clientCertificate`
|
|
||||||
public let clientCertificate: CryptoContainer?
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.clientKey`
|
|
||||||
public let clientKey: CryptoContainer?
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.mtu`
|
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.mtu`
|
||||||
public let mtu: Int
|
public let mtu: Int
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.compressionFraming`
|
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.sessionConfiguration`
|
||||||
public let compressionFraming: SessionProxy.CompressionFraming
|
public let sessionConfiguration: SessionProxy.Configuration
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.tlsWrap`
|
|
||||||
public let tlsWrap: SessionProxy.TLSWrap?
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.keepAliveSeconds`
|
|
||||||
public let keepAliveSeconds: Int?
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.renegotiatesAfterSeconds`
|
|
||||||
public let renegotiatesAfterSeconds: Int?
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.usesPIAPatches`
|
|
||||||
public let usesPIAPatches: Bool?
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.shouldDebug`
|
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.shouldDebug`
|
||||||
public let shouldDebug: Bool
|
public let shouldDebug: Bool
|
||||||
|
@ -474,32 +408,32 @@ extension TunnelKitProvider {
|
||||||
S.appGroup: appGroup,
|
S.appGroup: appGroup,
|
||||||
S.prefersResolvedAddresses: prefersResolvedAddresses,
|
S.prefersResolvedAddresses: prefersResolvedAddresses,
|
||||||
S.endpointProtocols: endpointProtocols.map { $0.rawValue },
|
S.endpointProtocols: endpointProtocols.map { $0.rawValue },
|
||||||
S.cipherAlgorithm: cipher.rawValue,
|
S.cipherAlgorithm: sessionConfiguration.cipher.rawValue,
|
||||||
S.digestAlgorithm: digest.rawValue,
|
S.digestAlgorithm: sessionConfiguration.digest.rawValue,
|
||||||
S.ca: ca.pem,
|
S.ca: sessionConfiguration.ca.pem,
|
||||||
S.mtu: mtu,
|
S.mtu: mtu,
|
||||||
S.debug: shouldDebug
|
S.debug: shouldDebug
|
||||||
]
|
]
|
||||||
if let clientCertificate = clientCertificate {
|
if let clientCertificate = sessionConfiguration.clientCertificate {
|
||||||
dict[S.clientCertificate] = clientCertificate.pem
|
dict[S.clientCertificate] = clientCertificate.pem
|
||||||
}
|
}
|
||||||
if let clientKey = clientKey {
|
if let clientKey = sessionConfiguration.clientKey {
|
||||||
dict[S.clientKey] = clientKey.pem
|
dict[S.clientKey] = clientKey.pem
|
||||||
}
|
}
|
||||||
if let resolvedAddresses = resolvedAddresses {
|
if let resolvedAddresses = resolvedAddresses {
|
||||||
dict[S.resolvedAddresses] = resolvedAddresses
|
dict[S.resolvedAddresses] = resolvedAddresses
|
||||||
}
|
}
|
||||||
dict[S.compressionFraming] = compressionFraming.rawValue
|
dict[S.compressionFraming] = sessionConfiguration.compressionFraming.rawValue
|
||||||
if let tlsWrapData = tlsWrap?.serialized() {
|
if let tlsWrapData = sessionConfiguration.tlsWrap?.serialized() {
|
||||||
dict[S.tlsWrap] = tlsWrapData
|
dict[S.tlsWrap] = tlsWrapData
|
||||||
}
|
}
|
||||||
if let keepAliveSeconds = keepAliveSeconds {
|
if let keepAliveSeconds = sessionConfiguration.keepAliveInterval {
|
||||||
dict[S.keepAlive] = keepAliveSeconds
|
dict[S.keepAlive] = keepAliveSeconds
|
||||||
}
|
}
|
||||||
if let renegotiatesAfterSeconds = renegotiatesAfterSeconds {
|
if let renegotiatesAfterSeconds = sessionConfiguration.renegotiatesAfter {
|
||||||
dict[S.renegotiatesAfter] = renegotiatesAfterSeconds
|
dict[S.renegotiatesAfter] = renegotiatesAfterSeconds
|
||||||
}
|
}
|
||||||
if let usesPIAPatches = usesPIAPatches {
|
if let usesPIAPatches = sessionConfiguration.usesPIAPatches {
|
||||||
dict[S.usesPIAPatches] = usesPIAPatches
|
dict[S.usesPIAPatches] = usesPIAPatches
|
||||||
}
|
}
|
||||||
if let debugLogKey = debugLogKey {
|
if let debugLogKey = debugLogKey {
|
||||||
|
@ -550,26 +484,26 @@ extension TunnelKitProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("\tProtocols: \(endpointProtocols)")
|
log.info("\tProtocols: \(endpointProtocols)")
|
||||||
log.info("\tCipher: \(cipher)")
|
log.info("\tCipher: \(sessionConfiguration.cipher)")
|
||||||
log.info("\tDigest: \(digest)")
|
log.info("\tDigest: \(sessionConfiguration.digest)")
|
||||||
if let _ = clientCertificate {
|
if let _ = sessionConfiguration.clientCertificate {
|
||||||
log.info("\tClient verification: enabled")
|
log.info("\tClient verification: enabled")
|
||||||
} else {
|
} else {
|
||||||
log.info("\tClient verification: disabled")
|
log.info("\tClient verification: disabled")
|
||||||
}
|
}
|
||||||
log.info("\tMTU: \(mtu)")
|
log.info("\tMTU: \(mtu)")
|
||||||
log.info("\tCompression framing: \(compressionFraming)")
|
log.info("\tCompression framing: \(sessionConfiguration.compressionFraming)")
|
||||||
if let keepAliveSeconds = keepAliveSeconds, keepAliveSeconds > 0 {
|
if let keepAliveSeconds = sessionConfiguration.keepAliveInterval, keepAliveSeconds > 0 {
|
||||||
log.info("\tKeep-alive: \(keepAliveSeconds) seconds")
|
log.info("\tKeep-alive: \(keepAliveSeconds) seconds")
|
||||||
} else {
|
} else {
|
||||||
log.info("\tKeep-alive: never")
|
log.info("\tKeep-alive: never")
|
||||||
}
|
}
|
||||||
if let renegotiatesAfterSeconds = renegotiatesAfterSeconds, renegotiatesAfterSeconds > 0 {
|
if let renegotiatesAfterSeconds = sessionConfiguration.renegotiatesAfter, renegotiatesAfterSeconds > 0 {
|
||||||
log.info("\tRenegotiation: \(renegotiatesAfterSeconds) seconds")
|
log.info("\tRenegotiation: \(renegotiatesAfterSeconds) seconds")
|
||||||
} else {
|
} else {
|
||||||
log.info("\tRenegotiation: never")
|
log.info("\tRenegotiation: never")
|
||||||
}
|
}
|
||||||
if let tlsWrap = tlsWrap {
|
if let tlsWrap = sessionConfiguration.tlsWrap {
|
||||||
log.info("\tTLS wrapping: \(tlsWrap.strategy)")
|
log.info("\tTLS wrapping: \(tlsWrap.strategy)")
|
||||||
} else {
|
} else {
|
||||||
log.info("\tTLS wrapping: disabled")
|
log.info("\tTLS wrapping: disabled")
|
||||||
|
@ -589,18 +523,9 @@ extension TunnelKitProvider.Configuration: Equatable {
|
||||||
- Returns: An editable `TunnelKitProvider.ConfigurationBuilder` initialized with this configuration.
|
- Returns: An editable `TunnelKitProvider.ConfigurationBuilder` initialized with this configuration.
|
||||||
*/
|
*/
|
||||||
public func builder() -> TunnelKitProvider.ConfigurationBuilder {
|
public func builder() -> TunnelKitProvider.ConfigurationBuilder {
|
||||||
var builder = TunnelKitProvider.ConfigurationBuilder(ca: ca)
|
var builder = TunnelKitProvider.ConfigurationBuilder(sessionConfiguration: sessionConfiguration)
|
||||||
builder.endpointProtocols = endpointProtocols
|
builder.endpointProtocols = endpointProtocols
|
||||||
builder.cipher = cipher
|
|
||||||
builder.digest = digest
|
|
||||||
builder.clientCertificate = clientCertificate
|
|
||||||
builder.clientKey = clientKey
|
|
||||||
builder.mtu = mtu
|
builder.mtu = mtu
|
||||||
builder.compressionFraming = compressionFraming
|
|
||||||
builder.tlsWrap = tlsWrap
|
|
||||||
builder.keepAliveSeconds = keepAliveSeconds
|
|
||||||
builder.renegotiatesAfterSeconds = renegotiatesAfterSeconds
|
|
||||||
builder.usesPIAPatches = usesPIAPatches
|
|
||||||
builder.shouldDebug = shouldDebug
|
builder.shouldDebug = shouldDebug
|
||||||
builder.debugLogKey = debugLogKey
|
builder.debugLogKey = debugLogKey
|
||||||
builder.debugLogFormat = debugLogFormat
|
builder.debugLogFormat = debugLogFormat
|
||||||
|
@ -612,15 +537,8 @@ extension TunnelKitProvider.Configuration: Equatable {
|
||||||
public static func ==(lhs: TunnelKitProvider.Configuration, rhs: TunnelKitProvider.Configuration) -> Bool {
|
public static func ==(lhs: TunnelKitProvider.Configuration, rhs: TunnelKitProvider.Configuration) -> Bool {
|
||||||
return (
|
return (
|
||||||
(lhs.endpointProtocols == rhs.endpointProtocols) &&
|
(lhs.endpointProtocols == rhs.endpointProtocols) &&
|
||||||
(lhs.cipher == rhs.cipher) &&
|
|
||||||
(lhs.digest == rhs.digest) &&
|
|
||||||
(lhs.ca == rhs.ca) &&
|
|
||||||
(lhs.clientCertificate == rhs.clientCertificate) &&
|
|
||||||
(lhs.clientKey == rhs.clientKey) &&
|
|
||||||
(lhs.mtu == rhs.mtu) &&
|
(lhs.mtu == rhs.mtu) &&
|
||||||
(lhs.compressionFraming == rhs.compressionFraming) &&
|
(lhs.sessionConfiguration == rhs.sessionConfiguration)
|
||||||
(lhs.keepAliveSeconds == rhs.keepAliveSeconds) &&
|
|
||||||
(lhs.renegotiatesAfterSeconds == rhs.renegotiatesAfterSeconds)
|
|
||||||
// XXX: tlsWrap not copied
|
// XXX: tlsWrap not copied
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,13 +83,15 @@ open class TunnelKitProvider: NEPacketTunnelProvider {
|
||||||
private let prngSeedLength = 64
|
private let prngSeedLength = 64
|
||||||
|
|
||||||
private var cachesURL: URL {
|
private var cachesURL: URL {
|
||||||
return URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0])
|
guard let appGroup = appGroup else {
|
||||||
|
fatalError("Accessing cachesURL before parsing app group")
|
||||||
|
}
|
||||||
|
guard let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else {
|
||||||
|
fatalError("No access to app group: \(appGroup)")
|
||||||
|
}
|
||||||
|
return containerURL.appendingPathComponent("Library/Caches/")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func temporaryURL(forKey key: String) -> URL {
|
|
||||||
return cachesURL.appendingPathComponent("\(key).pem")
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Tunnel configuration
|
// MARK: Tunnel configuration
|
||||||
|
|
||||||
private var appGroup: String!
|
private var appGroup: String!
|
||||||
|
@ -181,69 +183,17 @@ open class TunnelKitProvider: NEPacketTunnelProvider {
|
||||||
completionHandler(ProviderConfigurationError.prngInitialization)
|
completionHandler(ProviderConfigurationError.prngInitialization)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let caPath: String
|
|
||||||
let clientCertificatePath: String?
|
|
||||||
let clientKeyPath: String?
|
|
||||||
do {
|
|
||||||
let url = temporaryURL(forKey: Configuration.Keys.ca)
|
|
||||||
try cfg.ca.write(to: url)
|
|
||||||
caPath = url.path
|
|
||||||
} catch {
|
|
||||||
completionHandler(ProviderConfigurationError.certificateSerialization)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if let clientCertificate = cfg.clientCertificate {
|
|
||||||
do {
|
|
||||||
let url = temporaryURL(forKey: Configuration.Keys.clientCertificate)
|
|
||||||
try clientCertificate.write(to: url)
|
|
||||||
clientCertificatePath = url.path
|
|
||||||
} catch {
|
|
||||||
completionHandler(ProviderConfigurationError.certificateSerialization)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clientCertificatePath = nil
|
|
||||||
}
|
|
||||||
if let clientKey = cfg.clientKey {
|
|
||||||
do {
|
|
||||||
let url = temporaryURL(forKey: Configuration.Keys.clientKey)
|
|
||||||
try clientKey.write(to: url)
|
|
||||||
clientKeyPath = url.path
|
|
||||||
} catch {
|
|
||||||
completionHandler(ProviderConfigurationError.certificateSerialization)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clientKeyPath = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.print(appVersion: appVersion)
|
cfg.print(appVersion: appVersion)
|
||||||
|
|
||||||
// log.info("Temporary CA is stored to: \(caPath)")
|
|
||||||
var sessionConfiguration = SessionProxy.ConfigurationBuilder(caPath: caPath)
|
|
||||||
sessionConfiguration.credentials = credentials
|
|
||||||
sessionConfiguration.cipher = cfg.cipher
|
|
||||||
sessionConfiguration.digest = cfg.digest
|
|
||||||
sessionConfiguration.clientCertificatePath = clientCertificatePath
|
|
||||||
sessionConfiguration.clientKeyPath = clientKeyPath
|
|
||||||
sessionConfiguration.compressionFraming = cfg.compressionFraming
|
|
||||||
sessionConfiguration.tlsWrap = cfg.tlsWrap
|
|
||||||
if let keepAliveSeconds = cfg.keepAliveSeconds {
|
|
||||||
sessionConfiguration.keepAliveInterval = TimeInterval(keepAliveSeconds)
|
|
||||||
}
|
|
||||||
if let renegotiatesAfterSeconds = cfg.renegotiatesAfterSeconds {
|
|
||||||
sessionConfiguration.renegotiatesAfter = TimeInterval(renegotiatesAfterSeconds)
|
|
||||||
}
|
|
||||||
sessionConfiguration.usesPIAPatches = cfg.usesPIAPatches ?? false
|
|
||||||
|
|
||||||
let proxy: SessionProxy
|
let proxy: SessionProxy
|
||||||
do {
|
do {
|
||||||
proxy = try SessionProxy(queue: tunnelQueue, configuration: sessionConfiguration.build())
|
proxy = try SessionProxy(queue: tunnelQueue, configuration: cfg.sessionConfiguration, cachesURL: cachesURL)
|
||||||
} catch let e {
|
} catch let e {
|
||||||
completionHandler(e)
|
completionHandler(e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
proxy.credentials = credentials
|
||||||
proxy.delegate = self
|
proxy.delegate = self
|
||||||
self.proxy = proxy
|
self.proxy = proxy
|
||||||
|
|
||||||
|
@ -382,10 +332,6 @@ open class TunnelKitProvider: NEPacketTunnelProvider {
|
||||||
}
|
}
|
||||||
// stopped externally, unrecoverable
|
// stopped externally, unrecoverable
|
||||||
else {
|
else {
|
||||||
let fm = FileManager.default
|
|
||||||
for key in [Configuration.Keys.ca, Configuration.Keys.clientCertificate, Configuration.Keys.clientKey] {
|
|
||||||
try? fm.removeItem(at: temporaryURL(forKey: key))
|
|
||||||
}
|
|
||||||
cancelTunnelWithError(error)
|
cancelTunnelWithError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,23 +135,20 @@ extension SessionProxy {
|
||||||
/// The way to create a `SessionProxy.Configuration` object for a `SessionProxy`.
|
/// The way to create a `SessionProxy.Configuration` object for a `SessionProxy`.
|
||||||
public struct ConfigurationBuilder {
|
public struct ConfigurationBuilder {
|
||||||
|
|
||||||
/// The credentials.
|
|
||||||
public var credentials: Credentials?
|
|
||||||
|
|
||||||
/// The cipher algorithm for data encryption.
|
/// The cipher algorithm for data encryption.
|
||||||
public var cipher: Cipher
|
public var cipher: Cipher
|
||||||
|
|
||||||
/// The digest algorithm for HMAC.
|
/// The digest algorithm for HMAC.
|
||||||
public var digest: Digest
|
public var digest: Digest
|
||||||
|
|
||||||
/// The path to the CA for TLS negotiation (PEM format).
|
/// The CA for TLS negotiation (PEM format).
|
||||||
public let caPath: String
|
public let ca: CryptoContainer
|
||||||
|
|
||||||
/// The path to the optional client certificate for TLS negotiation (PEM format).
|
/// The optional client certificate for TLS negotiation (PEM format).
|
||||||
public var clientCertificatePath: String?
|
public var clientCertificate: CryptoContainer?
|
||||||
|
|
||||||
/// The path to the private key for the certificate at `clientCertificatePath` (PEM format).
|
/// The private key for the certificate in `clientCertificate` (PEM format).
|
||||||
public var clientKeyPath: String?
|
public var clientKey: CryptoContainer?
|
||||||
|
|
||||||
/// Sets compression framing, disabled by default.
|
/// Sets compression framing, disabled by default.
|
||||||
public var compressionFraming: CompressionFraming
|
public var compressionFraming: CompressionFraming
|
||||||
|
@ -166,16 +163,15 @@ extension SessionProxy {
|
||||||
public var renegotiatesAfter: TimeInterval?
|
public var renegotiatesAfter: TimeInterval?
|
||||||
|
|
||||||
/// Server is patched for the PIA VPN provider.
|
/// Server is patched for the PIA VPN provider.
|
||||||
public var usesPIAPatches: Bool
|
public var usesPIAPatches: Bool?
|
||||||
|
|
||||||
/// :nodoc:
|
/// :nodoc:
|
||||||
public init(caPath: String) {
|
public init(ca: CryptoContainer) {
|
||||||
credentials = nil
|
|
||||||
cipher = .aes128cbc
|
cipher = .aes128cbc
|
||||||
digest = .sha1
|
digest = .sha1
|
||||||
self.caPath = caPath
|
self.ca = ca
|
||||||
clientCertificatePath = nil
|
clientCertificate = nil
|
||||||
clientKeyPath = nil
|
clientKey = nil
|
||||||
compressionFraming = .disabled
|
compressionFraming = .disabled
|
||||||
tlsWrap = nil
|
tlsWrap = nil
|
||||||
keepAliveInterval = nil
|
keepAliveInterval = nil
|
||||||
|
@ -190,12 +186,11 @@ extension SessionProxy {
|
||||||
*/
|
*/
|
||||||
public func build() -> Configuration {
|
public func build() -> Configuration {
|
||||||
return Configuration(
|
return Configuration(
|
||||||
credentials: credentials,
|
|
||||||
cipher: cipher,
|
cipher: cipher,
|
||||||
digest: digest,
|
digest: digest,
|
||||||
caPath: caPath,
|
ca: ca,
|
||||||
clientCertificatePath: clientCertificatePath,
|
clientCertificate: clientCertificate,
|
||||||
clientKeyPath: clientKeyPath,
|
clientKey: clientKey,
|
||||||
compressionFraming: compressionFraming,
|
compressionFraming: compressionFraming,
|
||||||
tlsWrap: tlsWrap,
|
tlsWrap: tlsWrap,
|
||||||
keepAliveInterval: keepAliveInterval,
|
keepAliveInterval: keepAliveInterval,
|
||||||
|
@ -206,25 +201,22 @@ extension SessionProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The immutable configuration for `SessionProxy`.
|
/// The immutable configuration for `SessionProxy`.
|
||||||
public struct Configuration: Codable {
|
public struct Configuration: Codable, Equatable {
|
||||||
|
|
||||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.credentials`
|
|
||||||
public let credentials: Credentials?
|
|
||||||
|
|
||||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.cipher`
|
/// - Seealso: `SessionProxy.ConfigurationBuilder.cipher`
|
||||||
public let cipher: Cipher
|
public let cipher: Cipher
|
||||||
|
|
||||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.digest`
|
/// - Seealso: `SessionProxy.ConfigurationBuilder.digest`
|
||||||
public let digest: Digest
|
public let digest: Digest
|
||||||
|
|
||||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.caPath`
|
/// - Seealso: `SessionProxy.ConfigurationBuilder.ca`
|
||||||
public let caPath: String
|
public let ca: CryptoContainer
|
||||||
|
|
||||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.clientCertificatePath`
|
/// - Seealso: `SessionProxy.ConfigurationBuilder.clientCertificate`
|
||||||
public let clientCertificatePath: String?
|
public let clientCertificate: CryptoContainer?
|
||||||
|
|
||||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.clientKeyPath`
|
/// - Seealso: `SessionProxy.ConfigurationBuilder.clientKey`
|
||||||
public let clientKeyPath: String?
|
public let clientKey: CryptoContainer?
|
||||||
|
|
||||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.compressionFraming`
|
/// - Seealso: `SessionProxy.ConfigurationBuilder.compressionFraming`
|
||||||
public let compressionFraming: CompressionFraming
|
public let compressionFraming: CompressionFraming
|
||||||
|
@ -239,6 +231,41 @@ extension SessionProxy {
|
||||||
public let renegotiatesAfter: TimeInterval?
|
public let renegotiatesAfter: TimeInterval?
|
||||||
|
|
||||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.usesPIAPatches`
|
/// - Seealso: `SessionProxy.ConfigurationBuilder.usesPIAPatches`
|
||||||
public let usesPIAPatches: Bool
|
public let usesPIAPatches: Bool?
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a `SessionProxy.ConfigurationBuilder` to use this configuration as a starting point for a new one.
|
||||||
|
|
||||||
|
- Returns: An editable `SessionProxy.ConfigurationBuilder` initialized with this configuration.
|
||||||
|
*/
|
||||||
|
public func builder() -> SessionProxy.ConfigurationBuilder {
|
||||||
|
var builder = SessionProxy.ConfigurationBuilder(ca: ca)
|
||||||
|
builder.cipher = cipher
|
||||||
|
builder.digest = digest
|
||||||
|
builder.clientCertificate = clientCertificate
|
||||||
|
builder.clientKey = clientKey
|
||||||
|
builder.compressionFraming = compressionFraming
|
||||||
|
builder.tlsWrap = tlsWrap
|
||||||
|
builder.keepAliveInterval = keepAliveInterval
|
||||||
|
builder.renegotiatesAfter = renegotiatesAfter
|
||||||
|
builder.usesPIAPatches = usesPIAPatches
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Equatable
|
||||||
|
|
||||||
|
/// :nodoc:
|
||||||
|
public static func ==(lhs: Configuration, rhs: Configuration) -> Bool {
|
||||||
|
return
|
||||||
|
(lhs.cipher == rhs.cipher) &&
|
||||||
|
(lhs.digest == rhs.digest) &&
|
||||||
|
(lhs.ca == rhs.ca) &&
|
||||||
|
(lhs.clientCertificate == rhs.clientCertificate) &&
|
||||||
|
(lhs.clientKey == rhs.clientKey) &&
|
||||||
|
(lhs.compressionFraming == rhs.compressionFraming) &&
|
||||||
|
(lhs.keepAliveInterval == rhs.keepAliveInterval) &&
|
||||||
|
(lhs.renegotiatesAfter == rhs.renegotiatesAfter) &&
|
||||||
|
(lhs.usesPIAPatches == rhs.usesPIAPatches)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,10 +69,21 @@ public class SessionProxy {
|
||||||
case reconnect
|
case reconnect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct Caches {
|
||||||
|
static let ca = "ca.pem"
|
||||||
|
|
||||||
|
static let clientCertificate = "cert.pem"
|
||||||
|
|
||||||
|
static let clientKey = "key.pem"
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Configuration
|
// MARK: Configuration
|
||||||
|
|
||||||
private let configuration: Configuration
|
private let configuration: Configuration
|
||||||
|
|
||||||
|
/// The optional credentials.
|
||||||
|
public var credentials: Credentials?
|
||||||
|
|
||||||
private var keepAliveInterval: TimeInterval? {
|
private var keepAliveInterval: TimeInterval? {
|
||||||
let interval: TimeInterval?
|
let interval: TimeInterval?
|
||||||
if let negInterval = pushReply?.ping, negInterval > 0 {
|
if let negInterval = pushReply?.ping, negInterval > 0 {
|
||||||
|
@ -143,6 +154,22 @@ public class SessionProxy {
|
||||||
|
|
||||||
private var authenticator: Authenticator?
|
private var authenticator: Authenticator?
|
||||||
|
|
||||||
|
// MARK: Caching
|
||||||
|
|
||||||
|
private let cachesURL: URL
|
||||||
|
|
||||||
|
private var caURL: URL {
|
||||||
|
return cachesURL.appendingPathComponent(Caches.ca)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var clientCertificateURL: URL {
|
||||||
|
return cachesURL.appendingPathComponent(Caches.clientCertificate)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var clientKeyURL: URL {
|
||||||
|
return cachesURL.appendingPathComponent(Caches.clientKey)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Init
|
// MARK: Init
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,9 +178,10 @@ public class SessionProxy {
|
||||||
- Parameter queue: The `DispatchQueue` where to run the session loop.
|
- Parameter queue: The `DispatchQueue` where to run the session loop.
|
||||||
- Parameter configuration: The `SessionProxy.Configuration` to use for this session.
|
- Parameter configuration: The `SessionProxy.Configuration` to use for this session.
|
||||||
*/
|
*/
|
||||||
public init(queue: DispatchQueue, configuration: Configuration) throws {
|
public init(queue: DispatchQueue, configuration: Configuration, cachesURL: URL) throws {
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
self.configuration = configuration
|
self.configuration = configuration
|
||||||
|
self.cachesURL = cachesURL
|
||||||
|
|
||||||
keys = [:]
|
keys = [:]
|
||||||
oldKeys = []
|
oldKeys = []
|
||||||
|
@ -172,10 +200,29 @@ public class SessionProxy {
|
||||||
} else {
|
} else {
|
||||||
controlChannel = ControlChannel()
|
controlChannel = ControlChannel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cache PEMs locally (mandatory for OpenSSL)
|
||||||
|
let fm = FileManager.default
|
||||||
|
try configuration.ca.pem.write(to: caURL, atomically: true, encoding: .ascii)
|
||||||
|
if let container = configuration.clientCertificate {
|
||||||
|
try container.pem.write(to: clientCertificateURL, atomically: true, encoding: .ascii)
|
||||||
|
} else {
|
||||||
|
try? fm.removeItem(at: clientCertificateURL)
|
||||||
|
}
|
||||||
|
if let container = configuration.clientKey {
|
||||||
|
try container.pem.write(to: clientKeyURL, atomically: true, encoding: .ascii)
|
||||||
|
} else {
|
||||||
|
try? fm.removeItem(at: clientKeyURL)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
cleanup()
|
cleanup()
|
||||||
|
|
||||||
|
let fm = FileManager.default
|
||||||
|
for url in [caURL, clientCertificateURL, clientKeyURL] {
|
||||||
|
try? fm.removeItem(at: url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Public interface
|
// MARK: Public interface
|
||||||
|
@ -565,8 +612,8 @@ public class SessionProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func hardResetPayload() -> Data? {
|
private func hardResetPayload() -> Data? {
|
||||||
guard !configuration.usesPIAPatches else {
|
guard !(configuration.usesPIAPatches ?? false) else {
|
||||||
let caMD5 = TLSBox.md5(forCertificatePath: configuration.caPath)
|
let caMD5 = TLSBox.md5(forCertificatePath: caURL.path)
|
||||||
log.debug("CA MD5 is: \(caMD5)")
|
log.debug("CA MD5 is: \(caMD5)")
|
||||||
return try? PIAHardReset(
|
return try? PIAHardReset(
|
||||||
caMd5Digest: caMD5,
|
caMd5Digest: caMD5,
|
||||||
|
@ -606,7 +653,7 @@ public class SessionProxy {
|
||||||
negotiationKey.controlState = .preAuth
|
negotiationKey.controlState = .preAuth
|
||||||
|
|
||||||
do {
|
do {
|
||||||
authenticator = try Authenticator(configuration.credentials?.username, pushReply?.authToken ?? configuration.credentials?.password)
|
authenticator = try Authenticator(credentials?.username, pushReply?.authToken ?? credentials?.password)
|
||||||
try authenticator?.putAuth(into: negotiationKey.tls)
|
try authenticator?.putAuth(into: negotiationKey.tls)
|
||||||
} catch let e {
|
} catch let e {
|
||||||
deferStop(.shutdown, e)
|
deferStop(.shutdown, e)
|
||||||
|
@ -722,9 +769,9 @@ public class SessionProxy {
|
||||||
log.debug("Start TLS handshake")
|
log.debug("Start TLS handshake")
|
||||||
|
|
||||||
negotiationKey.tlsOptional = TLSBox(
|
negotiationKey.tlsOptional = TLSBox(
|
||||||
caPath: configuration.caPath,
|
caPath: caURL.path,
|
||||||
clientCertificatePath: configuration.clientCertificatePath,
|
clientCertificatePath: (configuration.clientCertificate != nil) ? clientCertificateURL.path : nil,
|
||||||
clientKeyPath: configuration.clientKeyPath
|
clientKeyPath: (configuration.clientKey != nil) ? clientKeyURL.path : nil
|
||||||
)
|
)
|
||||||
do {
|
do {
|
||||||
try negotiationKey.tls.start()
|
try negotiationKey.tls.start()
|
||||||
|
|
|
@ -60,11 +60,12 @@ class AppExtensionTests: XCTestCase {
|
||||||
let hostname = "example.com"
|
let hostname = "example.com"
|
||||||
let credentials = SessionProxy.Credentials("foo", "bar")
|
let credentials = SessionProxy.Credentials("foo", "bar")
|
||||||
|
|
||||||
builder = TunnelKitProvider.ConfigurationBuilder(ca: CryptoContainer(pem: "abcdef"))
|
var sessionBuilder = SessionProxy.ConfigurationBuilder(ca: CryptoContainer(pem: "abcdef"))
|
||||||
|
sessionBuilder.cipher = .aes128cbc
|
||||||
|
sessionBuilder.digest = .sha256
|
||||||
|
builder = TunnelKitProvider.ConfigurationBuilder(sessionConfiguration: sessionBuilder.build())
|
||||||
XCTAssertNotNil(builder)
|
XCTAssertNotNil(builder)
|
||||||
|
|
||||||
builder.cipher = .aes128cbc
|
|
||||||
builder.digest = .sha256
|
|
||||||
cfg = builder.build()
|
cfg = builder.build()
|
||||||
|
|
||||||
let proto = try? cfg.generatedTunnelProtocol(withBundleIdentifier: identifier, appGroup: appGroup, hostname: hostname, credentials: credentials)
|
let proto = try? cfg.generatedTunnelProtocol(withBundleIdentifier: identifier, appGroup: appGroup, hostname: hostname, credentials: credentials)
|
||||||
|
@ -81,11 +82,11 @@ class AppExtensionTests: XCTestCase {
|
||||||
|
|
||||||
let K = TunnelKitProvider.Configuration.Keys.self
|
let K = TunnelKitProvider.Configuration.Keys.self
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.appGroup] as? String, appGroup)
|
XCTAssertEqual(proto?.providerConfiguration?[K.appGroup] as? String, appGroup)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.cipherAlgorithm] as? String, cfg.cipher.rawValue)
|
XCTAssertEqual(proto?.providerConfiguration?[K.cipherAlgorithm] as? String, cfg.sessionConfiguration.cipher.rawValue)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.digestAlgorithm] as? String, cfg.digest.rawValue)
|
XCTAssertEqual(proto?.providerConfiguration?[K.digestAlgorithm] as? String, cfg.sessionConfiguration.digest.rawValue)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.ca] as? String, cfg.ca.pem)
|
XCTAssertEqual(proto?.providerConfiguration?[K.ca] as? String, cfg.sessionConfiguration.ca.pem)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.mtu] as? Int, cfg.mtu)
|
XCTAssertEqual(proto?.providerConfiguration?[K.mtu] as? Int, cfg.mtu)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.renegotiatesAfter] as? Int, cfg.renegotiatesAfterSeconds)
|
XCTAssertEqual(proto?.providerConfiguration?[K.renegotiatesAfter] as? TimeInterval, cfg.sessionConfiguration.renegotiatesAfter)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.debug] as? Bool, cfg.shouldDebug)
|
XCTAssertEqual(proto?.providerConfiguration?[K.debug] as? Bool, cfg.shouldDebug)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.debugLogKey] as? String, cfg.debugLogKey)
|
XCTAssertEqual(proto?.providerConfiguration?[K.debugLogKey] as? String, cfg.debugLogKey)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue