How to list keychains "created" by persistent extension

Hello,

I'm investigating the use of persistent extension to expose certificates and keys to applications. I am investigating on macOS and iOS but I am currently testing on macOS.

I'm able to list the exposed certificate. I thought I could restrict the search to my particular token with kSecAttrTokenID (and the ID I provided to addTokenConfiguration(for: ), e.g. the string "COMPANY-macOS-pext"), but it doesn't work.

So I tried to list all the tokens available from my app, using the following code adapted from SecurityTool:

static func listAllKeychains() {
    listKeychains (ofType: SecPreferencesDomain.user)
    listKeychains (ofType: SecPreferencesDomain.system)
    listKeychains (ofType: SecPreferencesDomain.common)
    listKeychains (ofType: SecPreferencesDomain.dynamic)
  }
   
static func listKeychains (ofType type: SecPreferencesDomain) {
    var searchList: CFArray?
     
    let status = SecKeychainCopyDomainSearchList(type, &searchList)
    if ( status != errSecSuccess) {
      logger.debug("error getting Keychains list : \(status).")
      return
    }

    guard let keychains = searchList as? [SecKeychain] else {
      logger.debug("Error on retrieved keychains")
      return
    }
     
    for keychain in keychains {
      var pName = Array(repeating: 0 as Int8, count: 1024)
      var pLength = UInt32(pName.count)
      let oStatus = SecKeychainGetPath(keychain, &pLength, &pName)
      if oStatus == errSecSuccess {
        let buffer = [UInt8](unsafeBitCast(pName, to: [UInt8].self))
        let name: String = String(bytes: buffer, encoding: .ascii) ?? "Unable to get string"
        logger.debug("Keychain \(keychain.hashValue) : \(name)")
      } else {
        logger.debug("Error getting pathname of keychain \(keychain.hashValue)")
      }
    }
  }

I just get the user keychain and the system keychain.

  • Am I missing something here ?
  • How can I list the keychain provided by the extension ?
  • Is it possible to restrict a search for the items provided by my extension ?

Regards, ++dom

Replies

To partly answer my question,

we are able to restrict the search to a particular TokenID using SecItemCopyMatching and the query:

// pExtBundleIdentifier = Bundle identifier of the pExt
let tokenDriverConfiguration = TKTokenDriver.Configuration.driverConfigurations[pExtBundleIdentifier]

...
// tokenID = a String
let tokenConfig = tokenDriverConfiguration?.addTokenConfiguration(for: tokenID)

...

var query: [String: Any]

...

query[kSecAttrTokenID as String] = pExtBundleIdentifier + ":" + tokenID

...

SecItemCopyMatching(query as CFDictionary, &result)

...

So in the end, we can list all elements related to a particular persistent extension by listing all keychains items, looking for the ones with kSecAttrTokenID attribute and filter against this attribute.

If you have a more straightforward solution, don't hesitate to post it :-)

Regards, ++dom