ios--https自签CA的双向认证

2020-01-20  本文已影响0人  简鱼7819

之前自签https也做过,不过都是单向的,服务端认证客户端的。

这次项目需求遇到需要双向认证的,保证一次接口请求的双方都是符合“安全考验”的。

废话不多说,现在网络上这样的代码示例有很多,下面我来写一下我自己的梳理。

1,整个需求逻辑

1),现在客户端ios--服务端server,要建立https双向认证。

2),ios开发不管是OC的AFN还是swift是Alamofire,都是我们最常用的网络请求框架,我下面拿oc的afnetworking做示例。

3),建立双向认证,咱们客户端需要在工程集成两种证书,一个cer,一个p12。

4),两个证书的来源,确定的说都是来自后台服务端开发,开发过程中都是服务端创建CA根证书,而ios客户端集成需要两种证书都是需要CA根证书签发。

5),校验两种证书的代码,以及info.plist设置

2,代码

info.plist设置看我的这一篇N久前写的简书ios-App使用AFNetworking支持https(CA证书和自签证书)

cer证书代码,上面简书已经有了。下面再啰嗦一遍,多写一遍多熟悉一点。😝

/* cer 证书处理 begin */

    AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];

    policy.allowInvalidCertificates = YES;//客户端是否信任非法证书

    policy.validatesDomainName = NO;//是否在证书域字段中验证域名

    manager.securityPolicy= policy;

    //关闭缓存避免干扰测试

    manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;

    /* cer 证书处理 end */

处理p12证书的代码

//校验证书

+ (void)checkCredential:(AFURLSessionManager *)manager

{

    [managersetSessionDidBecomeInvalidBlock:^(NSURLSession * _Nonnull session, NSError * _Nonnull error) {

    }];

    __weaktypeof(manager)weakManager = manager;

    [managersetSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession*session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing*_credential) {

        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;

        __autoreleasingNSURLCredential*credential =nil;

        NSLog(@"authenticationMethod=%@",challenge.protectionSpace.authenticationMethod);

        //判断服务器要求客户端的接收认证挑战方式,如果是NSURLAuthenticationMethodServerTrust则表示去检验服务端证书是否合法,NSURLAuthenticationMethodClientCertificate则表示需要将客户端证书发送到服务端进行检验

        if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {

            // 基于客户端的安全策略来决定是否信任该服务器,不信任的话,也就没必要响应挑战

            if([weakManager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {

                // 创建挑战证书(注:挑战方式为UseCredential和PerformDefaultHandling都需要新建挑战证书)

                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

                // 确定挑战的方式

                if(credential) {

                    //证书挑战  设计policy,none,则跑到这里

                    disposition =NSURLSessionAuthChallengeUseCredential;

                }else{

                    disposition =NSURLSessionAuthChallengePerformDefaultHandling;

                }

            }else{

                disposition =NSURLSessionAuthChallengeCancelAuthenticationChallenge;

            }

        }else{//只有双向认证才会走这里

            // client authentication

            SecIdentityRefidentity =NULL;

            SecTrustReftrust =NULL;

            NSString *p12 = [[NSBundle mainBundle] pathForResource:@"client"ofType:@"p12"];

            NSFileManager *fileManager =[NSFileManager defaultManager];

            if(![fileManagerfileExistsAtPath:p12])

            {

                NSLog(@"client.p12:not exist");

            }

            else

            {

                NSData*PKCS12Data = [NSDatadataWithContentsOfFile:p12];

                NSLog(@"--PKCS12Data-->%@",PKCS12Data);

                if([selfextractIdentity:&identityandTrust:&trustfromPKCS12Data:PKCS12Data])

                {

                    SecCertificateRefcertificate =NULL;

                    SecIdentityCopyCertificate(identity, &certificate);

                    constvoid*certs[] = {certificate};

                    CFArrayRefcertArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL);

                    credential =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge  NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];

                    disposition =NSURLSessionAuthChallengeUseCredential;

                }

            }

        }

        *_credential = credential;

        returndisposition;

    }];

}

//读取p12文件中的密码

+ (BOOL)extractIdentity:(SecIdentityRef*)outIdentityandTrust:(SecTrustRef*)outTrustfromPKCS12Data:(NSData*)inPKCS12Data {

    OSStatussecurityError =errSecSuccess;

    //client certificate password 123456

    NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@"123456"

                                                                 forKey:(__bridgeid)kSecImportExportPassphrase];

    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);

    securityError =SecPKCS12Import((__bridgeCFDataRef)inPKCS12Data,(__bridgeCFDictionaryRef)optionsDictionary,&items);

    if(securityError ==0) {

        CFDictionaryRefmyIdentityAndTrust =CFArrayGetValueAtIndex(items,0);

        constvoid*tempIdentity =NULL;

        tempIdentity=CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemIdentity);

        *outIdentity = (SecIdentityRef)tempIdentity;

        constvoid*tempTrust =NULL;

        tempTrust =CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust);

        *outTrust = (SecTrustRef)tempTrust;

    }else{

        NSLog(@"Failedwith error code %d",(int)securityError);

        returnNO;

    }

    return YES;

}

整体的调用逻辑

遇到,解决,记录,分享~~

上一篇下一篇

猜你喜欢

热点阅读