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