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

标签 ios ssl certificate self-signed

我有一个应用程序,我需要执行两步身份验证,长话短说,我从服务器获取每个用户的 base64 编码的 pem 格式证书,并在每个请求中使用它们。

首先,我生成一个 key 对,创建一个 CSR,将 CSR 提供​​给他们,他们将证书提供给我,这就是我必须使用它但失败的地方。对于每个单独的请求,我在控制台中收到以下错误:

CFNetwork SSLHandshake 失败 (-4)

CFNetwork SSLHandshake 失败 (-9824)

CFNetwork SSLHandshake 失败 (-9824)

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

我的方法如下:

-从他们发送给我的 PEM 格式签名证书中获取 DER 编码数据

-制作一个 SecCertificateRef,我将其添加到钥匙串(keychain)中

-通过标签查询keychain中的SecIdentityRef

-然后我做了一些大部分不必要的事情,比如从身份中获取 SecCertificateRef 和私钥,主要是为了确定发生了什么

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

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

所以到目前为止,没有任何东西是 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>

关于iOS:自签名证书有问题。 SSL 握手错误 (-9824),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33551795/

相关文章:

ios - 在 GCD 中,何时使用全局并发队列与自定义并发队列?

ios - viewDidLoad 中的代码在每次调用时运行

ios - 解析 PFUser QueryWithPredicate 不工作

ios - 如果用户禁用了应用程序的推送,是否可以进行静默远程通知?

java - 在 java 程序中发出 STARTTLS 命令后,startHandshake 出现不支持或无法识别的 ssl 消息异常

security - 数字证书在用于保护网站(使用 SSL)时如何工作?

.net - HttpWebRequest 似乎没有发送客户端 SSL 证书

ios - 与多个开发人员进行代码签名

android - RapidSSL 证书在 Android 平板电脑上不受信任

certificate - 证书的颁发者无效 : keychain