Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use certificate callback in SslStream.AuthenticateAsClient method?

My C#.NET SSL connect works when I import the certificate manually in IE (Tools/Internet Options/Content/Certificates), but how can I load the certificate by code? Here is my code:

TcpClient client = new TcpClient(ConfigManager.SSLSwitchIP, Convert.ToInt32(ConfigManager.SSLSwitchPort));

SslStream sslStream = new SslStream(
                client.GetStream(),
                false,
                new RemoteCertificateValidationCallback(ValidateServerCertificate),
                null
                );
sslStream.AuthenticateAsClient("Test");

The above code works fine if i import my certificate file manually in Internet Explorer. But if i remove my certificate from IE and use the following code instead, i get Authentication exception:

sslStream.AuthenticateAsClient("Test", GetX509CertificateCollection(), SslProtocols.Default, false);

and here is the 'GetX509CertificateCollection' method :

public static X509CertificateCollection GetX509CertificateCollection()
        {
            X509Certificate2 certificate1 = new X509Certificate2("c:\\ssl.txt");
            X509CertificateCollection collection1 = new X509CertificateCollection();
            collection1.Add(certificate1);
            return collection1;
        }

What should I do to load my certificate dynamically?

like image 785
losingsleeep Avatar asked Oct 30 '25 00:10

losingsleeep


2 Answers

To build upon owlstead's answer, here's how I use a single CA certificate and a custom chain in the verification callback to avoid Microsoft's store.

I have not figured out how to use this chain (chain2 below) by default such that there's no need for the callback. That is, install it on the ssl socket and the connection will "just work". And I have not figured out how install it such that its passed into the callback. That is, I have to build the chain for each invocation of the callback. I think these are architectural defects in .Net, but I might be missing something obvious.

The name of the function does not matter. Below, VerifyServerCertificate is the same callback as RemoteCertificateValidationCallback. You can also use it for the ServerCertificateValidationCallback in ServicePointManager.

static bool VerifyServerCertificate(object sender, X509Certificate certificate,
    X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    try
    {
        String CA_FILE = "ca-cert.der";
        X509Certificate2 ca = new X509Certificate2(CA_FILE);

        X509Chain chain2 = new X509Chain();
        chain2.ChainPolicy.ExtraStore.Add(ca);

        // Check all properties
        chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;

        // This setup does not have revocation information
        chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

        // Build the chain
        chain2.Build(new X509Certificate2(certificate));

        // Are there any failures from building the chain?
        if (chain2.ChainStatus.Length == 0)
            return true;

        // If there is a status, verify the status is NoError
        bool result = chain2.ChainStatus[0].Status == X509ChainStatusFlags.NoError;
        Debug.Assert(result == true);

        return result;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }

    return false;
}
like image 66
jww Avatar answered Nov 01 '25 13:11

jww


A quick Google pointed me to a piece of text from the Microsoft SslStream class.

The authentication is handled by the Security Support Provider (SSPI) channel provider. The client is given an opportunity to control validation of the server's certificate by specifying a RemoteCertificateValidationCallback delegate when creating an SslStream. The server can also control validation by supplying a RemoteCertificateValidationCallback delegate. The method referenced by the delegate includes the remote party's certificate and any errors SSPI encountered while validating the certificate. Note that if the server specifies a delegate, the delegate's method is invoked regardless of whether the server requested client authentication. If the server did not request client authentication, the server's delegate method receives a null certificate and an empty array of certificate errors.

So simply implement the delegate and do the verification yourself.

like image 21
Maarten Bodewes Avatar answered Nov 01 '25 12:11

Maarten Bodewes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!