【问题标题】:NSURLSession using client SSL cert gives "Error Domain=NSURLErrorDomain Code=-999 "cancelled""使用客户端 SSL 证书的 NSURLSession 给出“错误域 = NSURLErrorDomain 代码 = -999 “已取消””
【发布时间】:2016-01-18 05:37:30
【问题描述】:

我正在尝试使用 NSUrlsession 通过 SSL (.p12) 客户端证书连接服务器。我已成功使用 NSURLConnection 连接到同一台服务器。 但是使用 NSURLsession 我得到“取消”错误。 以下是我的设置:

    -(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 给出以下错误:

错误 :Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://domain:port/serviceName/method/parameter, NSErrorFailingURLStringKey=https://domain:port/serviceName/method/parameter, NSLocalizedDescription=cancelled}

任何帮助将不胜感激。

【问题讨论】:

  • 这听起来与in this related question 完全相同的问题(我很想将其标记为重复)
  • 不是骗子。 ATS 对 NSURLConnection 和 NSURLSession 的影响是一样的。

标签: objective-c authentication ssl-certificate ios9 nsurlsession


【解决方案1】:

NSURLAuthenticationMethodServerTrust 并不像你认为的那样做。它用于验证服务器提供的 TLS 证书。如果要覆盖自签名证书,请使用它。

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

如果身份验证方法是 NSURLAuthenticationMethodHTTPBasicNSURLAuthenticationMethodHTTPDigest,则该代码块似乎应该实际运行。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-07
    • 2017-03-19
    • 1970-01-01
    • 2021-10-24
    • 2017-03-14
    • 2020-02-22
    • 1970-01-01
    • 2019-04-22
    相关资源
    最近更新 更多