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.
Mutual authentication stepsThe server also provides a session ID and a client certificate request. The server sends its digital certificate, along with its public key. The server sends a "Server Hello Done" message. The client verifies the server's certification information.
Similarly, mutual authentication verifies both parties in a digital communications channel. For example, a client and a server using mutual authentication take steps to independently verify each other's identity, instead of only the client authenticating the server.
MTLS is a form of client authentication and an extension of OAuth 2.0 that provides a mechanism of binding access tokens to a client certificate. It is one of many attempts at improving the security of Bearer Tokens by requiring the application using the token to authenticate itself.
In practice, mTLS can identify and authorize the following: Devices onto a corporate network. Users into applications. Content delivery network (CDNs) or cloud security services to back-end web servers.
The code I wrote works perfectly, the problem was server side.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With