Проверка подлинности 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, поэтому что-то должно быть не так в моем коде. Пожалуйста помоги!

Ответы на вопрос(2)

Ваш ответ на вопрос