Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not able to do authentication using client certificate in iPhone

team,

I have .net based REST service configured with 2-way SSL. In my iphone side, i have installed the server certificate in the device profiles and client certificate is bundled as application resource. Server certificate validation is working fine, but the client certificate authentication fails. Below is my code snippet

- (void)connection:(NSURLConnection *) connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    NSLog(@"Authentication challenge with host: %@", challenge.protectionSpace.host);

    if([challenge previousFailureCount] == 0) {
        NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
        NSString *authMethod = [protectionSpace authenticationMethod];
        if(authMethod == NSURLAuthenticationMethodServerTrust ) {
            NSLog(@"Verifying The Trust");
            [[challenge sender] useCredential:[NSURLCredential credentialForTrust:[protectionSpace serverTrust]] forAuthenticationChallenge:challenge];
        } 
        else if(authMethod == NSURLAuthenticationMethodClientCertificate ) {
            NSLog(@"Trying Certificate");
            // load cert

            NSString *thePath = [[NSBundle mainBundle]
                                 pathForResource:@"Myclientcertificate" ofType:@"pfx"];
            NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
            CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data;             

            OSStatus status = noErr;
            SecIdentityRef myIdentity;
            SecTrustRef myTrust;

            status = extractIdentityAndTrust(
                                             inPKCS12Data,
                                             &myIdentity,
                                             &myTrust); 

            SecTrustResultType trustResult;

            if (status == noErr) {                                      
                status = SecTrustEvaluate(myTrust, &trustResult);
            }

            SecCertificateRef myCertificate;
            SecIdentityCopyCertificate(myIdentity, &myCertificate);
            const void *certs[] = { myCertificate };
            CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL);


            NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity certificates:(NSArray*)certsArray persistence:NSURLCredentialPersistencePermanent];

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


        }
    } 

}

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    BOOL result;
    NSLog(@"canAuthenticateAgainstProtectionSpace: %@", protectionSpace.authenticationMethod);
    if ([protectionSpace authenticationMethod] == NSURLAuthenticationMethodServerTrust) {
        result= YES;
    } else if([protectionSpace authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
        result = YES;
    }   
    return result;
}

OSStatus extractIdentityAndTrust(CFDataRef inPKCS12Data, SecIdentityRef *identity, SecTrustRef *trust){
    OSStatus securityError = errSecSuccess;


    CFStringRef password = CFSTR("1234");
    const void *keys[] =   { kSecImportExportPassphrase };
    const void *values[] = { password };
    CFDictionaryRef optionsDictionary = CFDictionaryCreate(
                                                           NULL, keys,
                                                           values, 1,
                                                           NULL, NULL); 
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    securityError = SecPKCS12Import(inPKCS12Data,
                                    optionsDictionary,
                                    &items);  

      if (securityError == 0) {                                  
        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
        const void *tempIdentity = NULL;
        tempIdentity = CFDictionaryGetValue (myIdentityAndTrust,
                                             kSecImportItemIdentity);
        *identity = (SecIdentityRef)tempIdentity;
        const void *tempTrust = NULL;
        tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
        *trust = (SecTrustRef)tempTrust;
    }

    if (optionsDictionary) {
        CFRelease(optionsDictionary);
    }

    return securityError;
}

My connection is failing with below mentioned error.

{
    NSErrorFailingURLKey = "https://myIpdaddress/Service1.svc/test/random";
    NSErrorFailingURLStringKey = "https://myIpdaddress/Service1.svc/test/random";
    NSLocalizedDescription = "The server \U201cmyIpdaddress\U201d requires a client certificate.";
    NSUnderlyingError = "Error Domain=kCFErrorDomainCFNetwork Code=-1206 \"The server \U201cmyIpdaddress\U201d requires a client certificate.\" UserInfo=0x4b240b0 {NSErrorFailingURLKey=https://myIpdaddress/Service1.svc/test/random, NSErrorFailingURLStringKey=https://myIpdaddress/Service1.svc/test/random, NSLocalizedDescription=The server \U201cmyIpdaddress\U201d requires a client certificate.}";
}

Kindly help me how to reslove this.

like image 598
shatthi Avatar asked Dec 30 '11 08:12

shatthi


People also ask

How do I fix certificate not trusted on iPhone?

If you want to turn on SSL/TLS trust for that certificate, go to Settings > General > About > Certificate Trust Settings. Under "Enable full trust for root certificates," turn on trust for the certificate.

How do I enable client authentication certificate?

On the taskbar, click Start, and then click Control Panel. In Control Panel, click Programs and Features, and then click Turn Windows Features on or off. Expand Internet Information Services, then select Client Certificate Mapping Authentication, and then click OK.


1 Answers

I was running into this exact same problem.

The fix for me was to correct the 'Host' HTTP Header.

The one I was using included the port and a portion of the path. Once I corrected this header to only include only the host portion of the url, things started working.

I think that the server was rejecting my identity when I had the wrong host header, and I think that the "requires a client certificate" message is a general response that can also mean the server did not accept the certificate presented.

like image 163
Rich Waters Avatar answered Oct 10 '22 04:10

Rich Waters