.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,需要通过注册表配置开启:
服务器端注册表配置
- 打开注册表编辑器,定位到:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server - 若不存在
TLS 1.3或Server项,手动创建 - 新建两个
DWORD值:Enabled:设置为1DisabledByDefault:设置为0
客户端注册表配置
- 定位到:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client - 同样新建两个
DWORD值:Enabled:设置为1DisabledByDefault:设置为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);
验证步骤
- 重启系统后,先运行服务器端程序
- 运行客户端程序,检查是否成功输出
Client authenticated with TLS 1.3和Server authenticated with TLS 1.3 - 验证数据读写是否正常
内容的提问来源于stack exchange,提问作者Matteo
相关产品推荐
相关产品推荐

