1

I have one server and three clients in which a windows service is running with local system privileges. Clients and server are mutual authenticated using SSL over TCP and certificates (I'm using the SSLStream class C++\CLI http://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.90).aspx#Y1124)

The problem is that i need three certificates (one for every client) because i'm authenticating the hosts. Now i want to authenticate the windows service and not the host so i can distribute the same certificate for every host.

Anyone know how can do it ?

--- EDIT 1 ---- To give you an example of what i want to do. In every Microsoft Office copy is deployed a certificate that is used to communicate with microsoft servers throught an encrypted/authenticated channel.

-- SOLVED --

As Jon said my problem was that the SslStream class perform standard validation which is included the hostname. I provided a custom RemoteCertificateValidationCallback and now it works.

bool ValidateServerCertificate( Object^ sender, X509Certificate^ certificate, X509Chain^ chain, SslPolicyErrors sslPolicyErrors ) {            

  Console::Write("[+] Validating server certificate: ");                                 

  // check certificate hash                                                               
  if( certificate->GetCertHashString()->Equals("cert hash") ) {                                                                                                          
      Console::Write( "oK\n" );                                                      
      return true;                                                                   
  }                                                                                      

   Console::Write(" ERROR\n");                  
   Console::WriteLine("[-] Hash doesn't match");                                 

   // Do not allow this client to communicate with unauthenticated servers.                           
   return false;                                                                                                                                                                                                  
} 
DropTheCode
  • 465
  • 1
  • 7
  • 14

1 Answers1

0

You simply need to load the certificate e.g. from a file and use that specific certificate to authenticate. If you want to do this on the server side of the connection:

var certificate = new X509Certificate2("cert.pfx");
sslStream.AuthenticateAsServer(certificate);

And on the client side:

X509Certificate certificate = new X509Certificate2("cert.pfx");
var certCollection = new X509CertificateCollection(new[] { certificate });
sslStream.AuthenticateAsClient(targetHost, certCollection, protocols, checkRevocation);

If the certificates are in password protected files there's a second parameter to the X509Certificate2 constructor that accepts the password. And of course you probably want to use different certificates for the clients and the server.

Update:

So it seems that your problem is that your certificates are not accepted because you are letting .NET perform standard validation (which includes validating the host). You simply need to provide a RemoteCertificateValidationCallback to your SslStream constructor. You can then make all checks you want (or not) inside that. For example, here's a validator that will blindly accept any certificate:

private bool DefaultCertificateValidationHandler(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
{
    return true;
}
Jon
  • 428,835
  • 81
  • 738
  • 806
  • But for what i know the SUBJECT field of a x509 certificate must be the name of the host/website. I have to authenticate the windows service not the host. – DropTheCode Jan 17 '12 at 15:33
  • @drop: See the update, but please do provide *all* relevant information up front (e.g. what the whole picture is, what you have done, and exactly what is giving you issues). – Jon Jan 17 '12 at 15:40
  • Thank you for your help, but maybe you don't understand my problem. I have 1 server and 3 clients, on each client is runnnig a windows service. The goal of this windows service is to connect to the server and exchange some messages. This communication need to be encrypted and authenticated (both sides)to do this i used the SSLStream class and .pfx certificate (x509). It works fine but on every client i need a **different** certificate. I want to use only 1 certificate for all clients, to do this i think that i have to authenticate the windows service and NOT the host. – DropTheCode Jan 17 '12 at 15:58
  • @drop: Use the code above to take control of the certificate validation process. I think I got that part. – Jon Jan 17 '12 at 15:59
  • Yes but that certificate authenticate only one client because when i create the certificate with the command `makecert -r -pe -n "**CN=HOST NAME**" -sky exchange ....` the CN field is unique for that host. I cannot install that certificate on another host. – DropTheCode Jan 17 '12 at 16:09
  • @drop: I have successfully used this technique to write a portable client/server app with SSL, so I know it works. I can only guess at what problems you are facing. But *you do not need to install the certificate*. – Jon Jan 17 '12 at 16:14
  • When you created the certificate what name to do you set in the CN field ? – DropTheCode Jan 17 '12 at 16:20
  • `CN=server.whatever.com` -- it makes no difference at all because you are not going to validate the certificate based on that. – Jon Jan 17 '12 at 16:28
  • Are you sure ? Because the wikipedia page on x509 it's written: Its subject contains many personal details, but the most important part is usually the common name (CN), as this is the part that must match the host being authenticated. Thus, i cannot set CN with a random name. – DropTheCode Jan 18 '12 at 08:31
  • In fact if i set a random name (CN=abc) i obtain this error: RemoteCertificateNameMismatch. – DropTheCode Jan 18 '12 at 10:28