K
kinged
Guest
In our .NET 4.5 application, we use the System.Net.Security.SslStream class to make a secure connection to a server.
On Windows 10, this works fine...but our app servers are Windows Server 2008R2.
On Windows 7 & Windows Server 2008R2 & Windows Server 2012, the call to SslStream.AuthenticateAsClient throws an exception.
The exception is "AuthenticationException: A call to SSPI failed, see inner exception". The inner exception is "The message or signature supplied for verification has been altered".
This has been tested on multiple Windows 7 desktops, 08 & 12 servers and fails with the same exception on all.
Using OpenSSL in the command prompt, this connection can be made successfully, so the issue isnt with the certs or firewall.
StackTrace:
at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)\r\n at
MyTestApp.Program.LoginToAppliance(String[] args) in c:\\Data\\MyTestApp\\Program.cs:line 216" string
A system error is logged into the EventViewer whenever this occurs:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Schannel" Guid="{1F678132-5938-4686-9FDC-C8FF68F15C85}" />
<EventID>36887</EventID>
<Version>0</Version>
<Level>2</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="2017-01-11T15:34:48.544792500Z" />
<EventRecordID>799306</EventRecordID>
<Correlation />
<Execution ProcessID="740" ThreadID="23280" />
<Channel>System</Channel>
<Computer>MyDesktop.company.com</Computer>
<Security UserID="S-1-5-18" />
</System>
- <EventData>
<Data Name="AlertDesc">20</Data>
</EventData>
</Event>
The SChannel 20 error according to https://blogs.msdn.microsoft.com/kaushal/2012/10/05/ssltls-alert-protocol-the-alert-codes/ is:
bad_record_mac = This alert is returned if a record is received with an incorrect MAC.
This alert also MUST be returned if an alert is sent because a TLSCiphertext decrypted in an invalid way: either it wasnt an
even multiple of the block length, or its padding values, when checked, werent correct. This message is always fatal.
Code:
var client = new TcpClient(parameters.Hostname, parameters.Port);
var ssl = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), new LocalCertificateSelectionCallback(SelectLocalCertificate));
var certs = new X509Certificate2Collection();
certs.Add(new X509Certificate2(parameters.CertificateFile, parameters.CertificatePassword));
ssl.AuthenticateAsClient("CAServer", certs, System.Security.Authentication.SslProtocols.Tls11, false);
private static X509Certificate SelectLocalCertificate(object sender, string targetHost,
X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
{
if ((acceptableIssuers != null) && (acceptableIssuers.Length > 0) &&
(localCertificates != null) && (localCertificates.Count > 0))
{
foreach (X509Certificate certificate in localCertificates)
{
if (Array.IndexOf(acceptableIssuers, certificate.Issuer) != -1)
{
return certificate;
}
}
}
if ((localCertificates != null) && (localCertificates.Count > 0))
{
return localCertificates[0];
}
return null;
}
private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if ((sslPolicyErrors == SslPolicyErrors.None) || (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch))
{
return true;
}
else
{
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
return false;
}
}
When the code reaches ssl.AuthenticateAsClient()...it makes 2 successfull calls to the LocalCertificateSelectionCallback method, ValidateServerCertificate().
Then it throws the exception above.
The code never makes it to the RemoteCertificateValidationCallback method, (ValidateServerCertificate) as it does when the call is successful on Windows 10.
Any ideas on how to resolve this?
Continue reading...
On Windows 10, this works fine...but our app servers are Windows Server 2008R2.
On Windows 7 & Windows Server 2008R2 & Windows Server 2012, the call to SslStream.AuthenticateAsClient throws an exception.
The exception is "AuthenticationException: A call to SSPI failed, see inner exception". The inner exception is "The message or signature supplied for verification has been altered".
This has been tested on multiple Windows 7 desktops, 08 & 12 servers and fails with the same exception on all.
Using OpenSSL in the command prompt, this connection can be made successfully, so the issue isnt with the certs or firewall.
StackTrace:
at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at
System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)\r\n at
MyTestApp.Program.LoginToAppliance(String[] args) in c:\\Data\\MyTestApp\\Program.cs:line 216" string
A system error is logged into the EventViewer whenever this occurs:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Schannel" Guid="{1F678132-5938-4686-9FDC-C8FF68F15C85}" />
<EventID>36887</EventID>
<Version>0</Version>
<Level>2</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="2017-01-11T15:34:48.544792500Z" />
<EventRecordID>799306</EventRecordID>
<Correlation />
<Execution ProcessID="740" ThreadID="23280" />
<Channel>System</Channel>
<Computer>MyDesktop.company.com</Computer>
<Security UserID="S-1-5-18" />
</System>
- <EventData>
<Data Name="AlertDesc">20</Data>
</EventData>
</Event>
The SChannel 20 error according to https://blogs.msdn.microsoft.com/kaushal/2012/10/05/ssltls-alert-protocol-the-alert-codes/ is:
bad_record_mac = This alert is returned if a record is received with an incorrect MAC.
This alert also MUST be returned if an alert is sent because a TLSCiphertext decrypted in an invalid way: either it wasnt an
even multiple of the block length, or its padding values, when checked, werent correct. This message is always fatal.
Code:
var client = new TcpClient(parameters.Hostname, parameters.Port);
var ssl = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), new LocalCertificateSelectionCallback(SelectLocalCertificate));
var certs = new X509Certificate2Collection();
certs.Add(new X509Certificate2(parameters.CertificateFile, parameters.CertificatePassword));
ssl.AuthenticateAsClient("CAServer", certs, System.Security.Authentication.SslProtocols.Tls11, false);
private static X509Certificate SelectLocalCertificate(object sender, string targetHost,
X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
{
if ((acceptableIssuers != null) && (acceptableIssuers.Length > 0) &&
(localCertificates != null) && (localCertificates.Count > 0))
{
foreach (X509Certificate certificate in localCertificates)
{
if (Array.IndexOf(acceptableIssuers, certificate.Issuer) != -1)
{
return certificate;
}
}
}
if ((localCertificates != null) && (localCertificates.Count > 0))
{
return localCertificates[0];
}
return null;
}
private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if ((sslPolicyErrors == SslPolicyErrors.None) || (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch))
{
return true;
}
else
{
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
return false;
}
}
When the code reaches ssl.AuthenticateAsClient()...it makes 2 successfull calls to the LocalCertificateSelectionCallback method, ValidateServerCertificate().
Then it throws the exception above.
The code never makes it to the RemoteCertificateValidationCallback method, (ValidateServerCertificate) as it does when the call is successful on Windows 10.
Any ideas on how to resolve this?
Continue reading...