Проверка подлинности SSL для приложения .p12 для iOS - ошибка неверного сертификата (-9825)
Изменить 6/6/14:
Я создал локальный сервер Apache Tomcat для проверки подлинности SSL с сертификатом. Я был успешным! Все работает, как и ожидалось, используя оба моих подхода ниже. (MKNetworkKit и пользовательский код). Хотя это говорит о том, что мой код работает, моя первоначальная проблема все еще не решена. Я обновил название вопроса, чтобы более конкретно отразить проблему. Кто-нибудь знает, нужны ли SAP Portal специальные настройки для приема сертификатов из приложения iOS? Помните, я смог успешно пройти аутентификацию с помощью Safari mobile после импорта CA и .p12 в общую цепочку для ключей, я потерпел неудачу только в коде (который теперь я знаю, что код работает, но не с порталом).
Я создаю очень простое приложение iOS7 Cordova 3.2 с настраиваемым плагином для получения данных из веб-службы SSL путем предоставления только сертификата .p12 для аутентификации (не требуются базовая аутентификация или другие учетные данные пользователя). Я выполняю все тесты на физическом iPad (без симулятора). Веб-служба работает на портале разработки SAP NetWeaver с использованием самозаверяющего сертификата. Сейчас я импортировал CA сервера в связку ключей iOS, чтобы избежать ошибок доверия к сертификату. В целях тестирования мой сертификат .p12 локально связан внутри приложения, в корне mainBundle.
При попытке подключиться к веб-сервису в консоли появляется следующая ошибка:
CFNetwork SSLHandshake failed (-9825)
NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9825)
Error Domain=NSURLErrorDomain Code=-1205 "The server “myhostremoved.com” did not accept the certificate." UserInfo=0x14e99000 {NSErrorFailingURLStringKey=https://myhostremoved.com/sslwebservice/, NSErrorFailingURLKey=https://myhostremoved.com/sslwebservice/, NSLocalizedDescription=The server “myhostremoved.com” did not accept the certificate., NSUnderlyingError=0x14d9b1d0 "The server “myhostremoved.com” did not accept the certificate.", NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x14d94720>}
Согласно сСайт документации Appleошибка -9825 относится к неверному сертификату.
Есть много вопросов по SO, связанных с тем, что я пытаюсь сделать, но ни один из них конкретно не касается ошибки, которую я вижу. Я подошел к разработке кода двумя разными способами.
Первый Я пытался использовать код уже на SO, адаптируя его к моему варианту использования. Смотрите код ниже:
- (void)startConnection:(CDVInvokedUrlCommand*)command {
NSDictionary *options = [command.arguments objectAtIndex:0];
NSURL *serverURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@", [options objectForKey:@"host"]]];//hostname provided by Cordova plugin, but could just as easily be hardcoded here
NSMutableURLRequest *connectionRequest = [NSMutableURLRequest requestWithURL:serverURL];
NSURLConnection *connection = nil;
connection = [[NSURLConnection alloc] initWithRequest:connectionRequest delegate:self startImmediately:YES];
}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
// gets a certificate from local resources
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"mycert" ofType:@"p12"];
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
SecIdentityRef identity;
// extract the ideneity from the certificate
[self extractIdentity :inPKCS12Data :&identity];
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate);
const void *certs[] = {certificate};
CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
// create a credential from the certificate and ideneity, then reply to the challenge with the credential
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
- (OSStatus)extractIdentity:(CFDataRef)inP12Data :(SecIdentityRef*)identity {
OSStatus securityError = errSecSuccess;
CFStringRef password = CFSTR("MyCertPassw0rd");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import(inP12Data, options, &items);
if (securityError == 0) {
CFDictionaryRef ident = CFArrayGetValueAtIndex(items,0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue(ident, kSecImportItemIdentity);
*identity = (SecIdentityRef)tempIdentity;
}
if (options) {
CFRelease(options);
}
return securityError;
}
На моем втором подходеЯ попытался использовать библиотеку MKNetworkKit, которая абстрагирует много кода, необходимого для взаимодействия с сертификатом. Все, что вам нужно сделать, это указать путь к сертификату и пароль. Я снова получаю ту же ошибку, что и выше. Этот код ниже.
- (void)startConnection:(CDVInvokedUrlCommand*)command {
NSDictionary *options = [command.arguments objectAtIndex:0];
NSURL *serverURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@", [options objectForKey:@"host"]]];//hostname provided by Cordova plugin, but could just as easily be hardcoded here
MKNetworkEngine *engine = [[MKNetworkEngine alloc] initWithHostName:serverURL customHeaderFields:nil];
MKNetworkOperation *op = [engine operationWithPath:nil params:nil httpMethod:@"GET" ssl:YES];
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"mycert" ofType:@"p12"];
[op setShouldContinueWithInvalidCertificate:YES];
op.clientCertificate = thePath;
op.clientCertificatePassword = @"MyCertPassw0rd";
[op addCompletionHandler:^(MKNetworkOperation *operation) {
NSLog(@"[operation responseData]-->>%@", [operation responseString]);
}errorHandler:^(MKNetworkOperation *errorOp, NSError* err) {
NSLog(@"MKNetwork request error : %@", [err localizedDescription]);
}];
[engine enqueueOperation:op];
}
Я получаю ту же ошибку, используя оба подхода. Есть идеи?
Известная информацияЯ знаю, что приложение находит сертификат .p12, потому что, когда я выдвигаю путь к сертификату .p12, я получаю сообщение об ошибке, в котором говорится, что не удается найти сертификат, который я обычно не вижу иначе.Я знаю, что пароль, который я предоставляю для файла сертификата, является правильным, потому что, когда я подделываю пароль, я получаю ошибку относительно пароля, которую я обычно не вижу иначе.Я не думаю, что доверие к сертификату является проблемой, потому что, если я удаляю CA моего сервера из цепочки ключей iOS, я получаю сообщение об ошибке в консоли, в котором конкретно говорится, что серверу нельзя доверять. После добавления ЦС эта ошибка больше не возникает, но я получаю ту же ошибку, что и выше (-9825)Другие тестыПри обеспечении базовой аутентификации в коде (в обход аутентификации сертификата) все работает как положено, и я не получаю ошибок.
Я также попробовал все те же шаги выше, но с использованием файла .pfx вместо моего сертификата .p12, те же ошибки.
Сервис SSL работает в мобильном Safari. Я импортировал сертификат .p12 в свою связку ключей с помощью утилиты iPhone Configuration и протестировал веб-сервис через мобильное сафари. Все работает, как и ожидалось, ошибок не возникает (также нет ошибок доверия), и я получаю ожидаемый результат.
Я также могу успешно протестировать веб-сервис на своем рабочем столе, используяУтилита rest-client
TL; DRЯ пытаюсь пройти проверку подлинности в веб-службе SSL, используя только сертификат .p12 в target-c. Я знаю, что сервер и веб-служба работают с сертификатом для аутентификации, но я продолжаю получать ошибки, когда пытаюсь установить соединение в target-c, поэтому что-то должно быть не так в моем коде. Пожалуйста помоги!