手动验证 TLS 证书 (ios objective-c)

Manually validate TLS Certificate (ios objective-c)

我正在创建一个 iOS 应用程序,它使用 TLS 与 Web 服务器通信。当我访问 Web 服务器时,它会向我的设备提供证书,我想验证我是否可以信任它。

我将根证书作为 der 文件嵌入到我的 xcode 项目中。到目前为止,我的代码在 NSURLConnection 的委托函数中获取了两个证书的 NSString 版本以进行身份​​验证质询。

关于如何手动验证有什么想法吗?

这是我当前的代码:

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSLog(@"Certificate challenge");
if (self.stageNum==0) {
    id <NSURLAuthenticationChallengeSender> sender=challenge.sender;
    NSURLProtectionSpace *protectionSpace=challenge.protectionSpace;
    SecTrustRef trust=[protectionSpace serverTrust];

    //Get server certificate
    SecCertificateRef certificate=SecTrustGetCertificateAtIndex(trust, 0);
    NSData *serverCertificateData=(__bridge NSData *)SecCertificateCopyData(certificate);
    NSString *serverBase64Certificate=[serverCertificateData base64EncodedStringWithOptions:0];

    //Get our certificate
    NSData *certData1 = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"SUMOSRoot" ofType:@"der"]];
    NSString *certBase64=[certData1 base64EncodedStringWithOptions:0];

    //Heres where I need to compare the certificates
    //
    //

    [sender useCredential:[NSURLCredential credentialForTrust:protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
}

我认为 post 可以解决您的问题。漂亮 written/explained.

http://www.techrepublic.com/blog/software-engineer/use-https-certificate-handling-to-protect-your-ios-app/

懒得打开链接的人,我会在post这里添加一些描述。

我不确定您为什么想要 NSString 代表。获得 SecTrustRef 后,您可以调用 SecTrustCopyPublicKey 将 public 密钥复制到 SecKeyRef,然后将其与原始密钥数据(原始字节)进行比较。如果 public 密钥匹配,您应该接受证书。

这种技术称为 "certificate pinning",我相信 Stack Overflow 上可能有许多答案,如果您搜索该术语,可以提供完整的代码示例。

表面上你也可以比较证书,但这可能不是你想要做的,因为证书会定期过期并且必须更新。如果您比较密钥,那么即使他们重新生成证书,它也会继续工作(假设他们使用相同的 private/public 密钥对重新生成证书)。

或者,如果您愿意将它绑定到一个特定的长期私有根证书,您可以将其添加到受信任的锚点列表并重新评估信任对象,但需要注意的是,当私有时这将中断根证书过期。另一方面,如果你固定密钥,如果你出于某种原因必须更改私钥,它就会中断......所以这是一个权衡。

当然,一般来说,最好的选择是获得真正的 CA 证书,并且不要干扰任何链验证,但我假设这是不可能的 (例如,因为服务器位于 .local 域中,在无法访问 Internet 或其他类似原因生成自己的证书的物理设备上)。因此,对于与 .local 网络上的任意硬件进行安全通信之类的事情,密钥固定是最好的方法。如果密钥不匹配,则要求用户将其添加为新设备或其他。