我正在使用 sha1WithRSAEncryption(即不是 MD5,根据SecTrustEvaluate 在 iOS 5 上返回 kSecTrustResultRecoverableTrustFailure)使用简单的 ca->subca->server 沿袭生成的服务器证书。
openssl req -new -x509 -subj /CN=ca/O=1002 -nodes -keyout /dev/stdout -set_serial 4 -days 3650 > ca-1002.pem
openssl req -new -subj /CN=sub-ca/O=1002 -nodes -keyout subca-1002.pem -set_serial 5 -days 3650 | openssl x509 -CA ca-1002.pem -req -set_serial 1 >> subca-1002.pem
openssl req -new -subj /CN=localhost:2002/O=1002 -nodes -keyout cert-1002.pem -set_serial 6 -days 3650 | openssl x509 -CA subca-1002.pem -req -set_serial 1 >> cert-1002.pem
对于服务器;带有服务器 SSLCACertificateFile 的链和稍后将由 iPhone/iPad 应用程序读取的 DER 文件。
cat ca-1002.pem subca-1002.pem > chain-1002.pem
openssl x509 -in ca-1002.pem -outform DER -out ca-1002.der
我确保我在评估中有发言权:
-(BOOL)connection:(NSURLConnection *)aConnection
canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)space
{
DLog(@" authenticationMethod: %@",[space authenticationMethod]);
// nil/not set - rely on the keychain, set to an empty array indicates
// we know what we're doing -and accept anything - otherwise a list
// of certs gotten from reading in DER files.
//
NSArray *acceptableCAs = [delegate sslAcceptableServerCACertificates];
if ([[space authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
NSArray *acceptableCAs = [delegate sslAcceptableServerCACertificates];
return acceptableCAs != nil ? YES : NO;
}
// Client cert stuff snipped.
// the keychain is used.
return NO;
}
到目前为止,一切都很好。
-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSURLProtectionSpace * space = [challenge protectionSpace];
if ([space.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
NSArray *acceptableCAs = [delegate sslAcceptableServerCACertificates];
NSURLCredential *newCredential;
if (acceptableCAs == nil) { ... }
// We'll leave this to the keychain by doing nothing. (works splendidly)
else if ([acceptableCAs count] == 0) { }
// We'll accept 'anything' - or in this case - exactly this server.
// (this works just fine).
有效 - 但是当我明确指定 1 个或多个证书时 - 事情失败了:
else {
SecTrustRef secTrustRef = challenge.protectionSpace.serverTrust;
SecTrustResultType result;
NSMutableArray * serverChain = [[NSMutableArray alloc] init];
for(long i = 0; i < SecTrustGetCertificateCount(secTrustRef); i++) {
SecCertificateRef cr = SecTrustGetCertificateAtIndex(secTrustRef, i);
DLog(@"Server cert %04ld: %@", i, cr);
DLog(@" %@", [SimpleCertificate sha1fingerprint:cr]);
[serverChain addObject:(__bridge id)(cr)];
}
for(NSUInteger i = 0; i < [acceptableCAs count]; i++) { .. dump these too }
SecTrustSetAnchorCertificatesOnly(secTrustRef, YES);
SecTrustSetAnchorCertificates(secTrustRef, (__bridge CFArrayRef)acceptableCAs);
// SecTrustSetAnchorCertificatesOnly(secTrustRef, NO);
// assert(SecTrustCreateWithCertificates((__bridge CFTypeRef)(serverChain), SecPolicyCreateSSL(YES, nil), &secTrustRef) == noErr);
// assert(SecTrustCreateWithCertificates((__bridge CFTypeRef)(serverChain), SecPolicyCreateSSL(NO, nil), &secTrustRef) == noErr);
// assert(SecTrustCreateWithCertificates((__bridge CFTypeRef)(serverChain), SecPolicyCreateBasicX509(), &secTrustRef) == noErr);
// assert(SecTrustSetVerifyDate(secTrustRef, ...);
assert(SecTrustEvaluate(secTrustRef, &result) == noErr);
DLog(@"SecTrustEvaluate gives us: %lu", result);
....
我收到以下错误。SecTrustEvaluate 总是给我 5 分(有时是 4 分)。
尝试过各种建议;例如日期移位,验证它是 sha1 而不是 md5 等。
athAgstPrSp:] [Line 68] authenticationMethod: NSURLAuthenticationMethodServerTrust
didRecAChlg:] [Line 98] authenticationMethod: NSURLAuthenticationMethodServerTrust
didRecAChlg:] [Line 143] Server cert 0000: <cert(0xd637ce0) s: localhost:2002 i: sub-ca>
didRecAChlg:] [Line 144] 8D:21:95:20:11:D0:9C:27:86:56:B3:0B:A6:F7:A2:CF:4C:F6:67:64
didRecAChlg:] [Line 143] Server cert 0001: <cert(0xd638710) s: sub-ca i: ca>
didRecAChlg:] [Line 144] 30:58:8E:F9:B8:29:5E:84:46:E3:0B:98:0D:B0:28:23:3D:7E:86:A3
didRecAChlg:] [Line 143] Server cert 0002: <cert(0xd638af0) s: ca i: ca>
didRecAChlg:] [Line 144] 8E:A2:D9:13:AF:8B:AE:82:1C:39:E9:79:72:98:2A:B4:C0:17:0D:F0
didRecAChlg:] [Line 150] CA cert 0000: <cert(0xf0397f0) s: ca i: ca>
didRecAChlg:] [Line 151] 8E:A2:D9:13:AF:8B:AE:82:1C:39:E9:79:72:98:2A:B4:C0:17:0D:F0
didRecAChlg:] [Line 159] SecTrustEvaluate gives us: 5
注意 - 我试图避免与主要答案的 SHA1 进行手动比较: SecTrustEvaluate() 在应用程序钥匙串中查找根证书吗?尽可能干净地依赖钥匙串等等。因为我还有其他几个涉及芯片卡和钥匙串的用例。上面示例中的主机名匹配。在上面 - 服务器 001..003 证书与 openssl s_client 看到的 1:1 匹配;并且 CA 证书确实是提供的 DER 文件(与服务器刷新的 CA 证书 002 相同)。我们还尝试在 CA 和客户端上设置 SubjectAltNames;并没有看到有什么不同(如 SecTrustEvaluate 所建议的,总是返回 kSecTrustResultRecoverableTrustFailure 和 SecPolicyCreateSSL) 这是有道理的,因为我们知道在钥匙串/配置文件中手动导入它们会使相同的证书作为默认钥匙串对象工作得非常好。
欢迎任何和所有建议。在 NSURLConnectionDelegate 中寻找一种简洁的方式来接受钥匙串、接受“任何东西”或只接受特定的东西。
谢谢,
德。