I am trying to implement IKEv2 vpn connection on Mac OSX using NetworkExtension framework. Every time I get a popup to enter my vpn connection password. According to NEVPNProtocol specification password can be supplied by providing persistent reference of password stored in keychain. But it doesn't work. I've tried the same IKEv2 configuration code in iOS and it works perfectly.
I wrote a sample application to demonstrate how I do it - https://github.com/kestutisbalt/osx-ikev2-sample
How password is stored in keychain:
class func set(key: String, value: String) {
let query: [NSObject: AnyObject] = [
kSecValueData: value.dataUsingEncoding(NSUTF8StringEncoding)!,
kSecClass: kSecClassGenericPassword,
kSecAttrGeneric: key,
kSecAttrAccount: key,
kSecAttrAccessible: kSecAttrAccessibleAlways,
kSecAttrService: NSBundle.mainBundle().bundleIdentifier!
]
clear(key)
SecItemAdd(query as CFDictionaryRef, nil)
}
How persistent reference is retrieved from keychain:
class func persistentRef(key: String) -> NSData? {
let query: [NSObject: AnyObject] = [
kSecClass: kSecClassGenericPassword,
kSecAttrGeneric: key,
kSecAttrAccount: key,
kSecAttrAccessible: kSecAttrAccessibleAlways,
kSecMatchLimit: kSecMatchLimitOne,
kSecAttrService: NSBundle.mainBundle().bundleIdentifier!,
kSecReturnPersistentRef: kCFBooleanTrue
]
var secItem: AnyObject?
let result = SecItemCopyMatching(query, &secItem)
if result != errSecSuccess {
return nil
}
return secItem as? NSData
}
IKEv2 configuration:
private func createIKEv2Protocol(host: String,
username: String, password: String) -> NEVPNProtocolIKEv2 {
Keychain.set(username, value: password)
let passwordRef = Keychain.persistentRef(username)
if passwordRef == nil {
log("Failed to query password persistent ref")
}
let config = NEVPNProtocolIKEv2()
config.remoteIdentifier = host
config.serverAddress = host
config.useExtendedAuthentication = true
config.username = username
config.passwordReference = passwordRef
return config
}
Apple developer support replied to my question:
The issue with your code is that it’s attempting to set up VPN in an unsupported way. Specifically, IKEv2 VPN does not support password-based authentication. The options you have for IKEv2 are listed in the NEVPNIKEAuthenticationMethod
enum, namely, .Certificate and .SharedSecret.`