我有一个应用程序需要执行两步验证和长话短说明我从服务器获取每用户base64编码的pem格式证书并在每个请求中使用它们。
首先,我生成密钥对,制作CSR,给他们CSR,他们给我证书,这是我必须使用它并失败的地方。我在控制台中为每个请求收到以下错误:
CFNetwork SSLHandshake失败(-4)
CFNetwork SSLHandshake失败(-9824)
CFNetwork SSLHandshake失败(-9824)
NSURLConnection / CFURLConnection HTTP加载失败(kCFStreamErrorDomainSSL,-9824)
我的方法如下:
- 从他们发送给我的PEM格式签名证书中抓取DER编码数据
- 制作一个我添加到钥匙串的SecCertificateRef
- 按标签
查询钥匙串中的SecIdentityRef- 然后做一些大多数不必要的事情,比如从身份中获取SecCertificateRef和私钥主要是为了确定发生了什么
- 我还从服务器插入了CA证书,并从钥匙串中获取了对它的引用(不确定我是否需要将它用于凭证,但我尝试使用或不使用它 - 结果是相同的)
- 然后我使用身份和我的证书初始化凭证,并在我获得NSURLAuthenticationMethodClientCertificate auth方法时使用它(我不进行检查,但除了服务器信任之外,这是我得到的全部内容)。
所以到目前为止,没有什么是NULL,一切都被初始化并且看起来很好,但请求没有成功。当我尝试在所有请求上使用服务器信任凭证时,我通过并且没有得到错误,但我的服务器正在给我一个安全错误。只要我对任何挑战使用自定义凭据,我就会收到上述错误。
注意:我知道代码很乱,我不应该在每个请求上插入证书,但它仍然是非常早期的工作,这不是问题,因为refs得到正确的实例化
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
SSLConnectionWrapper *wrapper = [self wrapperForConnection:connection];
NSString *certStringBase64 = [[NSUserDefaults standardUserDefaults] SSLCertificateForUserWithID:wrapper.userID];
NSData *certData = [[NSData alloc] initWithBase64EncodedString:certStringBase64 options:0];
NSString *certString = [[NSString alloc] initWithData:certData encoding:NSUTF8StringEncoding];
certString = [certString stringByReplacingOccurrencesOfString:@"-----BEGIN CERTIFICATE-----" withString:@""];
certString = [certString stringByReplacingOccurrencesOfString:@"-----END CERTIFICATE-----" withString:@""];
certString = [[certString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:@""];
//at this point certString contains the DER encoded certificate data
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)([[NSData alloc] initWithBase64EncodedString:certString options:kNilOptions]));
OSStatus err = SecItemAdd((__bridge CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id) kSecClassCertificate, kSecClass,
cert, kSecValueRef,
kCFBooleanTrue, kSecReturnPersistentRef,
[NSString stringWithFormat:@"CertLabel_UserID_%@", wrapper.userID], kSecAttrLabel,
nil], NULL);
const void *keys[] = { kSecClass, kSecReturnRef, kSecAttrLabel };
const void *values[] = { kSecClassIdentity, kCFBooleanTrue, (__bridge const void *)([NSString stringWithFormat:@"CertLabel_UserID_%@", wrapper.userID]) };
CFDictionaryRef queryForIdentityDict = CFDictionaryCreate(NULL, keys, values,
3, NULL, NULL);
SecIdentityRef identityKeychainRef = NULL;
OSStatus s = SecItemCopyMatching(queryForIdentityDict, (CFTypeRef *)&identityKeychainRef);
SecCertificateRef certKeychainRef = NULL;
OSStatus s2 = SecIdentityCopyCertificate(identityKeychainRef, &certKeychainRef);
SecKeyRef privateKey;
SecIdentityCopyPrivateKey(identityKeychainRef, &privateKey);
NSString *stringForCACert = [self stringForCACert];
SecCertificateRef caCert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)([[NSData alloc] initWithBase64EncodedString:stringForCACert options:kNilOptions]));
OSStatus s3 = SecItemAdd((__bridge CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id) kSecClassCertificate, kSecClass,
caCert, kSecValueRef,
@"CACert", kSecAttrLabel,
nil], NULL);
const void *keys1[] = { kSecClass, kSecReturnRef, kSecAttrLabel };
const void *values1[] = { kSecClassCertificate, kCFBooleanTrue, @"CACert" };
CFDictionaryRef queryForCACert = CFDictionaryCreate(NULL, keys1, values1,
3, NULL, NULL);
SecCertificateRef caCertKeychainRef = NULL;
OSStatus s4 = SecItemCopyMatching(queryForCACert, (CFTypeRef *)&caCertKeychainRef);
NSURLCredential *credential = [[NSURLCredential alloc] initWithIdentity:identityKeychainRef certificates:@[ (__bridge id)certKeychainRef, (__bridge id) caCertKeychainRef] persistence:NSURLCredentialPersistencePermanent];
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}else{
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
}
答案 0 :(得分:0)
这是服务器面临的身份验证挑战。您可以通过以下代码绕过(使用NSURLCOnnection)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host {
return YES;
}
注意:如果您在应用商店上传应用,请不要在上面使用。
对于上面的iOS 9不起作用,请按如下方式编辑plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>