Keychain: store configurations in keychain instead of providerConfig

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld
2019-02-04 07:37:26 +01:00
parent a26d620f11
commit 8c3557a907
8 changed files with 201 additions and 31 deletions
@@ -12,17 +12,16 @@ enum PacketTunnelProviderError: String, Error {
}
extension NETunnelProviderProtocol {
enum Keys: String {
case wgQuickConfig = "WgQuickConfig"
}
convenience init?(tunnelConfiguration: TunnelConfiguration) {
convenience init?(tunnelConfiguration: TunnelConfiguration, previouslyFrom old: NEVPNProtocol? = nil) {
self.init()
let appId = Bundle.main.bundleIdentifier!
guard let name = tunnelConfiguration.name else { return nil }
guard let appId = Bundle.main.bundleIdentifier else { return nil }
providerBundleIdentifier = "\(appId).network-extension"
providerConfiguration = [Keys.wgQuickConfig.rawValue: tunnelConfiguration.asWgQuickConfig()]
passwordReference = Keychain.makeReference(containing: tunnelConfiguration.asWgQuickConfig(), called: name, previouslyReferencedBy: old?.passwordReference)
if passwordReference == nil {
return nil
}
let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint }
if endpoints.count == 1 {
@@ -35,9 +34,26 @@ extension NETunnelProviderProtocol {
}
func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? {
migrateConfigurationIfNeeded()
guard let serializedConfig = providerConfiguration?[Keys.wgQuickConfig.rawValue] as? String else { return nil }
return try? TunnelConfiguration(fromWgQuickConfig: serializedConfig, called: name)
migrateConfigurationIfNeeded(called: name ?? "unknown")
//TODO: in the case where migrateConfigurationIfNeeded is called by the network extension,
// before the app has started, and when there is, in fact, configuration that needs to be
// put into the keychain, this will generate one new keychain item every time it is started,
// until finally the app is open. Would it be possible to call saveToPreferences here? Or is
// that generally not available to network extensions? In which case, what should our
// behavior be?
guard let passwordReference = passwordReference else { return nil }
guard let config = Keychain.openReference(called: passwordReference) else { return nil }
return try? TunnelConfiguration(fromWgQuickConfig: config, called: name)
}
func destroyConfigurationReference() {
guard let ref = passwordReference else { return }
Keychain.deleteReference(called: ref)
}
func verifyConfigurationReference() -> Data? {
guard let ref = passwordReference else { return nil }
return Keychain.verifyReference(called: ref) ? ref : nil
}
}