在.NET Framework 4.0中使用VS 10,我编写了三个c#单元测试来检查不同服务器/客户端协议设置的SslStream行为。
private void InternalTestSsl(SslProtocols serverProtocols, SslProtocols clientProtocols)
{
X509Certificate2 certificate = RetrieveServerCertificate();
var server = new TcpListener(new IPEndPoint(IPAddress.Any, 20000));
server.Start();
try
{
// create and execute a task for server operations
var serverTask = new Task(() =>
{
TcpClient connectionToClient = server.AcceptTcpClient();
var sslStream = new SslStream(connectionToClient.GetStream(), false, (a, b, c, d) => true, (a, b, c, d, e) => certificate);
sslStream.AuthenticateAsServer(certificate, false, serverProtocols, true);
Assert.IsTrue(sslStream.IsAuthenticated);
});
serverTask.Start();
// create and execute a task for client operations
var clientTask = new Task(() =>
{
var clientConnection = new TcpClient();
clientConnection.Connect(new IPEndPoint(IPAddress.Loopback, 20000));
var sslStream = new SslStream(clientConnection.GetStream(), false, (a, b, c, d) => true, (a, b, c, d, e) => null);
sslStream.AuthenticateAsClient(Environment.MachineName, null, clientProtocols, true);
Assert.IsTrue(sslStream.IsAuthenticated);
});
clientTask.Start();
// wait for both server and client task to finish, check results
if (!serverTask.Wait(TimeSpan.FromSeconds(1)))
{
throw new Exception("Server task did not end in time.");
}
if (!clientTask.Wait(TimeSpan.FromSeconds(1)))
{
throw new Exception("Client task did not end in time.");
}
}
finally
{
server.Stop();
}
}
[TestMethod]
public void TestTlsTls()
{
InternalTestSsl(SslProtocols.Tls, SslProtocols.Tls);
}
[TestMethod]
public void TestTlsSsl3()
{
InternalTestSsl(SslProtocols.Tls, SslProtocols.Ssl3);
}
[TestMethod]
public void TestSsl3Tls()
{
InternalTestSsl(SslProtocols.Ssl3, SslProtocols.Tls);
}
TestTlsTls传递,因为服务器和客户端都定义了要使用的相同协议(仅限TLS)。 TestTlsSsl3的失败也是完全可以理解的(抛出AuthenticationException是因为服务器需要使用TLS,但客户端只想玩SSL3)。
我希望测试“TestSsl3Tls”以相同的AuthenticationException失败,而是我的自定义异常“服务器任务没有及时结束”。被解雇。在调试时,我看到只有客户端任务收到AuthenticationException,而serverTask仍然在AuthenticateAsServer的调用中。交换我的Wait命令导致相反的结果:“TestSsl3Tls”的AuthenticationException,“客户端没有及时结束”的“TestTlsSsl3”。
这是正常行为吗,AuthenticationException只被抛出一边,另一边等待(可能是新的身份验证尝试还是断开连接)?
答案 0 :(得分:2)
试试:
socket.ReceiveTimeout = //some timeout in millis
我遇到了同样的问题,但建议的处置解决方案在我的情况下不起作用。我的用例有点不同。我从 TcpListener 的异步 Begin/EndAcceptSocket 获得一个 Socket。当我使用协议不匹配的客户端调用 AuthenticateAsServer 时,它永远不会返回,并且处理流也不会使其返回。
我发现我必须设置socket.ReceiveTimeout,如下所示。
IAsyncResult asyncResult;//passed from BeginAcceptSocket callback
TcpListener listener = (TcpListener)asyncResult.AsyncState;
var socket = listener.EndAcceptSocket(asyncResult);
int timeoutInMillis;//set to whatever makes sense for your use case.
socket.ReceiveTimeout = timeoutInMillis; // This line fixed it for me
var stream = new SslStream(new NetworkStream(socket));
stream.AuthenticateAsServer(...); // This line doesn't hang any longer than the timeout.
在套接字上设置接收超时可确保 AuthenticateAsServer 调用在超时后返回,而不是在协议不匹配的情况下永远挂起。它可能并不适用于所有场景,但就我而言,我从来没有发送过如此多的数据,以至于需要超过几秒钟的时间。
在所有典型的连接场景中,它只会进行身份验证,我不需要超时,但它消除了可能永远挂起的边缘情况。
答案 1 :(得分:1)
我不知道你的问题的答案是否这种行为是正常的,但在我看来这是一个错误,我最近有同样的问题,因为我无法控制客户端安全协议,我的服务器最终冻结所有时间。
我通过Disposing sslstream解决了这个问题,这会在AuthenticateAsServer中导致异常,从而允许我的服务器继续运行。
这是代码片段
// wait for both server and client task to finish, check results
if (!serverTask.Wait(TimeSpan.FromSeconds(1)))
{
sslStream.Dispose(); // this line will cause an exception in the server task (AuthenticateAsServer), which allows the server to continue ...
}
既然你的问题引导我解决了我的问题,我会分享我的解决方案......