Unable to configure VPN connection using Network Extension Framework iOS 8 in Swift

So, I'm trying to use the iOS 8 Network Extension Framework to set up a VPN connection when users click on UIButton. I used the following tutorial: http://ramezanpour.net/post/2014/08/03/configure-and-manage-vpn-connections-programmatically-in-ios-8/

But for some reason, it keeps asking for a vpn password and a shared secret. Even if I set the passwordReference and sharedSecretReference. And if I enter this data when installing the profile, it still will not work. It just does nothing when starting a connection using the framework. When trying to connect using the settings application, it gives the error "there not sharedSecret".

This is the code that I use to configure the connection.

func toggleConnection(sender: UIButton) {
    if(!self.connected){
        self.manager.loadFromPreferencesWithCompletionHandler { (error) -> Void in
            if((error) != nil) {
                println("VPN Preferences error: 1")
            }
            else {
                var p = NEVPNProtocolIPSec()
                p.username = "$username"
                p.serverAddress = "$vpn"
                p.passwordReference = KeychainService.dataForKey("vpnPassword")!
                println(p.passwordReference)
                p.authenticationMethod = NEVPNIKEAuthenticationMethod.SharedSecret
                p.sharedSecretReference = KeychainService.dataForKey("sharedSecret")!
                println(p.sharedSecretReference)
                p.localIdentifier = "vpn"
                p.remoteIdentifier = "vpn"
                p.disconnectOnSleep = false


                self.manager.`protocol` = p
                self.manager.onDemandEnabled = true
                self.manager.localizedDescription = "VPN"

                self.manager.saveToPreferencesWithCompletionHandler({ (error) -> Void in
                    if((error) != nil) {
                        println("VPN Preferences error: 2")
                        println(error)
                    }
                    else {
                        var startError: NSError?
                        self.manager.connection.startVPNTunnelAndReturnError(&startError)
                        if((startError) != nil) {
                            println("VPN Preferences error: 3")
                            println(startError)
                        }
                        else {
                            println("Start VPN")
                        }
                    }
                })
            }
        }
    }
}

These are the functions that I use as a link to a link chain.

class func save(service: NSString, key: String, data: NSString) {
    var dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPassword, service, key, dataFromString], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecValueData])

    SecItemDelete(keychainQuery as CFDictionaryRef)

    if data == "" { return }

    var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)
    println(status)
}

class func load(service: NSString, key: String) -> NSData? {
    var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPassword, service, key, kCFBooleanTrue, kSecMatchLimitOne, kCFBooleanTrue], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData, kSecMatchLimit, kSecReturnPersistentRef])

    var dataTypeRef :Unmanaged<AnyObject>?

    let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
    println(status)
    if (status != errSecSuccess) {
        return nil
    }

    let opaque = dataTypeRef?.toOpaque()

    var contentsOfKeychain: NSData? = nil

    if let op = opaque {
        let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
        contentsOfKeychain = retrievedData
    }
    println(contentsOfKeychain)
    return contentsOfKeychain
}

Any help is appreciated!

+4
source share
1 answer

So I had to eventually replace the Swift library that I used to access the keychain with the following Obj-C methods. This solved my problem as far as I can tell.

+ (void) storeData: (NSString * )key data:(NSData *)data {
    NSLog(@"Store Data");
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
    [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
    [dict setObject:data forKey:(__bridge id)kSecValueData];

    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
    if(errSecSuccess != status) {
        NSLog(@"Unable add item with key =%@ error:%d",key,(int)status);
    }
}

+ (NSData *) getData: (NSString *)key {
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
    [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
    [dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    [dict setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnPersistentRef];

    CFTypeRef result = NULL;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);

    if( status != errSecSuccess) {
        NSLog(@"Unable to fetch item for key %@ with error:%d",key,(int)status);
        return nil;
    }

    NSData *resultData = (__bridge NSData *)result;
    return resultData;
}
+2
source

All Articles