#ios #objective-c #ssl #tls1.2 #afnetworking-3
#iOS #objective-c #ssl #tls1.2 #afnetworking-3
Вопрос:
Я хочу реализовать самоподписанное соединение tls с afnetworking. у меня есть файл 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 resu<
//This takes the serverTrust object and checkes it against your keychain
SecTrustEvaluate(challenge.protectionSpace.serverTrust, amp;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 trustResu< // Store trust result in this
SecTrustEvaluate(trust, amp;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, amp;p12Items);
if(result == noErr) {
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(p12Items, 0);
SecIdentityRef identityApp =(SecIdentityRef)CFDictionaryGetValue(identityDict,kSecImportItemIdentity);
SecCertificateRef certRef;
SecIdentityCopyCertificate(identityApp, amp;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;
}];
}
Ответ №1:
Если вы вызовете метод, 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, amp;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 trustResu< // Store trust result in this
SecTrustEvaluate(trust, amp;trustResult);
BOOL certificateIsValid = (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed);
if (certificateIsValid) {
*credential = [NSURLCredential credentialForTrust:trust];
return NSURLSessionAuthChallengeUseCredential;
} else {
return NSURLSessionAuthChallengePerformDefaultHandling;
}
}
}
Комментарии:
1. спасибо за помощь, вы правы. я исправляю это и работаю хорошо
Ответ №2:
Это работает хорошо, правильный код ниже
- (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];
_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) {
__weak typeof(self)weakSelf = self;
[_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]) {
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__autoreleasing NSURLCredential *credential =nil;
if([weakSelf.manager.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 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, amp;p12Items);
if(result == noErr) {
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(p12Items, 0);
SecIdentityRef identityApp =(SecIdentityRef)CFDictionaryGetValue(identityDict,kSecImportItemIdentity);
SecCertificateRef certRef;
SecIdentityCopyCertificate(identityApp, amp;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);
*_credential = credential;
// [[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 NSURLSessionAuthChallengeUseCredential;
}];
}