我正在编写一个需要通过SSL / TLS进行通信的应用程序。
当我使用以下代码时,设备连接,但我总是读取0字节:
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);
sslStream.Flush();
// 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);
当我使用此代码时,我能够读取字节但显然不能解码它们。这段代码读取正确的字节数,SSl出了什么问题,我不会得到任何字节?
var client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
var stream = client.GetStream();
// Loop to receive all the data sent by the client.
while (stream.Read(bytes, 0, bytes.Length) != 0)
{
var base64 = Convert.ToBase64String(bytes);
Console.WriteLine(base64);
更大的样本,我认为这是来自MSDN:
static void ProcessClient(TcpClient client)
{
// A client has connected. Create the
// SslStream using the client's network stream.
SslStream sslStream = new SslStream(client.GetStream(), false);
// Authenticate the server but don't require the client to authenticate.
try
{
sslStream.AuthenticateAsServer(serverCertificate,
false, SslProtocols.Tls, true);
// Display the properties and settings for the authenticated stream.
DisplaySecurityLevel(sslStream);
DisplaySecurityServices(sslStream);
DisplayCertificateInformation(sslStream);
DisplayStreamProperties(sslStream);
// 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();
return;
}
finally
{
// The client stream will be closed with the sslStream
// because we specified this behavior when creating
// the sslStream.
sslStream.Close();
client.Close();
}
}
static 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);
sslStream.Flush();
// 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();
}
答案 0 :(得分:0)
我最终确实解决了这个问题,并希望为每个人发布答案。证书是自签名的,因此“无效”,但这在设备上很常见。我必须创建一个始终返回 true 的验证回调。
我忘记在哪里找到这段代码了,但我认为是 MSDN
// The following method is invoked by the RemoteCertificateValidationDelegate.
private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
//DisplayCertificateInformation((SslStream)sender);
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Debug.WriteLine("Certificate error: {0}", sslPolicyErrors);
// Allow this client to communicate with unauthenticated servers.
return true;
}
我最终扩展了 TcpClient 类:
public class TlsTcpClient : TcpClient
{
public TlsTcpClient()
{
}
public TlsTcpClient(string ip, int port) : base(ip, port)
{
}
public new SslStream GetStream()
{
var sslStream = new SslStream(base.GetStream(),
true,
ValidateServerCertificate,
null);
try
{
sslStream.AuthenticateAsClient("Certname goes here");
}
catch (AuthenticationException e)
{
Debug.WriteLine($"Exception: {e.Message}");
if (e.InnerException != null)
{
Debug.WriteLine($"Inner exception: {e.InnerException.Message}");
}
Debug.WriteLine("Authentication failed - closing the connection.");
return null;
}
return sslStream;
}
}
答案 1 :(得分:-1)
下面找到一个通过sslstream original source here进行通信的客户端服务器示例。
服务器
static void Main(string[] args)
{
var _certificate = "certificate-string";
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 13000);
server.Start();
TcpClient client = server.AcceptTcpClient();
SslStream stream = new SslStream(client.GetStream(), false, VerifyClientCertificate, null);
X509Certificate2 certificate = new X509Certificate2(Convert.FromBase64String(_certificate));
stream.AuthenticateAsServer(certificate, false,
SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13, false);
if (stream.RemoteCertificate != null)
{
System.Console.WriteLine(stream.RemoteCertificate.Subject);
}
else
{
System.Console.WriteLine("No client certificate.");
}
StreamReader reader = new StreamReader(stream);
StreamWriter writer = new StreamWriter(stream);
bool clientClose = false;
while (!System.Console.KeyAvailable)
{
System.Console.WriteLine("Waiting for data...");
string line = reader.ReadLine();
System.Console.WriteLine("Received: {0}", line);
if (line == "close")
{
clientClose = true;
break;
}
writer.WriteLine(line);
writer.Flush();
}
if (!clientClose) System.Console.ReadKey();
stream.Close();
server.Stop();
}
private static bool VerifyClientCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
客户
static void Main(string[] args)
{
var _certificate = "certificate-string";
TcpClient client = new TcpClient("127.0.0.1", 13000);
SslStream stream = new SslStream(client.GetStream(), false, VerifyServerCertificate, null);
X509Certificate2 certificate = new X509Certificate2(Convert.FromBase64String(_certificate));
stream.AuthenticateAsClient("127.0.0.1", new X509Certificate2Collection(certificate),
SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13, false);
StreamReader reader = new StreamReader(stream);
StreamWriter writer = new StreamWriter(stream);
while (true)
{
string line = System.Console.ReadLine();
writer.WriteLine(line);
writer.Flush();
if (line == "close") break;
line = reader.ReadLine();
System.Console.WriteLine("Received: {0}", line);
}
stream.Close();
client.Close();
}
private static bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}