2016-08-12 50 views
1

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

我有作为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]; 
} 
} 

回答

1

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

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

人们谁是懒得打开链接,我会在这里从后添加一些说明。

enter image description here

+1

这会起作用,但它并不理想,因为证书最终会过期并重新生成,因此将不再匹配预期的散列值。最好从信任对象中获取公钥并将其与预期的密钥进行比较。这样,即使管理员重新生成证书(假设管理员不更改密钥),它仍将继续信任服务器。 – dgatwood

+0

感谢您的链接!我会看看 –

+0

这个链接是否工作? – Harsh

1

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

这种技术被称为“证书锁定”,并且我确信在Stack Overflow中可能有大量的答案,如果您搜索该术语可以提供完整的代码示例。

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

或者,如果您愿意将其与特定的长期私有根证书绑定,您可以将其添加到受信任的锚定列表中,并重新评估该信任对象,并注意这将在该私有根证书到期。另一方面,如果您固定密钥,如果您因为某些原因必须更改私钥,它将会中断...所以这是一个折衷。

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

+0

感谢您的回答。我将研究更多关于证书固定的内容。你是对的,在这种情况下不可能使用真正的CA证书 –