javasslhttpsjava-8lets-encrypt

In Java, what is the simplest way to create an SSLContext with just a PEM file?


I used LetsEncrypt's CertBot to generate PEM files for free. In other languages it is easy to start an HTTPS server using just a couple lines of code and the PEM/key files. The solutions I have found so far in java are overly complex and I'm looking for something simpler.

  1. I do not want to use java's command-line "keytool". I just want to drag and drop my PEM/key files into my eclipse, and programatically start up an HTTPS server using an SSLContext.
  2. I do not want to include massive external libraries like BouncyCastle. See the following link for a supposed solution using BouncyCastle: How to build a SSLSocketFactory from PEM certificate and key without converting to keystore?

Is there a better/easier way to do this?


Solution

  • My full solution that I currently use:

    1. Use certbot on your server to generate the certificate. I use the command "certbot certonly -d myawesomedomain.com"
    2. I use the following code to convert that certbot certificate into a java SSLContext: https://github.com/mirraj2/bowser/blob/master/src/bowser/SSLUtils.java
    package bowser;
    
    import static com.google.common.base.Preconditions.checkState;
    import static ox.util.Utils.propagate;
    
    import java.io.File;
    import java.security.KeyStore;
    
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManagerFactory;
    
    import com.google.common.base.Splitter;
    
    import ox.IO;
    import ox.Log;
    
    public class SSLUtils {
    
      public static SSLContext createContext(String domain) {
        String pass = "spamspam";
    
        File dir = new File("/etc/letsencrypt/live/" + domain);
        if (!dir.exists()) {
          Log.warn("Could not find letsencrypt dir: " + dir);
          return null;
        }
    
        File keystoreFile = new File(dir, "keystore.jks");
        File pemFile = new File(dir, "fullchain.pem");
    
        boolean generateKeystore = false;
    
        if (keystoreFile.exists()) {
          if (keystoreFile.lastModified() < pemFile.lastModified()) {
            Log.info("SSUtils: It looks like a new PEM file was created. Regenerating the keystore.");
            keystoreFile.delete();
            generateKeystore = true;
          }
        } else {
          generateKeystore = true;
        }
    
        if (generateKeystore) {
          Splitter splitter = Splitter.on(' ');
          try {
            String command = "openssl pkcs12 -export -out keystore.pkcs12 -in fullchain.pem -inkey privkey.pem -passout pass:"
                + pass;
            Log.debug(command);
            Process process = new ProcessBuilder(splitter.splitToList(command))
                .directory(dir).inheritIO().start();
            checkState(process.waitFor() == 0);
    
            command = "keytool -importkeystore -srckeystore keystore.pkcs12 -srcstoretype PKCS12 -destkeystore keystore.jks -srcstorepass "
                + pass + " -deststorepass " + pass;
            Log.debug(command);
            process = new ProcessBuilder(splitter.splitToList(command))
                .directory(dir).inheritIO().start();
            checkState(process.waitFor() == 0);
    
            new File(dir, "keystore.pkcs12").delete();// cleanup
          } catch (Exception e) {
            throw propagate(e);
          }
        }
    
        try {
          KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
          keystore.load(IO.from(keystoreFile).asStream(), pass.toCharArray());
    
          KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
          keyManagerFactory.init(keystore, pass.toCharArray());
    
          SSLContext ret = SSLContext.getInstance("TLSv1.2");
          TrustManagerFactory factory = TrustManagerFactory.getInstance(
              TrustManagerFactory.getDefaultAlgorithm());
          factory.init(keystore);
          ret.init(keyManagerFactory.getKeyManagers(), factory.getTrustManagers(), null);
    
          return ret;
        } catch (Exception e) {
          throw propagate(e);
        }
      }
    
    }