Kuldeep Choudhary
Kuldeep Choudhary

Reputation: 69

SecItemCopyMatching failed: -50 while trying to create a VPN connection programmatically in ios swift

I'm trying to to install the profile to create a VPN connection using Swift. It creates a VPN connection but I'm getting the following error and I'm not able to connect using that VPN connection.

SecItemCopyMatching failed: -50

There is some issue with the keychain save-retrieve data but not getting exactly.

Here is the code:

installVPNProfile(){

    let server: String? = "127.0.0.1"
    let username: String? = "MyServer"
    var _: String? = ""
    var _: String? = ""

    // Save password & psk
    //var password_Data = KeyChain.stringToNSDATA(string:"password")
    keychain.set(("12345").data(using: .utf8)!, forKey: "VPN_PASSWORD")        
    keychain.set(("12345abcde").data(using: .utf8)!, forKey: "PSK")

    vpnManager.loadFromPreferences(completionHandler: {(_ error: Error?) -> Void in
        if error != nil {
            print("Load config failed [\(String(describing: error?.localizedDescription))]")
            return
        }
        var p: NEVPNProtocolIPSec? = (vpnManager.protocolConfiguration as? NEVPNProtocolIPSec)
        if p != nil {
            // Protocol exists.
            // If you don't want to edit it, just return here.
        }
        else {
            // create a new one.
            p = NEVPNProtocolIPSec()
        }
        // config IPSec protocol
        p?.username = username
        p?.serverAddress = server
        p?.passwordReference = self.keychain.getData("VPN_PASSWORD")        // PSK
        p?.authenticationMethod = authentication type
        p?.sharedSecretReference = self.keychain.getData("PSK")
        p?.useExtendedAuthentication = true
        p?.disconnectOnSleep = false
        self.vpnManager.protocolConfiguration = p
        self.vpnManager.localizedDescription = "VPN Demo"
        self.vpnManager.isEnabled = true
        self.vpnManager.saveToPreferences(completionHandler: {(_ error: Error?) -> Void in
            if error != nil {
                print("Save config failed [\(error?.localizedDescription)]")
            }
        })
    })

}

Upvotes: 0

Views: 590

Answers (1)

Marcel
Marcel

Reputation: 6579

The shared secret reference and the password reference should not be the secret data itself, but should be a persistence reference to the data.

When you set the passwordReference, you give it the data that is returned from the getData function:

p?.passwordReference = self.keychain.getData("VPN_PASSWORD")

You do the same when setting the sharedSecretReference. I don't know what code you are using that is wrapping the keychain code, but there should be a function that returns the reference, not the data itself. If your wrapper code doesn't have this function, you should use a Keychain library the does support this, or create it yourself.

You can get this persistent reference when you query the keychain by setting the kSecReturnPersistentRef key to true. The data you get back from this query is then the persistent reference, not the secret. The VPN framework will use this reference to fetch the data from the keychain when starting the VPN connection.

Check out this example how to create and reference secrets for a VPN profile: http://blog.moatazthenervous.com/create-a-key-chain-for-apples-vpn/

Upvotes: 1

Related Questions