代码之家  ›  专栏  ›  技术社区  ›  Li Wu

Java SSL套接字Web服务器证书错误

  •  0
  • Li Wu  · 技术社区  · 11 年前

    我正试图为我自己的一个个人项目构建一个HTTPS Web服务器,以帮助学习Java和网络,但已经被困了大约9个小时,所以我请求帮助。

    问题是我的https服务器将崩溃,并出现错误“ javax.net.ssl.ssl握手异常:收到致命警报:bad_certificate “,每当我真正尝试从输入流中读取时。我已经尝试在互联网上搜索了几个小时,尝试了不同的方法来生成密钥,并尝试了所有方法,但不断收到其他错误消息。

    如果重要的话,我正在做的是在我的计算机上运行我的Java应用程序,它绑定到443端口,然后我打开FireFox连接到它,然后当它试图从接受的套接字输入流(代码中注明的位置)读取时进行调试,它会因上面的致命错误而崩溃。如果一切正常,我应该有机会在firefox中选择忽略SSL证书显示的SSL警告,并继续到页面,但我不能这样做,因为这个致命错误导致我的java SSL web服务器瘫痪。

    我是如何生成证书的:

    #GENERATE KEYS
    keytool -genkeypair -alias plainserverkeys -keyalg RSA -dname "CN=Plain Server,OU=kl2217,O=kl2217org,L=Boston,ST=MA,C=US" -keypass password -keystore plainserver.jks -storepass password
    keytool -genkeypair -alias plainclientkeys -keyalg RSA -dname "CN=Plain Client,OU=kl2217,O=kl2217org,L=Boston,ST=MA,C=US" -keypass password -keystore plainclient.jks -storepass password
    
    #EXPORT SERVER CERT + IMPORT NEW KEYSTORE
    keytool -exportcert -alias plainserverkeys -file serverpub.cer -keystore plainserver.jks -storepass password
    keytool -importcert -keystore serverpub.jks -alias serverpub -file serverpub.cer -storepass password
    
    #EXPORT CLIENT CERT + IMPORT NEW KEYSTORE
    keytool -exportcert -alias plainclientkeys -file clientpub.cer -keystore plainclient.jks -storepass password
    keytool -importcert -keystore clientpub.jks -alias clientpub -file clientpub.cer -storepass password
    
    #EXPORT PLAIN CLIENT CERT + IMPORT TO MAIN JAVA KEYSTORE
    keytool -export -alias plainclientkeys -keystore plainclient.jks -rfc -file plainclient.cert
    keytool -import -trustcacerts -keystore /usr/java/jdk1.7.0_25/jre/lib/security/cacerts -storepass changeit -noprompt -alias mycert -file plainclient.cert
    

    源代码:

    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLServerSocket;
    import javax.net.ssl.SSLServerSocketFactory;
    import javax.net.ssl.TrustManagerFactory;
    
    public class Main
    {
        public static void main(String[] args)
        {
            SSLContext context;
            KeyManagerFactory kmf;
            KeyStore ks;
            char[] storepass = "password".toCharArray();
            char[] keypass = "password".toCharArray();
            String storename = "plainserver.jks";
            try
            {
                //KEY MANAGER
                context = SSLContext.getInstance("TLS");
                kmf = KeyManagerFactory.getInstance("SunX509");
                FileInputStream fin = new FileInputStream(storename);
                ks = KeyStore.getInstance("JKS");
                ks.load(fin, storepass);
                kmf.init(ks, keypass);
    
                //TRUST MANAGER
                KeyStore clientPub = KeyStore.getInstance("JKS");
                clientPub.load(new FileInputStream("clientpub.jks"),"password".toCharArray());
                TrustManagerFactory trustManager = TrustManagerFactory.getInstance("SunX509");
                trustManager.init(clientPub);
    
                //INIT SERVER STUFF
                context.init(kmf.getKeyManagers(), trustManager.getTrustManagers(), null);
                SSLServerSocketFactory ssf = context.getServerSocketFactory();
                //ServerSocket ss = ssf.createServerSocket(443);
                SSLServerSocket ss = (SSLServerSocket) ssf.createServerSocket(443);
    
                while (true)
                {
                    System.out.println("ACCEPT");
                    Socket s = ss.accept();
                    System.out.println("PROCESS! (1)");
                    BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
                    System.out.println("PROCESS! (2)");
                    String x = in.readLine();       //!!!!!PROGRAM WILL CRASH HERE!!!!
                    System.out.println("PROCESS! (3)");
                    System.out.println(x);
                    s.close();
                }
            }
            catch (KeyStoreException | IOException | NoSuchAlgorithmException | KeyManagementException | 
                    UnrecoverableKeyException | CertificateException e)
            {
                e.printStackTrace();
            }
        }
    }
    

    我在这件事上已经坚持了很长一段时间,我想试着弄清楚出了什么问题以及为什么。我到处搜索,尝试了大约15个关于生成证书和密钥的不同教程,甚至用其他代码来代替我自己的代码,看看这是否是我出现问题的原因。我仍在学习Java,如果您能提供任何帮助(代码或其他方面),我将不胜感激。

    1 回复  |  直到 11 年前
        1
  •  1
  •   user207421    11 年前

    A.“碰撞”

    异常不是崩溃,也不应该导致应用程序崩溃。这只是糟糕的代码结构和糟糕的异常处理。您需要为每个可接受的套接字启动一个线程,在其运行方法中有自己的异常处理。

    B.证书步骤。

    #GENERATE KEYS
    keytool -genkeypair -alias plainserverkeys -keyalg RSA -dname "CN=Plain Server,OU=kl2217,O=kl2217org,L=Boston,ST=MA,C=US" -keypass password -keystore plainserver.jks -storepass password
    keytool -genkeypair -alias plainclientkeys -keyalg RSA -dname "CN=Plain Client,OU=kl2217,O=kl2217org,L=Boston,ST=MA,C=US" -keypass password -keystore plainclient.jks -storepass password
    

    到现在为止,一直都还不错。在这里,您创建或更新了两个密钥库:一个用于服务器,一个用于客户端。

    #EXPORT SERVER CERT + IMPORT NEW KEYSTORE
    keytool -exportcert -alias plainserverkeys -file serverpub.cer -keystore plainserver.jks -storepass password
    keytool -importcert -keystore serverpub.jks -alias serverpub -file serverpub.cer -storepass password
    

    在这里,您已经为客户端创建或更新了信任库。

    #EXPORT CLIENT CERT + IMPORT NEW KEYSTORE
    keytool -exportcert -alias plainclientkeys -file clientpub.cer -keystore plainclient.jks -storepass password
    keytool -importcert -keystore clientpub.jks -alias clientpub -file clientpub.cer -storepass password
    

    在这里,您已经为服务器创建或更新了信任库。

    因此,您的意图显然是参与相互认证的SSL。

    #EXPORT PLAIN CLIENT CERT + IMPORT TO MAIN JAVA KEYSTORE
    keytool -export -alias plainclientkeys -keystore plainclient.jks -rfc -file plainclient.cert
    keytool -import -trustcacerts -keystore /usr/java/jdk1.7.0_25/jre/lib/security/cacerts -storepass changeit -noprompt -alias mycert -file plainclient.cert
    

    我不明白你为什么要走这一步。第一个命令只是创建您已经拥有的文件“clientpub.cer”的另一个副本。第二部分将其放入JDK信任库,原因我不理解。你不需要这两个步骤和前两个步骤,只需要前两个或这两个。

    但我不明白你为什么要做这四件事中的任何一件。您不需要客户端证书、客户端密钥库和服务器信任库 完全 除非:

    1. 您已启用 wantClientAuth needClientAuth 在服务器上,以及
    2. 您已经在Firefox浏览器中安装了客户端证书。