Home > Enterprise >  Keychain API is looking only into system keychain not in login keychain Mac OS Swift
Keychain API is looking only into system keychain not in login keychain Mac OS Swift

Time:09-17

I need some help in keychain API. I am searching a certificate in keychain using keychain API in a mac os application. However, it is searching only in system.keychain not in login.keychain. I didn't find any document where i can put or specify keychain in keychain search query. The current code is as below.

func isKeychainhasCert(for sNumber:Data) -> Bool {
      
        var query = [String: AnyObject]()
        query[kSecClass as String] = kSecClassCertificate
        query[kSecAttrSerialNumber as String] = sNumber as CFData
        query[kSecReturnRef as String] = true as CFBoolean
        var queryResult: AnyObject?
        let status = withUnsafeMutablePointer(to: &queryResult, {
            SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
        })
        guard status != errSecItemNotFound else {
            return false
        }
        
        return true
    }

Any help or suggestion. Based on above code the method return only true if cert is present system.keychain. If present in login.keychain but not in system.keychain return false.

CodePudding user response:

This is not an answer, but might shed some light on how to get the certs:

import Foundation
import Security

var result: OSStatus

// Usually, we operate in the "user" domain, check this:
var domain: SecPreferencesDomain = .system
result = SecKeychainGetPreferenceDomain(&domain)
if result == errSecSuccess {
    assert(domain == .user)
}

// Get the list of searched keychains of the current domain:
// (it should include the "default" keychain for the "user" domain)
var searchList: CFArray? = nil
result = SecKeychainCopyDomainSearchList(domain, &searchList)
guard result == errSecSuccess, let searchedKeyChains = searchList as? [SecKeychain] else {
    fatalError("SecKeychainCopyDomainSearchList failed")
}

print("Keychain search list:")
searchedKeyChains.forEach { keyChain in
    print(keyChain)
}
print("")

// Get the default keychain for the current domain:
var defaultKeyChain: SecKeychain? = nil
result = SecKeychainCopyDefault(&defaultKeyChain)
guard result == errSecSuccess, defaultKeyChain != nil else {
    fatalError("SecKeychainCopyDefault failed")
}
print("Default Keychain: \(defaultKeyChain!)")

Up until here, we only did some checks and tests.

Now, search the all certificates in the keychain(s):

// Here, search all "searchable" keychains, by not specifying a
// kSecMatchSearchList value.
var copyResult: CFTypeRef? = nil
result = SecItemCopyMatching([
    kSecClass: kSecClassCertificate,
    kSecMatchLimit: kSecMatchLimitAll,
    kSecReturnRef: true
] as NSDictionary, &copyResult)

guard result == errSecSuccess, let certificates1 = copyResult as? [SecCertificate] else {
    fatalError("unexpected result type: \(copyResult)")
}

Print all found certificates:

certificates1.forEach { cert in
    print(cert)
}

Search only in the "default" keychain for the current domain (which should be .user). We do this, by specifying the kSecMatchSearchList parameter:

// Here, search only the default keychain:
result = SecItemCopyMatching([
    kSecClass: kSecClassCertificate,
    kSecMatchLimit: kSecMatchLimitAll,
    kSecMatchSearchList: [defaultKeyChain] as CFArray,
    kSecReturnRef: true
] as NSDictionary, &copyResult)

guard result == errSecSuccess, let certificates2 = copyResult as? [SecCertificate] else {
    fatalError("unexpected result type: \(copyResult)")
}

Now, lets see what additional certs have been found in any other keychain than the default one:


let diff = Array(Set(certificates1).symmetricDifference(Set(certificates2)))
print("Difference:")

diff.forEach { cert in
    print(cert)
}
print("")

  • Related