Currently I am working on an app that uses mutual authentication in order to communicate with a REST interface. Because I am very new to this topic I studied several examples - and now I have some questions. I hope that I am able to stick all knowledge pieces together to gain a better view of the whole process.
The process should look like the following:
- I got the exported server certificate which contains the server's public key and added it to the app bundle (which is later used for SSL Pinning).
- The first Request, which represents the beginning of the 2 way authentication, is a Post Request which also contains a Certificate Signing Request to get a client certificate (which is required to talk with the secured part of the REST interface). The CSR is dynamically generated in code via openSSL lib.
- The response of the server returns the signed certificate which is used for client authentication. This certificate is in DER Format and Base64 encoded.
The code I use to perform the SSL Pinning for the first request looks like the following and the SSL Pinning works as expected.
- (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server-cert" ofType:@"cer"];
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
NSData *localCertificateData = [NSData dataWithContentsOfFile:cerPath];
if ([remoteCertificateData isEqualToData:localCertificateData]) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:[challenge protectionSpace]];
NSLog(@"Certificate Pinning Succeeded");
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
NSLog(@"Certificate Pinning Failed");
}
}
But how do I deal with the returned certificate from the server? As far as I know I have to use the following NSURLConnection delegate methods - and to provide this certificate somehow to the server (for further requests).
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace: (NSURLProtectionSpace *)protectionSpace
{
if([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSLog(@"Wants to Authenticate Server Trust");
return YES;
}
if([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodClientCertificate]) {
NSLog(@"Wants to Authenticate Client Certificate");
return YES;
}
return NO;
}
And
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
Now my question. I saw several examples using the PKCS12 Format (which requires a private key and the certificate authority) instead of a DER encoded certificate, to authenticate self against the server. But how do I use my signed certificate which is in DER Format in `didReceiveAuthenticationChallenge for further requests? There is also an Android App which uses the same process for mutual auth, and it doesnt need a PKCS12 certificate.
Would be glad for some hints. Thx.