Search code examples
c#sslhttps

Can .NET SslStream AuthenticateAsServer respect client-sent Server Name Indicator?


Client: Visit
1. https://host1.com/
2. https://host2.com/

Server: There are two certificates.
certificates1.pfx CN=host1.com and certificates2.pfx CN=host2.com

use wireshark
Client visit https://host1.com/
1: C --> S SYN
2: C <-- S SYN,ACK
3: C --> S ACK
4: C --> S Client Hello (Contain Server Name: host1.com)
... How do I select certificate1 in C#
5: C <-- S Server Hello, Certificate, Server Hello Done

Client visit https://host2.com/
1: C --> S SYN
2: C <-- S SYN,ACK
3: C --> S ACK
4: C --> S Client Hello (Contain Server Name: host2.com)
... How do I select certificate2 in C#
5: c <-- S Server Hello, Certificate, Server Hello Done

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;
}

Solution

  • It is not possible to select a certificate using a LocalCertificateSelectionCallback delegate with SslStream acting as a server. You can specify only one certificate in this case, as the first parameter for the AuthenticateAsServer method.

    The documentation for SslStream Class on MSDN also mentions the usage of the LocalCertificateSelectionCallback delegate on the client:

    If the server requires client authentication, the client must specify one or more certificates for authentication. If the client has more than one certificate, the client can provide a LocalCertificateSelectionCallback delegate to select the correct certificate for the server.

    And finally you can check this question that seems to be related with your issue Does SslStream use LocalCertificateSelectionCallback when acting as a server?