SSLStream服务端与客户端认证失败问题排查求助
在实现服务端与客户端SSL连接时,始终无法完成认证,核心问题是在AuthenticateAsServer()代码行捕获到如下异常:
System.Security.Authentication.AuthenticationException: 'Authentication failed, see inner exception.'
Win32Exception: the credentials supplied to the package were not recognized.
目前已通过Chrome访问https://192.168.1.113:32581测试服务端,同样无法完成认证,说明问题不在AuthenticateAsClient()部分。
测试端口为32581(computer.IpPort=32581),服务端IP为192.168.1.103(computer.IpAddress="192.168.1.103")。
操作步骤
- 使用PowerShell命令生成自签名证书:
New-SelfSignedCertificate -Subject DESKTOP-12345
服务端代码中getServerCert()可正确返回证书,ValidateServerCertificate()暂时直接返回true。
服务端代码
private readonly Computer computer; private TcpClient TCP_Client; private NetworkStream TCP_Stream; private SslStream SSL_Stream; private X509Certificate2 clientCertificate; private ConcurrentQueue<string> TCP_pendingCommands = new ConcurrentQueue<string>(); private void TCP_Listen() { try { ServerCertificate = getServerCert(); if (ServerCertificate == null) { throw new Exception("Client certificate is not set."); } // Listen TCP_Listener = new TcpListener(IPAddress.Any, computer.IpPort); TCP_Listener.Start(); while (true) { Console.WriteLine("Waiting for a client to connect..."); Thread.Sleep(2000); TCP_Client = TCP_Listener.AcceptTcpClient(); ProcessClient(); } } catch (Exception e) { Disconnect(); Console.WriteLine(e.Message); Thread.Sleep(1000); } } private void ProcessClient() { try { IPEndPoint remoteIpEndPoint = TCP_Client.Client.RemoteEndPoint as IPEndPoint; computer.IpAddress = remoteIpEndPoint.Address.ToString(); TCP_Stream = TCP_Client.GetStream(); TCP_Stream.ReadTimeout = Timeout.Infinite; SSL_Stream = new SslStream(TCP_Stream, false, ValidateServerCertificate); SSL_Stream.AuthenticateAsServer(ServerCertificate, false, SslProtocols.Tls12, false); if (!SSL_Stream.IsAuthenticated) throw new Exception("Failed to connect."); new Thread(() => TCP_Write(TCP_Client)) { IsBackground = true, Name = "SSL server TCP Write thread" }.Start(); new Thread(() => TCP_Read(TCP_Client)) { IsBackground = true, Name = "SSL server TCP Read thread" }.Start(); TCP_pendingCommands = new ConcurrentQueue<string>(); } catch (Exception e) { Disconnect(); Console.WriteLine(e.Message); Thread.Sleep(1000); } } private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { // lets just return true here return true; } private X509Certificate getServerCert() { X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadOnly); X509Certificate2 foundCertificate = null; foreach (X509Certificate2 currentCertificate in store.Certificates) { if (currentCertificate.IssuerName.Name != null && currentCertificate.IssuerName. Name.Equals("CN=DESKTOP-12345")) { foundCertificate = currentCertificate; break; } } return foundCertificate; }
客户端代码(暂未成功使用)
private void Connect() { try { TCP_Client = new TcpClient(computer.IpAddress, computer.IpPort) { NoDelay = true }; TCP_Stream = TCP_Client.GetStream(); TCP_Stream.ReadTimeout = Timeout.Infinite; SSL_Stream = new SslStream(TCP_Stream, false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); SSL_Stream.AuthenticateAsClient("DESKTOP-12345"); byte[] buffer = new byte[4096]; int bytesRead = SSL_Stream.Read(buffer, 0, buffer.Length); if (!SSL_Stream.IsAuthenticated) throw new Exception("Failed to connect."); RaisePropertyChanged(nameof(Power)); computer.RaiseComputerPropertyChanged(nameof(Power)); computer.SetComputerConnected(true); TCP_pendingCommands = new ConcurrentQueue<string>(); } catch (Exception e) { Disconnect(); Debug.Writeline(e.Message); Thread.Sleep(1000); } } public bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) { return true; } Console.WriteLine("Certificate error: {0}", sslPolicyErrors); // refuse connection return true; }
补充说明
也尝试用OpenSSL生成证书和密钥:
req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout private.key -out certificate.crt
并替换服务端证书加载代码为:
string certFilePath = "C:\\Path\\To\\certificate.crt"; string privateKeyPath = "C:\\Path\\To\\private.key"; ServerCertificate = X509Certificate2.CreateFromPemFile(certFilePath, privateKeyPath);
但仍出现相同异常。
内容的提问来源于stack exchange,提问作者Hugo_vdms

