繁体   English   中英

使用NSURLConnection使用自签名证书连接到https时,出现kSecTrustResultRecoverableTrustFailure

[英]kSecTrustResultRecoverableTrustFailure when connecting to https with self-signed certificate using NSURLConnection

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

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

据我了解,我可以将客户端证书捆绑到应用中并用于验证。 我可以在没有服务器内部任何数据的情况下获得有效的客户端证书吗?

我已经在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连接。 我没有来自服务器的任何内部数据,例如其私钥。

在这种情况下,您需要一种安全性多样化策略。 古特曼在他的“ 工程安全”一书中对此进行了详细的论述。

它的缺点:第一次遇到该证书时,请明智地对其进行验证。 您仍然可以使用大多数传统的PKI / PKIX测试。 一旦证书通过了所有测试(“受信任的根路径”除外),则将其称为“受信任”。 此策略称为首次使用信任或TOFU。

在后续连接中,您不再需要TOFU,因为您已经遇到了证书或公钥。 在随后的连接中,您确保证书或公钥是连续的(即不变),IP与以前遇到的区域相同,以此类推。如果证书发生更改,请确保其证书有效,因为自签名即将到期。 警惕意料之外的变化。


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

有关kSecTrustResultUnspecified ,请参见技术问答QA1360 本质上,这是一个可恢复的错误。 问与答提示用户。 古特曼(和我)说要使用如上所述的安全多元化策略。

您需要使用户脱离循环,因为他们总是会做出使他们尽快越过消息框的决定。 无论他们回答对还是错都无所谓-他们想看跳舞的兔子。

同样,安全性多样化策略甚至适用于kSecTrustResultProceed 考虑一下: DiginotarTrustwave都破坏了PKI {X},并且Cocoa / CocoaTouch很高兴返回kSecTrustResultProceed 这并不是真正的Cocoa / CocoaTouch的错-PKI {X}会存在体系结构缺陷。


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

这种做法破坏了PKI {X}的目的。 如果您将接受任何主机,任何公钥或任何签名,那么为什么一开始还要打扰PKI {X}? PKI {X}中X509的全部重点是使用受信任的第三方签名(在这种情况下为自签名)将实体或主机绑定到公钥。

如果您不关心绑定,只需使用Anonymous Diffie-Hellman并结束安全战区。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM