Доступ к элементу связки ключей OS X из доверенного приложения

Я создаю связку ключей, а затем добавляю в нее элемент с предопределенным списком доверенных приложений:

SecKeychainCreate([keychainPath UTF8String], (UInt32)strlen(keychainPass), keychainPass, FALSE, NULL, &someKeychain);
OSStatus someStatus = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &list, len, encryptedPass, someKeychain, accessRef, &someKeychainItem);

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

настройки списка контроля доступа

Проблема в том, что когда я пытаюсь прочитать ключ из этой связки ключей через одно из доверенных приложений

SecKeychainUnlock(someKeychain, (UInt32)strlen(keychainPass), keychainPass, TRUE);

UInt32 passwordLen = 0;
void *passData = nil;

const char *cUser_name = [NSUserName() cStringUsingEncoding:NSUTF8StringEncoding];

OSStatus genericPassErr = SecKeychainFindGenericPassword(someKeychain, 0, NULL, strlen(cUser_name), cUser_name, &passwordLen, &passData, NULL);

genericPassErr равно -25293, что означает Error: 0xFFFF9D33 -25293 The user name or passphrase you entered is not correct.

Ранее в коде я запускаю SecKeychainSetUserInteractionAllowed(0), и если я закомментирую эту строку, система запросит у меня разрешение на доступ приложения к связке ключей, и если я его предоставлю, все будет работать нормально. Однако все дело в том, что мне нужно иметь возможность сделать это без запроса пользователя. И я ожидаю, что это будет работать так, как я добавил приложение в ACL. Вы знаете, что я делаю неправильно?

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


person Michał Siwek    schedule 21.06.2014    source источник
comment
Что возвращает SecKeychainUnlock?   -  person tsnorri    schedule 26.06.2014
comment
@TuukkaNorri значение возврата OSStatus равно 0, кажется, все работает нормально.   -  person Michał Siwek    schedule 26.06.2014
comment
1.) Вы перекомпилируете доверенное приложение между добавлением его в ACL и попыткой доступа к созданному элементу? // 2.) Используете ли вы подпись кода?   -  person mvanallen    schedule 27.06.2014
comment
@mvanallen 1) Я нет - я компилирую приложение, которое добавляет себя в ACL, а затем пытается прочитать из цепочки для ключей, но все за один раз. 2) Нет, я не такой, и я бы хотел, чтобы это было так, если это возможно. Однако проблема может заключаться в том, что я перемещаю связку ключей в другое место после ее создания и записи в нее ACL. Я попытаюсь создать его в месте назначения, а не перемещать, но для этого мне потребуются права суперпользователя (мне нужно написать /Library). Что вам кажется лучшим способом запустить SecKeychainCreate от имени пользователя root?   -  person Michał Siwek    schedule 28.06.2014


Ответы (1)


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

Вот код:

#import <Foundation/Foundation.h>
#import <Security/Security.h>

int main()
{
    @autoreleasepool
    {
        SecKeychainRef kc;
        OSStatus status = SecKeychainSetUserInteractionAllowed(false);
        printf("status: %d\n", status);

        status = SecKeychainOpen("/Users/tsnorri/Library/Keychains/test.keychain", &kc);
        printf("status: %d\n", status);

        {
            char const *keychainPass = "test123";
            status = SecKeychainUnlock(kc, (UInt32) strlen(keychainPass), keychainPass, true);
            CFStringRef err = SecCopyErrorMessageString(status, NULL);
            printf("status: %d err: %s\n", status, [(id) err UTF8String]);
            CFRelease(err);
        }

        UInt32 passwordLen = 0;
        void *passData = NULL;

        char const *userName = "tsnorri";
        char const *serviceName = "test";

        {
            SecKeychainItemRef item = NULL;
            status = SecKeychainFindGenericPassword(kc, strlen(serviceName), serviceName, strlen(userName), userName, &passwordLen, &passData, &item);
            CFStringRef err = SecCopyErrorMessageString(status, NULL);
            printf("status: %d err: %s\n", status, [(id) err UTF8String]);
            CFRelease(err);
        }

        printf("pass: %s\n", passData);
    }
    return 0;
}
person tsnorri    schedule 26.06.2014
comment
Похоже, проблема в том, что я перемещаю файл связки ключей в другое место после его создания, но ваш ответ указал мне правильное направление. Спасибо и вот ваши 50pt :) - person Michał Siwek; 30.06.2014