【问题标题】:SSL Connection with self-signed certificate error (C# Socket connect to Java Server Socket)带有自签名证书错误的 SSL 连接(C# Socket 连接到 Java Server Socket)
【发布时间】:2015-05-13 20:58:14
【问题描述】:

起初...这个程序只是 4-fun 并且永远不会发布。它只是用于测试 Sockets,所以不要关心这个连接的安全性。 我编写了一个小信使,您可以在其中在文本框中输入消息,它将被发送到服务器并从服务器发送到所有客户端。到目前为止,一切都很好。只是为了好玩,我想为此连接使用 SSL。 但是当我尝试连接到服务器套接字时,它会在 ValidateServerCertificate 处返回 RemoteCertificateNameMismatch。 添加一些调试消息后,我发现 Sslstream.LocalCertificate 为空。如何修复此丢失的证书?我正在使用自签名证书。

请帮忙,这是我的代码......是的......对不起我的英语不好:/:

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


}

如果你需要什么,请告诉我...

【问题讨论】:

  • 有人刚刚问了一个类似的问题 - stackoverflow.com/questions/30224607/…
  • 但是,您在客户端使用 C#,我对此一无所知。但是基本问题是一样的——我认为你可以很容易地用谷歌搜索异常。
  • 这对我没有帮助...我尝试 init() SSLContext ...但这给了我一个错误。 “而且我认为你可以轻松地用谷歌搜索异常”-> 我是......但我发现没有任何用处。

标签: java c# certificate server self-signed


【解决方案1】:

RemoteCertificateNameMismatch 策略错误与缺少本地证书无关。此错误只是告诉您接收到的服务器证书中的 SAN(主题备用名称),或者,如果没有 SAN,则接收到的服务器证书的主题名称的公用名与您连接的主机名不匹配。如果您不希望在这两个位置之一看到证书中的主机名,则可以忽略此错误。

我猜你没有本地证书,因为你是从一个文件加载证书,并且在 Windows 私钥存储中没有这个证书对应的私钥。

尝试使用 MMC 将证书和私钥(例如,从同时具有证书和私钥的 PFX 文件)导入本地计算机个人证书存储,然后加载 那个证书这里使用 .NET 证书存储 API。只要您有权访问私钥(如果是导入 PFX 的 Windows 用户,您将可以访问该私钥),那么您应该能够使用此客户端证书进行连接。

在您的代码中,不是从文件中读取证书,而是从证书存储中加载它,如下所示:

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 返回的内容。

【讨论】:

  • 感谢您的精彩回答!我要去看看这个。我会告诉你这是否对我有用:)
  • 对不起...我对 C# 编码真的很陌生。我以前只用 Java 编写过代码……但是如何设置证书?我将 .pfx 添加到“个人证书存储”部分,但 LocalCertificate 仍然为空......我还搜索了 .NET Certificate Api 以将证书分配给我的应用程序,但我没有找到任何东西......
  • @Wlad4Coding 我用一些 C# 代码更新了我的答案,以从当前用户的个人证书存储中查找证书。
猜你喜欢
  • 2014-02-15
  • 2019-04-26
  • 1970-01-01
  • 2017-03-28
  • 2012-01-14
  • 2014-01-21
  • 1970-01-01
  • 2015-02-09
  • 1970-01-01
相关资源
最近更新 更多