SSL套接字连接iOS

8
我正在尝试建立到Java运行的SSLServerSocket的安全连接。
我已经创建了自己的根CA,并使用此证书签名了Java SSLServerSocket使用的证书。
我想将此根证书添加到我的应用程序中,以便任何由根证书签名的证书都可以正常工作。
到目前为止,我已经通过将读写流属性设置为以下内容使安全连接正常工作:
NSDictionary *settings = [[NSDictionary alloc] initWithObjectsAndKeys:
(id)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamPropertySocketSecurityLevel,
[NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
[NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredRoots,
[NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,nil];

我这样将证书添加到钥匙串中:

-(void)addRootCert{
NSString* rootCertPath = [[NSBundle mainBundle] pathForResource:@"rootCA" ofType:@"der"];
NSData* rootCertData = [NSData dataWithContentsOfFile:rootCertPath];

OSStatus err = noErr;
SecCertificateRef rootCert = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)rootCertData);
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge_transfer id)kSecClassCertificate, kSecClass, rootCert, kSecValueRef, nil];

err = SecItemAdd((__bridge CFDictionaryRef) dict, NULL);
if (err == noErr) {
    NSLog(@"Sucessfully added root certificate");
}else if (err == errSecDuplicateItem){
    NSLog(@"Root certificate already exists");
}else{
    NSLog(@"Root certificate add failed");
}
}

这很好,但我希望验证证书链,以便我的应用程序只接受由我的CA(或默认的受信任证书)签名的证书。
我该怎么做?
如果我将 kCFStreamSSLValidatesCertificateChain 设置为是,我会收到错误:CFNetwork SSLHandshake failed (-9807),但如果设置为否,不管谁签署了服务器证书,都可以连接(我认为是这样的?)
谢谢!
2个回答

6

Technote 2232,“HTTPS服务器信任评估”,应该能够解决您所有问题。其中包含了文档和多个评估服务器信任的示例。


谢谢提供这个链接,根据它关于使用SecTrustSetAnchorCertificates的说明,我想将我的根证书添加到其中,但我没有SecTrustRef,我该如何创建一个?所有我看到的例子都是使用NSURLConnection委托方法,但我正在使用套接字。 - ABC
3
这可能是你在寻找的内容:https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html。 - quellish
谢谢,那个最后的链接非常完美! - ABC
@quellish,你的建议对我帮助很大。谢谢! - Goppinath

0

我之前遇到了同样的问题,虽然手动添加证书确实可以解决问题,但这也意味着每次服务器上的证书更改时(例如过期,对我来说只剩几天),必须更新应用程序。

如果您使用IP地址连接到套接字,并且证书是用于FQDN(完全限定域名,即子域名.example.com)的,则当操作系统检查证书时,它会查看您正在连接的IP地址,将其与证书中的名称进行比较,并认为两者不同,从而导致链验证失败。

因此,对于任何遇到此问题的人,我建议在CFStreamCreatePairWithSocketToHost的第二个参数中使用FQDN而不是IP地址。之后,应该能够正常工作,无需包含证书并手动验证。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接