簡體   English   中英

iOS 和 SSL:無法驗證自簽名服務器證書

[英]iOS and SSL: Unable to validate self-signed server certificate


我對使用 SSL 通道使用網絡服務還很陌生。 經過相當不錯的搜索,我找到了一種使用 NSURLConnection 委托 API 執行 SSL/HTTPS 身份驗證的方法。 以下是執行實際身份驗證的代碼片段:

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
[self printLogToConsole:@"Authenticating...."];
[self printLogToConsole:[NSString stringWithFormat:@"\n%@\n", [challenge description]]];
NSLog(@"\n\nserverTrust: %@\n", [[challenge protectionSpace] serverTrust]);

/* Extract the server certificate for trust validation
 */
NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
assert(protectionSpace);
SecTrustRef trust = [protectionSpace serverTrust];    
assert(trust);
CFRetain(trust); // Make sure this thing stays around until we're done with it
NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];


/* On iOS 
 * we need to convert it to 'der' certificate. It can be done easily through Terminal as follows:
 * $ openssl x509 -in certificate.pem -outform der -out rootcert.der
 */
NSString *path = [[NSBundle mainBundle] pathForResource:@"rootcert" ofType:@"der"];
assert(path);
NSData *data = [NSData dataWithContentsOfFile:path];
assert(data);

/* Set up the array of certificates, we will authenticate against and create credentials */
SecCertificateRef rtCertificate = SecCertificateCreateWithData(NULL, CFBridgingRetain(data));
const void *array[1] = { rtCertificate };
trustedCerts = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
CFRelease(rtCertificate); // for completeness, really does not matter

/* Build up the trust anchor using our root cert */
int err;
SecTrustResultType trustResult = 0;
err = SecTrustSetAnchorCertificates(trust, trustedCerts);
if (err == noErr) {
    err = SecTrustEvaluate(trust, &trustResult);
}
CFRelease(trust); // OK, now we're done with it

[self printLogToConsole:[NSString stringWithFormat:@"trustResult: %d\n", trustResult]];

/* http://developer.apple.com/library/mac/#qa/qa1360/_index.html
 */
BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultConfirm) || (trustResult == kSecTrustResultUnspecified));

// Return based on whether we decided to trust or not
if (trusted) {
    [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
    [self printLogToConsole:@"Success! Trust validation successful."];
} else {
    [self printLogToConsole:@"Failed! Trust evaluation failed for service root certificate.\n"];
    [[challenge sender] cancelAuthenticationChallenge:challenge];
}

}

但我收到以下錯誤:

2012-06-11 17:10:12.541 SecureLogin[3424:f803] Error during connection: Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x682c790 {NSErrorFailingURLKey=https://staging.esecure.url/authentication/signin/merchants, NSErrorFailingURLStringKey=https://staging.esecure.url/authentication/signin/merchants}


我正在使用從服務器獲得的相同證書並將其轉換為“der”格式。 我正在為 iOS 5.x 構建應用程序。 我不確定我是否錯過了什么。 讓我知道你的建議。

謝謝。

編輯在此處檢查證書后輸出的外觀:Portecle 應用程序考試


如果有什么問題,請告訴我。

謝謝。

我不知道,如果你的代碼是有效還是無效,因為我用RestKit為使用REST接口,但最常見的問題,導致NSURLErrorDomain Code=-1012是自簽名的證書不具有subject alternative name擴展指向網絡服務,如果地址。

要檢查您的證書,請下載Portecle 應用程序,如果您需要查看 ssl 證書,該應用程序非常有用。 運行它並從菜單中選擇“檢查”->“檢查證書”並導航到您的證書。 您將看到有關您的證書的基本信息,現在按檢查按鈕,然后按主題備用名稱,並確保您的網絡服務的正確 IP 地址在那里。 如果沒有,您需要使用此信息再次創建證書。

我確實想出了如何解決這個問題。

我最終逐字節比較了客戶端和服務器信任證書。 雖然可能有另一種方法來解決自簽名證書的此類問題,但對於此解決方案確實有效。 這是我如何使用它們的 CFData 對象逐字節比較客戶端和服務器證書(您也可以參考 Apple 提供的“AdvancedURLConnections”示例代碼):

success = NO;
        pServerCert = SecTrustGetLeafCertificate(trust);
        if (clientCert != NULL) {
            CFDataRef       clientCertData;
            CFDataRef       serverCertData;

            clientCertData = SecCertificateCopyData(clientCert);
            serverCertData   = SecCertificateCopyData(pServerCert);

            assert(clientCertData != NULL);
            assert(serverCertData   != NULL);

            success = CFEqual(clientCertData, serverCertData);

            CFRelease(clientCertData);
            CFRelease(serverCertData);
        }
        if (success) {
            [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
            [self printLogToConsole:@"Success! Trust validation successful."];
        } else {
            [self printLogToConsole:@"Failed! Trust evaluation failed for service root certificate.\n"];
            [[challenge sender] cancelAuthenticationChallenge:challenge];
        }

希望這會幫助正在尋找類似問題解決方案的人,

謝謝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM