iOS:遇到自签名证书问题。 SSL握手错误(-9824)

问题描述:

我有一个应用程序,我需要执行一种2步骤认证和长话短说我从服务器获取每用户base64编码的pem格式证书并在每个服务器上使用它们请求。iOS:遇到自签名证书问题。 SSL握手错误(-9824)

首先我生成一个密钥对,做一个CSR,给他们CSR,他们给我证书,这是我必须使用它并失败的地方。我收到以下错误控制台中的每个单独的请求:

CFNetwork的SSLHandshake失败(-4)

CFNetwork的SSLHandshake失败(-9824)

CFNetwork的SSLHandshake失败( -9824)

NSURLConnection/CFURLConnection HTTP加载失败(kCFStreamErrorDomainSSL,-9824)

我的做法是这样的:

-grab从PEM的DER编码数据的格式化签名的证书,他们就送我

-make一个SecCertificateRef我添加到钥匙扣

-query对于SecIdentityRef中的标签钥匙扣

- 然后做一些大多不需要的东西,比如从身份证书中获取SecCertificateRef和私钥以确定发生了什么

- 我还从服务器中插入了一个CA证书,并从钥匙串中获取对它的引用(不确定是否需要将它用于证书,但是我尝试使用或不使用它 - 结果是相同)

- 然后,我使用身份和证书初始化凭证,并在获得NSURLAuthenticationMethodClientCertificate auth方法时使用它(我没有执行检查,但这是我除了服务器信任之外所得到的)。

所以到目前为止,没有什么是NULL,所有的东西都被初始化并且看起来不错,但是请求并不成功。当我尝试在所有请求中使用服务器信任凭证时,我会通过并且不会收到错误信息,但是我的服务器正在给它发送安全错误。只要我使用自定义凭据进行任何挑战,我都会收到上述错误。

注:我知道代码是凌乱的,我不应该将每个请求证书,但它仍然在进步非常早期的工作,这不是因为裁判得到正确的初始化

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{ 
    SSLConnectionWrapper *wrapper = [self wrapperForConnection:connection]; 


    NSString *certStringBase64 = [[NSUserDefaults standardUserDefaults] SSLCertificateForUserWithID:wrapper.userID]; 
    NSData *certData = [[NSData alloc] initWithBase64EncodedString:certStringBase64 options:0]; 
    NSString *certString = [[NSString alloc] initWithData:certData encoding:NSUTF8StringEncoding]; 

    certString = [certString stringByReplacingOccurrencesOfString:@"-----BEGIN CERTIFICATE-----" withString:@""]; 
    certString = [certString stringByReplacingOccurrencesOfString:@"-----END CERTIFICATE-----" withString:@""]; 
    certString = [[certString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:@""]; 
    //at this point certString contains the DER encoded certificate data 

    SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)([[NSData alloc] initWithBase64EncodedString:certString options:kNilOptions])); 

    OSStatus err = SecItemAdd((__bridge CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys: 
                  (__bridge id) kSecClassCertificate, kSecClass, 
                  cert, kSecValueRef, 
                  kCFBooleanTrue, kSecReturnPersistentRef, 
                  [NSString stringWithFormat:@"CertLabel_UserID_%@", wrapper.userID], kSecAttrLabel, 
                  nil], NULL); 

    const void *keys[] = { kSecClass, kSecReturnRef, kSecAttrLabel }; 

    const void *values[] = { kSecClassIdentity, kCFBooleanTrue, (__bridge const void *)([NSString stringWithFormat:@"CertLabel_UserID_%@", wrapper.userID]) }; 

    CFDictionaryRef queryForIdentityDict = CFDictionaryCreate(NULL, keys, values, 
                   3, NULL, NULL); 

    SecIdentityRef identityKeychainRef = NULL; 
    OSStatus s = SecItemCopyMatching(queryForIdentityDict, (CFTypeRef *)&identityKeychainRef); 

    SecCertificateRef certKeychainRef = NULL; 
    OSStatus s2 = SecIdentityCopyCertificate(identityKeychainRef, &certKeychainRef); 

    SecKeyRef privateKey; 
    SecIdentityCopyPrivateKey(identityKeychainRef, &privateKey); 

    NSString *stringForCACert = [self stringForCACert]; 

    SecCertificateRef caCert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)([[NSData alloc] initWithBase64EncodedString:stringForCACert options:kNilOptions])); 
    OSStatus s3 = SecItemAdd((__bridge CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys: 
                  (__bridge id) kSecClassCertificate, kSecClass, 
                  caCert, kSecValueRef, 
                  @"CACert", kSecAttrLabel, 
                  nil], NULL); 

    const void *keys1[] = { kSecClass, kSecReturnRef, kSecAttrLabel }; 

    const void *values1[] = { kSecClassCertificate, kCFBooleanTrue, @"CACert" }; 

    CFDictionaryRef queryForCACert = CFDictionaryCreate(NULL, keys1, values1, 
                   3, NULL, NULL); 

    SecCertificateRef caCertKeychainRef = NULL; 
    OSStatus s4 = SecItemCopyMatching(queryForCACert, (CFTypeRef *)&caCertKeychainRef); 

    NSURLCredential *credential = [[NSURLCredential alloc] initWithIdentity:identityKeychainRef certificates:@[ (__bridge id)certKeychainRef, (__bridge id) caCertKeychainRef] persistence:NSURLCredentialPersistencePermanent]; 

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 

     [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; 
    }else{ 
     [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; 
    } 

} 

问题

这是服务器面临的认证挑战。您可以通过下面的代码绕过(使用NSURLConnection的)

+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host { 
    return YES; 
} 

注意:如果您在应用商店上传应用程序,不要使用上面。

对于iOS 9个以上是行不通的,请编辑的plist如下

<key>NSAppTransportSecurity</key> 
<dict> 
    <key>NSAllowsArbitraryLoads</key> 
    <true/> 
</dict> 
+0

我已经启用了AllowsArbitraryLoads。我也尝试过这个类别,但它并没有做到这一点。它被调用,但不会阻止发生握手错误。它也与iOS 9的TLS 1.2策略无关。 –