Objective-C报”NSStreamSocketSSLError”异常的原因和解决办法

  • Post category:IOS

Objective-C中,当进行加密通信的时候,可能会出现”NSStreamSocketSSLError”异常。扫描错误代码可以发现,其错误码为-9843,错误描述为”Informative SSL connection failed”,而其根本原因往往是证书验证失败。

处理这种错误的方法,一般有以下两种:

1. 忽略证书验证

一些情况下,我们可能并不关心对方是否是安全的,或者我们使用的是自签名证书,此时,我们可以忽略证书验证,直接进行加密通信,示例代码如下:

// 给流操作设置安全属性,此处省略流操作细节
NSDictionary *sslProperties = @{
    (__bridge NSString*)kCFStreamSSLValidatesCertificateChain: @NO
};
[stream setProperty:sslProperties forKey:(__bridge NSString*)kCFStreamPropertySSLSettings];

// 进行加密通信

不过,需要注意的是,忽略证书验证可能会存在安全隐患,因此在实际应用中应该谨慎使用。

2. 添加根证书

在某些情况下,我们必须要验证对方的证书是否有效,此时我们需要添加对方的证书的根证书,才能进行加密通信。步骤如下:

2.1 获取对方证书

通常对方会提供一份证书给我们,我们可以从网络上下载对方的证书。以Apple的公钥为例,可以使用以下代码从官方网站上下载证书:

NSURL *url = [NSURL URLWithString:@"https://www.apple.com/"];
NSData *certData = [NSData dataWithContentsOfURL:[url URLByAppendingPathComponent:@"security/certs/GeoTrust_Primary_CA.pem"]];

2.2 导入根证书

我们需要将对方证书的根证书导入到我们的钥匙串中,使得我们可以进行验证。步骤如下:

  • 双击证书文件(.pem)打开它
  • 在”钥匙串访问”界面,选择证书,将其拖动到”我的证书”目录下,就会在钥匙串中添加一份新证书
  • 右击新证书,选择”显示简介”,在对话框中,找到”信任”选项,选择”始终信任”

2.3 验证对方证书

在导入根证书后,我们可以在代码中进行证书验证,以确保对方的证书是真实有效的。示例代码如下:

// 给流操作设置安全属性,此处省略流操作细节

// 创建可信评审对象
SecTrustRef trust = (__bridge SecTrustRef)([sslProperties objectForKey:(__bridge id)_kCFStreamPropertySSLPeerTrust]);
SecTrustResultType resultType;
OSStatus status = SecTrustEvaluate(trust, &resultType);
BOOL certificateIsValid = (status == errSecSuccess) && (resultType == kSecTrustResultUnspecified);

if (!certificateIsValid) {
    // 证书非法
    [stream close];
    return;
}

// 进行加密通信

需要注意的是,生产环境中,我们可以使用自己的证书进行验证,以确保通信安全。