Take a cache URL in SessionProxy to store PEMs

This commit is contained in:
Davide De Rosa 2018-10-25 08:18:31 +02:00
parent 3fd0329736
commit 197d29042c
2 changed files with 57 additions and 51 deletions

View File

@ -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,42 +183,6 @@ 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)
@ -239,7 +205,7 @@ open class TunnelKitProvider: NEPacketTunnelProvider {
let proxy: SessionProxy let proxy: SessionProxy
do { do {
proxy = try SessionProxy(queue: tunnelQueue, configuration: sessionConfiguration.build()) proxy = try SessionProxy(queue: tunnelQueue, configuration: sessionConfiguration.build(), cachesURL: cachesURL)
} catch let e { } catch let e {
completionHandler(e) completionHandler(e)
return return
@ -382,10 +348,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)
} }
} }

View File

@ -69,6 +69,14 @@ 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
@ -143,6 +151,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 +175,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 +197,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
@ -566,7 +610,7 @@ public class SessionProxy {
private func hardResetPayload() -> Data? { private func hardResetPayload() -> Data? {
guard !configuration.usesPIAPatches else { guard !configuration.usesPIAPatches 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,
@ -722,9 +766,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()