SecTrustEvaluate всегда возвращает kSecTrustResultRecoverableTrustFailure с SecPolicyCreateSSL
Мое приложение пытается оценить сертификат доверия сервера для самозаверяющего сертификата. Это работает нормально с SecPolicyCreateBasicX509, но не работает для SecPolicyCreateSSL
Вот мой код:
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
// create trust from protection space
SecTrustRef trustRef;
int trustCertificateCount = SecTrustGetCertificateCount(challenge.protectionSpace.serverTrust);
NSMutableArray* trustCertificates = [[NSMutableArray alloc] initWithCapacity:trustCertificateCount];
for (int i = 0; i < trustCertificateCount; i++) {
SecCertificateRef trustCertificate = SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, i);
[trustCertificates addObject:(id) trustCertificate];
}
// set evaluation policy
SecPolicyRef policyRef;
// policyRef = SecPolicyCreateBasicX509(); this is working
policyRef = SecPolicyCreateSSL(NO, (CFStringRef)
SecTrustCreateWithCertificates((CFArrayRef) trustCertificates, policyRef, &trustRef);
[trustCertificates release];
// load known certificates from keychain and set as anchor certificates
NSMutableDictionary* secItemCopyCertificatesParams = [[NSMutableDictionary alloc] init];
[secItemCopyCertificatesParams setObject:(id)kSecClassCertificate forKey:(id)kSecClass];
[secItemCopyCertificatesParams setObject:@"Server_Cert_Label" forKey:(id)kSecAttrLabel];
[secItemCopyCertificatesParams setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnRef];
[secItemCopyCertificatesParams setObject:(id)kSecMatchLimitAll forKey:(id)kSecMatchLimit];
CFArrayRef certificates;
certificates = nil;
SecItemCopyMatching((CFDictionaryRef) secItemCopyCertificatesParams, (CFTypeRef*) &certificates);
if (certificates != nil && CFGetTypeID(certificates) == CFArrayGetTypeID()) {
SecTrustSetAnchorCertificates(trustRef, certificates);
SecTrustSetAnchorCertificatesOnly(trustRef, NO);
}
SecTrustResultType result;
OSStatus trustEvalStatus = SecTrustEvaluate(trustRef, &result);
if (trustEvalStatus == errSecSuccess) {
if (result == kSecTrustResultConfirm || result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
// evaluation OK
[challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
} else {
// evaluation failed
// ask user to add certificate to keychain
} else {
// evaluation failed - cancel authentication
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
После многих исследований я уже внес изменения в самоподписанный сертификат, добавив расширение, как упомянуто в этом посте: Невозможно доверять самоподписанному сертификату на iphone.
У кого-нибудь есть еще один намек на то, что здесь может отсутствовать?
2 ответа
После многих испытаний я решил эту проблему. Следующее было изменено.
Политика оценивается как NO для оценки сервера. Это означает, что сертификат проверен на подлинность клиента. Очевидно, что сертификат сервера не будет иметь этого! Установка этого значения в YES фактически проверит,
extendedKeyUsage
установлен вserverAuth
для сертификата сервера.SecTrustSetAnchorCertificates
а такжеSecTrustSetAnchorCertificatesOnly
всегда следует вызывать перед оценкой, а не только если вы предоставляете свои собственные якорные сертификаты. Вы должны вызывать это с пустым массивом, иначе известные системные сертификаты привязки не используются для оценки. Даже установленные доверенные корневые сертификаты от MDM работают тогда.
Вот рабочий пример, основанный на первом коде:
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
// create trust from protection space
SecTrustRef trustRef;
int trustCertificateCount = SecTrustGetCertificateCount(challenge.protectionSpace.serverTrust);
NSMutableArray* trustCertificates = [[NSMutableArray alloc] initWithCapacity:trustCertificateCount];
for (int i = 0; i < trustCertificateCount; i++) {
SecCertificateRef trustCertificate = SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, i);
[trustCertificates addObject:(id) trustCertificate];
}
// set evaluation policy
SecPolicyRef policyRef;
// set to YES to verify certificate extendedKeyUsage is set to serverAuth
policyRef = SecPolicyCreateSSL(YES, (CFStringRef) challenge.protectionSpace.host);
SecTrustCreateWithCertificates((CFArrayRef) trustCertificates, policyRef, &trustRef);
[trustCertificates release];
// load known certificates from keychain and set as anchor certificates
NSMutableDictionary* secItemCopyCertificatesParams = [[NSMutableDictionary alloc] init];
[secItemCopyCertificatesParams setObject:(id)kSecClassCertificate forKey:(id)kSecClass];
[secItemCopyCertificatesParams setObject:@"Server_Cert_Label" forKey:(id)kSecAttrLabel];
[secItemCopyCertificatesParams setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnRef];
[secItemCopyCertificatesParams setObject:(id)kSecMatchLimitAll forKey:(id)kSecMatchLimit];
CFArrayRef certificates;
certificates = nil;
SecItemCopyMatching((CFDictionaryRef) secItemCopyCertificatesParams, (CFTypeRef*) &certificates);
if (certificates != nil && CFGetTypeID(certificates) == CFArrayGetTypeID()) {
SecTrustSetAnchorCertificates(trustRef, certificates);
SecTrustSetAnchorCertificatesOnly(trustRef, NO);
} else {
// set empty array as own anchor certificate so system anchos certificates are used too!
SecTrustSetAnchorCertificates(trustRef, (CFArrayRef) [NSArray array]);
SecTrustSetAnchorCertificatesOnly(trustRef, NO);
}
SecTrustResultType result;
OSStatus trustEvalStatus = SecTrustEvaluate(trustRef, &result);
if (trustEvalStatus == errSecSuccess) {
if (result == kSecTrustResultConfirm || result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
// evaluation OK
[challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
else {
// evaluation failed
// ask user to add certificate to keychain
}
}
else {
// evaluation failed - cancel authentication
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
Надеюсь, это кому-нибудь поможет.
Это может быть проблема с сертификатом сервера....
Проверьте здесь, я решил мою проблему kSecTrustResultRecoverableTrustFailure, добавив subjectAltName = DNS:example.com
в конфигурационный файл openssl, в частности, при генерации ключей сервера...
Если вы не используете openssl для его генерации, извините, но я могу вам помочь. В любом случае, если вы хотите использовать openssl, вот хороший учебник, чтобы сгенерировать эти ключи и подписать их с помощью своего собственного корневого центра сертификации.
Из этого урока я просто изменил свой конфигурационный файл сервера openssl на:
[server] basicConstraints = критический,CA:FALSE keyUsage = digitalSignature, keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth nsCertType = имя_сервера сервера AltName = IP:10.0.1.5,DNS:office.totendev.com
Надеюсь, поможет!