SecKeyCreateSignature 从哪里获取钥匙串签名授权对话框的密钥名称?

Where does SecKeyCreateSignature get the key name for Keychain signing authorization dialog?

我注意到 Keychain 中的某些键在 Keychain 签名对话框中的显示方式有所不同,我无法弄清楚为什么有些键以特定方式显示,而另一些则不是。

这里是一些测试代码,使用钥匙串中的身份来签署数据样本位。

 func testCreateSignature() throws {
        
        let query: [String: Any] = [kSecClass as String: kSecClassIdentity,
                                    kSecMatchLimit as String: kSecMatchLimitAll,
                                    kSecReturnAttributes as String: false,
                                    kSecReturnRef as String: true,
                                    kSecReturnData as String: true]
        
        var resultsRef: CFTypeRef?
        let status = SecItemCopyMatching(query as CFDictionary, &resultsRef)
        guard status == errSecSuccess else { throw SecurityError.unhandledError(status: status) }
        
        
        guard let results =  resultsRef as? [[String:Any]] else {
            throw SecurityError.unexpectedCertificateData
        }
        
        let data = Data([0xDE, 0xAD, 0xBE, 0xEF])
        var privateKey: SecKey!

        for result in results {
            
            let secIdentity = result[kSecValueRef as String] as! SecIdentity
            
            try SecIdentityCopyPrivateKey(secIdentity, &privateKey).check()
            
            var error: Unmanaged<CFError>?
            let signature = SecKeyCreateSignature(privateKey, .rsaSignatureMessagePKCS1v15SHA1, data as CFData, &error)!
            if let error = error {
                throw error.takeRetainedValue()
            }

            print(signature)
        }

        
    }

当代码尝试使用 Xcode 安装的密钥之一进行代码签名时,生成的对话框如下所示:

但是,当代码尝试使用我安装的密钥时,无论钥匙串中密钥上的标签是什么,它总是如下所示:

当我的应用程序尝试使用密钥进行签名时,我希望用户看到该应用程序要使用的密钥名称,而不仅仅是通用的“privateKey”,但我找不到此信息可能在哪里存储在密钥上。

我已经检查了身份和私钥的 kSecAttrLabelkSecAttrApplicationLabel 属性,但找不到出现在对话框中的文本。

我找到了。它是钥匙串项的访问控制列表的 属性。参见 'descriptor' param for SecAccessCreate

如果您在导入密钥时没有指定自定义 ACL,它将默认为“privateKey”。

我正在使用 SecPKCS12Import 导入 .pfx 文件。我试图将 options 参数中的 kSecImportExportAccess 键设置为自定义 SecAccess 对象,但它始终会使用默认 ACL 导入。

我最终重构了代码以使用 SecItemImport 而不是导入 .pfx 文件并提供了自定义 SecAccess 实例:

    static func importIdentity(contentsOf url: URL, password: String) throws {
        
        let data = try Data.init(contentsOf: url)
        
        var access: SecAccess!
        try SecAccessCreate("License Key" as CFString, nil, &access).check()
        
        var keychain: SecKeychain!
        var outItems: CFArray?
        let filename: CFString? = url.isFileURL ? url.lastPathComponent as CFString : nil
        var inputFormat: SecExternalFormat = .formatPKCS12
        var itemType: SecExternalItemType = .itemTypeAggregate
        let unmanagedPassword = Unmanaged<AnyObject>.passRetained(password as AnyObject)
        let unmanagedAccess = Unmanaged<SecAccess>.passRetained(access)
        
        var params: SecItemImportExportKeyParameters = SecItemImportExportKeyParameters(version: UInt32(SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION),
                                                      flags: .importOnlyOne,
                                                      passphrase: unmanagedPassword,
                                                      alertTitle: nil,
                                                      alertPrompt: nil,
                                                      accessRef: unmanagedAccess,
                                                      keyUsage: nil,
                                                      keyAttributes: nil)

        try SecKeychainCopyDefault(&keychain).check()
        try SecItemImport(data as CFData, filename, &inputFormat, &itemType, [], &params, keychain, &outItems).check()
   }

如上导入身份将导致在签名对话框中显示“许可证密钥”而不是“privateKey”。