Я пытаюсь реализовать аутентификацию сертификата клиента https в iOS с NSURLSession
. Вот что я делаю:iOS NSURLErrorDomain Code = -1005 с вызовом проверки ClientCertificate
-(void) httpPostWithCustomDelegate :(NSDictionary *) params
{
NSString *ppyRequestURL = [NSString stringWithFormat:@"%@/fetchcountryCities", PPBaseURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:ppyRequestURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request setHTTPMethod:@"POST"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
Log(@"ASDAD");
}];
[postDataTask resume];
}
я обеспечиваю сертификат клиента в обработчике вызов вроде этого:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler{
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}
else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) {
NSURLCredential *credential = [self provideClientCertificate];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}
}
Вот как я загрузить мой сертификат клиента,
- (SecIdentityRef)findClientCertificate {
SecIdentityRef clientCertificate = NULL;
if (clientCertificate) {
CFRelease(clientCertificate);
clientCertificate = NULL;
}
NSString *pkcs12Path = [[NSBundle mainBundle] pathForResource:@"johndoe" ofType:@"p12"];
NSData *pkcs12Data = [[NSData alloc] initWithContentsOfFile:pkcs12Path];
CFDataRef inPKCS12Data = (__bridge CFDataRef)pkcs12Data;
CFStringRef password = CFSTR("password");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = NULL;
OSStatus err = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
CFRelease(optionsDictionary);
CFRelease(password);
if (err == errSecSuccess && CFArrayGetCount(items) > 0) {
CFDictionaryRef pkcsDict = CFArrayGetValueAtIndex(items, 0);
SecTrustRef trust = (SecTrustRef)CFDictionaryGetValue(pkcsDict, kSecImportItemTrust);
if (trust != NULL) {
clientCertificate = (SecIdentityRef)CFDictionaryGetValue(pkcsDict, kSecImportItemIdentity);
CFRetain(clientCertificate);
}
}
if (items) {
CFRelease(items);
}
return clientCertificate;
}
- (NSURLCredential *)provideClientCertificate {
SecIdentityRef identity = [self findClientCertificate];
if (!identity) {
return nil;
}
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate);
const void *certs[] = {certificate};
CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray *)certArray persistence:NSURLCredentialPersistencePermanent];
CFRelease(certArray);
return credential;
}
сейчас когда API называется, я возвращаю эту ошибку:
Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={NSUnderlyingError=0x7f8428df4d40 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={_kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}
Я получаю ту же ошибку на симуляторе и устройстве. Я полностью застрял. Не уверен, что здесь происходит.
***** Обновление ***** Я проверил с прокси-сервером Charles, чтобы узнать более подробную информацию. К моему удивлению, когда я добавил сертификат клиента на charles proxy, я возвращаю ответ с сервера, так что я пропускаю некоторые настройки в plist или проблемы с загрузкой p12?
Из настроек Plist,
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>test.mydomain.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSRequiresCertificateTransparency</key>
<false/>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<false/>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<true/>
</dict>
</dict>
</dict>
Спасибо за ваш ответ. Я пробовал все ваши предложения, но все равно возвращал ту же ошибку. – Zach
Я проверил с помощью прокси-сервера charles, чтобы узнать больше. К моему удивлению, когда я добавил сертификат клиента на charles proxy, я возвращаю ответ с сервера, так что я пропускаю некоторые настройки в plist или проблемы с загрузкой p12? – Zach
Подождите ... это работает, если вы проходите через прокси-сервер, но в противном случае он терпит неудачу? – dgatwood