I was reading MSDN info articles for quite a long time and still I fail to understand it.
Based on the assumption that client Authentication is not required:
1.When I call SslStream.AuthenticateAsServer(...)
do I call this method on the server side or on the client side?
2.When establishing a SslStream is it only the responsibility of the server to establish the SslStream
or both server and client?
3.If it is only the responsibility of the server, does it mean that the client can just use regular send()
and receive()
operations without creating a SslStream by himself?
4.Does the client need to get the certificate file in order to authenticate the server?
Thank you very much in advance, I really could not find much information about this topic and I've been searching for this information for a long time...
EDIT: the MSDN has a complete working example at the bottom of this page: https://msdn.microsoft.com/en-us/library/system.net.security.sslstream?f=255&MSPPError=-2147217396 - so you should really start experimenting there because that example has it all.
Original answer:
I must preface this answer that "client authentication not required" is the case for most of the SSL implementations. Client authentication is rare: you're likely to see it in VPN apps, the banking industry and other secure apps. So it would be wise when you are experimenting with SslStream() to start without client authentication.
When you browse to an HTTPS website, you don't authenticate your browser with a client cert, instead you just want to confirm the server name you are connecting to matches up to the CNAME found in the cert and that the server cert is signed by a CA that your machine trusts - there's more to it, but essentially that's what it boils down to.
So, having said that, let me answer your questions:
1) SslStream.AuthenticateAsServer(...)
is done ONLY on server side with the server 509 certificate. On the client side, you must call SslStream.AuthenticateAsClient(serverName)
with server name being the CNAME (common name) of your certificate (example: "domain.com")
2) SslStream
must be created for both the client and the server. You create it simply by "wrapping" a TcpClient
NetworkStream
around it (for example, but there are other methods)
Example for the server:
// assuming an 509 certificate has been loaded before in an init method of some sort
X509Certificate serverCertificate = X509Certificate2.CreateFromCertFile("c:\\mycert.cer"); // for illustration only, don't do it like this in production
...
// assuming a TcpClient tcpClient was accepted somewhere above this code
slStream sslStream = new SslStream(tcpClient.GetStream(), false);
sslStream.AuthenticateAsServer(
serverCertificate,
false,
SslProtocols.Tls,
true);
3) No. The communication is encrypted on both ends. So both sides must use SslStream
. Using receive()
and send()
on the client would yield binary encrypted data.
4) No. The client passes a callback method to the SslStream
creation in order to validate the certificate received by the server.
Example:
// assuming a TcpClient tcpClient was connected to the server somewhere above this code
SslStream sslStream = new SslStream(
tcpClient.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
null
);
sslStream.AuthenticateAsClient(serverName); // serverName: "domain.com" for example
then somewhere else in your code:
public static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None) {
return true;
}
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
// refuse connection
return false;
}