3 Replies
      Latest reply on Jul 17, 2019 2:01 AM by chrsgrf
      bjhomer Level 1 Level 1 (0 points)

        I'm trying to get a persistent reference for a SecIdentityRef so I can reliably retrieve it later. I've tried a variety of things in the query parameter of SecItemCopyMatching, but I can't get it to work. I know the item exists in the keychain; I just barely called SecItemAdd not long ago. Here's what I've got right now:


        let identityArray: CFArray = [identity] as CFArray
        let query: [CFString: AnyObject] = [kSecClass: kSecClassIdentity,
                                            kSecMatchItemList: identityArray,
                                            kSecReturnPersistentRef: true]
        var _persistentItems: AnyObject?
        let copyResult = SecItemCopyMatching(query, &_persistentItems)
        // copyResult is -50 (errSecParam)


        I've tried the following other queries as well:


        let query = [kSecMatchItemList: selfArray,
                     kSecReturnPersistentRef: true]  // Produces -50 (errSecParam)


        let query = [kSecClass: kSecClassIdentity,
                     kSecValueRef: identity,
                     kSecReturnPersistentRef: true] // Produces -25291 (errSecNotAvailable)


        let query = [kSecValueRef: self,
                     kSecReturnPersistentRef: true] // Produces -25300 (errSecItemNotFound)


        Is it possible to get a persistent keychain ref to a SecIdentityRef on iOS? (For that matter, I need to do the same on OS X, but I've generally found that the OS X APIs are more likely to do what I expect.)

        • Re: iOS: Getting a persistent ref for a SecIdentityRef
          bjhomer Level 1 Level 1 (0 points)

          I've also considered the possibility that because a SecIdentity is a "virtual" object, it might not be possible to get a persistent ref to one. I could instead get a persistent reference to the SecCertificate, but I don't currently know of a way to go from a SecCertificate to a SecIdentity, and I'm relying on having an identity elsewhere.

          • Re: iOS: Getting a persistent ref for a SecIdentityRef
            eskimo Apple Staff Apple Staff (11,655 points)

            In general I prefer to get the persistent ref to the identity as I import it.  Here’s some code that does that:

            func test() {
                let identity = importIdentity()
                var addResult: AnyObject?
                let addErr = SecItemAdd([
                    kSecValueRef as String:            identity,
                    kSecReturnPersistentRef as String:  true
                ], &addResult)
                assert(addErr == errSecSuccess);
                let persistentRef = addResult! as! NSData
                var copyResult: AnyObject?
                let copyErr = SecItemCopyMatching([
                    kSecValuePersistentRef as String:  persistentRef,
                    kSecReturnRef as String:            true
                ], &copyResult)
                assert(copyErr == errSecSuccess)
                let identity2 = copyResult! as! SecIdentity

            If you have an object ref and you want to get a persistent ref, you can do that as well.  For example, just add the following to the end of the code shown above.

            var copyResult2: AnyObject?
            let copyErr2 = SecItemCopyMatching([
                kSecValueRef as String:            identity2,
                kSecReturnPersistentRef as String:  true
            ], &copyResult2)
            assert(copyErr2 == errSecSuccess)
            let persistentRef2 = copyResult2! as! NSData

            If you run this you’ll find that persistentRef and persistentRef2 are the same value.

            Share and Enjoy

            Quinn “The Eskimo!”
            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
            let myEmail = "eskimo" + "1" + "@apple.com"