2012-06-11 220 views
1


       我是相當新的使用SSL通道消費web服務。經過相當不錯的搜索後,我發現了一種使用NSURLConnection委託API執行SSL/HTTPS身份驗證的方法。以下是代碼片段進行實際驗證的事情:
iOS和SSL:無法驗證自簽名的服務器證書

- (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 app Examination


讓我知道如果有什麼不對。

謝謝。

+0

不,我沒有使用ASIHTTPRequest APIs。我正在使用NSURLConnection API,此時不能更改爲其他第三方庫。 我正在使用使用OpenSSL創建的服務器使用自簽名證書。 –

+0

[NSURLConnection問題]的可能重複(http:// stackoverflow。com/questions/3766755/problem-with-nsurlconnection) – paulmelnikow

回答

1

我弄清楚瞭如何解決這個問題。

我結束了比較客戶端和服務器信任證書,逐字節。儘管可能有另一種解決這類自簽證書問題的方法,但對於此解決方案確實起作用。 這裏是我正在做的客戶端和服務器證書的比較,逐字節,用他們的CFData對象(您也可以參考蘋果公司提供「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]; 
     } 

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

謝謝。

2

我無法確定您的代碼是否有效,因爲我使用RestKit來使用REST接口,但導致NSURLErrorDomain Code=-1012的最常見問題是自簽名證書沒有指向Web服務的subject alternative name擴展名地址。

要檢查您的證書,請下載Portecle app,如果您需要查看SSL證書,非常有用。運行它並從菜單中選擇檢查 - >檢查證書並導航到您的證書。您將看到有關您的證書的基本信息,現在請按檢查按鈕,然後使用主題替代名稱,並確保您的Web服務的正確IP地址在那裏。如果沒有,您需要重新創建證書,並附上這些信息。

+0

謝謝@lawicko。我下載了Portecle應用程序並檢查了證書。 –

+1

正如你所看到的,'擴展'按鈕是灰色的,這意味着你的證書沒有任何。這是證書未在我的案例中驗證的直接原因。我所做的只是要求負責Web服務的人創建新證書。不幸的是,我所知道的是他爲此使用了openssl,所以我無法提供更多幫助,但我認爲這值得進一步研究。 – lawicko

+0

謝謝謝謝謝謝謝謝謝謝! – Dexter