IOS Mutual Authentication
Asked Answered
L

1

12

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:

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.

Leuco answered 20/9, 2012 at 13:7 Comment(2)
The code I wrote works perfectly, the problem was server side.Leuco
You should post your solution as an answer and accept it by clicking the big checkmark next to it, that's how you mark questions as solved here.Perfectionism
L
2

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

Leuco answered 23/9, 2012 at 17:42 Comment(2)
can you please add what was the server side problem? I am having the same issueShaft
There doesn't appear to be a clear description of how this was solved - giving some indication as to the server side change would be helpful.Colver

© 2022 - 2024 — McMap. All rights reserved.