Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
268 views
in Technique[技术] by (71.8m points)

iphone - Determining Trust With NSURLConnection and NSURLProtectionSpace

I would like to ask a followup question to a previously posed question. I've got the code to create an NSURLRequest/Connection, run it and have the callback methods for authentication get called. Here's the specific code:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault];
}

-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{   

    if ([challenge previousFailureCount] > 0) {
        [[challenge sender] cancelAuthenticationChallenge:challenge];
        NSLog(@"Bad Username Or Password");
        badUsernameAndPassword = YES;
        finished = YES;
        return;
    }

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        if (appDelegate._allowInvalidCert)
        {
            // Go ahead...trust me!
            [challenge.sender useCredential:
             [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                 forAuthenticationChallenge: challenge];
        }
        else
        {
            TrustGenerator *tg = [[TrustGenerator alloc] init];

            if ([tg getTrust:challenge.protectionSpace])
            {
                // Go ahead...trust me!
                [challenge.sender useCredential:
                 [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                     forAuthenticationChallenge: challenge];
            }
            else {
                [[challenge sender] cancelAuthenticationChallenge:challenge];
            }
        }
    }
    else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault) {
        NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceNone];
        [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
    }
}

What I'm running into is that "didReceiveAuthenticationChallenge" with "[challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]" is ALWAYS being called, even when the certificate on the server I'm attempting to connect to is trusted (doing testing with a Verisign cert). So what I'm seeing is my application is always prompting the end user to trust even when the website is trusted. Bad karma considering that's what's suppose to happen with a man in the middle attack, etc. What I'm really looking for is some code like this:

        if (appDelegate._allowInvalidCert)
        {
            // Go ahead...trust me!
            [challenge.sender useCredential:
             [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                 forAuthenticationChallenge: challenge];
        }
        else if(The OS trusts the cert on the server)
        {
             [challenge.sender useCredential:
                 [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                     forAuthenticationChallenge: challenge];
        }
        else{...
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

So I spent a few days researching this. It looks like while the NSURLConnection API cannot determine if a certificate is trusted, there's a method in the Security Framework that handels that. So here's the code I came up with:

-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{   

    if ([challenge previousFailureCount] > 0) {
        [[challenge sender] cancelAuthenticationChallenge:challenge];
        NSLog(@"Bad Username Or Password");
        badUsernameAndPassword = YES;
        finished = YES;
        return;
    }

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {

        SecTrustResultType result;
        //This takes the serverTrust object and checkes it against your keychain
        SecTrustEvaluate(challenge.protectionSpace.serverTrust, &result);

        if (appDelegate._allowInvalidCert)
        {
            [challenge.sender useCredential:
             [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                 forAuthenticationChallenge: challenge];
        }
        //When testing this against a trusted server I got kSecTrustResultUnspecified every time. But the other two match the description of a trusted server
        else if(result == kSecTrustResultProceed || result == kSecTrustResultConfirm ||  result == kSecTrustResultUnspecified){
            [challenge.sender useCredential:
             [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                 forAuthenticationChallenge: challenge];
        }
        else
        {
            //Asks the user for trust
            TrustGenerator *tg = [[TrustGenerator alloc] init];

            if ([tg getTrust:challenge.protectionSpace])
            {

                //May need to add a method to add serverTrust to the keychain like Firefox's "Add Excpetion"
                [challenge.sender useCredential:
                 [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                     forAuthenticationChallenge: challenge];
            }
            else {
                [[challenge sender] cancelAuthenticationChallenge:challenge];
            }
        }
    }
    else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault) {
        NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceNone];
        [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...