user2153861
user2153861

Reputation: 51

SecTrustSetAnchorCertificates with client certificate

I am developing iOS Application. We have custom certificate authority with self-signed ca-cert. Certification authority issues certificates both for users and for https server too. I would like to create iOS application which can authenticate https server using ca certificate and also can communicate to https server using client certificate. I already have the code for communicating with https server using client certificate, but I need to have ca-certificate imported to system keyring. I would like to have ca certificate hard-coded into application. My code looks like this:

- (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");
        .....

Everything works like a charm, until server does not require client certificate. At this moment I will receive error The certificate for this server is invalid and execution will never reach point

 NSLog(@"Trying Certificate");

When I have .der ca-cert loaded into system keyring, everything works, even client certificate is sent to server, and server can recognize user. I thing that

SecTrustSetAnchorCertificates(serverTrust, certArrayRef);

affects somehow trust, cause when I skip this call, I can simply do:

[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];

without any error, but I'm not able to verify certificate in this case.

What am I doing wrong?

Big thanks, Adam

Upvotes: 3

Views: 5220

Answers (1)

Dirk-Willem van Gulik
Dirk-Willem van Gulik

Reputation: 7706

Have a look at this code

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

which does both by fairly carefully keeping the two trust blocks separate (which you seem to be mixing).

Upvotes: 2

Related Questions