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

2023-12-12

*solved*

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

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

我的应用程序应该能够使用此证书连接到 n 个服务器(可能在零配置服务中找到)使用 TCP 连接,由以下方式建立GCDAsyncSocket。我的应用程序中有证书的公共部分,我想将其添加到我的“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);
    });
}

UPDATE 1

removed

[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*/) in

// 2. kCFStreamSSLCertificates

value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLCertificates];
if ([value isKindOfClass:[NSArray class]])
{
    CFArrayRef certs = (__bridge CFArrayRef)value;

    status = SSLSetCertificate(sslContext, certs);
...

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

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


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

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

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

在您的代码片段中,您做错的一件事是如何向 GCDAsyncSocket 模块提供证书。从而找到您提到的错误。

正确的方法如下:

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

根据 Apple 文档,使用 kCFStreamSSLCertificates 时身份是强制性的:

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


完整详细信息:

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

  1. 将您的公共部分证书保存在应用程序资源包中。
  2. 读取上面的证书并将证书添加到钥匙串中
  3. 实现委托功能-

(void)soc​​ket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host 端口:(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];
  1. 如果您选择手动验证信任,请覆盖以下委托方法。

(void)soc​​ket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust 完成处理程序:(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);
    });
}

Update:

根据苹果文档:

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

根据 Apple 的建议,如果您使用 .cer 格式的证书,则应使用对等域名(完全限定域名)来匹配两个证书。

您可以使用此功能来验证通用名称字段 同行的证书。如果你调用这个函数和通用名称 该证书与您在 peerName 中指定的值不匹配 参数,则握手失败并返回 errSSLXCertChainInvalid。 该函数的使用是可选的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Objective-C:评估由我们自己的 PKI(根 CA)在 TLS TCP 连接上签名的服务器证书 的相关文章

随机推荐