Я разрабатываю приложение для iOS. У нас есть собственный центр сертификации с самозаверяющим ca-cert. Удостоверяющий центр выдает сертификаты как для пользователей, так и для https-сервера. Я хотел бы создать приложение iOS, которое может аутентифицировать сервер https с использованием сертификата ca, а также может связываться с сервером https с использованием сертификата клиента. У меня уже есть код для связи с https-сервером с использованием клиентского сертификата, но мне нужно импортировать ca-сертификат в системный набор ключей. Я хотел бы, чтобы сертификат ca был жестко запрограммирован в приложении. Мой код выглядит так:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
bool result=NO;
if ([protectionSpace authenticationMethod] == NSURLAuthenticationMethodServerTrust) {
result= YES;
} else if([protectionSpace authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
result = YES;
}
return result;
}
- (BOOL)shouldTrustProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
CFDataRef certDataRef = (__bridge_retained CFDataRef)self.rootCertData;
SecCertificateRef cert = SecCertificateCreateWithData(NULL, certDataRef);
SecTrustRef serverTrust = protectionSpace.serverTrust;
CFArrayRef certArrayRef = CFArrayCreate(NULL, (void *)&cert, 1, NULL);
SecTrustSetAnchorCertificates(serverTrust, certArrayRef);
SecTrustResultType trustResult;
SecTrustEvaluate(serverTrust, &trustResult);
return trustResult == kSecTrustResultUnspecified;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSLog(@"Did receive auth challange %@",[challenge debugDescription]);
NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
NSString *authMethod = [protectionSpace authenticationMethod];
if(authMethod == NSURLAuthenticationMethodServerTrust ) {
NSLog(@"Verifying The Trust");
NSURLCredential* cred=[NSURLCredential credentialForTrust:[protectionSpace serverTrust]];
if ([self shouldTrustProtectionSpace:challenge.protectionSpace]) {
[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];
NSLog(@"OK");
} else {
NSLog(@"FAILED");
[challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
}
}
if(authMethod == NSURLAuthenticationMethodClientCertificate ) {
NSLog(@"Trying Certificate");
.....
Все работает как часы, пока сервер не требует клиентского сертификата. В этот момент я получаю сообщение об ошибке. Сертификат для этого сервера недействителен, и выполнение никогда не достигнет точки
NSLog(@"Trying Certificate");
Когда я загружаю .der ca-cert в системный брелок, все работает, даже сертификат клиента отправляется на сервер, и сервер может распознать пользователя. Я думаю, что
SecTrustSetAnchorCertificates(serverTrust, certArrayRef);
как-то влияет на доверие, потому что, когда я пропускаю этот вызов, я могу просто сделать:
[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];
без ошибок, но я не могу проверить сертификат в этом случае.
Что я делаю неправильно?
Большое спасибо, Адам