iOS NSURLAuthenticationMethodClientCertificate не запрашивается vs ActiveSync server
Я пытаюсь реализовать аутентификацию сертификата в клиенте ActiveSync, который я разрабатываю. Код для использования сертификата auth может работать, но на данный момент сервер, или, точнее, интерпретация библиотеки iOS ответа сервера, кажется мне неправильной. Вот мой код:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
NSString *authenticationMethod = [protectionSpace authenticationMethod];
if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate])
{
NSURLCredential* credential = [ self buildCredentialClientCert];
if ( credential == nil )
{
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
else
{
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
}
else if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
.... // do other stuff
проблема в том, что, хотя я знаю, что сервер поддерживает аутентификацию сертификата клиента, когда я устанавливаю точку останова, тогда authenticationMethod
всегда NSURLAuthenticationMethodServerTrust
.
сырой Ответ сервера HTTPS содержит следующее:
Код Ошибки: 403 Запрет. Страница требует сертификат клиента как часть процесса проверки подлинности. Если вы используете смарт-карту, вам нужно будет вставить смарт-карту, чтобы выбрать соответствующий сертификат. В противном случае, обратитесь к администратору сервера. (12213)
мой вопрос в том, что определяет, является ли проблема аутентификации NSURLAuthenticationMethodServerTrust
и NSURLAuthenticationMethodClientCertificate
?
1 ответов
Так как никто не ответил на это, и я в конце концов пришел к рабочему решению, вот оно.
доверие сервера не является вызовом от сервера к клиенту, это возможность для клиента проверить доверие, предлагаемое сервером. Имея это в виду, приведенный ниже код не проверяет это доверие, но может.
обычно вы получаете NSURLAuthenticationMethodServerTrust, затем впоследствии вы получаете NSURLAuthenticationMethodClientCertificate. Это ни то,ни другое. Вот рабочий код.
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
NSString *authenticationMethod = [protectionSpace authenticationMethod];
if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate] && self.accountCertKeychainRef != nil)
{
SecIdentityRef identity = [KeychainUtilities retrieveIdentityWithPersistentRef:self.accountCertKeychainRef];
NSURLCredential* credential = [CertificateUtilities getCredentialFromCert:identity];
if ( credential == nil )
{
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
else
{
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
}
else if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
else if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM] || [authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
self.lastProtSpace = [challenge protectionSpace];
if ([challenge previousFailureCount] > 2)
{
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
else
{
[[challenge sender] useCredential:[self buildCredential] forAuthenticationChallenge:challenge];
}
}
else
{
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
для вопроса ниже, Вот как вы можете получить идентичность:
+ (SecIdentityRef)copyIdentityAndTrustWithCertData:(CFDataRef)inPKCS12Data password:(CFStringRef)keyPassword
{
SecIdentityRef extractedIdentity = nil;
OSStatus securityError = errSecSuccess;
const void *keys[] = {kSecImportExportPassphrase};
const void *values[] = {keyPassword};
CFDictionaryRef optionsDictionary = NULL;
optionsDictionary = CFDictionaryCreate(NULL, keys, values, (keyPassword ? 1 : 0), NULL, NULL);
CFArrayRef items = NULL;
securityError = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
if (securityError == errSecSuccess) {
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
// get identity from dictionary
extractedIdentity = (SecIdentityRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
CFRetain(extractedIdentity);
}
if (optionsDictionary) {
CFRelease(optionsDictionary);
}
if (items) {
CFRelease(items);
}
return extractedIdentity;
}
для тех, кто заинтересован, вот getCredentialForCert:
+ (NSURLCredential *)getCredentialFromCert:(SecIdentityRef)identity
{
SecCertificateRef certificateRef = NULL;
SecIdentityCopyCertificate(identity, &certificateRef);
NSArray *certificateArray = [[NSArray alloc] initWithObjects:(__bridge_transfer id)(certificateRef), nil];
NSURLCredentialPersistence persistence = NSURLCredentialPersistenceForSession;
NSURLCredential *credential = [[NSURLCredential alloc] initWithIdentity:identity
certificates:certificateArray
persistence:persistence];
return credential;
}