Search code examples
swift3rsacore-foundation

CFDictionaryCreate crashes in Xcode 8 swift 3


I have the following code for retrieving and storing RSAkeydata

fileprivate func retrieveAndStoreRSAKeyData(isPublic: Bool) throws -> CFData {

    var resultCode = noErr
    var result: CFData
    let value = {
        if isPublic {
            let t = self.publicTag
            print(t)
        }
        else
        {
            let s = self.privateTag
            print(s)
        }
    }
    var keyCallbacks = kCFTypeDictionaryKeyCallBacks
    var valueCallbacks = kCFTypeDictionaryValueCallBacks
    let keys = [Unmanaged.passUnretained(kSecClass).toOpaque(), Unmanaged.passUnretained(kSecAttrApplicationTag).toOpaque(), Unmanaged.passUnretained(kSecAttrKeyType).toOpaque(), Unmanaged.passUnretained(kSecReturnData).toOpaque()]
    let values = [Unmanaged.passUnretained(kSecClassKey).toOpaque(), Unmanaged<AnyObject>.passUnretained(value as AnyObject).toOpaque(), Unmanaged.passUnretained(kSecAttrKeyTypeRSA).toOpaque(), Unmanaged.passUnretained(kCFBooleanTrue).toOpaque()]
    let queryKey = CFDictionaryCreate(kCFAllocatorDefault,UnsafeMutablePointer.allocate(capacity: keys.count),UnsafeMutablePointer.allocate(capacity: values.count), 4, &keyCallbacks, &valueCallbacks)

    // Get the key.
    var item: AnyObject?
    resultCode = SecItemCopyMatching(queryKey!, &item)

    if(resultCode != noErr) {

        try generateKeyPair()
        /*
        Recurcively call the retrieval again after keys have been generated
        */
        result = try retrieveAndStoreRSAKeyData(isPublic: isPublic)
    }
    else {

        result = item as! CFData
    }

    return result
}

The CFDictionaryCreate always fails and code crashes in this line in

     let queryKey = CFDictionaryCreate(kCFAllocatorDefault,UnsafeMutablePointer.allocate(capacity: keys.count),UnsafeMutablePointer.allocate(capacity: values.count), 4, &keyCallbacks, &valueCallbacks)

Can someone help me out on this. Thanks in advance


Solution

  • to generate a key pair

    func generateKeyPair(_ publicTag: String, privateTag: String, keySize: Int)->Bool {
            let privateAttributes = [String(kSecAttrIsPermanent): true,
                                     String(kSecAttrApplicationTag): privateTag] as [String : Any]
            let publicAttributes = [String(kSecAttrIsPermanent): true,
                                    String(kSecAttrApplicationTag): publicTag] as [String : Any]
    
            let pairAttributes = [String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
                                  String(kSecAttrKeySizeInBits): keySize,
                                  String(kSecPublicKeyAttrs): publicAttributes,
                                  String(kSecPrivateKeyAttrs): privateAttributes] as [String : Any]
    
            var publicRef: SecKey?
            var privateRef: SecKey?
            switch SecKeyGeneratePair(pairAttributes as CFDictionary, &publicRef, &privateRef) {
            case noErr: return true
            default: return false
            }
        }
    

    and few helper functions

    func obtainKey(_ tag: String) -> SecKey? {
        var keyRef: AnyObject?
        let query: Dictionary<String, AnyObject> = [
            String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
            String(kSecReturnRef): kCFBooleanTrue as CFBoolean,
            String(kSecClass): kSecClassKey as CFString,
            String(kSecAttrApplicationTag): tag as CFString,
            ]
    
        let status = SecItemCopyMatching(query as CFDictionary, &keyRef)
    
        switch status {
        case noErr:
            if let ref = keyRef {
                return (ref as! SecKey)
            }
        default:
            break
        }
    
        return nil
    }
    
    func obtainKeyData(_ tag: String) -> Data? {
        var keyRef: AnyObject?
        let query: Dictionary<String, AnyObject> = [
            String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
            String(kSecReturnData): kCFBooleanTrue as CFBoolean,
            String(kSecClass): kSecClassKey as CFString,
            String(kSecAttrApplicationTag): tag as CFString,
            ]
    
        let result: Data?
    
        switch SecItemCopyMatching(query as CFDictionary, &keyRef) {
        case noErr:
            result = keyRef as? Data
        default:
            result = nil
        }
    
        return result
    }
    
    func insertPublicKey(_ publicTag: String, data: Data) -> SecKey? {
        let query: Dictionary<String, AnyObject> = [
            String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
            String(kSecClass): kSecClassKey as CFString,
            String(kSecAttrApplicationTag): publicTag as CFString,
            String(kSecValueData): data as CFData,
            String(kSecReturnPersistentRef): true as CFBoolean]
    
        var persistentRef: AnyObject?
        let status = SecItemAdd(query as CFDictionary, &persistentRef)
    
        if status != noErr && status != errSecDuplicateItem {
            return nil
        }
    
        return obtainKey(publicTag)
    }
    
    func deleteKey(_ tag: String) -> Bool {
        let query: Dictionary<String, AnyObject> = [
            String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
            String(kSecClass): kSecClassKey as CFString,
            String(kSecAttrApplicationTag): tag as CFString]
    
        return SecItemDelete(query as CFDictionary) == noErr
    }
    
    func updateKey(_ tag: String, data: Data) -> Bool {
        let query: Dictionary<String, AnyObject> = [
            String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
            String(kSecClass): kSecClassKey as CFString,
            String(kSecAttrApplicationTag): tag as CFString]
    
        return SecItemUpdate(query as CFDictionary, [String(kSecValueData): data] as CFDictionary) == noErr
    }