The SecKeyCreateSignature method always prompts for the current user's login password.

I downloaded a P12 file (containing a private key) from the company server, and retrieved the private key from this P12 file using a password :

private func loadPrivateKeyFromPKCS12(path: String, password: String) throws -> SecKey? {
     let p12Data: Data
	  do {
		  p12Data = try Data(contentsOf: fileURL)
	  } catch let readError {
		 ...
	  }

	let options: [CFString: Any] = [
		kSecImportExportPassphrase: password as CFString
	]

	var items: CFArray?
	let status = SecPKCS12Import(p12Data as CFData, options as CFDictionary, &items)

	guard status == errSecSuccess  else {
		 throw exception
	}

	var privateKey: SecKey?
		
	let idd = identity as! SecIdentity
	let _ = SecIdentityCopyPrivateKey(idd, &privateKey)
	return privateKey
}

However, when I use this private key to call SecKeyCreateSignature for data signing, a dialog box always pops up to ask user to input the Mac admin password.

What confuses me is that this private key is clearly stored in the local P12 file, and there should be no access to the keychain involved in this process. Why does the system still require the user's login password for signing?

Is it possible to perform silent signing (without the system dialog popping up) in this scenario?

Answered by DTS Engineer in 880078022
this private key is clearly stored in the local P12 file

That’s not the caes, at least on macOS. SecPKCS12Import behaves differently on iOS and macOS:

  • On iOS it imports the PKCS#12 file and gives you back an in-memory digital identity.
  • On macOS, it defaults to importing the PKCS#12 file to the default keychain, and gives you back a digital identity that references that keychain.

If you want the iOS behaviour on macOS, you have to opt it to that by setting kSecImportToMemoryOnly.

Having said that, I’m not sure that continuing to re-import the file is the right option. In general, it’s better to store secrets in the keychain rather than in a .p12 file on disk. But that raises the question of which keychain. I generally recommend the data protection keychain, in which case the path forward is:

  1. Get an in-memory digital identity.
  2. Call SecItemAdd with the kSecUseDataProtectionKeychain to add it to the data protection keychain.

For a detailed explanation of these subtleties, see TN3137 On Mac keychain APIs and implementations.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

this private key is clearly stored in the local P12 file

That’s not the caes, at least on macOS. SecPKCS12Import behaves differently on iOS and macOS:

  • On iOS it imports the PKCS#12 file and gives you back an in-memory digital identity.
  • On macOS, it defaults to importing the PKCS#12 file to the default keychain, and gives you back a digital identity that references that keychain.

If you want the iOS behaviour on macOS, you have to opt it to that by setting kSecImportToMemoryOnly.

Having said that, I’m not sure that continuing to re-import the file is the right option. In general, it’s better to store secrets in the keychain rather than in a .p12 file on disk. But that raises the question of which keychain. I generally recommend the data protection keychain, in which case the path forward is:

  1. Get an in-memory digital identity.
  2. Call SecItemAdd with the kSecUseDataProtectionKeychain to add it to the data protection keychain.

For a detailed explanation of these subtleties, see TN3137 On Mac keychain APIs and implementations.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

The SecKeyCreateSignature method always prompts for the current user's login password.
 
 
Q