使用NSURLConnection连接到具有自签名证书的https时,kSecTrustResultRecoverableTrustFailure

我在这里看到几个问题,但没有一个帮助我。 人们主要解决的问题是重新生成服务器证书: kSecTrustResultRecoverableTrustFailure的原因是什么?

假设我需要使用自签名证书与服务器进行https连接。 我没有从服务器的任何内部数据,如其私钥。 例如,服务器是https://www.pcwebshop.co.uk/

据我所知,我可以将客户端证书捆绑到应用程序中,并将其用于validation。 我是否可以获得有效的客户端证书,而无需从服务器获取任何内部数据?

我在这里使用了一个教程http://www.indelible.org/ink/trusted-ssl-certificates

以下是我如何获得客户端证书

openssl s_client \ -showcerts -connect "${HOST}:443" </dev/null 2>/dev/null | \ openssl x509 -outform DER >"../resources/${HOST}.der" 

这是代码(几乎不变):

 - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; } - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if ([self shouldTrustProtectionSpace:challenge.protectionSpace]) { [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; } else { [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; } } - (BOOL)shouldTrustProtectionSpace:(NSURLProtectionSpace *)protectionSpace { // load up the bundled certificate NSString *certPath = [[NSBundle mainBundle] pathForResource:protectionSpace.host ofType:@"der"]; if (certPath == nil) return NO; OSStatus status; NSData *certData = [[NSData alloc] initWithContentsOfFile:certPath]; CFDataRef certDataRef = (__bridge_retained CFDataRef)certData; SecCertificateRef cert = SecCertificateCreateWithData(NULL, certDataRef); // establish a chain of trust anchored on our bundled certificate CFArrayRef certArrayRef = CFArrayCreate(NULL, (void *)&cert, 1, NULL); SecTrustRef serverTrust = protectionSpace.serverTrust; status = SecTrustSetAnchorCertificates(serverTrust, certArrayRef); // status == 0 // verify that trust SecTrustResultType trustResult; status = SecTrustEvaluate(serverTrust, &trustResult); // status == 0 CFRelease(certArrayRef); CFRelease(cert); CFRelease(certDataRef); return trustResult == kSecTrustResultUnspecified; } 

trustResult始终是kSecTrustResultRecoverableTrustFailure。

我究竟做错了什么? 谢谢。

更新 :好的,我发现原因是“服务器的证书不符合URL”。

是否可以通过忽略服务器证书的URL(主机名)来解决客户端问题?

假设我需要使用自签名证书与服务器进行https连接。 我没有从服务器的任何内部数据,如其私钥。

在这种情况下,您需要一个安全多元化战略。 Gutmann在他的“ 工程安全 ”( Engineering Security)一书中详细介绍了它。

缺点是:第一次遇到证书时会明智地validation证书。 您仍然可以使用大部分传统的PKI / PKIXtesting。 一旦证书通过了所有testing(除“可信根path”之外),则您将其称为“可信”。 这种策略被称为信任首先使用或TOFU。

在随后的连接中,由于您已经遇到证书或公钥,因此不需要再次使用TOFU。 在随后的连接中,确保证书或公钥是连续的(即不会更改),IP与以前遇到的区域相同,等等。如果证书发生更改,请确保它是因为自签名过期。 警惕意外的变化。


 Here's the code (almost unchanged): ... trustResult == trustResult == kSecTrustResultUnspecified 

对于kSecTrustResultUnspecified ,请参阅技术问答QA1360 。 本质上,它是一个可恢复的错误。 问答表示提示用户。 古特曼(和我)说如上所述使用安全多样化战略。

您需要将用户从循环中取出,因为他们总是会尽可能快地通过消息框来做出决定。 如果他们回答正确或错误,他们就不会死了 – 他们想看跳舞的兔子。

此外,安全多样化战略甚至适用于kSecTrustResultProceed 。 考虑一下: Diginotar和Trustwave都破坏了PKI {X},而Cocoa / CocoaTouch非常乐意返回kSecTrustResultProceed 。 它不是真正的Cocoa / CocoaTouch的缺点 – 有PKI {X}的架构缺陷。


是否可以通过忽略服务器证书的URL(主机名)来解决客户端问题?

这种打破了PKI {X}的目的。 如果您接受任何主机,任何公钥或任何签名,为什么还要打扰PKI {X}呢? PKI {X}中X509的全部要点是使用受信任的第三方签名(或本例中的自签名)将实体或主机绑定到公钥。

如果你不关心绑定,只需使用匿名Diffie-Hellman,并结束安全剧场。