I am trying to have UIWebView access the https website requesting a client certificate for two-way SSL. My starting point was Apple's documentation: Programming Guide for Certificates, Keys, and Trusted Services. There is also a lot of useful information about the stack flow.
I came up with the following code to respond to the authentication request, uploaded the p12 authentication file and crt intermediate certificates, and then presented them.
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSLog(@"Auth method: %@", challenge.protectionSpace.authenticationMethod);
if([challenge previousFailureCount] <5) {
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(@"Getting client certificate");
SecIdentityRef identity = [self getClientCertificate:@"mycert" withPassword:@"password"];
SecCertificateRef intermediateCert = [self getCertificate:@"intermediatecert"];
SecCertificateRef rootCA = [self getCertificate:@"cacert"];
NSMutableArray *combinedCerts = [NSMutableArray array];
[combinedCerts addObject:(__bridge id)intermediateCert];
[combinedCerts addObject:(__bridge id)rootCA];
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:combinedCerts persistence:NSURLCredentialPersistencePermanent];
NSLog(@"Sending credential");
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
} else {
NSLog(@"Not dealing with challenge %@",authMethod);
}
} else {
NSLog(@"Auth Challenge Failed");
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
The results, well ... not very good. The call ends with a handshake error. Calling a site with chrome and the same certificate actually works fine, which made me check in Wireshark what the difference is between the two calls.
With Chrome, everything looks fine, as with the TLS handshake.
iOS TLSv1 Chrome SSLv3: . , , - :
Frame 102: 66 bytes on wire (528 bits), 66 bytes captured (528 bits)
Ethernet II, Src: Apple_XX:XX:XX (XX:XX:XX:XX:XX:XX), Dst: Cisco-Li_3d:96:d0 (XX:XX:XX:XX:XX:XX)
Internet Protocol Version 4, Src: imac.local (192.168.1.9), Dst: xxx.xxx.xxx (xxx.xxx.xxx.xxx)
Transmission Control Protocol, Src Port: 63324 (63324), Dst Port: https (443), Seq: 187, Ack: 4244, Len: 12
Secure Sockets Layer
TLSv1 Record Layer: Handshake Protocol: Certificate
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 7
Handshake Protocol: Certificate
Handshake Type: Certificate (11)
Length: 3
Certificates Length: 0
:
Frame 108: 248 bytes on wire (1984 bits), 248 bytes captured (1984 bits)
Ethernet II, Src: Apple_XX:XX:XX (XX:XX:XX:XX:XX:XX), Dst: Cisco-Li_XX:XX:XX (XX:XX:XX:XX:XX)
Internet Protocol Version 4, Src: imac.local (192.168.1.9), Dst: xxx.xxx.xxx (xxx.xxx.xxx.xxx)
Transmission Control Protocol, Src Port: 63325 (63325), Dst Port: https (443), Seq: 2947, Ack: 4244, Len: 194
[3 Reassembled TCP Segments (2954 bytes): #106(1380), #107(1380), #108(194)]
Secure Sockets Layer
TLSv1 Record Layer: Handshake Protocol: Certificate
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 2949
Handshake Protocol: Certificate
Handshake Type: Certificate (11)
Length: 2945
Certificates Length: 2942
Certificates (2942 bytes)
Certificate Length: 1024
Certificate (id-at-organizationName=XX,id-at-organizationalUnitName=XX,id-at-serialNumber=XX,id-at-countryName=XX,id-at-commonName=XXXXXX)
Certificate Length: 995
Certificate (id-at-serialNumber=XX,id-at-commonName=XXXX,id-at-countryName=XX)
Certificate Length: 914
Certificate (id-at-commonName=XXXX,id-at-countryName=XX)
- - - ?
, - - , , , ...