Objective-C:在TLS TCP连接上模拟由我们自己的PKI(根CA)签名的服务器证书



*已解决*

我的问题涉及以下问题:
Objective-C:如何与签名者验证SecCertificateRef';s的公钥?

我们有自己的PKI,也有我们信任的rootCA。使用这个rootCA,我们对传递到个人服务器的证书进行签名。现在我想连接iOS应用程序,检查从服务器发送的证书是否与我们的CA 签名

我的应用程序应该能够使用GCDAsyncSocket建立的TCP连接连接到具有此证书的n台服务器(可能使用零conf服务)。我的应用程序中有证书的公共部分,我想将其添加到我的"CertChain"中,以便应用程序在连接时信任它们。

我已经尝试了很多,但仍然无法以有效的结果通过SecTrustEvaluate(trust, &result);。(我想在生产中使用它,所以请不要告诉我任何关于停用验证的信息)

我的证书:
应用程序内:rootCA,oldServerCA(cer)
在服务器上(通过信任):homeServer,oldServer

我的证书链:
rootCA签名的homeServer
oldServerCA签名的oldServer

我的代码部分:
添加了更新

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
{
// Configure SSL/TLS settings
NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:3];
// Allow self-signed certificates
[settings setObject:[NSNumber numberWithBool:YES]
             forKey:GCDAsyncSocketManuallyEvaluateTrust];
[sock startTLS:settings];
// get the certificates as data for further operations
NSString *certFilePath1 = [[NSBundle mainBundle] pathForResource:@"rootCA" ofType:@"cer"]; // also tried it with 'der', same result
NSData *certData1 = [NSData dataWithContentsOfFile:certFilePath1];
NSString *certFilePath2 = [[NSBundle mainBundle] pathForResource:@"oldServerCA" ofType:@"cer"];
NSData *certData2 = [NSData dataWithContentsOfFile:certFilePath2];
// if data exists, use it
if(certData1 && certData2)
{
    SecCertificateRef   cert1;
    cert1 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData1);
    SecCertificateRef   cert2;
    cert2 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData2);
    // only working for "cer"
    NSString *name = [NSString stringWithUTF8String:CFStringGetCStringPtr(SecCertificateCopySubjectSummary(cert1), kCFStringEncodingUTF8)];
    // maybe I understood the usage of "name" in "kSecAttrApplicationTag" wrong?
    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
                                                   (__bridge id)(kSecClassKey), kSecClass,
                                                   (__bridge id)kSecAttrKeyTypeRSA, kSecAttrKeyType,
                                                   (__bridge id)kSecAttrKeyClassPublic, kSecAttrKeyClass,
                                                   kCFBooleanTrue, kSecAttrIsPermanent,
                                                   [name dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag,
                                                   certData1, kSecValueData,
                                                   kCFBooleanTrue, kSecReturnPersistentRef,
                                                   nil],
                                 NULL);   //don't need public key ref
    // Setting "cer" is successfully and delivers "noErr" in first run, then "errKCDuplicateItem"
    NSLog(@"evaluate with status %d", (int)status);
    NSString *name2 = [NSString stringWithUTF8String:CFStringGetCStringPtr(SecCertificateCopySubjectSummary(cert2), kCFStringEncodingUTF8)];
    OSStatus status2 = SecItemAdd((__bridge CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
                                                            (__bridge id)(kSecClassKey), kSecClass,
                                                            (__bridge id)kSecAttrKeyTypeRSA, kSecAttrKeyType,
                                                            (__bridge id)kSecAttrKeyClassPublic, kSecAttrKeyClass,
                                                            kCFBooleanTrue, kSecAttrIsPermanent,
                                                            [name2 dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag,
                                                            certData2, kSecValueData,
                                                            kCFBooleanTrue, kSecReturnPersistentRef,
                                                            nil],
                                 NULL);   //don't need public key ref
    NSLog(@"evaluate with status %d", (int)status2);
    // log here -> certificates were loaded. Fine
    // create references of each to proof them seperatly
    const void *ref[] = {cert1};
    CFArrayRef aryRef = CFArrayCreate(NULL, ref, 1, NULL);
    const void *ref2[] = {cert2};
    CFArrayRef aryRef2 = CFArrayCreate(NULL, ref2, 1, NULL);
    // need this way to get sock.sslContext, otherways it's NULL (see implementation of GCDAsyncSocket)
    [sock performBlock:^{
        SSLContextRef sslContext = sock.sslContext;
        OSStatus status = SSLSetCertificate(sslContext, aryRef);
        // the status is everywhere always -909 -> badReqErr /*bad parameter or invalid state for operation*/
        if(status == noErr)
            NSLog(@"successfully set ssl certificates");
        else
            NSLog(@"setting ssl certificates failed");
        status = SSLSetCertificate(sock.sslContext, aryRef2);
        if(status == noErr)
            NSLog(@"successfully set ssl certificates");
        else
            NSLog(@"setting ssl certificates failed");
        status = SSLSetEncryptionCertificate(sock.sslContext, aryRef);
        if(status == noErr)
            NSLog(@"successfully set ssl certificates");
        else
            NSLog(@"setting ssl certificates failed");
    }];
}
@synchronized( self )
{
    if( isConnected == NO )
    {
        if(gcdAsyncSocket && [gcdAsyncSocket isConnected])
        {
            isConnected = YES;
            [gcdAsyncSocket readDataWithTimeout:READ_TIMEOUT tag:0];
            [NSThread detachNewThreadSelector:@selector(readDataToData:withTimeout:tag:) toTarget:gcdAsyncSocket withObject:nil];
            [gcdAsyncSocket readDataToData:[GCDAsyncSocket LFData] withTimeout:READ_TIMEOUT tag:0];
            [del onConnect];
        }
    }
} 
}

嗯。。。如果在此不工作,请手动检查。。。

- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust
completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler
{
//    https://code.csdn.net/OS_Mirror/CocoaAsyncSocket/file_diff/a4b9c4981b3c022ca89d0cdaadecc70b825ad4f1...5d58af30d2d8a3e0f7219487e72f1b4b2c3b4894/GCD/Xcode/SimpleHTTPClient/Desktop/SimpleHTTPClient/SimpleHTTPClientAppDelegate.m
    dispatch_queue_t bgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(bgQueue, ^{
    // This is where you would (eventually) invoke SecTrustEvaluate.
    // Presumably, if you're using manual trust evaluation, you're likely doing extra stuff here.
    // For example, allowing a specific self-signed certificate that is known to the app.
    NSString *certFilePath1 = [[NSBundle mainBundle] pathForResource:@"rootCA" ofType:@"cer"];
    NSData *certData1 = [NSData dataWithContentsOfFile:certFilePath1];
    NSString *certFilePath2 = [[NSBundle mainBundle] pathForResource:@"oldServerCA" ofType:@"cer"];
    NSData *certData2 = [NSData dataWithContentsOfFile:certFilePath2];
    if(certData1 && certData2)
    {
        CFArrayRef arrayRefTrust = SecTrustCopyProperties(trust);
        SecTrustResultType result = kSecTrustResultUnspecified;
        // usualy should work already here
        OSStatus status = SecTrustEvaluate(trust, &result);
        NSLog(@"evaluate with result %d and status %d", result, (int)status);
        NSLog(@"trust properties: %@", arrayRefTrust);
        /* log:
         evaluate with result 5 and status 0
         trust properties: (
         {
            type = error;
            value = "Root certificate is not trusted."; // expected, when top part was not working
         }
         */
        SecCertificateRef   cert1;
        cert1 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData1);
        SecCertificateRef   cert2;
        cert2 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData2);
        const void *ref[] = {cert1};
        CFIndex count = SecTrustGetCertificateCount(trust);
//            CFMutableArrayRef aryRef = CFArrayCreateMutable(NULL, count + 1, NULL);
//            CFArrayAppendValue(aryRef, ref);
        CFArrayCreate(NULL, ref, 2, NULL);
        // # # # #
        // so check one by one...
        BOOL isMatching = NO;
        for (int i = 0; i < count; i++)
        {
            SecCertificateRef certRef = SecTrustGetCertificateAtIndex(trust, i);
            NSString *name = [NSString stringWithUTF8String:CFStringGetCStringPtr(SecCertificateCopySubjectSummary(certRef), kCFStringEncodingUTF8)]; // only working for "cer"
            NSLog(@"remote cert at index %d is '%@'", i, name);
            /*
                first is 'homeserver', second is 'oldServer'
            */
//                const void *ref[] = {certRef, cert1, cert2};
//                CFArrayRef aryCheck = CFArrayCreate(NULL, ref, 3, NULL);
            // check against the new cert (rootCA)
            const void *ref[] = {certRef, cert1};
            CFArrayRef aryCheck = CFArrayCreate(NULL, ref, 2, NULL);
            SecTrustRef trustManual;
            OSStatus certStatus = SecTrustCreateWithCertificates(aryCheck, SecPolicyCreateBasicX509(), &trustManual);
            // certStatus always noErr
            NSLog(@"certStatus: %d", (int)certStatus);
            SecTrustResultType result;
            OSStatus status =  SecTrustEvaluate(trustManual, &result);
            CFArrayRef arrayRef = SecTrustCopyProperties(trustManual);
            NSLog(@"evaluate with result %d and status %d", result, (int)status);
            NSLog(@"trust properties: %@", arrayRef);
            /* log:
             evaluate with result 5 and status 0
             trust properties: (
             {
             type = error;
             value = "Root certificate is not trusted.";
             }
             */
            // always else-part because result is "kSecTrustResultRecoverableTrustFailure"
            if (status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified))
            {
                isMatching = YES;
                NSLog(@"certificates matches");
            }
            else
            {
                NSLog(@"certificates differs");
            }
        }

        if (isMatching || (status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)))
        {
            completionHandler(YES);
        }
        else
        {
            completionHandler(NO);
        }
    }
    completionHandler(NO);
    });
}

更新1

删除

[settings setObject:[NSNumber numberWithBool:YES]
             forKey:GCDAsyncSocketManuallyEvaluateTrust];

现在使用

SecCertificateRef   cert1, cert2;
// init certs, see top part
// according to @SeanBaker "Certs[0] would be nil (you don't want to do client auth), and certs[1...] would be the root certificates you want to trust in establishing the connection"
const void *certs[] = {NULL, cert1, cert2};
// const void *certs[] = {nil, cert1, cert2};
    CFArrayRef aryCerts = CFArrayCreate(NULL, certs, 3, NULL);
[settings setObject:(__bridge NSArray*)aryCerts
                 forKey:(NSString *)kCFStreamSSLCertificates];

但是在中得到OSStatus-50(/*error in user parameter list*/

// 2. kCFStreamSSLCertificates
value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLCertificates];
if ([value isKindOfClass:[NSArray class]])
{
    CFArrayRef certs = (__bridge CFArrayRef)value;
    status = SSLSetCertificate(sslContext, certs);
...

看起来我用错了,但我没有看到错误:/(不经常使用核心基础)

如果您需要更多信息,只需询问即可。每个提示都可以拯救生命:)

我自己使用自定义证书来验证我们的消息应用程序在开发模式中使用的多个服务器。

如果您有权访问p12(包括私钥和签名身份)文件,则可以使用kCFStreamSSLCertificates 验证服务器证书

否则(如果只是公钥),您可以选择通过对等名称kCFStreamSSLPerName进行验证。

在您的代码片段中,有一件事您做得不正确,那就是如何将证书提供给GCDAsyncSocket模块。从而找到您提到的错误。

正确的方法如下:

    NSArray *myCerts = [[NSArray alloc] initWithObjects:(__bridge id)identity1, (__bridge id)myReturnedCertificate1, nil];
    [settings setObject:myCerts forKey:(NSString *)kCFStreamSSLCertificates];

根据Apple文档,在使用kCFStreamSSL证书时,身份是强制性的:

您必须在certRefs[0]中放置一个SecIdentityRef对象,用于标识叶证书及其对应的私钥。指定根证书是可选的;


完整详细信息:

如果您使用自定义签名的CA证书,请执行以下步骤。请注意:示例基于GCDAsyncSocket

  1. 将您的公共部件证书保存在应用程序资源捆绑包中
  2. 阅读以上证书并将证书添加到密钥链
  3. 执行委派功能-

(void)套接字:(GCDAsyncSocket*)sock-didConnectToHost:(NSString*)主机端口:(uint16_t)端口;

在该功能中,将您的证书提供给GCDAsyncSocket

    NSArray *myCerts = [[NSArray alloc] initWithObjects:(__bridge id)identity1, (__bridge id)myReturnedCertificate1, nil];
    [settings setObject:myCerts forKey:(NSString *)kCFStreamSSLCertificates];

根据是否要手动验证信任,请在下面使用YES(不推荐)或NO?

   [settings setObject:[NSNumber numberWithBool:YES]
                 forKey:GCDAsyncSocketManuallyEvaluateTrust];
  1. 如果您选择手动验证信任,请覆盖以下委派方法

(void)socket:(GCDAsyncSocket*)sock-didReceiveTrust:(SecTrustRef)trustcompletionHandler:(void(^)(BOOL shouldTrustPeer))completionHandler

在这个函数中,您应该从信任中读取所有证书,并尝试与您随应用程序提供的证书匹配。

示例代码:


- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
{
    // Configure SSL/TLS settings
    NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:3];
    // get the certificates as data for further operations

    SecIdentityRef identity1 = nil;
    SecTrustRef trust1 = nil;
    NSData *certData1 = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"[Dev] InHouse_Certificates" ofType:@"p12"]];
    CFDataRef myCertData1 = (__bridge_retained CFDataRef)(certData1);
    [self extractIdentityAndTrust:myCertData1 withIdentity:&identity1 withTrust:&trust1 withPassword:CFSTR("1234")];
    NSString* summaryString1 = [self copySummaryString:&identity1];

    SecIdentityRef identity2 = nil;
    SecTrustRef trust2 = nil;
    NSData *certData2 = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"[Dis] InHouse_Certificates" ofType:@"p12"]];
    CFDataRef myCertData2 = (__bridge_retained CFDataRef)(certData2);
    [self extractIdentityAndTrust:myCertData2 withIdentity:&identity2 withTrust:&trust2 withPassword:CFSTR("1234")];
    NSString* summaryString2 = [self copySummaryString:&identity2];
    // if data exists, use it
    if(myCertData1 && myCertData2)
    {
        //Delete if already exist. Just temporary
        SecItemDelete((__bridge CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
                                                (__bridge id)(kSecClassKey), kSecClass,
                                                (__bridge id)kSecAttrKeyTypeRSA, kSecAttrKeyType,
                                                (__bridge id)kSecAttrKeyClassPublic, kSecAttrKeyClass,
                                                kCFBooleanTrue, kSecAttrIsPermanent,
                                                [summaryString1 dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag,
                                                certData1, kSecValueData,
                                                kCFBooleanTrue, kSecReturnPersistentRef,
                                                nil]);
        OSStatus status1 = SecItemAdd((__bridge CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
                                                                (__bridge id)(kSecClassKey), kSecClass,
                                                                (__bridge id)kSecAttrKeyTypeRSA, kSecAttrKeyType,
                                                                (__bridge id)kSecAttrKeyClassPublic, kSecAttrKeyClass,
                                                                kCFBooleanTrue, kSecAttrIsPermanent,
                                                                [summaryString1 dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag,
                                                                certData1, kSecValueData,
                                                                kCFBooleanTrue, kSecReturnPersistentRef,
                                                                nil],
                                     NULL);   //don't need public key ref
        // Setting "cer" is successfully and delivers "noErr" in first run, then "errKCDuplicateItem"
        NSLog(@"evaluate with status %d", (int)status1);
        //Delete if already exist. Just temporary
        SecItemDelete((__bridge CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
                                                 (__bridge id)(kSecClassKey), kSecClass,
                                                 (__bridge id)kSecAttrKeyTypeRSA, kSecAttrKeyType,
                                                 (__bridge id)kSecAttrKeyClassPublic, kSecAttrKeyClass,
                                                 kCFBooleanTrue, kSecAttrIsPermanent,
                                                 [summaryString2 dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag,
                                                 certData2, kSecValueData,
                                                 kCFBooleanTrue, kSecReturnPersistentRef,
                                                 nil]);
        //NSString *name2 = [NSString stringWithUTF8String:CFStringGetCStringPtr(SecCertificateCopySubjectSummary(cert2), kCFStringEncodingUTF8)];
        OSStatus status2 = SecItemAdd((__bridge CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
                                                                 (__bridge id)(kSecClassKey), kSecClass,
                                                                 (__bridge id)kSecAttrKeyTypeRSA, kSecAttrKeyType,
                                                                 (__bridge id)kSecAttrKeyClassPublic, kSecAttrKeyClass,
                                                                 kCFBooleanTrue, kSecAttrIsPermanent,
                                                                 [summaryString2 dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag,
                                                                 certData2, kSecValueData,
                                                                 kCFBooleanTrue, kSecReturnPersistentRef,
                                                                 nil],
                                      NULL);   //don't need public key ref
        NSLog(@"evaluate with status %d", (int)status2);

        SecCertificateRef myReturnedCertificate1 = NULL;
        OSStatus status3 = SecIdentityCopyCertificate (identity1, &myReturnedCertificate1);
        SecCertificateRef myReturnedCertificate2 = NULL;
        OSStatus status4 = SecIdentityCopyCertificate (identity2, &myReturnedCertificate2);
        NSArray *myCerts = [[NSArray alloc] initWithObjects:(__bridge id)identity1, (__bridge id)myReturnedCertificate1, nil];
        [settings setObject:myCerts forKey:(NSString *)kCFStreamSSLCertificates];
        // Allow self-signed certificates
        [settings setObject:[NSNumber numberWithBool:YES]
                     forKey:GCDAsyncSocketManuallyEvaluateTrust];
        [sock startTLS:settings];
    }
}

如果出于某种原因,您决定手动评估信任。

- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler
{
    dispatch_queue_t bgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(bgQueue, ^{
        // This is where you would (eventually) invoke SecTrustEvaluate.
        SecIdentityRef identity1 = nil;
        SecTrustRef trust1 = nil;
        NSData *certData1 = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"[Dev] InHouse_Certificates" ofType:@"p12"]];
        CFDataRef myCertData1 = (__bridge_retained CFDataRef)(certData1);
        [self extractIdentityAndTrust:myCertData1 withIdentity:&identity1 withTrust:&trust1 withPassword:CFSTR("1234")];
        SecIdentityRef identity2 = nil;
        SecTrustRef trust2 = nil;
        NSData *certData2 = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"[Dis] InHouse_Certificates" ofType:@"p12"]];
        CFDataRef myCertData2 = (__bridge_retained CFDataRef)(certData2);
        [self extractIdentityAndTrust:myCertData2 withIdentity:&identity2 withTrust:&trust2 withPassword:CFSTR("1234")];
        if(myCertData1 && myCertData2)
        {
            CFArrayRef arrayRefTrust = SecTrustCopyProperties(trust);
            SecTrustResultType result = kSecTrustResultUnspecified;
            // usualy should work already here
            OSStatus status = SecTrustEvaluate(trust, &result);
            NSLog(@"evaluate with result %d and status %d", result, (int)status);
            NSLog(@"trust properties: %@", arrayRefTrust);
            /* log:
             evaluate with result 5 and status 0
             trust properties: (
             {
             type = error;
             value = "Root certificate is not trusted."; // expected, when top part was not working
             }
             */
            SecCertificateRef myReturnedCertificate1 = NULL;
            OSStatus status3 = SecIdentityCopyCertificate (identity1, &myReturnedCertificate1);
            SecCertificateRef myReturnedCertificate2 = NULL;
            OSStatus status4 = SecIdentityCopyCertificate (identity2, &myReturnedCertificate2);

            const void *ref[] = {myReturnedCertificate1};
            CFIndex count = SecTrustGetCertificateCount(trust);
            //            CFMutableArrayRef aryRef = CFArrayCreateMutable(NULL, count + 1, NULL);
            //            CFArrayAppendValue(aryRef, ref);
            CFArrayCreate(NULL, ref, 2, NULL);
            // # # # #
            // so check one by one...
            BOOL isMatching = NO;
            for (int i = 0; i < count; i++)
            {
                SecCertificateRef certRef = SecTrustGetCertificateAtIndex(trust, i);
                NSString *name = [NSString stringWithUTF8String:CFStringGetCStringPtr(SecCertificateCopySubjectSummary(certRef), kCFStringEncodingUTF8)]; 
                NSLog(@"remote cert at index %d is '%@'", i, name);

                const void *ref[] = {certRef, myReturnedCertificate1};
                CFArrayRef aryCheck = CFArrayCreate(NULL, ref, 2, NULL);
                SecTrustRef trustManual;
                OSStatus certStatus = SecTrustCreateWithCertificates(aryCheck, SecPolicyCreateBasicX509(), &trustManual);
                // certStatus always noErr
                NSLog(@"certStatus: %d", (int)certStatus);
                SecTrustResultType result;
                OSStatus status =  SecTrustEvaluate(trustManual, &result);
                CFArrayRef arrayRef = SecTrustCopyProperties(trustManual);
                NSLog(@"evaluate with result %d and status %d", result, (int)status);
                NSLog(@"trust properties: %@", arrayRef);
                /* log:
                 evaluate with result 5 and status 0
                 trust properties: (
                 {
                 type = error;
                 value = "Root certificate is not trusted.";
                 }
                 */
                if (status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified))
                {
                    isMatching = YES;
                    NSLog(@"certificates matches");
                }
                else
                {
                    NSLog(@"certificates differs");
                }
            }
            if (isMatching || (status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)))
            {
                completionHandler(YES);
            }
            else
            {
                completionHandler(NO);
            }
        }
        completionHandler(NO);
    });
}

更新:

根据Apple文档:

您必须在certRefs[0]中放置一个SecIdentityRef对象,用于标识叶证书及其对应的私钥。指定根证书是可选的;

根据苹果公司的建议,如果你使用.cer格式的证书,你应该使用对等域名(完全限定域名)来匹配这两个证书。

您可以使用此函数验证同行证书。如果您在证书与您在peerName中指定的值不匹配参数,则握手失败并返回errSSLXCertChainInvalid。此功能的使用是可选的。

通过在手动检查- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler中将证书设置为信任的anchorCertificates来解决问题,但感谢您的提示和努力:)将为此提供一些奖励。

    NSString *certFilePath1 = [[NSBundle mainBundle] pathForResource:@"rootCA" ofType:@"cer"];
    NSData *certData1 = [NSData dataWithContentsOfFile:certFilePath1];
    NSString *certFilePath2 = [[NSBundle mainBundle] pathForResource:@"oldServerCA" ofType:@"cer"];
    NSData *certData2 = [NSData dataWithContentsOfFile:certFilePath2];
    OSStatus status = -1;
    SecTrustResultType result = kSecTrustResultDeny;
    if(certData1 && certData2)
    {
        SecCertificateRef   cert1;
        cert1 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData1);
        SecCertificateRef   cert2;
        cert2 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData2);
        const void *ref[] = {cert1, cert2};
        CFArrayRef ary = CFArrayCreate(NULL, ref, 2, NULL);
        SecTrustSetAnchorCertificates(trust, ary);
        status = SecTrustEvaluate(trust, &result);
    }
    else
    {
        NSLog(@"local certificates could not be loaded");
        completionHandler(NO);
    }
    if ((status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)))
    {
        completionHandler(YES);
    }
    else
    {
        CFArrayRef arrayRefTrust = SecTrustCopyProperties(trust);
        NSLog(@"error in connection occuredn%@", arrayRefTrust);
        completionHandler(NO);
    }

为什么要手动评估信任?您是否可以将您的CA证书设置为GCDAsyncSocket在SSL设置中评估的唯一受信任根,并让它为您进行验证?

在这样的模型中,您将(1)减少自己的编码工作量[和风险],以及(2)只信任由您的私有CA为此连接签名的证书[同时信任默认信任存储中的公共CA]。

我只是觉得我会把它提供给今天看到它的人-我创建了一个包来帮助在iOS上使用TLS,并有新的iOS 13限制。把它放在这里,以防它对某人有帮助。欢迎投稿:

https://github.com/eamonwhiter73/IOSObjCWebSockets

最新更新