SecTrustSetAnchorCertificates с сертификатом клиента

Я разрабатываю приложение для 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];

без ошибок, но я не могу проверить сертификат в этом случае.

Что я делаю неправильно?

Большое спасибо, Адам


person user2153861    schedule 10.03.2013    source источник


Ответы (1)


Взгляните на этот код

https://github.com/dirkx/Security-Pinning-by-CA

что делает и то, и другое, довольно тщательно разделяя два блока доверия (которые вы, кажется, смешиваете).

person Dirk-Willem van Gulik    schedule 25.03.2013