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

时间:2016-08-12 21:24:44

标签: ios objective-c certificate nsurlconnection tls1.2

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

我将xcode项目中嵌入的根证书作为der文件。到目前为止,我所拥有的代码在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];
}
}

2 个答案:

答案 0 :(得分:1)

我认为这篇文章解决了你的目的。精美的书面/解释。

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

懒得打开链接的人,我会在帖子中添加一些描述。

enter image description here

答案 1 :(得分:1)

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

这种技术称为&#34;证书固定&#34;,我确定Stack Overflow上可能有很多答案可以提供完整的代码示例,如果你搜索该术语。

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

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

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