What I've found tends to mislead most developers (including myself) is the Data? type of NEVPNProtocol's passwordReference and sharedSecretReference's properties.
As such, we all get started by taking our password strings and generating a Data representation of it using UTF8 encoding: it seems sensible, but that just won't work as the system will not be able to access those secrets when required.
This will cause to one or more of the following symptoms:
- secitemcopymatching failed: -50 (logged in the debugger)
- The Settings app asking to enter the password info when the VPN gets switched ON
- Log lines such as the below in the Console:
failed to create a com.apple.vpn-plugin sandbox extension for /System/Library/Frameworks/NetworkExtension.framework/PluginIKEv2.vpnplugin
What the documentation states, although I admit the API reference docs may be improved to stress this aspect, is that both passwordReference and sharedSecretReference require an object of type Data that is a persistent reference to the keychain item which stores the real password or sharedSecret data. In order to obtain such persistent reference representation, you will need to query the keychain via SecItemCopyMatching and set the kSecReturnPersistantRef entry of the query dictionary to YES.
Below an extract in Objective-C:
NSMutableDictionary* query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService : @"Your service name here",
(__bridge id)kSecAttrAccount : @"Your account name here",
};
query[(__bridge id)kSecReturnPersistentRef] = @YES
__block OSStatus status;
CFTypeRef results = nil;
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &results);
The data obtained in such a way will be a persistent keychain item reference that can be stored in the protocol's passwordReference property and that, once saved via NEVPNManager's saveToPreferences method, can be accessed by the system when required (eg: when the VPN's switch gets toggled).
Hope this helps.