美文网首页
ios--https自签CA的双向认证

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

作者: 简鱼7819 | 来源:发表于2020-01-20 17:32 被阅读0次

    之前自签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;

    }

    整体的调用逻辑

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

    相关文章

      网友评论

          本文标题:ios--https自签CA的双向认证

          本文链接:https://www.haomeiwen.com/subject/eunjzctx.html