.NET SslStream AuthenticateAsServer 是否可以尊重客户端发送的服务器名称指示器

本文关键字:服务器 指示器 客户端 AuthenticateAsServer SslStream 是否 NET | 更新日期: 2023-09-27 18:30:56

客户:访问
1. https://host1.com/
2. https://host2.com/

服务器:有两个证书。
证书 1.pfx CN=主机 1.com 和 证书 2.pfx CN=主机 2.com

使用线鲨
客户访问 https://host1.com/
1: C --> S SYN
2: C <-- S 合成,ACK
3: C --> S ACK
4:C --> S 客户端问候(包含服务器名称:host1.com)
...如何在 C#
中选择证书 15: C <-- S 服务器 你好, 证书, 服务器 你好 完成

客户访问 https://host2.com/
1: C --> S SYN
2: C <-- S 合成,ACK
3: C --> S ACK
4:C --> S 客户端问候(包含服务器名称:host2.com)
...如何在 C#
中选择证书 25: c <-- S 服务器 你好, 证书, 服务器 你好 完成

SslStream sslStream = new SslStream(
  clientStream,
  false,
  new RemoteCertificateValidationCallback(ValidateServerCertificate),
  new LocalCertificateSelectionCallback(SelectLocalCertificate)
);
X509Certificate2 certificate = new X509Certificate2("certificates1.pfx");
sslStream.AuthenticateAsServer(certificate , false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, true);
private X509Certificate SelectLocalCertificate(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
{
  //In Debug, targetHost is empty string and remoteCertificate=null
  //I can't return right Certificates
  return null;
}
private bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    return true;
}

.NET SslStream AuthenticateAsServer 是否可以尊重客户端发送的服务器名称指示器

虽然 SslStream 本身不支持 SNI,但我已经确认可以解决。 在服务器上,如果在启动 SslStream 之前从 NetworkStream 读取一些字节,您可以看到从客户端发送到服务器的初始数据包实际上是客户端 hello,其中包括请求的服务器名称。

有一个问题,因为网络流不支持偷看字节... 因此,您必须使用包装流类。 (这里有一个实现:https://stackoverflow.com/a/7281113/1726692)。

还有另一个问题 - 一旦你得到了字节,你必须弄清楚如何处理它们。 我敢肯定这是特定于实现的,并且受数十个标准的约束...... 我目前没有实现来解析这些初始字节,但是当我将 Win7 SSlStream 客户端连接到 Win8 SslStream 服务器,并且我捕获从客户端到服务器的第一个数据包时,我可以非常清楚地看到发送到服务器的请求服务器名称在这些字节中,可通过上面的 PeekableStream 提供给服务器, 在服务器上启动 SslStream 之前。

所以这绝对是可能的。 问题是在哪里可以找到可靠的实现。

使用具有

SslStream 充当服务器的 LocalCertificateSelectionCallback 委托无法选择证书。在这种情况下,只能指定一个证书作为 AuthenticateAsServer 方法的第一个参数。

MSDN 上的 SslStream 类的文档还提到了客户端上 LocalCertificateSelectionCallback 委托的使用:

如果服务器需要客户端身份验证,则客户端必须指定 一个或多个用于身份验证的证书。如果客户端有更多 超过一个证书,客户端可以提供 本地证书选择回调委托以选择正确的 服务器的证书。

最后,您可以检查这个问题,该问题似乎与您的问题有关 SslStream 在充当服务器时是否使用 LocalCertificateSelectionCallback?

我不确定为什么targetHost是空白的。

您还可以尝试检查remoteCertificate.Subject以标识服务器。ValidateServerCertificate方法应确保此方法与主机匹配。