Ios 目标C:在TLS TCP连接上开发由我们自己的PKI(根CA)签名的服务器证书

Ios 目标C:在TLS TCP连接上开发由我们自己的PKI(根CA)签名的服务器证书,ios,objective-c,tcp,self-signed,gcdasyncsocket,Ios,Objective C,Tcp,Self Signed,Gcdasyncsocket,*已解决* 我的问题涉及以下问题: 我们有自己的PKI,因此我们信任自己的rootCA。通过这个rootCA,我们可以对发送到个人服务器的证书进行签名。现在,我想连接iOS应用程序,检查从服务器发送的证书是否与我们的CA签署 我的应用程序应该能够使用由GCDAsyncSocket建立的TCP连接连接到具有此证书的n台服务器(可能使用零配置服务)。我的应用程序中有证书的公共部分,我想将其添加到我的“CertChain”中,以便应用程序在connect上信任它们 我已经尝试了很多,但仍然无法通过S

*已解决*

我的问题涉及以下问题:

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

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

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

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

我的证书链:
rootCA签名的主服务器
oldServerCA已签名oldServer

我的代码部分:
新增更新

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

- (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);
    });
}
现在使用

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(
/*用户参数列表中的错误*/

似乎我用错了,但我看不出错误:/(不经常使用核心基础)


如果你需要进一步的信息,尽管问。每个提示都可以拯救生命:)

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


在这样的模型中,您将(1)减少自己的编码工作量[和风险](2)只信任您的私人CA为此连接签署的证书[而不是信任默认信任存储中的公共CA]。

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

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

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

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

正确的方法如下:

    NSArray *myCerts = [[NSArray alloc] initWithObjects:(__bridge id)identity1, (__bridge id)myReturnedCertificate1, nil];
    [settings setObject:myCerts forKey:(NSString *)kCFStreamSSLCertificates];
根据苹果公司文档,在使用KCFStreamSlc证书时,身份是强制性的:

您必须在certRefs[0]中放置一个识别 叶证书及其相应的私钥。指定 根证书是可选的


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

    NSArray *myCerts = [[NSArray alloc] initWithObjects:(__bridge id)identity1, (__bridge id)myReturnedCertificate1, nil];
    [settings setObject:myCerts forKey:(NSString *)kCFStreamSSLCertificates];
  • 将公共部件证书保存在应用程序资源包中
  • 阅读上述证书并将证书添加到密钥链
  • 执行委托功能-
  • (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];
    
    根据您是否要手动验证信任,在下面使用是(不推荐)或否

       [settings setObject:[NSNumber numberWithBool:YES]
                     forKey:GCDAsyncSocketManuallyEvaluateTrust];
    
  • 如果选择手动验证信任,请重写以下委托方法
  • (void)socket:(GCDAsyncSocket*)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void(^)(BOOL shouldTrustPeer))completionHandler

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

    示例代码:
    如果出于某种原因,您决定手动评估信任

    - (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);
        });
    }
    
    -(void)socket:(GCDAsyncSocket*)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void(^)(BOOL shouldTrustPeer))completionHandler
    {
    调度队列bgQueue=调度获取全局队列(调度队列优先级默认为0);
    调度异步(bgQueue^{
    //这就是您(最终)调用SecTrustEvaluate的地方。
    SecIdentityRef identity1=nil;
    SecTrustRef trust1=nil;
    NSData*certData1=[[NSData alloc]initWithContentsOfFile:[[NSBundle mainBundle]路径资源:@“p12”类型的“[Dev]内部证书”;
    CFDataRef myCertData1=(uu_u桥u保留CFDataRef)(certData1);
    [self-ExtractIdentity and Trust:myCertData1 with Identity:&identity1 with Trust:&trust1 with Password:CFSTR(“1234”);
    SecIdentityRef identity2=nil;
    SecTrustRef trust2=零;
    NSData*certData2=[[NSData alloc]initWithContentsOfFile:[[NSBundle mainBundle]路径资源:@“p12”类型的“[Dis]内部证书”;
    CFDataRef myCertData2=(uu_u桥u保留CFDataRef)(certData2);
    [self-ExtractIdentity and Trust:myCertData2 with Identity:&identity2 with Trust:&trust2 with Password:CFSTR(“1234”);
    if(myCertData1&&myCertData2)
    {
    CFArrayRef arrayRefTrust=SecTrustCopyProperties(信任);
    SecTrustResultType result=kSecTrustResultUnspecified;
    //通常应该已经在这里工作了
    OSStatus状态=部门信任评估(信任和结果);
    NSLog(@“评估结果为%d,状态为%d”,结果为(int)状态);
    NSLog(@“信任属性:%@”,arrayRefTrust);
    /*日志:
    使用结果5和状态0进行评估
    信托财产:(
    {
    类型=错误;
    value=“根证书不受信任。”;//顶部部件不工作时应为
    }
    */
    SecCertificateRef myReturnedCertificate1=NULL;
    奥斯塔特斯街
    
       [settings setObject:[NSNumber numberWithBool:YES]
                     forKey:GCDAsyncSocketManuallyEvaluateTrust];
    
    - (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);
        });
    }
    
        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);
        }