Search code examples
.netservicec++-clicertificatesslstream

SSL over TCP Authenticate Windows Service with certificate


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;                                                                                                                                                                                                  
} 

Solution

  • 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;
    }