سؤال

I'm trying to build a HTTPS Web Server for one of my own personal projects to help learn Java and networking and have been stuck for about 9 hours and so I am asking for assistance.

The problem is my https server will crash with the error "javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate", whenever I actually try to read from the input stream. I've tried searching the internet for hours, trying different ways to generate the keys and tried them all, but kept getting other error messages.

If it matters, what I am doing is running my Java application on my computer, it binds to port 443, and then I open FireFox to connect to it, then from debugging when it tries to read from the accepted sockets input stream (Location noted in code), it crashes with that fatal error above. If everything was working correctly, I should be given the chance in firefox to choose to ignore the SSL warning that is displayed with an SSL Certificate and continue to the page, but I can't do that since the fatal error brings down my java ssl web server.

How I generated the Certificates:

#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

SOURCE CODE:

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

I've been stuck on this for a long time and would like to try to figure out what's going wrong and why. I've searched all over, tried about 15 different tutorials on generating certificates, keys and even used other code to replace my own to see if that was the reason for my problems. I'm still learning Java and I would be grateful for any assistance (code or otherwise), all you experts out there could provide.

هل كانت مفيدة؟

المحلول

A. 'Crash'

An exception isn't a crash, and it shouldn't bring down your application. That's just poor code structure and poor exception handling. You need to start a thread per accepted socket, with its own exception handling in its run method.

B. Certificate steps.

#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

So far so good. Here you have created or updated two keystores: one for the server, one for the client.

#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

Here you have created or updated a truststore for the client.

#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

Here you have created or updated a truststore for the server.

So your intention is clearly to engage in mutually authenticated 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

I don't understand why you're doing this step. The first command just creates another copy of the file 'clientpub.cer' that you already have. The second part puts it into the JDK truststore, for reasons I don't understand. You don't need both these two steps and the previous two, just either the previous two or these two.

But I don't understand why you're doing any of the four. You don't need a client certificate, a client keystore, and a server truststore at all, unless:

  1. You have enabled wantClientAuth or needClientAuth at the server, and
  2. You have installed the client certificate in your Firefox browser.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top