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

geo*_*geo 5 tcp objective-c self-signed ios gcdasyncsocket

*解决*

我的问题是引用以下问题:
Objective-C:如何使用签名者的公钥验证SecCertificateRef?

我们拥有自己的PKI,因此我们信任自己的rootCA.使用此rootCA,我们将签署提供给个人服务器的证书.现在我想连接iOS应用程序并检查从服务器发送的证书是否已使用我们的CA签名.

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

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

我的证书:
在app中: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];
        }
    }
} 
}
Run Code Online (Sandbox Code Playgroud)

好吧......如果不在这里工作,那么手动检查......

- (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);
    });
}
Run Code Online (Sandbox Code Playgroud)

更新1

去除

[settings setObject:[NSNumber numberWithBool:YES]
             forKey:GCDAsyncSocketManuallyEvaluateTrust];
Run Code Online (Sandbox Code Playgroud)

现在用

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];
Run Code Online (Sandbox Code Playgroud)

但获得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);
...
Run Code Online (Sandbox Code Playgroud)

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

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

bll*_*akk 6

我自己使用自定义证书来验证我们的消息传递应用程序在开发模式下使用的多个服

如果您可以访问p12(包含私钥并因此签名身份)文件,则可以使用kCFStreamSSLCertificates验证服务器证书

否则(仅在公钥的情况下)您可以选择通过对等名称kCFStreamSSLPeerName进行验证.

在您的代码片段中,您做错的一件事是如何将证书提供给GCDAsyncSocket模块.因此找到你提到的错误.

正确的方法如下:

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

根据Apple文档,使用kCFStreamSSLCertificates时必须标识:

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


完整细节:

以下是使用自定义签名CA证书时要遵循的步骤.请注意:示例基于GCDAsyncSocket

  1. 将公共部分证书保留在应用程序资源包中.
  2. 阅读上述证书并将证书添加到钥匙串
  3. 实施代表职能 -

(void)socket:(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];
Run Code Online (Sandbox Code Playgroud)

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

   [settings setObject:[NSNumber numberWithBool:YES]
                 forKey:GCDAsyncSocketManuallyEvaluateTrust];
Run Code Online (Sandbox Code Playgroud)
  1. 如果您选择手动验证信任,请覆盖以下委托方法.

(void)socket:(GCDAsyncSocket*)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(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];

    }

}
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因您决定手动评估信任.

- (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);
    });
}
Run Code Online (Sandbox Code Playgroud)

更新:

根据Apple文档:

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

正如Apple建议的那样,如果您使用的是in.cer格式的证书,则应使用对等域名(完全限定的域名)匹配两个证书.

您可以使用此功能验证对等证书中的公共名称字段.如果调用此函数并且证书中的公用名与peerName参数中指定的值不匹配,则握手失败并返回errSSLXCertChainInvalid.使用此功能是可选的.


geo*_*geo 3

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

    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 occured\n%@", arrayRefTrust);

        completionHandler(NO);
    }
Run Code Online (Sandbox Code Playgroud)