Swift keychain and training profiles

We created an application in swift that uses keychain. The application works fine when running on the device or in the simulator, but cannot access the keychain, provided that Testflight does not provide a new device that has never been installed using Xcode 6.1.

The following is a keychain code snippet:

import UIKit import Security let serviceIdentifier = "com.ourdomain" let kSecClassValue = kSecClass as NSString let kSecAttrAccountValue = kSecAttrAccount as NSString let kSecValueDataValue = kSecValueData as NSString let kSecClassGenericPasswordValue = kSecClassGenericPassword as NSString let kSecAttrServiceValue = kSecAttrService as NSString let kSecMatchLimitValue = kSecMatchLimit as NSString let kSecReturnDataValue = kSecReturnData as NSString let kSecMatchLimitOneValue = kSecMatchLimitOne as NSString class KeychainManager { class func setString(value: NSString, forKey: String) { self.save(serviceIdentifier, key: forKey, data: value) } class func stringForKey(key: String) -> NSString? { var token = self.load(serviceIdentifier, key: key) return token } class func removeItemForKey(key: String) { self.save(serviceIdentifier, key: key, data: "") } class func save(service: NSString, key: String, data: NSString) { var dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! // Instantiate a new default keychain query var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, key, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue]) // Delete any existing items SecItemDelete(keychainQuery as CFDictionaryRef) if data == "" { return } // Add the new keychain item var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil) } class func load(service: NSString, key: String) -> NSString? { // Instantiate a new default keychain query // Tell the query to return a result // Limit our results to one item var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, key, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue]) var dataTypeRef :Unmanaged<AnyObject>? // Search for the keychain items let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef) let opaque = dataTypeRef?.toOpaque() var contentsOfKeychain: NSString? if let op = opaque? { let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue() // Convert the data retrieved from the keychain into a string contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding) } else { return nil } return contentsOfKeychain } } 

After the application was already installed on the device using Xcode 6.1, I noticed that the " serviceIdentifier " - com.ourdomain "was incorrect and the application package identifier did not match, as required during the configuration.

Then I changed the value of " serviceIdentifier " to match the package identifier - " com.ourdomain.appname ", however, the application simply will not work on the device if using Testflight. I am sure that this is due to the fact that the device already has a keychain for the package identifier installed with the wrong identifier, but I can’t figure out how to get around this, either to delete the keychain when the application is deleted, or to get the profile profile of the existing keyring (with invalid id)

Any help would be greatly appreciated. thanks in advance

+5
source share
3 answers

Use the withUnsafeMutablePointer function and the UnsafeMutablePointer struct to retrieve data, as shown below:

 var result: AnyObject? var status = withUnsafeMutablePointer(&result) { SecItemCopyMatching(keychainQuery, UnsafeMutablePointer($0)) } if status == errSecSuccess { if let data = result as NSData? { if let string = NSString(data: data, encoding: NSUTF8StringEncoding) { // ... } } } 

It works great with release build (fastest optimization).

+5
source

Good, so everything in the training profile and key codec was fine. The problem was setting up the Swift compiler! Changing the optimization level for Release from Fastest to None seems to have solved the problem.

enter image description here

+2
source

Changing the quick optimizer works, but is not a good way to solve the problem. As pointed out in the comments, this seems like a bug in a fast compiler with optimizations.

This is not only iOS, the same thing happens on OSX (maybe add a tag to the question). OSStatus is 0 (success), but the link pointer is zero as soon as the optimization is done.

The best workaround is to implement key binding in objective-c or with a wrapper like EMKeychain (OSX only, sorry, t know iOS Wrapper at the moment)

0
source

Source: https://habr.com/ru/post/1204627/


All Articles