简体   繁体   中英

SSL Connection with self-signed certificate error (C# Socket connect to Java Server Socket)

At first... This program is only just-4-fun and wont be published ever. It's only for testing Sockets, so don't care about the security of this connection. I coded a little messenger where you can type in a message in a textbox and it will be send to the server and from the server to all clients. So far, so good. Just for fun I wanted to use SSL for this connection. But when I'm trying to connect to the server socket it returns RemoteCertificateNameMismatch at ValidateServerCertificate. After I added some debug-messages I discovered that Sslstream.LocalCertificate is null. How can I fix this missing certificate? I am using a self-signed certificate.

Please help, here's my code... and yes... sorry for my bad english :/ :

C# Client

[...]

             public bool ValidateServerCertificate(
             object sender,
             X509Certificate certificate,
             X509Chain chain,
             SslPolicyErrors sslPolicyErrors)
             {                 
              //sslPolicyErrors returns RemoteCertificateNameMismatch
              return true; //Code shortened
             }

        public X509CertificateCollection getCertificates()
        {

            X509CertificateCollection cCollection = new X509CertificateCollection();
            cCollection.Add(getCertificate());

            return cCollection;
        }

        private X509Certificate getCertificate()
        {
            string Certificate = "D:/Wlad/Programmierung/Zertifikat/CA/CertificateAuthority.crt";
            string ClientCertificatePassword = "...";

            return new X509Certificate(Certificate, ClientCertificatePassword);
        }

        public X509Certificate SelectLocalCertificate(
            object sender,
            string targetHost,
            X509CertificateCollection localCertificates,
            X509Certificate remoteCertificate,
            string[] acceptableIssuers)
        {

            foreach(X509Certificate cer in localCertificates) {
                return cer;
            }

            return getCertificate();
        }

        public void connect(String username)
        {
                XMLConfigManager xml = XMLConfigManager.getInstance();
                String ip = xml.get("ip");


                tc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ;
                tc.Connect(ip, int.Parse(xml.get("port")));

                networdstream = new NetworkStream(tc);

                using(sslstream = new SslStream(networdstream, false, new RemoteCertificateValidationCallback(ValidateServerCertificate),  new LocalCertificateSelectionCallback(SelectLocalCertificate)))
                {

                        sslstream.AuthenticateAsClient(ip, getCertificates(), SslProtocols.Default, true);

                }



                sendMessage(username);

                t = new Thread(new ThreadStart(checkInput));
                t.Start();
                tm.addThread(t);

                th = new Thread(new ThreadStart(userTimer));
                th.Start();
                tm.addThread(th);

        }

        public void disconnect()
        {
            if(sslstream != null) {
                sslstream.Close();
            }

            if(tc != null) {
                tc.Close();
            }


        }

        [...]

        static byte[] GetBytes(string str)
        {
            byte[] bytes = new byte[str.Length * sizeof(char)];
            System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
            return bytes;
        }

        public void sendMessage(String s)
        {
            try
            {
                if ((s != null) && (s.Length > 0))
                {
                    try
                    {
                        sslstream.Write(GetBytes(s));
                    }
                    catch (Exception)
                    {

                    }

                }
            }
            catch (Exception ex)
            {
                endError(ex);
                return;
            }

        }

        public void userTimer()
        {
            Thread.Sleep(2000);


            sendCommand("usercount");

            th = new Thread(new ThreadStart(userTimer));
            th.Start();
            tm.addThread(th);
        }

        [...]

        static String ReadMessage(SslStream sslStream)
        {
            byte[] buffer = new byte[2048];
            StringBuilder messageData = new StringBuilder();
            int bytes = -1;
            do
            {
                bytes = sslStream.Read(buffer, 0, buffer.Length);

                // Use Decoder class to convert from bytes to UTF8
                // in case a character spans two buffers.
                Decoder decoder = Encoding.UTF8.GetDecoder();
                char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                decoder.GetChars(buffer, 0, bytes, chars, 0);
                messageData.Append(chars);
            } while (bytes != 0);

            return messageData.ToString();
        }

        public void checkInput()
        {
            try 
            {
                Form2 f2 = f1.f;

                if(!isConnected()) {
                    t.Abort();
                    return;
                }

                String s = ReadMessage(sslstream);

                if(s == null) {
                    t.Abort();
                    return;
                }



                CommandHandler ch = new CommandHandler();
                Boolean handle = ch.handle(s, f1.f);

                if (!handle) {

                    if (s == "Der Benutzername ist schon vergeben.")
                    {
                        endDuplicatename();
                        return;
                    }
                    f2.Invoke(new Action(() => f2.chat.Items.Add(s)));
                    f2.Invoke(new Action(() => f2.select_newest()));

                }




            } 
            finally 
            {
                t = new Thread(new ThreadStart(checkInput));
                t.Start();
                tm.addThread(t);
            }
        }

Java Server Socket

package de.wladhd.server;

import java.net.Socket;

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;

import de.wladhd.client.Client;
import de.wladhd.client.ClientManager;
import de.wladhd.logs.Log;
import de.wladhd.logs.LogType;

public class DateServer {

    private SSLServerSocket server;
    private boolean running = true;

    private String keyStore = "D:/Wlad/Programmierung/Zertifikat/CA/CertificateAuthority.pfx";
    private String keyStorePassword = "...";
    private String keyStoreType = "PKCS12";


    private String trustStore = "D:/Wlad/Programmierung/Zertifikat/CA/CertificateAuthority.pfx";
    private String trustStorePassword = "...";
    private String trustStoreType = "PKCS12";

    public void execute() throws Exception {
        //System.setProperty("javax.net.debug","all");

        System.setProperty("javax.net.ssl.keyStoreType", keyStoreType);
        System.setProperty("javax.net.ssl.keyStore", keyStore);
        System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);

        System.setProperty("javax.net.ssl.trustStoreType", trustStoreType);
        System.setProperty("javax.net.ssl.trustStore", trustStore);
        System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
        //System.setProperty("javax.net.ssl.trustStore", "de.wladhd.server.Trusting");

        SSLServerSocketFactory serverFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();

        if(serverFactory == null) {
            new Log("Error occured... Server Factory == null!", LogType.ERROR);
            return;
        }

        server = (SSLServerSocket) serverFactory.createServerSocket(9090);




        running = true;

        new Log("Server now running on query: " + server.getInetAddress().getHostAddress() + ":" + server.getLocalPort(), LogType.INFO);

        while (running) {
            try {
                if(server.isClosed()) {
                    return;
                }

                new Log("Client connecting...", LogType.DEBUG);

                final Socket rawsocket = server.accept();

                if(!(rawsocket instanceof SSLSocket)) {
                    new Log("Client isnt an instance of SSLSocket!", LogType.DEBUG);
                    return; 
                }

                final SSLSocket socket = (SSLSocket) rawsocket;

                try {
                    socket.startHandshake();
                } catch (Exception ex) {

                }


                new Log("Client - Connected: " + socket.isConnected(), LogType.DEBUG);

                new Log("Client - Protocol: " + socket.getSession().getProtocol(), LogType.DEBUG);

                new Log("Client - Session valid: " + socket.getSession().isValid(), LogType.DEBUG);

                new Log("Client - CipherSuite: " + socket.getSession().getCipherSuite(), LogType.DEBUG);

                new Log("Client - NeedClientAuth: " + socket.getNeedClientAuth(), LogType.DEBUG);

                new Log("Client - WantClientAuth: " + socket.getWantClientAuth(), LogType.DEBUG);

                Client c = new Client(socket);

                //socket.getHandshakeSession() returns null and peer not authenticated exception...

            } catch (Exception ex) {
                ex.printStackTrace();
                continue;
            }
        } 

    }

    public void disconnect() throws Exception {
        new Log("Server disconnecting...", LogType.INFO);
        setRunning(false);

        ClientManager.getInstance().disconnectClients();

        if(server != null) {
            server.close();
        }

        new Log("Server successfully disconnected!", LogType.INFO);

    }

    public boolean isRunning() {
        return running;
    }

    public void setRunning(boolean state) {
        running = state;
    }


}

If you need something please tell me...

The RemoteCertificateNameMismatch policy error is not related to a missing local certificate. This error just tells you that the SAN (Subject Alternative Name) in the received server certificate, or, if there is no SAN, then the Common Name of the received server certificate's Subject name, does NOT match the hostname that you connect to. You can ignore this error if you do not expect to see the hostname in the certificate in one of these two places.

I would guess that you have no local certificate, because you are loading the certificate from a file, and there is no corresponding private key for this certificate in the Windows private key store.

Try importing a certificate and private key (for example, from a PFX file that has both the certificate and the private key) using MMC to the local computer Personal certificate store, and then load that certificate here using the .NET certificate store APIs. As long as you have access to the private key (which you will if you are the Windows user that imported the PFX), then you should be able to connect with this client certificate.

In your code, instead of reading the certificate from a file, load it from the certificate store, with something like this:

var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);

store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

try
{
  X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
  return TakeFirstCertificate(collection);
}
finally
{
  store.Close();
}

You can look for it using something other that thumbprint -- this is just an example. This is what you have SelectLocalCertificate return.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM