Задачи служб цепочки для ключей OS X

В этой главе описываются и иллюстрирует использование основных функций Keychain Services в OS X. Для использования Keychain Services в iOS посмотрите Задачи iOS Keychain Services.

Функции, описанные в этой главе, включают Вам к:

Понятия Keychain Services обеспечивают введение в понятия и терминологию Keychain Services. Для получения дальнейшей информации обо всех функциях Keychain Services, посмотрите Ссылку Keychain Services.

Добавление простых служб цепочки для ключей к приложению

Большинство приложений должно использовать Keychain Services только, чтобы добавить новый пароль к цепочке для ключей или получить пароль при необходимости. Keychain Services обеспечивает следующих пар функций для того, чтобы выполнить эти задачи:

Вы используете интернет-пароли для доступа к серверам и веб-сайтам по Интернету и универсальным паролям для любой другой защищенной паролем службы (таким как база данных или планирование приложения). Пароли AppleShare (т.е. элементы цепочки для ключей с кодом класса kSecAppleSharePasswordItemClass) сохранены как универсальные пароли.

Функции «находки» получают информацию (атрибуты, или защитите данные) от элемента в цепочке для ключей. «Добавить» функции добавляют элемент к цепочке для ключей. Эти функции вызывают другие функции Keychain Services для выполнения их задач. Поскольку Keychain Services выделяет буферы, в которых возвращаются данные элемента и атрибуты, необходимо вызвать SecKeychainItemFreeContent освободить эти буферы после использования одной из находки функционирует для получения атрибутов или безопасных данных от элемента цепочки для ключей. (Если Keychain Services не находит, что элемент или сбои возвращают какие-либо данные по некоторой другой причине, это не выделяет буферов, и Вы не должны вызывать SecKeychainItemFreeContent функция.)

Рисунок 3-1 показывает блок-схему того, как приложение могло бы использовать эти функции для получения доступа к интернет-Ftp-серверу.

Рисунок 3-1  , Получающий доступ к использованию Интернет-сервера OS X Keychain Services
Accessing an Internet server using Keychain Services

Пользователь приложения запускает путем выбора сервера File Transfer Protocol (FTP). Вызовы приложения SecKeychainFindInternetPassword, передача его приписывает, которые идентифицируют службу и пользователя для поиска. Если пароль находится на цепочке для ключей, функция возвращает пароль приложению, отправляющему его в Ftp-сервер для аутентификации пользователя. Приложение тогда вызывает SecKeychainItemFreeContent освободить буфер данных, выделенный для пароля (отмечают, что Вы не должны вызывать эту функцию, если никакие данные не возвращаются). Если аутентификация успешно выполняется, подпрограмма закончена. Если аутентификация перестала работать, отображения приложения диалоговое окно для запроса имени пользователя и пароля.

Если пароль не находится на цепочке для ключей, то SecKeychainFindInternetPassword возвраты errSecItemNotFound код результата. В этом случае также, отображения приложения диалоговое окно для запроса имени пользователя и пароля. (Это диалоговое окно должно также включать Кнопку отмены, но тот выбор был опущен от фигуры, чтобы препятствовать блок-схеме становиться чрезмерно сложной.)

Получив пароль от пользователя, приложение продолжается для аутентификации пользователя к Ftp-серверу. Когда аутентификация успешно выполнилась, приложение может предположить, что информация, вводимая пользователем, была допустима. Приложение тогда выводит на экран другое диалоговое окно, спрашивая пользователя, сохранить ли пароль на цепочке для ключей. Если пользователь выбирает No, то подпрограмма закончена. Если пользователь выбирает Yes, то приложение вызывает SecKeychainAddInternetPassword функция (если это - новый элемент цепочки для ключей), или SecKeychainItemModifyAttributesAndData функция (для обновления существующего элемента цепочки для ключей) прежде, чем закончить подпрограмму.

Если нет никакой цепочки для ключей, SecKeychainFindInternetPassword или SecKeychainAddInternetPassword функционируйте выводит на экран диалоговое окно, разрешающее пользователю “сбрасывать к значениям по умолчанию” (см. рисунок 1-5), который создает новую названную цепочку для ключей login.keychain с паролем учетной записи пользователя. Если цепочка для ключей заблокирована, функция выводит на экран диалоговое окно, запрашивающее пользователя вводить пароль для разблокирования цепочки для ключей (рисунок 1-6). Пользователь может отменить работу в это время также.

Перечисление 3-1 показывает, как типовое приложение могло бы использовать функции Keychain Services, чтобы получить и установить пароли для универсальных элементов. Можно получить и установить атрибуты элемента цепочки для ключей (такие как имя пользователя или имя службы) использующий эти те же функции; см. Перечисление 3-2 для примера.

Перечисление 3-1  , Добирающееся и устанавливающее пароли в OS X Keychain Services

 
 
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <CoreServices/CoreServices.h>
 
 
//Call SecKeychainAddGenericPassword to add a new password to the keychain:
OSStatus StorePasswordKeychain (void* password,UInt32 passwordLength)
{
    OSStatus status;
    status = SecKeychainAddGenericPassword (
                NULL,            // default keychain
                10,              // length of service name
                "SurfWriter",    // service name
                10,              // length of account name
                "MyUserAcct",    // account name
                passwordLength,  // length of password
                password,        // pointer to password data
                NULL             // the item reference
    );
    return (status);
}
 
//Call SecKeychainFindGenericPassword to get a password from the keychain:
OSStatus GetPasswordKeychain (void **passwordData,UInt32 *passwordLength,
                                                SecKeychainItemRef *itemRef)
{
    OSStatus status1 ;
 
 
    status1 = SecKeychainFindGenericPassword (
                 NULL,           // default keychain
                 10,             // length of service name
                 "SurfWriter",   // service name
                 10,             // length of account name
                 "MyUserAcct",   // account name
                 passwordLength,  // length of password
                 passwordData,   // pointer to password data
                 itemRef         // the item reference
    );
    return (status1);
}
 
//Call SecKeychainItemModifyAttributesAndData to change the password for
// an item already in the keychain:
OSStatus ChangePasswordKeychain (SecKeychainItemRef itemRef)
{
    OSStatus status;
    void * password = "myNewP4sSw0rD";
 
    size_t passwordLength = strlen(password);
    assert(passwordLength <= 0xffffffff);
 
    status = SecKeychainItemModifyAttributesAndData (
                 itemRef,         // the item reference
                 NULL,            // no change to attributes
                 (UInt32)passwordLength,  // length of password
                 password         // pointer to password data
    );
    return (status);
}
 
 
/* ********************************************************************** */
 
int tryIt(void)
{
    OSStatus status;
 
    void * myPassword = "myP4sSw0rD";
 
    size_t myPasswordLength = strlen(myPassword);
    assert(myPasswordLength <= 0xffffffff);
 
    void *passwordData = NULL; // will be allocated and filled in by
                               //SecKeychainFindGenericPassword
    SecKeychainItemRef itemRef = NULL;
 
    UInt32 passwordLength = 0;
 
    // Call SecKeychainFindGenericPassword
    status = GetPasswordKeychain (&passwordData,&passwordLength,&itemRef);
 
    if (status == noErr)       //If call was successful, authenticate user
                                    //and continue.
    {
        //Free the data allocated by SecKeychainFindGenericPassword:
        status = SecKeychainItemFreeContent (
                 NULL,           //No attribute data to release
                 passwordData    //Release data buffer allocated by
                 //SecKeychainFindGenericPassword
        );
    } else if (status == errSecItemNotFound) { //Is password on keychain?
        /*
           If password is not on keychain, display dialog to prompt user
           for name and password.
 
           Authenticate user.
 
           If unsuccessful, prompt user again for name and password.
           If successful, ask user whether to store new password on keychain.
 
           If no, return.
           If yes, store password by calling SecKeychainAddGenericPassword.
        */
        status = StorePasswordKeychain (myPassword,(UInt32)myPasswordLength);
 
        return (status);
    }
 
    /*
       If password is on keychain, authenticate user.
 
       If authentication succeeds, return.
 
       If authentication fails, prompt user for new user name and password and
       authenticate again.
 
       If unsuccessful, prompt again.
       If successful, ask whether to update keychain with new information.
 
       If no, return.
       If yes, store new information by calling SecKeychainItemModifyAttributesAndData.
    */
    status = status ?: ChangePasswordKeychain (itemRef);
    if (itemRef) CFRelease(itemRef);
    return (status);
 
 }

Этот пример следует за той же общей последовательностью, показанной на рисунке 3-1; однако, в отличие от числа, пример иллюстрирует использование универсальных паролей, а не интернет-паролей.

Несмотря на то, что пример в Перечислении 3-1 записан в процедурном C, можно вызвать эти те же функции с помощью Objective C. Перечисление 3-2 показывает, как Вы могли бы создать интернет-элемент пароля, если бы Вы хотели некоторые значения пользовательского атрибута. Обратите внимание на то, что строки атрибута должны все быть закодированы в формате UTF-8.

Усовершенствованные темы

Для большинства приложений нужны только функции Keychain Services, описанные в Adding Simple Keychain Services к Вашему Приложению. Однако при определенных обстоятельствах Вы могли бы хотеть использовать некоторые из других функций, предоставленных Keychain Services. Например, Вы могли бы хотеть вывести на экран пользовательскую метку для своего приложения в утилите Keychain Access. Или, если Вы пишете сервер, Вы могли бы хотеть отключить автоматический дисплей диалоговых окон и вместо этого заботиться о разблокировании цепочки для ключей в Вашем приложении.

Создание пользовательского элемента цепочки для ключей

В этом разделе рассматриваются, как создать элемент цепочки для ключей, если Вы хотите управление низшего уровня, чем предоставлены SecKeychainAddInternetPassword или SecKeychainAddGenericPassword. Например, Вы могли бы хотеть иметь отображение приложения Доступа Цепочки для ключей пользовательская метка для Вашего элемента цепочки для ключей, или Вы могли бы хотеть указать больше чем одно доверяемое приложение, которое может получить доступ к элементу. В частности этот раздел иллюстрирует использование SecKeychainItemCreateFromContent функция для создания элемента цепочки для ключей и SecAccessCreate функционируйте для установки списка доступа. Для получения дополнительной информации об этих и других низкоуровневых функциях, посмотрите Ссылку Keychain Services.

Когда Вы используете SecKeychainAddInternetPassword или SecKeychainAddGenericPassword, функция создает метку для элемента цепочки для ключей автоматически. Для интернет-пароля это использует URL, минус имя схемы, двоеточие и ведущие наклонные черты. Например, метка (выведенный на экран в Поле имени в Доступе Цепочки для ключей) для нового интернет-пароля для URL http://www .apple.com становится www.apple.com. Для универсального пароля функция использует атрибут службы для метки. В обоих случаях, Имя и Где поля в доступе Цепочки для ключей идентичны. Если Вы хотите уникальное имя для элемента цепочки для ключей, отличающегося от URL или имени службы, можно указать метку (kSecLabelItemAttr) припишите, когда Вы вызовете SecKeychainItemCreateFromContent.

SecKeychainAddInternetPassword и SecKeychainAddGenericPassword функции создают первоначальный список доступа для Вас. Этот список доступа по умолчанию включает только одно доверяемое приложение (т.е. одно приложение, которое может получить доступ к элементу цепочки для ключей каждый раз, когда цепочка для ключей разблокирована), а именно, приложение, создавшее элемент цепочки для ключей. SecKeychainItemCreateFromContent функция принимает список доступа как ввод. Однако, если Вы передаете NULL, эта функция создает список доступа, состоящий из единственного приложения, вызывающего функцию. Поэтому необходимо вызвать SecAccessCreate функция прежде, чем вызвать SecKeychainItemCreateFromContent функционируйте, если Вы хотите список доступа больше чем с одним доверяемым приложением. Также можно изменить список доступа существующего элемента цепочки для ключей; посмотрите Изменение Списка доступа Существующего Элемента Цепочки для ключей.

Перечисление 3-2 иллюстрирует создание интернет-элемента цепочки для ключей с пользовательской меткой и списком доступа, включающим два доверяемых приложения. Это перечисление также иллюстрирует использование Keychain Services API из приложения Objective C.

Перечисление 3-2  , Создающее элемент цепочки для ключей с пользовательскими атрибутами

#import <Foundation/Foundation.h>
 
#include <Security/Security.h>
 
SecAccessRef createAccess(NSString *accessLabel)
{
    OSStatus err;
    SecAccessRef access=nil;
    NSArray *trustedApplications=nil;
 
    //Make an exception list of trusted applications; that is,
    // applications that are allowed to access the item without
    // requiring user confirmation:
    SecTrustedApplicationRef myself, someOther;
 
    //Create trusted application references; see SecTrustedApplications.h:
    err = SecTrustedApplicationCreateFromPath(NULL, &myself);
    err = err ?: SecTrustedApplicationCreateFromPath("/Applications/Mail.app",
                                                            &someOther);
 
    if (err == noErr) {
        trustedApplications = [NSArray arrayWithObjects:(__bridge_transfer id)myself,
                                                    (__bridge_transfer id)someOther, nil];
    }
 
    //Create an access object:
    err = err ?: SecAccessCreate((__bridge CFStringRef)accessLabel,
                            (__bridge CFArrayRef)trustedApplications, &access);
    if (err) return nil;
 
    return access;
}
 
 
OSStatus addInternetPassword(NSString *password, NSString *account,
                    NSString *server, NSString *itemLabel, NSString *path,
                    SecProtocolType protocol, int port)
{
    OSStatus err;
    SecKeychainItemRef item = nil;
    const char *pathUTF8 = [path UTF8String];
    const char *serverUTF8 = [server UTF8String];
    const char *accountUTF8 = [account UTF8String];
    const char *passwordUTF8 = [password UTF8String];
    const char *itemLabelUTF8 = [itemLabel UTF8String];
 
    //Create initial access control settings for the item:
    SecAccessRef access = createAccess(itemLabel);
 
    //Following is the lower-level equivalent to the
    // SecKeychainAddInternetPassword function:
 
    assert(strlen(itemLabelUTF8) <= 0xffffffff);
    assert(strlen(accountUTF8) <= 0xffffffff);
    assert(strlen(serverUTF8) <= 0xffffffff);
    assert(strlen(pathUTF8) <= 0xffffffff);
 
    //Set up the attribute vector (each attribute consists
    // of {tag, length, pointer}):
    SecKeychainAttribute attrs[] = {
        { kSecLabelItemAttr, (UInt32)strlen(itemLabelUTF8), (char *)itemLabelUTF8 },
        { kSecAccountItemAttr, (UInt32)strlen(accountUTF8), (char *)accountUTF8 },
        { kSecServerItemAttr, (UInt32)strlen(serverUTF8), (char *)serverUTF8 },
        { kSecPortItemAttr, sizeof(int), (int *)&port },
        { kSecProtocolItemAttr, sizeof(SecProtocolType),
                                        (SecProtocolType *)&protocol },
        { kSecPathItemAttr, (UInt32)strlen(pathUTF8), (char *)pathUTF8 }
    };
    SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]),
                                            attrs };
 
 
    assert(strlen(passwordUTF8) <= 0xffffffff);
 
    err = SecKeychainItemCreateFromContent(
        kSecInternetPasswordItemClass,
        &attributes,
        (UInt32)strlen(passwordUTF8),
        passwordUTF8,
        NULL, // use the default keychain
        access,
        &item);
 
    if (access) CFRelease(access);
    if (item) CFRelease(item);
 
    return err;
}
 
 
int tryAdd(void)
{
         //Add an example password to the keychain:
    return addInternetPassword(@"sample password", @"sample account",
            @"samplehost.apple.com", @"sampleName", @"cgi-bin/bogus/testpath",
                                                kSecProtocolTypeHTTP, 8080);
}

Изменение списка доступа существующего элемента цепочки для ключей

По умолчанию список доступа элемента цепочки для ключей содержит только приложение, создавшее элемент цепочки для ключей. Перечисление 3-2 иллюстрирует создание интернет-элемента цепочки для ключей со списком доступа, включающим два доверяемых приложения. Перечисление 3-3 иллюстрирует, как изменить существующий элемент цепочки для ключей. Перечисление находит определенный элемент цепочки для ключей, извлекает объект доступа, включая список доверяемых приложений, тегов авторизации и другой информации (см. Записи ACL), добавляет доверяемое приложение на список, перераспределяет объект доступа и записывает новый объект доступа обратно к элементу цепочки для ключей. Несмотря на то, что эта выборка иллюстрирует изменение списка доверяемых приложений, можно использовать подобную последовательность, чтобы изменить любую информацию в объекте доступа — например, добавить или удалить тег авторизации.

Перечисление 3-3 запускается путем вызова SecKeychainSearchCreateFromAttributes функция для создания поисковой ссылки. В этом примере код ищет элемент цепочки для ключей своей меткой (как замечено в приложении Доступа Цепочки для ключей); можно искать другие атрибуты, однако, такие как дата модификации. Используя эту поисковую ссылку, демонстрационные вызовы SecKeychainSearchCopyNext найти элемент цепочки для ключей.

Перечисляющие следующие вызовы SecKeychainItemCopyAccess получать объект доступа элемента цепочки для ключей. Как обсуждено в Средствах управления доступом Цепочки для ключей, объект доступа включает одну или более записей ACL. Перечисление вызывает SecAccessCopySelectedACLList функция и передачи это значение тега авторизации CSSM_ACL_AUTHORIZATION_DECRYPT. Этот тег авторизации является одним из тегов, обычно связанных со списком доступа, используемым для секретных операций, и является списком, выведенным на экран приложением Доступа Цепочки для ключей. Для получения всех записей ACL для объекта доступа используйте SecAccessCopyACLList функция вместо этого.

SecAccessCopySelectedACLList функционируйте возвращает объект CFArrayRef, содержащий все записи ACL, встречающие критерии выбора. В этом случае код предполагает, что должна быть только одна запись ACL, использующая CSSM_ACL_AUTHORIZATION_DECRYPT тег. Перечисление вызывает CFArrayGetValues функция для создания массива C SecACLRef объекты от CFArrayRef и затем вызывают SecACLCopySimpleContents функция, передавая его первое (и по-видимому только) элемент в массиве. SecACLCopySimpleContents функция также получает CFArrayRef, содержащий список доверяемых приложений, строки описания элемента цепочки для ключей и быстрого селекторного флага. Эти значения необходимы для перераспределения записи ACL после добавления доверяемого приложения на список.

Затем, перечисление использует CFArrayGetValues функционируйте снова, на сей раз для извлечения массива доверяемых приложений от CFArrayRef. Перечисление вызывает SecTrustedApplicationCreateFromPath функция для создания нового доверяемого объекта приложения, добавляет новое приложение к списку и вызовы CFArrayCreate создать новый CFArrayRef.

Прежде, чем добавить новую запись ACL в объект доступа, перечисление вызывает SecACLGetAuthorizations функция для получения списка авторизации тегирует от старого объекта доступа. Затем извлекая всю информацию из старой записи ACL, код вызывает SecACLRemove функция для удаления старой записи ACL из объекта доступа. Перечисление тогда вызывает SecACLCreateFromSimpleContents функция для создания новой записи ACL для объекта доступа. Эта функция автоматически добавляет запись в объект доступа; с этой целью нет никакого отдельного вызова. Новая запись ACL имеет только список авторизации по умолчанию, однако, таким образом, перечисление вызывает SecACLSetAuthorizations функция, передающая в списке авторизации, извлечена из старой записи ACL.

Объект доступа теперь завершен с новой записью ACL, содержащей все доверяемые приложения в старой записи плюс новая, добавленная здесь. Только два шага остаются: Во-первых, перечисление вызывает SecKeychainItemSetAccess функционируйте для замены объекта доступа в элементе цепочки для ключей с новым объектом доступа; тогда перечисление вызывает CFRelease функция для каждого базового объекта основы, который больше не необходим для выпуска памяти.

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

Перечисление 3-3  , Изменяющее список доступа элемента цепочки для ключей

#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <CoreServices/CoreServices.h>
 
 
//Get an ACL out of a CFArray:
SecACLRef GetACL (CFIndex numACLs, CFArrayRef ACLList,
                CFArrayRef *applicationList, CFStringRef *description,
                SecKeychainPromptSelector *promptSelector)
{
    OSStatus status;
    //Because we limited our search to ACLs used for decryption, we
    // expect only one ACL for this item. Therefore, we extract the
    // application list from the first ACL in the array.
    const SecACLRef acl = (SecACLRef) CFArrayGetValueAtIndex(ACLList, 0);
    status = SecACLCopyContents (
        acl,                    // the ACL from which to extract
                                //  the list of trusted apps
        applicationList,        // the list of trusted apps
        description,            // the description string
        promptSelector          // the value of the prompt selector flag
                                        );
 
    if (status == noErr) {
        return acl;
    } else {
        return NULL;
    }
}
 
 
int modifyTheACL(void)
{
    OSStatus status;
 
    SecKeychainSearchRef searchReference = NULL;
    SecKeychainItemRef itemRef = NULL;
 
    SecAccessRef itemAccess = NULL;
    SecACLRef oldACL = NULL, newACL = NULL;
 
    CFIndex arrayCount;
    CFRange arrayRange;
    SecTrustedApplicationRef trustedAppArray[10];
    SecKeychainPromptSelector promptSelector;
    CFStringRef description = NULL;
    CFArrayRef newTrustedAppArray = NULL;
 
    const char *path = "/Applications/Mail.app";       //path to
                                        // trusted app to add to ACL
    SecTrustedApplicationRef trustedApp = NULL;
 
    /* Construct a search dictionary to find the desired item. */
    const void *keys[] = {
    	kSecAttrLabel,
        kSecReturnRef, /* return the item. */
        NULL
    };
    const void *values[] = {
        /* kSecAttrLabel => */ CFSTR("www.TestItem.com"),
        /* kSecReturnRef => */ kCFBooleanTrue,
        NULL
    };
 
    CFDictionaryRef searchDict = CFDictionaryCreate(kCFAllocatorDefault,
        keys,
        values,
        sizeof(keys) / sizeof(keys[0]),
        &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 
     CFArrayRef aclList = NULL;
     CFIndex numACLs = 0;
     CFArrayRef applicationList;
     CFTypeRef authorizationTag =
        kSecACLAuthorizationDecrypt;  // the authorization tag
                                        //  to search for.
 
     // Find the keychain item and obtain a keychain item reference object.
    // This returns a SecKeychainItemRef, which we must release when
    //  we're finished using it.
    status = SecItemCopyMatching(searchDict, (CFTypeRef *)&itemRef);
 
    if (status == noErr)
        {
        // Obtain the access reference object for the keychain item.
        // This returns a SecAccessRef, which we must release when
        //  we're finished using it.
        status = SecKeychainItemCopyAccess (itemRef, &itemAccess);
        // Obtain an array of ACL entry objects for the access object.
        // Limit the search to ACL entries with the specified
        //  authorization tag.
        aclList = SecAccessCopyMatchingACLList(itemAccess,
                                     authorizationTag);
        numACLs = CFArrayGetCount (aclList);
        // Extract the ACL entry object from the array of ACL entries,
        //  along with the ACL entry's list of trusted applications,
        //  its description, and its prompt selector flag setting.
        // This returns a SecACLRef and a CFArrayRef, which we must
        //  release we're finished using them.
        oldACL = GetACL (numACLs, aclList, &applicationList,
                                    &description, &promptSelector);
        if (oldACL) { CFRetain(oldACL); }
        arrayCount = CFArrayGetCount (applicationList);
 
        //  The application list is a CFArray.  Extract the list of
        //  applications from the CFArray.
        arrayRange.location = (CFIndex) 0;
        arrayRange.length = arrayCount;
        CFArrayGetValues (applicationList, arrayRange,
                                            (void *) trustedAppArray);
        // Create a new trusted application reference object for
        //  the application to be added to the list.
        status = status ?: SecTrustedApplicationCreateFromPath (path, &trustedApp);
        if (status == noErr)   // the function fails if the application is
                                // not found.
        {
            // Append the new application to the array and create a
            //  new CFArray.
            trustedAppArray[arrayCount] = trustedApp;
            newTrustedAppArray = CFArrayCreate (NULL,
                                (void *)trustedAppArray, arrayCount+1,
                                                &kCFTypeArrayCallBacks);
            // Get the authorizations from the old ACL.
            CFArrayRef authorizations = SecACLCopyAuthorizations(oldACL);
 
            // Delete the old ACL from the access object. The user is
            // prompted for permission to alter the keychain item.
            status = status ?: SecACLRemove (oldACL);
 
            // Create a new ACL with the same attributes as the old
            // one, except use the new CFArray of trusted applications.
            status = status ?: SecACLCreateWithSimpleContents (itemAccess,
                        newTrustedAppArray, description, promptSelector,
                                                            &newACL);
            // Set the authorizations for the new ACL to be the same as
            //  those for the old ACL.
            status = status ?: SecACLUpdateAuthorizations (newACL, authorizations);
 
            // Replace the access object in the keychain item with the
            //  new access object. The user is prompted for permission
            //  to alter the keychain item.
            status = status ?: SecKeychainItemSetAccess (itemRef, itemAccess);
 
            CFRelease(authorizations);
        }
        else {
            // Handle the error if the application was not found.
            // ...
        }
 
    // Release the objects we allocated or retrieved
    if (searchReference)
        CFRelease(searchReference);     //SecKeychainSearchRef
    if (itemRef)
        CFRelease(itemRef);             //SecKeychainItemRef
    if (itemAccess)
        CFRelease(itemAccess);          //SecAccessRef
    if (oldACL)
        CFRelease(oldACL);              //SecACLRef
    if (newACL)
        CFRelease(newACL);              //SecACLRef
    if (description)
        CFRelease(description);         //CFStringRef
    if (newTrustedAppArray)
        CFRelease(newTrustedAppArray);  //CFArrayRef
    if (trustedApp)
        CFRelease(trustedApp);          //SecTrustedApplicationRef
    if (aclList)
        CFRelease(aclList);             //CFArrayRef
    if (applicationList)
        CFRelease(applicationList);     //CFArrayRef
    }
    return (status);
 
}

Серверы и цепочка для ключей

Несколько функций Keychain Services автоматически выводят на экран диалоговое окно, запрашивающее, чтобы пользователь разблокировал цепочку для ключей или создал новую цепочку для ключей при необходимости. Keychain Services также выводит на экран диалоговые окна, чтобы подтвердить, что пользователь хочет, чтобы приложение получило доступ к цепочке для ключей (рисунок 3-2) и по другим причинам. Если Вы пишете серверное приложение, которое должно работать необслуживаемый, Вы могли бы хотеть отключить автоматический дисплей диалоговых окон и программно разблокировать или создать цепочки для ключей.

Рисунок 3-2  Подтверждает диалоговое окно доступа
Confirm access dialog

Используйте SecKeychainSetUserInteractionAllowed функция, чтобы включить или отключить автоматический дисплей диалоговых окон. Когда Вы вызываете эту функцию со значением FALSE для state параметр, любые функции Keychain Services, обычно открывающие диалоговые окна вместо этого, сразу возвращается с результатом errSecInteractionRequired. Можно использовать SecKeychainGetStatus функция, чтобы узнать, существует ли цепочка для ключей и разблокирована. Можно тогда использовать SecKeychainUnlock функция для разблокирования цепочки для ключей, или SecKeychainCreate функция для создания новой цепочки для ключей, по мере необходимости.

Добавление, удаляя и работая с ключами и сертификатами

В дополнение к паролям цепочка для ключей может также содержать ключи шифрования и сертификаты. При работе с ключами и сертификатами, необходимо использовать следующие функции:

Для примеров этих функций посмотрите Задачи iOS Keychain Services. Можно также узнать больше об этих функциях в Сертификате, Ключе и Руководстве по программированию Trust Services.