Problem with SslStream when using Windows Vista

  • Thread starter Thread starter Dave
  • Start date Start date
D

Dave

Hi.

When my client program runs under XP and calls a server (solaris in
this case) via an SslStream all is well. The client may make multiple
calls and multiple authentication calls and be fine. I expressly "clean up"
everything streamwise and socketwise and all is well.
Running the client under Vista, when the second authentication call is made
it returns the following SSPI error:

"A call to the SSPI failed, see inner exception"


which reads
"the Local Security Authority cannot be contacted"


Well that was pretty mystifying so I looked at what was going on with
ethereal. Apparently, on the second authentication go-round Vista asks the
server to re-use a session Id. The server responds and then
Vista rejects a re-used session Id (even though it asked to do that).


What I have found out is that the .net framework caches SslStream sessions
automatically, I have not found any way to turn this off for Vista - any
ideas on how to do this or to get Vista to use the cached SessionId which it
requested?

Here is a link to a sample that seemingly generates the same flaw that I
have described.

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1222194&SiteID=1

Thanks Dave
 
Hi Dave,

The session resumption can be turned off by setting the maximum cache size
\ time to a very small value. But this is a horrible workaround (not
advised)
http://msdn2.microsoft.com/en-us/library/aa922895.aspx

To help to find the root cause, is it possible for you to provide a little
sample project to demonstrate this problem? Once I can give it a local
reproduce, it would be easier to troubleshoot it and find a solution.

Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
I provided a link in the first post to a sample project provided by another
individual.

If you need something more just tell me and I will try to put it together.
 
Are you referring to the ClientCacheTime or MaximumCachSize ?
MaximumCachSize is defined as:
The maximum number of elements in a session cache.
 
Here is a sample that someone else posted and I had a link to in my first
post:

___

Exception: A call to SSPI failed, see inner exception.
Inner exception: The Local Security Authority cannot be contacted
Authentication failed - closing the connection.

I've reviewed tracing information and it doesn't really help. What seems to
occur is an internal error and then the client side connection is shutdown.

System.Net Information: 0 : [3804] AcceptSecurityContext(In-Buffer
length=1333,
Out-Buffer length=0, returned code=InternalError).

Anyone with any hints it would be much appreciated.

The code for the server & client follow.

--- server.cs --
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Threading;

namespace Examples.System.Net
{
public class SslTcpServer
{
private X509Certificate _serverCertificate = null;
private Thread _thread;
private int _port = 0;

// The certificate parameter specifies the name of the file
// containing the machine certificate.
void RunServer()
{
// Create a TCP/IP (IPv4) socket and listen for incoming
connections.
TcpListener listener = new TcpListener(IPAddress.Any, 0);
listener.Start();
lock(this)
{
_port = ((IPEndPoint)listener.LocalEndpoint).Port;
Monitor.Pulse(this);
}
Console.WriteLine("Waiting for a client to connect on port " +
_port);
TcpClient client = listener.AcceptTcpClient();
ProcessClient(client);
listener.Stop();
}

void ProcessClient(TcpClient client)
{
// A client has connected. Create the
// SslStream using the client's network stream.
SslStream sslStream = new SslStream(client.GetStream(), false);
try
{
sslStream.AuthenticateAsServer(
_serverCertificate, false, SslProtocols.Tls, true);

// Set timeouts for the read and write to 5 seconds.
sslStream.ReadTimeout = 5000;
sslStream.WriteTimeout = 5000;
// Read a message from the client.
Console.WriteLine("Waiting for client message...");
string messageData = ReadMessage(sslStream);
Console.WriteLine("Received: {0}", messageData);

// Write a message to the client.
byte[] message = Encoding.UTF8.GetBytes("Hello from the
server.<EOF>");
Console.WriteLine("Sending hello message.");
sslStream.Write(message);
}
catch (AuthenticationException e)
{
Console.WriteLine("Exception: {0}", e.Message);
if (e.InnerException != null)
{
Console.WriteLine("Inner exception: {0}",
e.InnerException.Message);
}
Console.WriteLine ("Authentication failed - closing the
connection.");
sslStream.Close();
client.Close();
}
finally
{
// The client stream will be closed with the sslStream
// because we specified this behavior when creating
// the sslStream.
sslStream.Close();
client.Close();
}
}

string ReadMessage(SslStream sslStream)
{
// Read the message sent by the client.
// The client signals the end of the message using the
// "<EOF>" marker.
byte [] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do
{
// Read the client's test message.
bytes = sslStream.Read(buffer, 0, buffer.Length);

// Use Decoder class to convert from bytes to UTF8
// in case a character spans two buffers.
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new
char[decoder.GetCharCount(buffer,0,bytes)];
decoder.GetChars(buffer, 0, bytes, chars,0);
messageData.Append (chars);
// Check for EOF or an empty message.
if (messageData.ToString().IndexOf("<EOF>") != -1)
{
break;
}
} while (bytes !=0);

return messageData.ToString();
}

public SslTcpServer()
{
_serverCertificate = new
X509Certificate2("s_rsa_nopass_ca1.pfx", "password");
_thread = new Thread(new ThreadStart(RunServer));
_thread.Name = "SslTcpServer";
_thread.Start();
}

public int GetPort()
{
lock(this)
{
while(_port == 0)
{
Monitor.Wait(this);
}
}
return _port;
}
}

public class FactoryServer
{
void ProcessClient(TcpClient client)
{
try
{
SslTcpServer server = new SslTcpServer();
int port = server.GetPort();
NetworkStream stream = client.GetStream();
byte[] msg = Encoding.UTF8.GetBytes(port.ToString());
stream.Write(msg, 0, msg.Length);
byte[] term = new byte[1];
term[0] = 0;
stream.Write(term, 0, 1);
stream.Flush();
int bytes = stream.Read(term, 0, 1);
}
finally
{
client.Close();
}
}

public void Run()
{
TcpListener listener = new TcpListener(IPAddress.Any, 8080);
listener.Start();
while (true)
{
Console.WriteLine("Waiting for a client to connect...");
// Application blocks while waiting for an incoming
connection.
// Type CNTL-C to terminate the server.
TcpClient client = listener.AcceptTcpClient();
ProcessClient(client);
}
}

}

public class Server
{
public static int Main(string[] args)
{
FactoryServer server = new FactoryServer();
server.Run();
return 0;
}
}
}
-- client.cs --
using System;
using System.Collections;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Threading;

namespace Examples.System.Net
{
public class SslTcpClient
{
private static Hashtable certificateErrors = new Hashtable();

public static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
return true;
}

public static void RunClient(int port)
{
TcpClient client = new TcpClient("127.0.0.1", port);
NetworkStream stream = client.GetStream();
Console.WriteLine("Client connected.");
// Create an SSL stream that will close the client's stream.
SslStream sslStream = new SslStream(
stream, false, new RemoteCertificateValidationCallback(
ValidateServerCertificate), null);
try
{
//sslStream.AuthenticateAsClient("localhost", null,
SslProtocols.Default, false);
sslStream.AuthenticateAsClient("localhost");
}
catch (AuthenticationException e)
{
Console.WriteLine("Exception: {0}", e.Message);
if (e.InnerException != null)
{
Console.WriteLine("Inner exception: {0}",
e.InnerException.Message);
}
Console.WriteLine ("Authentication failed - closing the
connection.");
client.Close();
return;
}
// Encode a test message into a byte array.
// Signal the end of the message using the "<EOF>".
byte[] messsage = Encoding.UTF8.GetBytes("Hello from the
client.<EOF>");
// Send hello message to the server.
sslStream.Write(messsage);
sslStream.Flush();
// Read message from the server.
string serverMessage = ReadMessage(sslStream);
Console.WriteLine("Server says: {0}", serverMessage);
// Close the client connection.
client.Close();
Console.WriteLine("Client closed.");
}
static string ReadMessage(SslStream sslStream)
{
// Read the message sent by the server.
// The end of the message is signaled using the
// "<EOF>" marker.
byte [] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do
{
bytes = sslStream.Read(buffer, 0, buffer.Length);

// Use Decoder class to convert from bytes to UTF8
// in case a character spans two buffers.
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new
char[decoder.GetCharCount(buffer,0,bytes)];
decoder.GetChars(buffer, 0, bytes, chars,0);
messageData.Append (chars);
// Check for EOF.
if (messageData.ToString().IndexOf("<EOF>") != -1)
{
break;
}
} while (bytes != 0);

return messageData.ToString();
}

private static int ReadPort(NetworkStream stream)
{
byte[] msg = new byte[1024];
int curr = 0;
do
{
int bytes = stream.Read(msg, curr, 1);
if(bytes == 0)
{
Console.WriteLine("Error reading port");
return 1;
}
if(msg[curr] == 0)
{
break;
}
++curr;
}
while(curr < msg.Length);
if(curr == msg.Length)
{
Console.WriteLine("Error reading port");
return 1;
}

Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new
char[decoder.GetCharCount(msg,0,msg.Length-1)];
decoder.GetChars(msg, 0, msg.Length-1, chars,0);
StringBuilder messageData = new StringBuilder();
messageData.Append(chars);
return Int32.Parse(messageData.ToString());
}

public static int Main(string[] args)
{
TcpClient client = new TcpClient("127.0.0.1", 8080);
NetworkStream stream = client.GetStream();
Console.WriteLine("Client connected.");
int port = ReadPort(stream);
Console.WriteLine("Connecting to " + port);

// Write termination byte drop the client.
byte[] term = new byte[1];
term[0] = 0;
stream.Write(term, 0, 1);
client.Close();

SslTcpClient.RunClient(port);
return 0;
}
}
}



"Jeffrey Tan[MSFT]" said:
Hi Dave,

The session resumption can be turned off by setting the maximum cache size
\ time to a very small value. But this is a horrible workaround (not
advised)
http://msdn2.microsoft.com/en-us/library/aa922895.aspx

To help to find the root cause, is it possible for you to provide a little
sample project to demonstrate this problem? Once I can give it a local
reproduce, it would be easier to troubleshoot it and find a solution.

Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no
rights.
 
Hi Dave,

I have created an empty server project in my Win2003 machine and copied
your code in it. Then I copied your client code in a project on another
Vista machine. Finally, I obtained a password protected pfx file from my
colleague and modify the server code to use it.

However, when I run the server and the the client project under debugger, I
did not get any exception like you got.

Is there anything I miss in the above steps? Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi Dave,

Oh, yes, please look into this:
http://technet2.microsoft.com/windowsserver/en/library/3f98fdd9-ed64-49f7-9c
20-a2d4581dfbea1033.mspx

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Jeffrey,

I have another client example to give you. Could you possibly give me an
email address to send it to you, I would prefer not posting it on the new
group in its current form.

Dave
 
Hi Dave,

Yes, you may send the reproduce project to
(e-mail address removed)(remove "online."). Please also send the detailed
steps to reproduce the problem, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Jeffrey,

Are you running the connect multiple times during the same run time session?
Don't exit the program. You might need to create a form and add a connect
and then close button. Then go through the sequence of connecting then
disconnecting, then reconnecting.

On the second attempt to connect you will receive the error. I just did
what you did, I put an ssl listener program on a windows 2003 server and ran
a client on a vista box. I generates the same error on the second attempt
to connect.

Dave
 
Hi Dave,

Thank you for the feedback.

Yes, I have tried to run the SSLClient on the Vista machine for more than 2
times. However, both will work without any error. It is strange that I can
not reproduce this error.

I have received your sample project through email. However, when I try to
connect your server(I run it without any modification), I will get "No such
host is known" SocketException. It seems that I can not connect your server
in my CorpNet.

Is it possible for you to provide client/server pair projects that can
reproduce this problem? I think reproducing it locally is easier than
connecting out of CorpNet.

I will wait for your further feedback, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Back
Top