Considering the SslStream.AuthenticateAsServer method, the second parameter clientCertificateRequired:
If it is set to true, a client certificate is required. It will throw an exception if not. The client certificate will be available in the property RemoteCertificate.
When set to false, no client certificate is required, the property RemoteCertificate shall always be null. Even if one is provided by the client.
What I like to accomplish is to let the client decide whether it will or will not provide a certificate. But, if they do provide one, I like to know it on the server.
I have tried to first set the variable to true, if this fails, fallback to not require the certificat. However, this result in an "Already Authenticated Exception".
try{
sslStream.AuthenticateAsServer(x509certificate, true, SslProtocols.Tls, true);
}catch(Exception ex){
sslStream.AuthenticateAsServer(x509certificate, false, SslProtocols.Tls, true);
}
I strongly believe this is a documentation flaw.
Actually the parameter
clientCertificateRequired
will control whether client certificates are not ignored. This means:clientCertificateRequired = false
will ignore any client certificate on the server side. No certificate is checked for existence nor validity.clientCertificateRequired = true
will respect any sent client certificate on the server side. If a client certificate is missing the validation callback is called withSslPolicyErrors.RemoteCertificateNotAvailable
which results in the exception you catch, when using the default implementation.So in your case: Set
clientCertificateRequired
totrue
and implement a custom validation callback, like this: