我使用SSL渠道消费webservices相当新。经过相当不错的搜索后,我找到了一种使用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构建应用程序。
我不确定我是否错过了什么。让我知道你的建议。
感谢。
修改 在此处检查证书之后输出的外观如何:
如果出现问题,请告诉我。
感谢。
答案 0 :(得分:2)
我无法确定您的代码是否有效,因为我使用RestKit来使用REST接口,但导致NSURLErrorDomain Code=-1012
的最常见问题是自签名证书没有subject alternative name
如果地址,则指向Web服务的扩展名。
要检查您的证书,请下载Portecle app,如果您需要查看ssl证书,这非常有用。运行它并从菜单中选择Examine-> Examine Certificate并导航到您的证书。您将看到有关证书的基本信息,现在按下“检查”按钮,然后按“主题备用名称”,并确保您的Web服务的IP地址正确。如果没有,您需要使用此信息再次创建证书。
答案 1 :(得分:1)
我确实知道如何解决这个问题。
我最终逐字节地比较了客户端和服务器信任证书。虽然可能有另一种方法来解决自签名证书的问题,但是对于这个解决方案确实有效。 下面是我如何使用他们的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];
}
希望这能帮助正在寻找类似问题解决方案的人,
感谢。