使用相同的 TLS 证书来验证客户端或服务器连接,然后第二次使用失败

如何解决使用相同的 TLS 证书来验证客户端或服务器连接,然后第二次使用失败

我发现特定的事件序列会导致 TLS 身份验证失败,并在之前成功时显示错误“客户端和服务器无法通信,因为它们没有通用算法”。这是 SChannel 中的错误吗?

使用 .NET 4.7.2 和 c# 开发。

PC 通过相互 TLS 身份验证相互连接。每台 PC 都支持客户端和服务器连接,并且可能是从一台 PC 连接的服务器,但将客户端连接到不同的 PC。 每台 PC 都有自己唯一的证书 (.pfx),我们将其用于服务器和客户端连接。

例如,PC1 和 PC2 都在与 PC3 通信。 PC1 与 PC3 建立连接。 PC3 使用它的 .pfx 调用 SslStream.AuthenticateAsServer,这成功了。

PC3 然后与 PC2 建立客户端连接并使用相同的 .pfx 调用 SslStream.AuthenticateAsClient。现在失败并出现错误“客户端和服务器无法通信,因为它们没有通用算法”

有趣的是,如果所有应用程序都重新启动并以相反的顺序进行连接,则行为会发生变化。如果先建立从 PC3 到 PC2 的客户端连接,则连接成功,但随后从 PC1 到 PC3 的服务器连接失败,并出现相同的错误。

一旦连接在一个方向上成功,我们就可以了,后续连接也会成功,但如果我们尝试在另一个方向上使用相同的证书,则除非重新启动应用程序,否则它将失败。

此外,我在 'AuthenticateAs' 方法中指定了 SslProtocols.None。 (推荐用于 .NET 4.7.2 以上)。如果我更改为指定 SslProtocols.Tls12,则两个连接都可以正常工作。

我不知道如何进一步调试。任何想法这里发生了什么? SChannel 是否保持某种内部状态,阻止我对客户端和服务器连接使用相同的证书?

我在下面放了一些示例代码来阐明我的意思。请注意,这只是一个示例,用于展示重现此问题的“服务器”和“客户端”代码。

 
        private static bool ValidateCertificate(object sender,X509Certificate certificate,X509Chain chain,SslPolicyErrors sslPolicyErrors)
        {
            // do some proper validation of cert...
            return true;
        }
        private X509Certificate UserCertificateSelectionCallback(object sender,string targetHost,X509CertificateCollection localCertificates,X509Certificate remoteCertificate,string[] acceptableIssuers)
        {
            if (localCertificates != null && localCertificates.Count > 0)
                return localCertificates[0];
            return null;
        }

        public async void Listen()
        {
            var tcpListener = new TcpListener(IPAddress.Any,Port);
            try
            {
                tcpListener.Start();
                Console.WriteLine("Server listening...");
                var client = await tcpListener.AcceptTcpClientAsync();
                Console.WriteLine("Server authenticating...");
                var sslStream = new SslStream(client.GetStream(),false,ValidateCertificate);
                var cert = new X509Certificate2("test.pfx","password");
                await sslStream.AuthenticateAsServerAsync(cert,true,System.Security.Authentication.SslProtocols.None,false);
                Console.WriteLine("Server authenticated.");

                // wait 5 secs then drop connection
                await Task.Delay(5000);
                sslStream.Dispose();
                cert.Reset();
                Console.WriteLine("Server dropped.");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                if (ex.InnerException != null)
                    Console.WriteLine(ex.InnerException.Message);
            }
            finally
            {
                tcpListener.Stop();
                Console.WriteLine("Server stopped Listening.");
            }
        }

        public async void Connect()
        {
            try
            {
                using (var socket = new Socket(AddressFamily.InterNetwork,System.Net.Sockets.SocketType.Stream,ProtocolType.Tcp))
                {
                    Console.WriteLine("Client connecting...");
                    await socket.ConnectAsync(Host,Port);

                    Console.WriteLine("Client authenticating...");

                    var sslStream = new SslStream(new NetworkStream(socket,true),ValidateCertificate,UserCertificateSelectionCallback,EncryptionPolicy.RequireEncryption);

                    using (var cert = new X509Certificate2("test.pfx","password"))
                    {
                        var certificateCollection = new X509Certificate2Collection(cert);
                        await sslStream.AuthenticateAsClientAsync(Host,certificateCollection,false);
                        Console.WriteLine("Client authenticated");

                        // wait 5 secs then drop connection
                        await Task.Delay(5000);
                    }

                    socket.Close();
                    Console.WriteLine("Client dropped");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                if (ex.InnerException != null)
                    Console.WriteLine(ex.InnerException.Message);
            }
        }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-