You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Framework 4.8下TLS 1.3连接建立失败问题求助

.NET Framework 4.8 下 TLS 1.3 连接失败问题解决

问题背景

我正在搭建测试环境,使用.NET Framework 4.8测试TLS 1.3通信。当不指定SslProtocols.Tls13时,客户端与服务器可正常完成握手并读写数据;但一旦强制指定该协议,就会抛出异常:

The client and server cannot communicate, because they do not possess a common algorithm

客户端代码

public class Tls13Client
{
    public static void Main()
    {
        string serverIP = "127.0.0.1";
        int serverPort = 8888;
        TcpClient client = new TcpClient();
        client.Connect(serverIP, serverPort);

        SslStream sslStream = new SslStream(client.GetStream(), false,
            new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
        X509Certificate2 certificate = LoadCertificate();

        try
        {
            sslStream.AuthenticateAsClient("localhost", new X509CertificateCollection(new[] { certificate }) , SslProtocols.Tls13, true);
            Console.WriteLine("Client authenticated with TLS 1.3");

            // Perform data exchange using the sslStream

            string messageToSend = "Hello from client!";
            byte[] buffer = Encoding.UTF8.GetBytes(messageToSend);
            sslStream.Write(buffer, 0, buffer.Length);
            Console.WriteLine("Sent to server: " + messageToSend);

            // Receive the response from the server
            byte[] responseBuffer = new byte[4096];
            int bytesRead = sslStream.Read(responseBuffer, 0, responseBuffer.Length);
            string responseData = Encoding.UTF8.GetString(responseBuffer, 0, bytesRead);
            Console.WriteLine("Received from server: " + responseData);

            sslStream.Close();
            client.Close();

            Console.WriteLine("Press enter to close...");
            Console.ReadLine();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception: " + ex.Message);
            if (ex.InnerException != null)
                Console.WriteLine("Inner exception: " + ex.InnerException.Message);
        }
        finally
        {
            sslStream.Dispose();
            client.Dispose();
        }
    }

    private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        // Add your custom server certificate validation logic here
        return true; // Accept any certificate (not recommended for production)
    }

    private static X509Certificate2 LoadCertificate()
    {
        // Load your client certificate here
        string certificatePath = "client_certificate.pfx";
        string certificatePassword = "password";

        return new X509Certificate2(certificatePath, certificatePassword);
    }
}

服务器代码

public class Tls13Server
{
    public static void Main()
    {
        int port = 8888;
        TcpListener listener = new TcpListener(IPAddress.Any, port);
        listener.Start();

        Console.WriteLine("Server started. Waiting for incoming connections...");

        TcpClient client = listener.AcceptTcpClient();
        SslStream sslStream = new SslStream(client.GetStream(), false);
        X509Certificate2 certificate = LoadCertificate();

        try
        {
            sslStream.AuthenticateAsServer(certificate, false, SslProtocols.Tls13, true);
            Console.WriteLine("Server authenticated with TLS 1.3");

            // Perform data exchange using the sslStream
            byte[] buffer = new byte[4096];
            int bytesRead;

            while ((bytesRead = sslStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Console.WriteLine("Received from client: " + receivedData);

                // Echo the received message back to the client
                byte[] responseBuffer = Encoding.UTF8.GetBytes("Server received: " + receivedData);
                sslStream.Write(responseBuffer, 0, responseBuffer.Length);
            }

            sslStream.Close();
            client.Close();


            Console.WriteLine("Press enter to close...");
            Console.ReadLine();

        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception: " + ex.Message);
            if (ex.InnerException != null)
                Console.WriteLine("Inner exception: " + ex.InnerException.Message);
        }
        finally
        {
            sslStream.Dispose();
            client.Dispose();
            listener.Stop();
        }
    }

    private static X509Certificate2 LoadCertificate()
    {
        // Load your server certificate here
        string certificatePath = "server_certificate.pfx";
        string certificatePassword = "password";

        return new X509Certificate2(certificatePath, certificatePassword);
    }
}

完整异常栈

Message : The client and server cannot communicate, because they do not possess a common algorithm
 at System.Net.SSPIWrapper.AcquireCredentialsHandle(SSPIInterface SecModule, String package, CredentialUse intent, SecureCredential scc)
   at System.Net.Security.SecureChannel.AcquireCredentialsHandle(CredentialUse credUsage, SecureCredential& secureCredential)
   at System.Net.Security.SecureChannel.AcquireCredentialsHandle(CredentialUse credUsage, X509Certificate2 selectedCert, Flags flags)
   at System.Net.Security.SecureChannel.AcquireServerCredentials(Byte[]& thumbPrint)
   at System.Net.Security.SecureChannel.GenerateToken(Byte[] input, Int32 offset, Int32 count, Byte[]& output)
   at System.Net.Security.SecureChannel.NextMessage(Byte[] incoming, Int32 offset, Int32 count)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
   at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.AuthenticateAsServer(X509Certificate serverCertificate, Boolean clientCertificateRequired, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
   at Tls13Server.Tls13Server.Main() in C:\Tls1.3\server\Tls13Server\Program.cs:line 27

解决方案

1. 确认系统版本要求

.NET Framework 4.8的TLS 1.3依赖系统SCHANNEL组件的支持,必须满足:

  • Windows 10 1903 及以上版本
  • Windows Server 2019 1903 及以上版本

旧系统(如Windows 7、Windows Server 2016)不支持TLS 1.3,无法通过.NET Framework 4.8启用。

2. 启用SCHANNEL的TLS 1.3支持

默认情况下,Windows可能未启用TLS 1.3,需要通过注册表配置开启:

服务器端注册表配置

  1. 打开注册表编辑器,定位到:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server
  2. 若不存在TLS 1.3或Server项,手动创建
  3. 新建两个DWORD值:
    • Enabled:设置为1
    • DisabledByDefault:设置为0

客户端注册表配置

  1. 定位到:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client
  2. 同样新建两个DWORD值:
    • Enabled:设置为1
    • DisabledByDefault:设置为0

配置完成后重启系统生效。

3. 确保证书算法兼容TLS 1.3

TLS 1.3对签名和密钥交换算法有严格限制,旧证书可能不兼容:

  • 签名算法:仅支持SHA256withRSA、SHA384withRSA、SHA512withRSA,或ECDSA的SHA256/384/512算法
  • 密钥交换:推荐使用ECDH(椭圆曲线)密钥交换;若使用RSA证书,需确保支持RSA-PSS签名算法(部分旧RSA证书不支持)

可以重新生成兼容的证书,例如使用OpenSSL生成ECDSA证书:

# 生成ECDSA私钥
openssl ecparam -genkey -name prime256v1 -out server.key
# 生成证书请求
openssl req -new -key server.key -out server.csr
# 自签名证书
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
# 转换为PFX格式
openssl pkcs12 -export -out server_certificate.pfx -inkey server.key -in server.crt

4. 应用程序配置调整

在项目的app.config(或web.config)中添加以下配置,确保.NET Framework启用系统默认TLS版本和强加密:

<configuration>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false;Switch.System.Net.DontEnableSystemDefaultTlsVersions=false" />
  </runtime>
</configuration>

5. 代码优化(可选)

如果不需要双向认证,客户端可以去掉证书加载逻辑,简化AuthenticateAsClient调用:

sslStream.AuthenticateAsClient("localhost", null, SslProtocols.Tls13, true);

验证步骤

  1. 重启系统后,先运行服务器端程序
  2. 运行客户端程序,检查是否成功输出Client authenticated with TLS 1.3和Server authenticated with TLS 1.3
  3. 验证数据读写是否正常

内容的提问来源于stack exchange,提问作者Matteo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:27:01