question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Creating KeyStore programmatically, from LetsEncrypt certificate

See original GitHub issue

I am trying to use Javalin (I love the project and the API!!) to make secure WebSockets + HTTPS REST API run at the same port.

Previously I have been using TooTallNate/Java-WebSocket for using WebSockets, they also have an example of how to create the KeyStore programmatically which if you follow the links ends up at a Stack Overflow answer. The issue with TooTallNate/Java-WebSocket is that it is only a WebSocket server and therefore I would need to use two different ports for WebSockets + HTTPS REST API.

So I tried to combine the TooTallNate/Java-WebSocket example above with the Javalin example and ended up with the following code: (ServerConfig is just my configuration object containing configuration for which ports to use and where to find the certificate files)

public static Javalin javalin(ServerConfig serverConfig) {
    return Javalin.create().server(() -> createServer(serverConfig));
}

private static Server createServer(ServerConfig serverConfig) {
    Server server = new Server();
    ServerConnector connector = new ServerConnector(server);
    connector.setPort(serverConfig.webSocketPort);
    if (serverConfig.useSecureWebsockets()) {
        ServerConnector sslConnector = new ServerConnector(server, createSslContextFactory(serverConfig));
        sslConnector.setPort(serverConfig.webSocketPortSSL);
        server.setConnectors(new Connector[]{sslConnector, connector});
    } else {
        server.setConnectors(new Connector[]{connector});
    }
    return server;
}

private static SslContextFactory createSslContextFactory(ServerConfig serverConfig) {
    String pathTo = serverConfig.certificatePath;
    String keyPassword = serverConfig.certificatePassword;
    try {
        byte[] certBytes = parseDERFromPEM(Files.readAllBytes(new File(pathTo + File.separator + "cert.pem").toPath()), "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
        byte[] keyBytes = parseDERFromPEM(Files.readAllBytes(new File(pathTo + File.separator + "privkey.pem").toPath()), "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----");

        X509Certificate cert = generateCertificateFromDER(certBytes);
        RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes);

        KeyStore keystore = KeyStore.getInstance("JKS");
        keystore.load(null);
        keystore.setCertificateEntry("cert-alias", cert);
        keystore.setKeyEntry("key-alias", key, keyPassword.toCharArray(), new X509Certificate[]{cert});

        SslContextFactory sslContextFactory = new SslContextFactory();
        sslContextFactory.setKeyStore(keystore);
        sslContextFactory.setKeyStorePassword(keyPassword);

        return sslContextFactory;
    } catch (IOException | KeyStoreException | InvalidKeySpecException | NoSuchAlgorithmException | CertificateException e) {
        throw new IllegalArgumentException(e);
    }
}

private static byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) {
    String data = new String(pem);
    String[] tokens = data.split(beginDelimiter);
    tokens = tokens[1].split(endDelimiter);
    return DatatypeConverter.parseBase64Binary(tokens[0]);
}

private static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory factory = KeyFactory.getInstance("RSA");
    return (RSAPrivateKey) factory.generatePrivate(spec);
}

private static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException {
    CertificateFactory factory = CertificateFactory.getInstance("X.509");

    return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
}

This however ends up with me getting “ERR_SSL_VERSION_OR_CIPHER_MISMATCH” whenever I try to connect with HTTPS to a REST endpoint or when connecting with WebSockets.

I understand that it might be me that is the problem here and not Javalin, but I am hoping for any assistance.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:4
  • Comments:11 (6 by maintainers)

github_iconTop GitHub Comments

6reactions
Zomiscommented, Feb 13, 2019

I found the solution myself!

Change:

KeyStore keystore = KeyStore.getInstance("JKS");

to:

KeyStore keystore = KeyStore.getInstance("PKCS12");

Done!

Now for another request: Document this. I bet more people than I would be interested in not having to do the KeyStore generation manually. (Or is what I’m doing here not recommended?)

3reactions
Zomiscommented, Feb 16, 2019

@tipsy Might take a while but yes, I could do that!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Creating KeyStore programmatically, from LetsEncrypt certificate
I am trying to use Javalin (I love the project and the API!!) to make secure WebSockets + HTTPS REST API run at...
Read more >
Tutorial - Java KeyStores (JKS) With Let's Encrypt
keytool is a java command line utility for working with JKS and is available with the Java ... Creating Keystore/Certificate for Tomcat.
Read more >
Using Let's Encrypt certificates in Java applications
Adding certificates to a keystore can be done by using OpenSSL and the keytool .
Read more >
Generate a Java KeyStore from Let's Encrypt for Java web ...
Add your domain and subdomains (sample: keybin.io, www.keybin.io) · Click NEXT and your certificate request will be generated (…Generating CSR text will be...
Read more >
Using LetsEncrypt certificates in your JKS - wissel.net
Using LetsEncrypt certificates in your JKS - Dealing with certificates in Java is always fun. The keystore Java uses is different from the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found