我有几个控制器管理他们自己的连接和数据,这些都是完美的。我只是想集中canAuthenticateAgainstProtectionSpace并进行ReceiveAuthenticationChallenge以避免重复代码。
我试图覆盖该课程但没有成功。
课程和协议:
#import <Foundation/Foundation.h>
@protocol SSLPiningDelegate;
@interface SSLPiningDelegate : NSURLConnection <NSURLConnectionDelegate>
{
id<SSLPiningDelegate> delegate;
}
@property (nonatomic,assign) id<SSLPiningDelegate> delegate;
@end
@protocol SSLPiningDelegate <NSURLConnectionDelegate>
@optional
-(id)initWithDelegate:(id)delegate;
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
@end
代码:
#import "SSLPiningDelegate.h"
@interface SSLPiningDelegate ()
{
CFArrayRef caChainArrayRef;
BOOL checkHostname;
}
@end
@implementation SSLPiningDelegate
-(id)initWithDelegate:(id)delegate {
//CGRect rect = [[UIScreen mainScreen] bounds];
if ((self = [super init])) {
_delegate = delegate;
}
return self;
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
// TODO manage this correctly
checkHostname = YES;
NSString * derCaPath;
NSMutableArray * chain = [NSMutableArray array];
for(int i=0; i<= 3; i++)
{
if (i==0)
derCaPath = [[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"cer"];
else if (i==1)
derCaPath = [[NSBundle mainBundle] pathForResource:@"comodorsacertificationauthority" ofType:@"cer"];
else if (i==2)
derCaPath = [[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"cer"];
else
derCaPath = [[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"cer"];
NSData *derCA = [NSData dataWithContentsOfFile:derCaPath];
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)derCA);
[chain addObject:(__bridge id)(caRef)];
}
caChainArrayRef = CFBridgingRetain(chain);
NSLog(@"Loading::didReceiveAuthenticationChallenge --- chain of trust length %lu", (unsigned long)[chain count]);
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
SecTrustRef trust = nil;
SecTrustResultType result = kSecTrustResultInvalid;
OSStatus err = errSecSuccess;
{
NSLog(@"Chain received from the server (working 'up'):");
CFIndex certificateCount = SecTrustGetCertificateCount(challenge.protectionSpace.serverTrust);
for(int i = 0; i < certificateCount; i++) {
SecCertificateRef certRef = SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, i);
CFStringRef str = SecCertificateCopySubjectSummary(certRef);
NSLog(@" %02i: %@", 1+i, str);
CFRelease(str);
}
NSLog(@"Local Roots we trust:");
for(int i = 0; i < CFArrayGetCount(caChainArrayRef); i++) {
SecCertificateRef certRef = (SecCertificateRef) CFArrayGetValueAtIndex(caChainArrayRef, i);
CFStringRef str = SecCertificateCopySubjectSummary(certRef);
NSLog(@" %02i: %@", 1+i, str);
CFRelease(str);
}
}
if (checkHostname) {
// We use the standard Policy of SSL - which also checks hostnames.
// -- see SecPolicyCreateSSL() for details.
//
trust = challenge.protectionSpace.serverTrust;
//
#if DEBUG
NSLog(@"The certificate is expected to match '%@' as the hostname",
challenge.protectionSpace.host);
#endif
}
else {
// Create a new Policy - which goes easy on the hostname.
//
// Extract the chain of certificates provided by the server.
//
CFIndex certificateCount = SecTrustGetCertificateCount(challenge.protectionSpace.serverTrust);
NSMutableArray * chain = [NSMutableArray array];
for(int i = 0; i < certificateCount; i++) {
SecCertificateRef certRef = SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, i);
[chain addObject:(__bridge id)(certRef)];
}
for(int i = 0; i < CFArrayGetCount(caChainArrayRef); i++) {
SecCertificateRef certRef = (SecCertificateRef) CFArrayGetValueAtIndex(caChainArrayRef, i);
[chain addObject:(__bridge id)(certRef)];
}
// And create a bland policy which only checks signature paths.
//
if (err == errSecSuccess)
err = SecTrustCreateWithCertificates((__bridge CFArrayRef)(chain),
SecPolicyCreateBasicX509(), &trust);
#if DEBUG
NSLog(@"The certificate is NOT expected to match the hostname '%@' ",
challenge.protectionSpace.host);
#endif
}
// Explicity specify the list of certificates we actually trust (i.e. those I have hardcoded
// in the app - rather than those provided by some randon server on the internet).
//
if (err == errSecSuccess)
err = SecTrustSetAnchorCertificates(trust,caChainArrayRef);
// And only use above - i.e. do not check the system its global keychain or something
// else the user may have fiddled with.
//
if (err == errSecSuccess)
err = SecTrustSetAnchorCertificatesOnly(trust, YES);
if (err == errSecSuccess)
err = SecTrustEvaluate(trust, &result);
if (err == errSecSuccess) {
switch (result) {
case kSecTrustResultProceed:
// User gave explicit permission to trust this specific
// root at some point (in the past).
//
NSLog(@"GOOD. kSecTrustResultProceed - the user explicitly trusts this CA");
[challenge.sender useCredential:[NSURLCredential credentialForTrust:trust]
forAuthenticationChallenge:challenge];
goto done;
break;
case kSecTrustResultUnspecified:
// The chain is technically valid and matches up to the root
// we provided. The user has not had any say in this though,
// hence it is not a kSecTrustResultProceed.
//
NSLog(@"GOOD. kSecTrustResultUnspecified - So things are technically trusted. But the user was not involved.");
[challenge.sender useCredential:[NSURLCredential credentialForTrust:trust]
forAuthenticationChallenge:challenge];
goto done;
break;
case kSecTrustResultInvalid:
NSLog(@"FAIL. kSecTrustResultInvalid");
break;
case kSecTrustResultDeny:
NSLog(@"FAIL. kSecTrustResultDeny (i.e. user said no explicitly)");
break;
case kSecTrustResultFatalTrustFailure:
NSLog(@"FAIL. kSecTrustResultFatalTrustFailure");
break;
case kSecTrustResultOtherError:
NSLog(@"FAIL. kSecTrustResultOtherError");
break;
case kSecTrustResultRecoverableTrustFailure:
NSLog(@"FAIL. kSecTrustResultRecoverableTrustFailure (i.e. user could say OK, but has not been asked this)");
break;
default:
NSAssert(NO,@"Unexpected result: %d", result);
break;
}
// Reject.
[challenge.sender cancelAuthenticationChallenge:challenge];
goto done;
};
//CFStringRef str =SecCopyErrorMessageString(err,NULL);
//NSLog(@"Internal failure to validate: result %@", str);
//CFRelease(str);
[[challenge sender] cancelAuthenticationChallenge:challenge];
done:
if (!checkHostname)
CFRelease(trust);
return;
}
// In this example we can cancel at this point - as we only do
// canAuthenticateAgainstProtectionSpace against ServerTrust.
//
// But in other situations a more gentle continue may be appropriate.
//
// [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
NSLog(@"Not something we can handle - so we're canceling it.");
[challenge.sender cancelAuthenticationChallenge:challenge];
}
@end
然后我宣布控制器
#import <UIKit/UIKit.h>
#import "TagUIViewControllerLoading.h"
#import <Foundation/Foundation.h>
#import "SSLPiningDelegate.h"
@interface Loading : TagUIViewControllerLoading <SSLPiningDelegate>
但代表从未被召集过。
欢迎任何帮助。
答案 0 :(得分:0)
事实上,我试图在第三级(控制器使用委托调用控制器构建)进行委托。第二个控制器级别附带的代码工作正常。