Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using X509Certificate with file and key in c#

I have given certificate and password to a server that accepts ssl connection. I tried to make a connection to this server but authentication fails, well mainly because I dont know how to use that file and password that I was given.

Here is my code:

    X509Certificate certificate = new X509Certificate(
        @"c:\mySrvKeystore", KEY_PASSWORD);

    public static bool ValidateCertificate(
        object sender,
        X509Certificate certificate,
        X509Chain chain,
        SslPolicyErrors errors)
    {
        if (errors == SslPolicyErrors.None)
            return true;

        Console.WriteLine("Certificate error: {0}", errors);
        return false;
    }

    public void RunClient(string address, int port)
    {
        Console.WriteLine("Starting client...");
        var client = new TcpClient(address, port);


        Console.WriteLine("Client connected.");


        var stream = new SslStream(client.GetStream(),false,
            ValidateCertificate, null);

        try
        {
            stream.AuthenticateAsClient(address);

            Console.WriteLine(stream.IsAuthenticated ? "Client authenticated." : "Client is not authenticated.");

            //TODO constantly read from server!
        }
        catch (AuthenticationException ae)
        {
            Console.WriteLine("Exception occured: {0}", ae.Message);

            if (ae.InnerException != null)
            {
                Console.WriteLine("Inner exception: {0}", ae.InnerException.Message);
            }

            Console.WriteLine("Failed to authenticate! closing the client...");

            client.Close();

            return;
        }
        catch (Exception ex)
        {
            Console.WriteLine("General exception occured {0}", ex.Message);
            client.Close();
            return;
        }
    }

So as you can see, there is no code in my code that somehow tells the server (either TcpClient or SSLStream) that I do have this file and key!

I have a javacode that connects to server with no problem, but I failed to convert it to c# yet. Any helps would be great!

    String keyPassword = "123456";
    // String keyPassword = "importkey";

    try {
        KeyManagerFactory keyManagerFactory;

        keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
        KeyStore keyStore = KeyStore.getInstance("JKS");
        InputStream keyInput = new FileInputStream("c:\\mySrvKeystore");
        keyStore.load(keyInput, keyPassword.toCharArray());
        keyInput.close();
        keyManagerFactory.init(keyStore, keyPassword.toCharArray());

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(keyManagerFactory.getKeyManagers(), trustAllCerts, new java.security.SecureRandom());
        SSLSocketFactory sslsocketfactory = sc.getSocketFactory();
        this.sslsocket = (SSLSocket) sslsocketfactory.createSocket(host, port);

    } catch (java.security.NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (java.security.KeyManagementException e) {
        e.printStackTrace();
    } catch (java.security.KeyStoreException e) {
        e.printStackTrace();
    } catch (java.security.cert.CertificateException e) {
        e.printStackTrace();
    } catch (java.security.UnrecoverableKeyException e) {
        e.printStackTrace();
    } finally {}
}

public void run() {
    try {
        InputStream inputstream = sslsocket.getInputStream();
        InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
        BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

        OutputStream outputstream = System.out;
        OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream);
        BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);

        //get text from server and stuff...no deal!

UPDATE

After converting the key to p12 according to gtrig the problem now is IOException in AutheneticateAsClient method here:

        try
        {
            var certificate = new X509Certificate2(@"d:\mySrvKeystore.p12", "123456");


            X509Certificate2[] X509Certificates = {certificate};
            var certsCollection = new X509CertificateCollection(X509Certificates);

            //IO EXCEPTION HERE-->
            stream.AuthenticateAsClient(address, certsCollection, SslProtocols.Ssl2, false);
            Console.WriteLine(stream.IsAuthenticated ? "Client authenticated." : "Client is not authenticated.");

            //TODO constantly read from server!
        }

Also when I use the SSlProtocols.Default the error is: RemoteCertificateNameMismatch, RemoteCertificateChainErrors

like image 752
Saeid Yazdani Avatar asked Nov 07 '13 15:11

Saeid Yazdani


1 Answers

This answer may not get you all the way there, but it should get you close.

You were given a Java KeyStore (JKS), containing a private key and corresponding certificate. The password to open the JKS according to your code is "123456".

Because the JKS contains a private key, and from looking at your Java code, it leads me to believe you need a 2-way (mutual) SSL connection. That basically means that you as the client authenticate the server AND the server authenticates you. This JKS file is your credential to use the server.

So how do you use this in C#? First, let's convert the JKS to a PKCS12 keystore with this command:

keytool -importkeystore -srckeystore mySrvKeystore -destkeystore mySrvKeystore.p12 -srcstoretype JKS -deststoretype PKCS12

Now, you can import the PKCS12 file into your Windows keystore, which should make it easily accessible from C#. OR, you can import it into an X509Certificate2 object with this code:

X509Certificate2 cert = X509Certificate2("C:\Path\mySrvKeystore.p12", "123456");

Now, you can use either the Windows keystore or the X509Certificate2 object in C# to establish the SSL connection.

like image 162
gtrig Avatar answered Oct 05 '22 12:10

gtrig