Search code examples
c#sslproxycertificatesslstream

understanding server/proxy/client certificates with .NET sslstream


I'm creating a TCP proxy with C# using TcpListener for the proxy server and TcpCLient for the communication between client and proxy and between proxy and target server. This works really nice.

I also have to support SSL and TLS encrypted communication. This works almost well. I create a SslStream from the proxy to the target server with this Code:

var sslStream = new SslStream(remoteStream, false);
sslStream.AuthenticateAsClient(state.RemoteHost);

And I create a SslStream from the proxy to the Client with the following code:

var sslStream = new SslStream(state.ClientStream, false);
sslStream.AuthenticateAsServer(certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, true);

The certificate is loaded from the X509Store:

X509Certificate2 certificate;
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, "CN=localhost", false);
store.Close();

if (certificates.Count == 0)
{
    Console.WriteLine("Server certificate not found...");
    return;
}
else
{
    certificate = certificates[0];
}

This also works well if i force the clients to trust the certificate manually.

My questions are:

  1. How can I force the (all) clients to trust the certificate?
  2. Which kind of certificate which is valid for all clients do I need on the proxy?
  3. If needed, what kind of client certificate do I have to install to force the clients to trust the proxy?
  4. How can I create the needed kinds of proxy with openssl or makecert?

I don't want to tunnel the SSL communication threw the proxy because I need to read and manipulate the streams.

[UPDATE] Yes I used Google and the search in StackOverflow and I tried some different solution without any success. I also tried the solutions in the following threads:

SSLStream example - how do I get certificates that work?

How do I identify my server name for server authentication by client in c#

[UPDATE2] This is a very good tutorial to create a CA and a server certificate with openssl, but it doesn't work for me: http://webserver.codeplex.com/wikipage?title=HTTPS&referringTitle=Home


Solution

  • There is no single certificate which is valid for all requests. So my idea doesn't work. Because it is not possible to generate a single license for every domain name.

    But the Answer is easier than expected: To solve my problem I have to create a certificate for every single request.

    All I need to do is:

    • to create a self-signed root certificate as a certificate authority
      • to install this in the clients "Trusted Root Certification Authorities" store.
    • to create the server certificates on-the-fly for every incoming request
      • sign this certificates with the root certificates tree to set the issuer
      • I can cache the certificates in files or in a system certificate store if needed.

    (this is completely the same in fiddler)