views:

269

answers:

1

I'm currently creating a C# program which will be fetching some data over https from my server. The server in question is using a CAcert certificate (http://www.cacert.org/), and I need a way of validating the servers certificate (checking the Subject and that it is signed by the cacert root certificate).

I'd like to do this without having to import the CAcert root as a trusted CA into the windows certificate store, some people might not like that, and AFAIK that requires admin.

I'm currently using a TcpClient and SslStream and not the WebRequest/WebResponse classes because I might move from using HTTP to using my own protocol some day, but if the task is easier using the *request classes I'll consider using them.

+1  A: 

First you want to use the overloaded SslStream constructor:

SslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback);

Then the RemoteCertificateValidationCallback method looks something like this:

public bool IsValid(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
     ... you logic here ...
}

You just need to simply walk the chain and look at the certificates until you find one you are willing to accept by verifying the public key:

  foreach(X509ChainElement e in chain.ChainElements)
   if( e.Certificate.Subject == "CN=XXX.xx" && e.Certificate.GetPublicKeyString() == "expected public key" )
    return true;
csharptest.net
Your solution only works if the root cert exists in the certificate store. Fortunately I found an easy way of adding the cert to the store, checking if the amount of certs in it changed and if so, removing the cert after the connection is done. Thanks for showing me how to walk the chain though :)
Aleksi
There should be no requirement on the certificate being in the root store. I use this in an SSL tunnel and neither end have ever seen the foreign certificate. When you return true from RemoteCertificateValidationCallback your bypassing the certificate store checks and saying allow it anyway.
csharptest.net
If the root cert is not in the store the chain only contains 1 element, the certificate of the host I am connecting to. If I add the root cert into the store however, the chain contains two elements, the server certificate and the root certificate. Sorry for the previous comment being unclear.
Aleksi
Oh right you are... sorry about that. I pretty much stick to self-signed for this type of stuff. No need to involve a third party when your not going to trust them anyway :)
csharptest.net
LOL : Content (not so) soon.
csharptest.net