CFDictionaryRef issues in Swift

I’m converting some of my older Objective-C code to Swift so I can move away from some deprecated methods but I keep getting a crash and so far I can’t seem to figure out what’s causing it. I’m getting a private key from a P12 Certificate and this method seems to work fine up until I get to the part where I actually need to get the dictionary from the CFArray, and even though the array has values in it the app keeps crashing. Here’s the code that I have :

func privateKeyFromCertificate(p12Name: String, withPassword password: String) -> SecKeyRef {
    let resourcePath: String = NSBundle.mainBundle().pathForResource(p12Name, ofType: "p12")!
    let p12Data: NSData = NSData(contentsOfFile: resourcePath)!
    let key : NSString = kSecImportExportPassphrase as NSString
    let options : NSDictionary = [key : password]

    var privateKeyRef: SecKeyRef? = nil


    var items : CFArray?


    let securityError: OSStatus = SecPKCS12Import(p12Data, options, &items)

    let description : CFString = CFCopyDescription(items)
    print(description)

    if securityError == noErr && CFArrayGetCount(items) > 0 {
        let objects : CFDictionaryRef = CFArrayGetValueAtIndex(items, 0) as! CFDictionaryRef
        let kString : NSString = kSecImportItemIdentity as NSString
        let identity : SecIdentityRef = CFDictionaryGetValue(objects, unsafeAddressOf(kString)) as! SecIdentityRef
        let securityError = SecIdentityCopyPrivateKey(identity, &privateKeyRef)
        if securityError != noErr {
            privateKeyRef = nil
        }
    }
    return privateKeyRef!
}

The app keeps crashing right in the if statement on the first line where I try to get the CFDictiionaryRef from the CFArray. I added the line to print the description of the CFArray as a test and it does have values :

  • Xcode 7 Beta 6, dyld ___NSArray0__ crash
  • Swift: CGPathRelease and ARC
  • iOS start Background Thread
  • How to retrieve the values for the particular key from CFMutableDictionary
  • strong @property with __attribute__((NSObject)) for a CF type doesn't retain
  • Is it safe to schedule and invalidate NSTimers on a GCD serial queue?
  • <CFArray 0x7fd2d2e8c2f0 [0x10b61f7b0]>{type = mutable-small, count = 1, values = (
    0 : <CFBasicHash 0x7fd2d2e8c190 [0x10b61f7b0]>{type = mutable dict, count = 3,entries =>
    0 : <CFString 0x10bfdd2c0 [0x10b61f7b0]>{contents = "trust"} = <SecTrustRef: 0x7fd2d2e8ad30>
    1 : <CFString 0x10bfdd300 [0x10b61f7b0]>{contents = "identity"} = <SecIdentityRef: 0x7fd2d2e80390>
    2 : <CFString 0x10bfdd2e0 [0x10b61f7b0]>{contents = "chain"} = <CFArray 0x7fd2d2d016e0 [0x10b61f7b0]>{type = mutable-small, count = 1, values = (
    0 : <cert(0x7fd2d2e8c610) s: Client (IPHONE-WebService) i:Client (IPHONE-WebService)>)}}
    

    Solutions Collect From Internet About “CFDictionaryRef issues in Swift”

    I ended up changing some things around to get to the data, it’s not the prettiest approach but it worked for me.

    func privateKeyFromCertificate() -> SecKeyRef {
        let certName : String = //name of the certificate//
        //get p12 file path
        let resourcePath: String = NSBundle.mainBundle().pathForResource(certName, ofType: "p12")!
        let p12Data: NSData = NSData(contentsOfFile: resourcePath)!
        //create key dictionary for reading p12 file
        let key : NSString = kSecImportExportPassphrase as NSString
        let options : NSDictionary = [key : "password_for_certificate"]
        //create variable for holding security information
        var privateKeyRef: SecKeyRef? = nil
    
        var items : CFArray?
    
        let securityError: OSStatus = SecPKCS12Import(p12Data, options, &items)
        //let description : CFString = CFCopyDescription(items)
        //print(description)
    
        let theArray : CFArray = items!
    
        if securityError == noErr && CFArrayGetCount(theArray) > 0 {
            let newArray = theArray as [AnyObject] as NSArray
            let dictionary = newArray.objectAtIndex(0)
            let secIdentity = dictionary.valueForKey(kSecImportItemIdentity as String) as! SecIdentityRef
            let securityError = SecIdentityCopyPrivateKey(secIdentity , &privateKeyRef)
            if securityError != noErr {
                privateKeyRef = nil
            }
        }
        return privateKeyRef!
    }