简体   繁体   中英

Unable to open secure websocket using custom CA

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).

I've never heard of being able to add a certificate to the application's trusted anchors. Generally, this can only be done at the device level through the iPhone Configuration Utility. Is that what you mean by "manually?" (ie installing it such that Safari would also honor it?) If you read down into the comments of the blog post you link, you note that Heath (who is a really smart guy, so I'm careful before I disagree with him), notes that:

I'm NOT adding a cert to the keychain. I'm creating a SecTrust object and using it to authenticate the connection. You can only add certs to the keychain with the iPhone Configuration Utility. Unless you add a cert to the keychain, I doubt NSURLConnection would work properly.

That matches my experience and tests. (I don't know why he says "Next, you can add your cert to your app's keychain. This is appropriate when you want iOS to trust your cert for every new socket you create.")

In my experience, you have to implement the authentication delegate methods for NSURLConnection and perform the SecTrustEvaluate yourself. Here's an example of that.

Remember, there really is only one keychain; there are just access groups into it that make it kind of look like you have a private keychain. And there is, as far as I've ever discovered, only one trusted anchor list in that keychain, shared by everyone.

This doesn't help you a lot with socket.io, because it doesn't give you access to its NSURLConnection delegate methods. You'd have to modify socket.io to accept a trust anchor.

You may find the presentation, Practical Security , useful. Start around page 5. This is where the example code above comes from.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM