2014-06-15 75 views
2

我在這裏看到幾個問題,但他們都沒有幫助我。人們通常會解決問題,主要是重新生成服務器證書:What is the reason of kSecTrustResultRecoverableTrustFailure?kSecTrustResultRecoverableTrustFailure使用NSURLConnection連接到使用自簽名證書的https

假設我需要使用自簽名證書與服務器進行https連接。我沒有來自服務器的任何內部數據,例如其私鑰。例如,服務器是https://www.pcwebshop.co.uk/

據我瞭解,我可以將客戶端證書捆綁到應用程序中,並將其用於驗證。我是否可以在沒有來自服務器的任何內部數據的情況下獲得有效的客戶端證書?

我GOOGLE了這裏的教程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。

我在做什麼錯?謝謝。

UPDATE:好的,我發現原因是「服務器的證書與URL不匹配」。

是否可以通過忽略服務器證書的URL(主機名)來解決客戶端問題?

回答

3

假設我需要使用自簽名證書與服務器進行https連接。我沒有任何來自服務器的內部數據,如其私鑰。

在這種情況下,您需要安全多元化戰略。古特曼在他的書Engineering Security中詳細地介紹了它。

它的缺點是:首次遇到它時明智地驗證證書。您仍然可以使用大部分傳統的PKI/PKIX測試。一旦證書通過了所有測試(除「可信根路徑」之外),您就稱其爲「可信」。這種策略被稱爲首次使用信託或TOFU。

在隨後的連接中,由於您已經遇到證書或公鑰,因此不需要再次TOFU。在隨後的連接中,您要確保證書或公鑰是連續的(即不會更改),IP來自之前遇到的同一區域,等等。如果證書發生更改,請確保它是因爲自簽名過期。警惕意外的變化。


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

對於kSecTrustResultUnspecified,看到Technical Q&A QA1360。從本質上講,它是一個可恢復的錯誤。 Q & A表示提示用戶。如上所述,古特曼(和我)說要使用安全多樣化策略。

您需要將用戶帶出循環,因爲他們總是會做出決定,讓他們儘快通過消息框。如果他們回答正確或錯誤,他們就不會死了 - 他們想看跳舞的兔子。

此外,安全多樣化策略甚至適用於kSecTrustResultProceed。考慮一下:DiginotarTrustwave破壞了PKI {X},而Cocoa/CocoaTouch非常樂意返回kSecTrustResultProceed。它不是真正的Cocoa/CocoaTouch的缺點 - PKI {X}存在架構缺陷。


是否有可能忽略了服務器證書的URL(主機名)來解決從客戶端的問題?

那種破壞PKI {X}的目的。如果您接受任何主機,任何公鑰或任何簽名,爲什麼還要首先考慮PKI {X}? PKI {X}中X509的全部要點是使用受信任的第三方簽名(或本例中的自簽名)將實體或主機綁定到公鑰。

如果您不關心綁定,只需使用Anonymous Diffie-Hellman並結束安全劇場即可。

+1

好的,現在我決定只是將服務器證書與本地副本進行比較,並檢查主機名的IP地址是否與我的本地副本匹配。希望我能找到如何檢索服務器證書和IP地址的工作示例=/ – alopatindev

+1

這是很好的策略。其稱爲證書鎖定。 IP塊很適合。你不希望有一天看到美國或英國的IP地址,然後看到下一個俄羅斯IP。可能會發生一些魚腥味...... – jww