我想使用afnetworking实现tls自签名连接。
我有一个p12和der文件尝试为自签名证书评估服务器信任证书,使用相同的证书文件android客户端连接成功,经过大量研究我仍然无法解决。任何人都可以帮助我。
那是我完整的代码
- (void)sendRequest{
// Do any additional setup after loading the view, typically from a nib.
NSURL * actionURL=[[NSURL alloc] initWithString:@"https://38.121.62.19"];
NSURL * relativeURL=[[NSURL alloc] initWithString:@"/"];
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"der"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
[securityPolicy setPinnedCertificates:[[NSSet alloc] initWithObjects:certData, nil]];
[securityPolicy setAllowInvalidCertificates:kAllowsInvalidSSLCertificate];
[securityPolicy setValidatesDomainName:NO];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:actionURL];
[manager setSecurityPolicy:securityPolicy];
manager.responseSerializer=[AFHTTPResponseSerializer serializer];
[manager GET:relativeURL.absoluteString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(@"Success");
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
// [manager setTaskDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSURLAuthenticationChallenge * _Nonnull challenge, NSURLCredential *__autoreleasing _Nullable * _Nullable credential) {
[manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession * _Nonnull session, NSURLAuthenticationChallenge * _Nonnull challenge, NSURLCredential *__autoreleasing _Nullable * _Nullable credential) {
if ([challenge previousFailureCount] > 0) {
//this will cause an authentication failure
[[challenge sender] cancelAuthenticationChallenge:challenge];
NSLog(@"Bad Username Or Password");
return NSURLSessionAuthChallengeUseCredential;
}
//this is checking the server certificate
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
SecTrustResultType result;
//This takes the serverTrust object and checkes it against your keychain
SecTrustEvaluate(challenge.protectionSpace.serverTrust, &result);
//if we want to ignore invalid server for certificates, we just accept the server
if (kAllowsInvalidSSLCertificate) {
NSData *rootCertData = [NSData dataWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"server" ofType:@"der"]];
CFDataRef myCertData = (__bridge CFDataRef)rootCertData;
SecCertificateRef rootCertRef = SecCertificateCreateWithData(NULL, (CFDataRef) myCertData);
SecTrustRef trust = [[challenge protectionSpace] serverTrust]; // Create trust object
NSArray *trustArray = [NSArray arrayWithObjects:(__bridge id _Nonnull)(rootCertRef), nil]; // Add as many certificates as needed
SecTrustSetAnchorCertificates(trust, (CFArrayRef) trustArray );
SecTrustSetAnchorCertificatesOnly(trust, YES);
SecTrustResultType trustResult; // Store trust result in this
SecTrustEvaluate(trust, &trustResult);
SecTrustResultType result1;
[challenge.sender useCredential:[NSURLCredential credentialForTrust: trust] forAuthenticationChallenge: challenge];
return NSURLSessionAuthChallengeUseCredential;
} else if(result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
//When testing this against a trusted server I got kSecTrustResultUnspecified every time. But the other two match the description of a trusted server
[challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge];
return NSURLSessionAuthChallengeUseCredential;
}
} else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
//this handles authenticating the client certificate
/*
What we need to do here is get the certificate and an an identity so we can do this:
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:myCerts persistence:NSURLCredentialPersistencePermanent];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
It's easy to load the certificate using the code in -installCertificate
It's more difficult to get the identity.
We can get it from a .p12 file, but you need a passphrase:
*/
NSData *p12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]];
CFStringRef password = CFSTR("123456");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef p12Items;
OSStatus result = SecPKCS12Import((__bridge CFDataRef)p12Data, optionsDictionary, &p12Items);
if(result == noErr) {
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(p12Items, 0);
SecIdentityRef identityApp =(SecIdentityRef)CFDictionaryGetValue(identityDict,kSecImportItemIdentity);
SecCertificateRef certRef;
SecIdentityCopyCertificate(identityApp, &certRef);
SecCertificateRef certArray[1] = { certRef };
CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
CFRelease(certRef);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identityApp certificates:(__bridge NSArray *)myCerts persistence:NSURLCredentialPersistencePermanent];
CFRelease(myCerts);
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
} else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault || [[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodNTLM) {
// For normal authentication based on username and password. This could be NTLM or Default.
/*
DAVCredentials *cred = _parentSession.credentials;
NSURLCredential *credential = [NSURLCredential credentialWithUser:cred.username password:cred.password persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
*/
NSLog(@"BASIC AUTHENTICATION");
} else {
//If everything fails, we cancel the challenge.
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
return NSURLSessionAuthChallengePerformDefaultHandling;
}];
}
最佳答案
如果您调用方法setSessionDidReceiveAuthenticationChallengeBlock
,则AFSecurityPolicy
将不起作用。这是AFNetworking
中的代码
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__block NSURLCredential *credential = nil;
if (self.sessionDidReceiveAuthenticationChallenge) {
disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
} else {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
if (credential) {
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
}
if (completionHandler) {
completionHandler(disposition, credential);
}
}
AFSecurityPolicy
和sessionDidReceiveAuthenticationChallenge
将无法一起使用。您不需要配置AFSecurityPolicy
的实例。您可以如下更改服务器信任代码:
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if (kAllowsInvalidSSLCertificate) {
NSData *rootCertData = [NSData dataWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"server" ofType:@"der"]];
CFDataRef myCertData = (__bridge CFDataRef)rootCertData;
SecCertificateRef rootCertRef = SecCertificateCreateWithData(NULL, (CFDataRef) myCertData);
SecTrustRef trust = [[challenge protectionSpace] serverTrust]; // Create trust object
NSArray *trustArray = [NSArray arrayWithObjects:(__bridge id _Nonnull)(rootCertRef), nil]; // Add as many certificates as needed
SecTrustSetAnchorCertificates(trust, (CFArrayRef) trustArray );
SecTrustSetAnchorCertificatesOnly(trust, YES);
SecTrustResultType trustResult; // Store trust result in this
SecTrustEvaluate(trust, &trustResult);
BOOL certificateIsValid = (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed);
if (certificateIsValid) {
*credential = [NSURLCredential credentialForTrust:trust];
return NSURLSessionAuthChallengeUseCredential;
} else {
return NSURLSessionAuthChallengePerformDefaultHandling;
}
}
}
关于ios - SecTrustEvaluate始终返回kSecTrustResultRecoverableTrustFailure,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40120628/