I have a working implementation of this, but I want to make sure that it is safe. The goal is to use SSLStream and only accept SSL certificates from the server that are signed with a specific RSA key.
Here is my connection code:
var client = new TcpClient("server_address", port_number); var sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); sslStream.AuthenticateAsClient("SpeechGrid");
And here is my implementation of ValidateServerCertificate:
private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { // Only accept our specific key pair foreach (var cert in chain.ChainElements) { if (cert.Certificate.GetPublicKeyString() == k_prodPublicKey) { return true; } } return false; }
Due to the richness of the X509Chain object, I want to make sure that I do not need to check things like X509ChainStatusFlags.NotSignatureValid, etc.
For example, can an attacker “require” to be signed with my public key, send an invalid signature, and this attack will work because .NET assumes that I check all these flags?
Thanks!!
UPDATE: Well, so far I have decided to put the following checks above the original foreach. Please note that this is a somewhat specific application; for example, if I need certificates for expiration, I would check NotTimeValid, etc.
foreach (var status in chain.ChainStatus) { switch (status.Status) { case X509ChainStatusFlags.Cyclic: case X509ChainStatusFlags.NotSignatureValid: case X509ChainStatusFlags.PartialChain: return false; } }