SSL-соединение с ошибкой самозаверяющего сертификата (C # Socket подключается к Java Server Socket)

Во-первых ... Эта программа всего лишь-4-забавная и никогда не будет опубликована. Это только для тестирования сокетов, поэтому не беспокойтесь о безопасности этого соединения. Я написал небольшой мессенджер, в котором вы можете ввести сообщение в текстовое поле, и оно будет отправлено на сервер и с сервера всем клиентам. Все идет нормально. Ради интереса я хотел использовать SSL для этого соединения. Но когда я пытаюсь подключиться к сокету сервера, он возвращает RemoteCertificateNameMismatch в ValidateServerCertificate. После того, как я добавил несколько отладочных сообщений, я обнаружил, что Sslstream.LocalCertificate имеет значение null. Как я могу исправить этот недостающий сертификат? Я использую самоподписанный сертификат.

Пожалуйста, помогите, вот мой код ... и да ... извините за мой плохой английский: /:

Клиент C #

[...]

             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-сервера

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


}

Если вам что-то нужно, скажите, пожалуйста ...


person Wlad4Coding    schedule 13.05.2015    source источник
comment
кто-то только что задал аналогичный вопрос - stackoverflow.com / questions / 30224607 /   -  person ZhongYu    schedule 14.05.2015
comment
однако вы используете C # на стороне клиента, о чем я не знаю. Но основные проблемы те же - и я думаю, что вы легко можете погуглить исключение.   -  person ZhongYu    schedule 14.05.2015
comment
Это мне не помогло ... Я попытался запустить init () SSLContext ... но это выдает ошибку. и я думаю, вы можете легко погуглить исключение - ›Я был ... но не нашел ничего полезного.   -  person Wlad4Coding    schedule 14.05.2015


Ответы (1)


Ошибка политики RemoteCertificateNameMismatch не связана с отсутствующим локальным сертификатом. Эта ошибка просто сообщает вам, что SAN (альтернативное имя субъекта) в полученном сертификате сервера или, если SAN отсутствует, то общее имя полученного имени субъекта сертификата сервера НЕ совпадает с именем хоста, к которому вы подключаетесь. Вы можете игнорировать эту ошибку, если не ожидаете увидеть имя хоста в сертификате в одном из этих двух мест.

Я предполагаю, что у вас нет локального сертификата, потому что вы загружаете сертификат из файла, а в хранилище закрытых ключей Windows нет соответствующего закрытого ключа для этого сертификата.

Попробуйте импортировать сертификат и закрытый ключ (например, из файла PFX, который содержит и сертификат, и закрытый ключ) с помощью MMC в хранилище личных сертификатов локального компьютера, а затем загрузите здесь этот сертификат с помощью API хранилища сертификатов .NET. Пока у вас есть доступ к закрытому ключу (который вы получите, если вы являетесь пользователем Windows, импортировавшим PFX), вы сможете подключиться с помощью этого сертификата клиента.

В вашем коде вместо чтения сертификата из файла загрузите его из хранилища сертификатов примерно так:

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

Вы можете найти его, используя что-то другое, кроме отпечатка пальца - это всего лишь пример. Это то, что вы получили от SelectLocalCertificate.

person Jim Flood    schedule 14.05.2015
comment
Спасибо за отличный ответ! Я собираюсь это проверить. Я расскажу, сработало ли это у меня :) - person Wlad4Coding; 14.05.2015
comment
Извините ... Я новичок в программировании на C #. Раньше кодировал только на Java ... А как поставить сертификат? Я добавил .pfx в раздел хранилища личных сертификатов, но LocalCertificate по-прежнему пуст ... Также я искал .NET Certificate Api, чтобы назначить сертификат моему приложению, но я ничего не нашел ... - person Wlad4Coding; 14.05.2015
comment
@ Wlad4Coding Я обновил свой ответ некоторым кодом C #, чтобы найти сертификат из личного хранилища сертификатов текущего пользователя. - person Jim Flood; 15.05.2015