1

我想用NSUrlsession连接服务器与SSL(.p12)客户端证书。我已成功连接到使用NSURLConnection的同一台服务器。 但与NSURLsession我得到“取消”错误。 以下是我的设置:NSURLSession使用客户端SSL证书给出“错误域= NSURLErrorDomain代码= -999”取消“”

-(void) loadDataFromServer{ 
     NSURL *url=[NSURL URLWithString:@"https://domain:port/serviceName/method/parameter"]; 
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; 
    NSURLSessionConfiguration *sessionConfig =[NSURLSessionConfiguration defaultSessionConfiguration]; 
     NSURLSession *session=[NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:Nil]; 
    NSURLSessionDataTask *downloadTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
     NSLog(@"Data :%@",data); 
     NSLog(@"Response :%@",response); 
     NSLog(@"Error :%@",error); 
     if (!error) { 
      NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response; 
      if (httpResp.statusCode == 200) {  
       NSDictionary* json = [NSJSONSerialization 
             JSONObjectWithData:data 
             options:kNilOptions 
             error:&error]; 
       NSLog(@"Data :%@",json);   
      } 
     } 
    }]; 
    [downloadTask resume];} 



    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler{ 
    NSURLCredential *newCredential; 
    NSString *authenticationMethod = challenge.protectionSpace.authenticationMethod; 
    if ([authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"]) { 

     // Replace the user login and password as appropriate. 
     newCredential = [NSURLCredential credentialWithUser:@"UserName" password:@"Password" persistence:NSURLCredentialPersistenceNone]; 

    } else if ([authenticationMethod isEqualToString:@"NSURLAuthenticationMethodClientCertificate"]) { 
     // load cert 
     NSString *path = [[NSBundle mainBundle] pathForResource:@"certificateName" ofType:@"p12"]; 
     NSData *p12data = [NSData dataWithContentsOfFile:path]; 
     CFDataRef inP12data = (__bridge CFDataRef)p12data;  
     SecIdentityRef myIdentity; 
     SecTrustRef myTrust; 
     OSStatus status = extractIdentityAndTrustCorpInv(inP12data, &myIdentity, &myTrust); 

     if (status == 0) { 
      SecCertificateRef myCertificate; 
      SecIdentityCopyCertificate(myIdentity, &myCertificate); 
      const void *certs[] = { myCertificate }; 
      CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL); 

      newCredential = [NSURLCredential credentialWithIdentity:myIdentity certificates:(__bridge NSArray*)certsArray persistence:NSURLCredentialPersistenceForSession]; 
     } 
    } 
    [[challenge sender]useCredential:newCredential forAuthenticationChallenge:challenge]; 
    completionHandler(NSURLSessionAuthChallengeUseCredential,newCredential); 
} 


#pragma mark - 
#pragma mark Identity and Trust 
- OSStatus extractIdentityAndTrustCorpInv(CFDataRef inP12data, SecIdentityRef *identity, SecTrustRef *trust) 
{ 
    OSStatus securityError = errSecSuccess; 
    CFStringRef password = CFSTR("CertPassword"); 
    const void *keys[] = { kSecImportExportPassphrase }; 
    const void *values[] = { password }; 
    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); 
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); 
    securityError = SecPKCS12Import(inP12data, options, &items); 

    if (securityError == 0) { 
     CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0); 
     const void *tempIdentity = NULL; 
     tempIdentity = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity); 
     *identity = (SecIdentityRef)tempIdentity; 
     const void *tempTrust = NULL; 
     tempTrust = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust); 
     *trust = (SecTrustRef)tempTrust; 
    } 
    if (options) { 
     CFRelease(options); 
    } 
    return securityError; 
} 

而且NSLog的给出以下错误:

错误:错误域= NSURLErrorDomain代码= -999 “取消” 的UserInfo = {NSErrorFailingURLKey = https://domain:port/serviceName/method/parameter,NSErrorFailingURLStringKey = https://domain:port/serviceName/method/parameter,NSLocalizedDescription =取消}

任何帮助,将不胜感激。

+0

这听起来完全一样的问题[在这个相关的问题](http://stackoverflow.com/questions/30739473/nsurlsession-nsurlconnection-http-load-failed-on-ios-9)(我是试图标记为重复) –

+0

不是一个重复。 ATS同样影响NSURLConnection和NSURLSession。 – dgatwood

回答

1

NSURLAuthenticationMethodServerTrust不会做你认为的事情。它用于验证服务器提供的TLS证书。如果您想覆盖自签名证书,请使用它。

使用您提供的代码,您的所有HTTPS请求都将不安全(信任服务器提供的任何证书)或将失败。 IIRC,对于NSURLConnection,它是不安全的,对于NSURLSession,它失败。

它看起来像代码块实际上应该运行如果认证方法为NSURLAuthenticationMethodHTTPBasicNSURLAuthenticationMethodHTTPDigest

如果方法是NSURLAuthenticationMethodServerTrust,您应该告诉URL加载系统使用默认处理。

如果您因某种原因想要使用自签名证书,请阅读Apple网站上的Overriding SSL Chain Validation Correctly,以了解如何以安全的方式进行操作。

相关问题