Где SecKeyCreateSignature получает имя ключа для диалога авторизации подписи цепочки ключей?

#swift #macos #keychain

#swift #macos #связка ключей

Вопрос:

Я заметил разницу между определенными ключами в связке ключей в отношении того, как они отображаются в диалоговом окне подписи цепочки ключей, и я не могу понять, почему некоторые отображаются определенным образом, а другие — нет.

Вот некоторый тестовый код для использования идентификаторов в цепочке ключей для подписи образца бита данных.

  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, amp;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, amp;privateKey).check()
            
            var error: Unmanaged<CFError>?
            let signature = SecKeyCreateSignature(privateKey, .rsaSignatureMessagePKCS1v15SHA1, data as CFData, amp;error)!
            if let error = error {
                throw error.takeRetainedValue()
            }

            print(signature)
        }

        
    }
 

Когда код пытается использовать один из ключей, установленных Xcode для подписи кода, результирующее диалоговое окно выглядит следующим образом:

подписание с помощью закрытого ключа Apple

Однако, когда код пытается использовать ключ, который я установил, независимо от того, какая метка на ключе в связке ключей, она всегда выглядит так:

подписание другим закрытым ключом

Когда мое приложение пытается использовать ключ для подписи, я бы хотел, чтобы пользователь видел имя ключа, который приложение хочет использовать, вместо обычного «PrivateKey», но я не могу найти, где эта информация может храниться в ключе.

Я проверил kSecAttrLabel и kSecAttrApplicationLabel атрибуты обоих идентификаторов и закрытых ключей и не могу найти текст, который появляется в диалогах.

Комментарии:

1. Я полагаю, что вышеупомянутый создается с использованием сертификата вместо закрытого ключа . Я не слишком уверен в процессе подписания приложения, но я полагаю, что вы создаете CSR с использованием сертификата или создаете сертификат как CA. В любом случае, приведенный выше, вероятно, получает имя из поля сертификата, а не из поля ключа

Ответ №1:

Я нашел это. Это свойство списка управления доступом элемента цепочки ключей. См. Параметр ‘descriptor’ для SecAccessCreate .

Если вы не укажете пользовательский ACL при импорте ключа, по умолчанию он будет «PrivateKey».

Я использовал SecPKCS12Import для импорта .pfx файла. Я попытался установить kSecImportExportAccess ключ в options параметре для пользовательского 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, amp;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(amp;keychain).check()
        try SecItemImport(data as CFData, filename, amp;inputFormat, amp;itemType, [], amp;params, keychain, amp;outItems).check()
   }
 

Импорт идентификатора, как указано выше, приведет к отображению «Лицензионного ключа» в диалоговом окне подписи, а не «PrivateKey».