1 Reply
      Latest reply on Aug 12, 2019 2:14 AM by eskimo
      PetrZacek Level 1 Level 1 (0 points)

        I am try to connect to ikev2 protocol with password authentication. I want to get password from keychain instead of pop up window with access the password for VPN. But i couldn't achieve that.

         

        my configuration VPN profile looks like :

        let passwordReference = Data(KeychainService.loadPassword(service: "Service", account: "myUsername")!.utf8)
        
        let config = NEVPNProtocolIKEv2()
        config.authenticationMethod = NEVPNIKEAuthenticationMethod.none
        config.serverAddress = "serverAddress"
        config.username = "myUsername"
        config.passwordReference = passwordReference
        config.localIdentifier = "localIdentifier"
        config.remoteIdentifier = "remote.identifier"
        config.useExtendedAuthentication = true
        config.deadPeerDetectionRate = .high
        config.disconnectOnSleep = true
        

         

        and keychain looks like:

        import Cocoa
        import Security
        
        let kSecClassValue = NSString(format: kSecClass)
        let kSecAttrAccountValue = NSString(format: kSecAttrAccount)
        let kSecValueDataValue = NSString(format: kSecValueData)
        let kSecClassGenericPasswordValue = NSString(format: kSecClassGenericPassword)
        let kSecAttrServiceValue = NSString(format: kSecAttrService)
        let kSecMatchLimitValue = NSString(format: kSecMatchLimit)
        let kSecReturnDataValue = NSString(format: kSecReturnData)
        let kSecMatchLimitOneValue = NSString(format: kSecMatchLimitOne)
        
        public class KeychainService: NSObject {
            
            class func updatePassword(service: String, account:String, data: String) {
                if let dataFromString: Data = data.data(using: String.Encoding.utf8, allowLossyConversion: false) {
                    
                    // Instantiate a new default keychain query
                    let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, account], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue])
                    
                    let status = SecItemUpdate(keychainQuery as CFDictionary, [kSecValueDataValue:dataFromString] as CFDictionary)
                    
                    if (status != errSecSuccess) {
                        if let err = SecCopyErrorMessageString(status, nil) {
                            print("Read failed: \(err)")
                        }
                    }
                }
            }
            
            
            class func removePassword(service: String, account:String) {
                
                // Instantiate a new default keychain query
                let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, account, kCFBooleanTrue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue])
                
                // Delete any existing items
                let status = SecItemDelete(keychainQuery as CFDictionary)
                if (status != errSecSuccess) {
                    if let err = SecCopyErrorMessageString(status, nil) {
                        print("Remove failed: \(err)")
                    }
                }
                
            }
            
            
            class func savePassword(service: String, account:String, data: String) {
                if let dataFromString = data.data(using: String.Encoding.utf8, allowLossyConversion: false) {
                    
                    // Instantiate a new default keychain query
                    let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, account, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue])
        
                    // Add the new keychain item
                    let status = SecItemAdd(keychainQuery as CFDictionary, nil)
        
                    if (status != errSecSuccess) {    // Always check the status
                        if let err = SecCopyErrorMessageString(status, nil) {
                            print("Write failed: \(err)")
                        }
                    }
                }
                
            }
            
            class func loadPassword(service: String, account:String) -> String? {
                // Instantiate a new default keychain query
                // Tell the query to return a result
                // Limit our results to one item
                let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, account, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
                
                var dataTypeRef :AnyObject?
                
                // Search for the keychain items
                let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
                var contentsOfKeychain: String?
                
                if status == errSecSuccess {
                    if let retrievedData = dataTypeRef as? Data {
                        contentsOfKeychain = String(data: retrievedData, encoding: String.Encoding.utf8)
                    }
                } else {
                    print("Nothing was retrieved from the keychain. Status code \(status)")
                }
        
                
                return contentsOfKeychain    }
            
        }
        

        After i start app and try to connect still showing window wiht authentication password instead of taking from keychain.

        • Re: Connect with NEVPNProtocolIKEv2
          eskimo Apple Staff Apple Staff (12,455 points)

          The first step in analysing any problem involving Personal VPN is to confirm that you have an API problem rather than a VPN problem.  To do this, create and install a VPN configuration profile and test that.  Does it work?

          Note The easiest way create and install such a profile is using Apple Configurator.

          If your configuration profile works but your code fails, the most likely cause of the problem is the way that you’ve set up the credentials.  See this post for some code that does that correctly.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"