документация по SecPKCS12Import гласит следующее:

[…] Затем вы можете использовать API служб связки ключей (см. Справочник служб связки ключей), чтобы поместить удостоверения и связанные сертификаты в связку ключей.

Это означает, что элементы, возвращенные в аргументе «items» (3-й аргумент этой функции), не должны автоматически добавляться в цепочку для ключей. Однако я обнаружил, что эти элементы автоматически добавляются в связку ключей при использовании этой функции. Если я попытаюсь добавить их с помощью SecItemAdd, я получу errSecDuplicateItem.

Это ошибка или должно быть так? Почему элементы добавляются автоматически?

Вот пример кода:

NSDictionary *options = [[NSDictionary alloc] initWithObjectsAndKeys:@"password", (id)kSecImportExportPassphrase, nil];
CFArrayRef items_ = NULL;
OSStatus ret = SecPKCS12Import((CFDataRef)pkcs12data /* get this from somewhere … */, (CFDictionaryRef)options, &items_);

Если вы воспользуетесь этим кодом, а затем откроете Keychain Access, вы увидите, что сертификат и закрытый ключ были добавлены в связку ключей.

С уважением, Дэвид.

4
David Murray 17 Окт 2015 в 02:45

2 ответа

Лучший ответ

Похоже, что документация Apple может быть устаревшей для этой ссылки (SecPKCS12Import), потому что эта ссылка https://developer.apple.com/library/ios/qa/qa1745/_index.html упоминает, что" чтение большого двоичного объекта в формате PKCS # 12 с последующим импортом содержимого большого двоичного объекта в связку ключей приложения с помощью функции SecPKCS12Import ... "

Судя по датам редакции документа, QA1745 является более свежим, чем Справочник по службам сертификатов, ключей и доверия.

2
satishmaha 16 Мар 2016 в 23:50

SecPKCS12Import НЕ добавляет элементы в связку ключей. Однако он БУДЕТ искать в связке ключей, есть ли там импортированные элементы. Если он найдет существующие элементы, они будут возвращены для SecIdentityRef (SecCertificateRef and SecKeyRef). Вот почему вы можете получить errSecDuplicateItem при вызове SecItemAdd после вызова SecPKCS12Import.

При отладке вы можете удалить все в вашей связке ключей, используя следующий код:

void _EraseKeychain()
{
    NSMutableArray *toDelete = [NSMutableArray array];
    NSArray *classes = @[(__bridge id)kSecClassCertificate,
                         (__bridge id)kSecClassKey,
                         (__bridge id)kSecClassIdentity,
                         (__bridge id)kSecClassInternetPassword,
                         (__bridge id)kSecClassGenericPassword];
    NSMutableDictionary *query = [NSMutableDictionary dictionary];
    query[(id)kSecClass] = (__bridge id)kSecClassIdentity;
    query[(id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
    query[(id)kSecReturnPersistentRef] = @YES;
    id class;
    for( class in classes )
    {
        query[(__bridge id)kSecClass] = class;
        CFTypeRef items = nil;
        OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)query, &items);
        if( result == errSecSuccess )
        {
            [toDelete addObjectsFromArray:(__bridge NSArray*)items];
            CFRelease(items);
        }
    }
    id deleteRef;
    for( deleteRef in toDelete )
    {
        NSString *objectKind = @"unknown";
        if( CFGetTypeID(deleteRef) == CFDataGetTypeID() )
        {
            objectKind = [[NSString alloc] initWithUTF8String:(char *)[(__bridge NSData*)deleteRef bytes]];
        }
        NSDictionary *delRequest = @{(id)kSecValuePersistentRef:deleteRef};
        OSStatus deleteResult = SecItemDelete((__bridge CFDictionaryRef)delRequest);
        if( deleteResult == errSecSuccess )
            NSLog(@"Deleted item(%@) with persistent ref %@", objectKind, deleteRef);
        else if( deleteResult == errSecItemNotFound )
            NSLog(@"Already deleted item(%@) with persistent ref %@", objectKind, deleteRef);
        else
            NSLog(@"Can't delete keychain item(%@) with persistent ref %@", objectKind, deleteRef);
    }
}
-1
Paul Nelson 9 Сен 2016 в 19:56