I am writing an iOS application that uses socket.io (the socket.io-objc library) to connect to local and remote servers. My connection to the remote server already uses TLS without any problems. The remote servers have certificates that are signed by a well-known CA. Now I want to secure the local connection using as well. However, it is not possible for these local certs to be signed by a well-known CA.
So far, I've generated a custom CA certificate and used that to sign the local server's certificate. I believe this is working because if i manually install the CA cert onto my iPad i am able to connect to the server.
Now I'm trying to install the CA certificate automatically in the application using this article as a reference. The problem I'm having is that although it appears I can successfully add the certificate to my app's keychain, my socket connection does not seem to be using it.
On startup, my app installs the CA:
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSData *iosTrustedCertDerData = [NSData dataWithContentsOfFile:[bundle pathForResource:@"myRootCA" ofType:@"der"]];
SecCertificateRef certificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef) iosTrustedCertDerData);
CFDictionaryRef dict = (__bridge CFDictionaryRef)([NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id) (kSecClassCertificate), kSecClass,
certificate, kSecValueRef,
nil]);
OSStatus err = SecItemAdd(dict, NULL);
if (err == noErr) {
NSLog(@"####### IT WORKS!!!!!!!!!");
}
else if (err == errSecDuplicateItem) {
NSLog(@"###### IT WAS ALREADY THERE!!!");
}
else {
NSLog(@"####### IT BROKEN!!!!!!!!");
}
The first time this ran, it printed out "IT WORKS". Now it prints out "IT WAS ALREADY THERE". This is as expected. Then, when I try to connect I just open my socket.io connection like normal
SocketIO* socketIO = [[SocketIO alloc] initWithDelegate:self];
socketIO.useSecure = YES;
[socketIO connectToHost:url onPort:port];
This results in the error:
The certificate for this server is invalid. You might be connecting to a server that is pretending to be “myserver.local” which could put your confidential information at risk.
Again, if i install the cert manually then everything works fine. All of my searches for how to programmatically add/trust a cert point back to SecItemAdd. But this does not appear to be working for me. Is it possible to add/trust a custom CA cert using socket.io-obj and SocketRocket libraries that are managing the socket connection?
Note: I do not want to completely disable certificate validation nor do I want to accept all self-signed certificates. If possible, i would prefer to accept only certificates that were signed by my custom CA (and the default trusted CAs).