Резюме
У меня есть файл p12, который я импортирую в свое приложение. Я хочу сохранить сертификат вместе с его идентификацией на цепочке для ключей. Этот сертификат будет использоваться для аутентификации на сервере с использованием аутентификации сертификата клиента TLS.
Я изо всех сил пытался сохранить сертификат и личность в связке ключей. Насколько я понимаю, личность является его личным ключом сертификата.
Я использовал документацию Apple, чтобы помочь мне, но она не работает, как ожидалось.
Приведенный ниже код основан на документах Apple Хранение сертификатов и Хранение удостоверений
Хранение кода
//Storing a Certificate Identity
if(CFDictionaryContainsKey(pkcs12Contents, kSecImportItemIdentity))
{
//Grab the identity from the dictionary
SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(pkcs12Contents, kSecImportItemIdentity);
CFRetain(identity);
NSDictionary* dict = @{ (id)kSecClass: (id)kSecClassIdentity,
(id)kSecValueRef: (__bridge id)identity,
(id)kSecAttrLabel: "some_unique_tag_for_id",
};
OSStatus securityError = SecItemAdd((CFDictionaryRef)dict, NULL);
//More Code
}
//Storing the Certificate
if(CFDictionaryContainsKey(pkcs12Contents, kSecImportItemCertChain))
{
CFArrayRef certs = (CFArrayRef) CFDictionaryGetValue(pkcs12Contents, kSecImportItemCertChain);
CFRetain(certs);
SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(certs, 0);
NSDictionary* dict = @{ (id)kSecValueRef: (__bridge id)cert,
(id)kSecClass: (id)kSecClassCertificate,
(id)kSecAttrLabel: "some_unique_tag_for_cert,
};
OSStatus securityError = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
//more code
}
поисковый код
+(SecIdentityRef)getLoginCertIdentityFromKeyChain
{
NSDictionary *getquery = @{ (id)kSecClass: (id)kSecClassIdentity,
(id)kSecAttrLabel: (id)KEY_LOGIN_CERT_ID_TAG,
(id)kSecReturnRef: @YES,
};
SecIdentityRef identity = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getquery,
(CFTypeRef *)&identity);
if (status != errSecSuccess)
{
if (status == errSecItemNotFound)
{
return nil;
}
// Add Error Cases Here
}
return identity;
}
+(SecCertificateRef)getLoginCertChainFromKeyChain
{
NSDictionary *getquery = @{ (id)kSecClass: (id)kSecClassCertificate,
(id)kSecAttrLabel: (id)KEY_LOGIN_CERT_TAG,
(id)kSecReturnRef: @YES,
};
SecCertificateRef cert = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getquery,
(CFTypeRef *)&cert);
if (status != errSecSuccess)
{
}
return cert;
}
Проблемы
1. Не могу получить личность
Я успешно сохранил и получил сертификат. Когда я сохраняю личность, я получаю errSecSuccess
, что означает, что личность успешно добавлена в цепочку для ключей. Однако, когда я пытаюсь получить Идентификацию из цепочки для ключей, используя мой getLoginCertIdentityFromKeyChain
, я получаю errSecItemNotFound
.
Это абсолютно бессмысленно для меня.
2. Сертификат уже существует, но не добавлен.
Чтобы обойти первую проблему, я удалил (id) kSecClass: (id) kSecClassIdentity
NSDictionary* dict = @{ (id)kSecValueRef: (__bridge id)identity,
(id)kSecAttrLabel: KEY_LOGIN_CERT_ID_TAG,
};
OSStatus securityError = SecItemAdd((CFDictionaryRef)dict, NULL);
Это позволило мне получить личность из цепочки для ключей. Не знаю, почему это работает, но это работает. Проблема сейчас в том, что при попытке сохранить сертификат я получаю errSecDuplicateItem
. Почему это уже сохранено? Я гарантировал, что я удалил все из цепочки для ключей.
Становится страннее, когда я пытаюсь получить этот сертификат, который "уже сохранен", используя мой getLoginCertChainFromKeyChain
метод, я получаю errSecItemNotFound
.
Я полагаю, что проблема заключается в том, что сертификат хранится под тегом идентификации? Я подтвердил это, но я до сих пор не знаю почему. Документация Apple делает ужасную работу, объясняя, что происходит.
3. Объяснение SecIdentityCopyCertificate
Наконец, это больше вопрос. Выдает ли SecIdentityCopyCertificate
тот же сертификат, который я получил при получении сертификата с использованием идентификационной метки?
Спасибо
Любое понимание того, что здесь происходит, будет высоко оценено.