0

我有几个控制器管理自己的连接和数据,这是完美的工作。我只是想集中canAuthenticateAgainstProtectionSpace和didReceiveAuthenticationChallenge以避免重复代码。NSURLConnection身份验证集中控制器

我试图重写没有成功的类。

类和协议:

#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

解决其实我试图委托在第三级(控制器调用一个委托控制器生成)。包含在第二个控制器级别的代码运行良好。