【问题标题】:Read ClientHello before AuthenticateAsServer在 AuthenticateAsServer 之前读取 ClientHello
【发布时间】:2013-07-02 13:39:51
【问题描述】:

我正在开发一个需要管理不同 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 方法中永远循环。

【问题讨论】:

    标签: c# ssl sni


    【解决方案1】:

    我知道我参加聚会有点晚了,但为什么不看看 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());
    
        }
    }
    

    【讨论】:

    • 不错!我没有想过只是偷看第一个字节来检查它。即使可能不是完全可靠,它也可以工作!我试试看!
    【解决方案2】:

    一旦您从TargetStream 读取数据,它就消失了,您的SslStream 将丢失握手的开始。

    我相信您需要做的是将您从TargetTcpClient.GetStream() 获得的Stream 包装为您自己的Stream 子类。在您的子类中,您可以从流中读取字节以解析客户端 Hello,但您应该将所有这些字节保存在缓冲区中。你的子类应该覆盖Stream.Read() - 当你的覆盖被调用时如果缓冲区中有任何东西然后返回它,否则将调用转发到包装的流。该方法类似于this answer,除了子类StreamReader 并且只缓冲单个字符。

    【讨论】:

    • 好主意!你认为 AuthenticateAsServer 方法会调用 Read 方法来读取 ClientHello 吗?我会尽快尝试
    • @Jamby 从文档中确实可以看出,从流中读取的任何方法最终都会调用 Read() 函数,因此应该使用您的覆盖。请注意,Stream.Read() 与链接答案中的StreamReader.Read() 采用不同的参数,而且您需要缓冲一个以上的字节,但基本概念是相同的。祝你好运!
    • 很遗憾,根据 Reflector 所说,SSLStream 没有使用Read 方法。我已经证明,通过简单地覆盖Read 方法以及ReadByteBeginRead 方法,放置一个断点并且当我调用AuthenticateAsServer 时它永远不会到达断点
    • @Jamby 这不是我在继承 Stream 时看到的行为。试试this wrapper proof of concept。该子类只是传递所有内容并在读写时写入控制台;窥视字节仍然取决于您。
    猜你喜欢
    • 2016-12-05
    • 2014-01-16
    • 1970-01-01
    • 2020-10-25
    • 2021-03-20
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多