How to add SecIdentityRef to keychain using swift

I am reading a p12 file and obtaining a SecIdentityRef and then add this Identity to keychain as follows



let certData:NSData = NSFileManager.defaultManager().contentsAtPath(filePath)!

let passDictionary:NSMutableDictionary = NSMutableDictionary()

passDictionary.setValue("pass",

forKey: kSecImportExportPassphrase as String)

print(kSecImportExportPassphrase as String)

var items: CFArray?

let error = SecPKCS12Import(certData, passDictionary, &items)

let unwrappedItems:CFArray = items!

if error == noErr && CFArrayGetCount(items) > 0{

let certChain = unwrappedItems as [AnyObject] as NSArray

let certificateDict = certChain.objectAtIndex(0)

var privateKeyRef : SecKeyRef? = nil

var certificateRef: SecCertificate? = nil

let secIdentity:SecIdentityRef = certificateDict.valueForKey(kSecImportItemIdentity as String) as! SecIdentityRef

let subject:NSString=SecCertificateCopySubjectSummary(certificateRef!)


let keyChainQuery:NSMutableDictionary = NSMutableDictionary(

objects: [String(kSecClassIdentity),subject,kCFBooleanTrue,String(kSecAttrAccessibleAlwaysThisDeviceOnly),secIdentity],

forKeys: [String(kSecClass),String(kSecAttrLabel), String(kSecAttrCanSign),String(kSecAttrAccessible),String(kSecValueRef)])

let status:OSStatus = SecItemAdd(keyChainQuery as CFDictionaryRef, nil)



This seems to work fine and returns 0 as status code, but when I try to read this item from the keychain:



var identity: AnyObject?

let searchQuery: NSMutableDictionary = NSMutableDictionary(objects: [String(kSecClassIdentity), kCFBooleanTrue], forKeys: [String(kSecClass),String(kSecReturnRef)])

let status:OSStatus = SecItemCopyMatching(searchQuery as CFDictionaryRef, &identity)





I receive a -25300 error code (not found item) and nil in identity, I am using iOS 9.1 as base SDK, what am I doing wrong?

Answered by DTS Engineer in 86646022

I’m not sure what’s going on with your code—I found it quite hard to understand given the lack of formatting and your use of

+dictionaryWithObjects:keys:
—but here’s how I’d do this (built with Xcode 7.1, tested on iOS 9.1).
func identityForImportedPKCS12Data(pkcs12Data: NSData, password: String) throws -> SecIdentity {
    func securityThrower(err: OSStatus) throws {
        if err != errSecSuccess {
            throw NSError(domain: NSOSStatusErrorDomain, code: Int(err), userInfo: nil)
        }
    }

    var importResult: CFArray? = nil
    try securityThrower( SecPKCS12Import(pkcs12Data, [
        kSecImportExportPassphrase as String: password
    ] as CFDictionary, &importResult) )
    let dictionaries = importResult! as NSArray as! [[String:AnyObject]]
    let identity = dictionaries.first![kSecImportItemIdentity as String] as! SecIdentity

    let label = NSUUID().UUIDString
    try securityThrower( SecItemAdd([
        kSecAttrLabel as String:    label,
        kSecValueRef as String:    identity
    ] as CFDictionary, nil) )

    var copyResult: AnyObject? = nil
    try securityThrower( SecItemCopyMatching([
        kSecClass as String:        kSecClassIdentity,
        kSecAttrLabel as String:    label,
        kSecReturnRef as String:    true
    ], &copyResult) )
    let copiedIdentity = copyResult as! SecIdentity

    return copiedIdentity
}

Note that I’ve labelled the identity with a UUID rather than the subject summary because there’s no guarantee that the subject summary will be unique.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Accepted Answer

I’m not sure what’s going on with your code—I found it quite hard to understand given the lack of formatting and your use of

+dictionaryWithObjects:keys:
—but here’s how I’d do this (built with Xcode 7.1, tested on iOS 9.1).
func identityForImportedPKCS12Data(pkcs12Data: NSData, password: String) throws -> SecIdentity {
    func securityThrower(err: OSStatus) throws {
        if err != errSecSuccess {
            throw NSError(domain: NSOSStatusErrorDomain, code: Int(err), userInfo: nil)
        }
    }

    var importResult: CFArray? = nil
    try securityThrower( SecPKCS12Import(pkcs12Data, [
        kSecImportExportPassphrase as String: password
    ] as CFDictionary, &importResult) )
    let dictionaries = importResult! as NSArray as! [[String:AnyObject]]
    let identity = dictionaries.first![kSecImportItemIdentity as String] as! SecIdentity

    let label = NSUUID().UUIDString
    try securityThrower( SecItemAdd([
        kSecAttrLabel as String:    label,
        kSecValueRef as String:    identity
    ] as CFDictionary, nil) )

    var copyResult: AnyObject? = nil
    try securityThrower( SecItemCopyMatching([
        kSecClass as String:        kSecClassIdentity,
        kSecAttrLabel as String:    label,
        kSecReturnRef as String:    true
    ], &copyResult) )
    let copiedIdentity = copyResult as! SecIdentity

    return copiedIdentity
}

Note that I’ve labelled the identity with a UUID rather than the subject summary because there’s no guarantee that the subject summary will be unique.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank you for your answer eskimo, I tried your code and it works in all simulators with version greater than deployment taget (8.1) and in real device with 9.1, but it's still failing in a real iPhone with 8.4.1 version, do you have any idea of what's happening??


Thank You!!

Finally I solved the problem Uninstalling the app and performing a SecItemmDelete to all Identity refetences, I hope this helps to anyone with the same problem Thank You!!

How to add SecIdentityRef to keychain using swift
 
 
Q