我正在开发一个需要管理不同SSL服务的服务器应用程序。 每项服务都有自己的证书(当然,有不同的CN)。 我想使用SNI来提供正确的证书,但在认证流之前,我正在努力阅读ClientHello(SNI扩展所在的位置)。
这就是代码:
byte[] ClientHello = new byte[3000];
Stream TargetStream = TargetTcpClient.GetStream();
//Whatever I write here let me be unable to successfully authenticate
//If I don't read anything (like in this way), it works perfectly
int ClientHelloN = 0; //TargetStream.ReadByte();// TargetStream.Read(ClientHello, 0, 3000);
/*SNI Logic to extract Server-name*/
Certificate = new X509Certificate2(/*PATH TO CORRECT CERTIFICATE*/);
SslStream SSLStream = new SslStream(TargetStream);
SSLStream.AuthenticateAsServer(Certificate);
如果我使用带前缀的证书直接进行身份验证,则没有问题,但是当我尝试在身份验证之前从流中读取一个字节时,它会在AuthenticateAsServer方法中永久循环。
答案 0 :(得分:2)
我知道我参加派对有点晚了,但为什么不偷看TcpClient的底层Socket?
byte[] peekBuffer = new byte[16];
Socket socket = targetTcpClient.Client;
int bytesAvailable = socket.Receive(peekBuffer, SocketFlags.Peek);
if (bytesAvailable > 0)
{
if (peekBuffer[0] == 0x16) // ClientHello?
{
SslStream secureStream = new SslStream(targetTcpClient.GetStream());
}
}
答案 1 :(得分:1)
一旦您从TargetStream
读取数据,它就会消失,您的SslStream
将会错过握手的开始。
我相信您需要做的是将Stream
的{{1}}与您自己的TargetTcpClient.GetStream()
子类包装起来。在您的子类中,您可以从流中读取字节以解析客户端Hello,但是您应该将所有这些字节保存在缓冲区中。你的子类应该覆盖Stream.Read() - 当调用你的覆盖时,如果缓冲区中有任何东西然后返回它,否则将调用转发给包装流。该方法类似于this answer,但子类Stream
除外,只缓冲单个字符。