IOS Mutual Authentication

I’m trying to implement mutual authentication in IOS 5 but i’m having troubles:

{NSUnderlyingError = "Error Domain=kCFErrorDomainCFNetwork Code=-1200 \"An SSL error has occurred and a secure connection to the server cannot be made.\" UserInfo=0x18d830 {NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., _kCFNetworkCFStreamSSLErrorOriginalValue=-9800, _kCFStreamPropertySSLClientCertificateState=0, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSErrorFailingURLStringKey=https://192.168.24.110:8081/t01.json, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0xceaa2d0>, NSErrorFailingURLKey=https://192.168.24.110:8081/t01.json}

I generated keys, certificates and pkcs12 for server (either self signed or with a fake CA I always got that problem) and client this way:

  • Best Method to Show a Popup Transparent Window on iPhone?
  • iOS10 Background fetch
  • Static Library path nightmare from hell
  • UINavigationBar with UISegmentedControl partially covers childViews
  • How to make generics in collection type constraint?
  • CCCrypt difference between iOS5 and iOS6
  • openssl genrsa -out client.key 1024
    openssl req -new -key client.key -out client.csr
    
    self-signed
    openssl req -new -key ca.key -x509 -days 1095 -out ca.crt
    
    CA signed
    openssl x509 -req -days 365 -in client.csr -CA server.crt -CAkey server.key -CAcreateserial -out client.crt
    
    CRT to PEM
    openssl x509 -in client.crt -out client.der -outform DER
    openssl x509 -in client.der -inform DER -out client.pem -outform PEM
    
    PEM TO PKCS 12
    openssl pkcs12 -export -in client.pem -inkey client.key -out client.p12
    

    The resulting client.p12 file works perfectly when I import it in the browser (FF15). So the problem is not locate in the previous steps.

    IOS side I tried this example: http://vanjakom.wordpress.com/tag/nsurlconnection/

    and this is what I wrote when I found that example not working:

    // Returns an array containing the certificate
    - (CFArrayRef)getCertificate:(SecIdentityRef) identity {
        SecCertificateRef certificate = nil;
    
        SecIdentityCopyCertificate(identity, &certificate);
        SecCertificateRef certs[1] = { certificate };
    
        CFArrayRef array = CFArrayCreate(NULL, (const void **) certs, 1, NULL);
    
        SecPolicyRef myPolicy   = SecPolicyCreateBasicX509();
        SecTrustRef myTrust;
    
        OSStatus status = SecTrustCreateWithCertificates(array, myPolicy, &myTrust);
        if (status == noErr) {
            NSLog(@"No Err creating certificate");
        } else {
            NSLog(@"Possible Err Creating certificate");
        }
        return array;
    }
    
    // Returns the identity
    - (SecIdentityRef)getClientCertificate {
        SecIdentityRef identityApp = nil;
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectoryPath = [paths objectAtIndex:0];
        NSString *myFilePath = [documentsDirectoryPath stringByAppendingPathComponent:@"file12.p12"]; 
        NSData *PKCS12Data = [NSData dataWithContentsOfFile:myFilePath];
    
        CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
        CFStringRef password = CFSTR("password");
        const void *keys[] = { kSecImportExportPassphrase };//kSecImportExportPassphrase };
        const void *values[] = { password };
        CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
        CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
        OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
        CFRelease(options);
        CFRelease(password);
        if (securityError == errSecSuccess) {
            NSLog(@"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
            CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
            identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
        } else {
            NSLog(@"Error opening Certificate.");
        }
    
        return identityApp;
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
        if ([challenge previousFailureCount] == 0) {
            SecIdentityRef identity = [self getClientCertificate];  // Go get a SecIdentityRef
            CFArrayRef certs = [self getCertificate:identity]; // Get an array of certificates
            // Convert the CFArrayRef to a NSArray
            NSArray *myArray = (__bridge NSArray *)certs;
    
            // Create the NSURLCredential
            NSURLCredential *newCredential = [NSURLCredential credentialWithIdentity:identity certificates:myArray persistence:NSURLCredentialPersistencePermanent];
    
            // Send
            [challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];    
        } else {
            // Failed
            [[challenge sender] cancelAuthenticationChallenge:challenge];
        }
    }
    
    - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
    {
        return YES;
    }
    

    In both cases I can’t autheticate the client.
    Moreover I also installed the server.crt certificate on the device (iPhone/iPad) but I keep receiving “Error Domain=NSURLErrorDomain Code=-1200”.

    Any ideas?
    Thank you.

    Solutions Collect From Internet About “IOS Mutual Authentication”

    The code I wrote works perfectly, the problem was server side.