2

I have a Jetty server where I'm opening opening more than one SSL ports and setting the SslContextFactory where I am pointing it to my custom keystore in which I have certificates for all the SSL ports.

public static SslContextFactory getCustomSSLContextFactory() throws IOException {
    KeyStoreInfo keyStoreInfo = KeyStoreInfo.getInstance();
    SslContextFactory sslContextFactory = new SslContextFactory(mycustomkeystorepath);
    sslContextFactory.setKeyStorePassword(mykeystorepassword);
    sslContextFactory.setKeyStoreType(keystoretype);
    sslContextFactory.setTrustStorePath(defaultcatruststore);
    sslContextFactory.setTrustStorePassword(password);
    sslContextFactory.setTrustStoreType(truststoretype);
    sslContextFactory.setNeedClientAuth(true);
    return sslContextFactory;       
}

This SslContextFactory I'm setting in ServerConnector SslConnectionFactory. And I have multiple ServerConnectors and all have the same SslContextFactory.

My question is as I have multiple PKI-cert and private key in custom key store. How SslConnectionFactory will know which PKI-cert and private key belongs to which SSL port?

Joakim Erdfelt
  • 46,896
  • 7
  • 86
  • 136

2 Answers2

3

The certificate and key used for an SSLContext server is selected by the KeyManager it is initialized with.

If you want to manually select the certificate and/or key you can implement your own KeyManager and place your code in:

String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)

PrivateKey getPrivateKey(String alias)

The first method allows you to specify which alias identifies the certificate and the second gets the alias defined in the first method and loads the private key.

If you implement the first method in a way that it returns the alias of the key/certificate in the key store you can delegate the second to an existing KeyManager instance.

The resulting code will look like this:

String algorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
keyManagerFactory.init(keyStore, "".toCharArray());

KeyManager[] defaultKeyManagers = keyManagerFactory.getKeyManagers();
KeyManager mykm = new MyKeyManager((X509KeyManager) defaultKeyManagers[0]);

sslContext.init(new KeyManager[] { mykm } , trustManagerFactory.getTrustManagers(), new SecureRandom());

static class  MyKeyManager implements X509KeyManager {
    final X509KeyManager delegate;

    public KeyManager(X509KeyManager delegate) {
        this.delegate = delegate;
    }

    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
        delegate.chooseClientAlias(keyType, issuers, socket);
    }

    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
        ... implement your code here
    }

    public X509Certificate[] getCertificateChain(String alias) {
        return delegate.getCertificateChain(alias);
    }

    public String[] getServerAliases(String keyType, Principal[] issuers) {
        return delegate.getServerAliases(keyType, issuers);
    }

    public String[] getClientAliases(String keyType, Principal[] issuers) {
        return delegate.getClientAliases(keyType, issuers);
    }

    public PrivateKey getPrivateKey(String alias) {
        return delegate.getPrivateKey(alias);
    }
}
Robert
  • 39,162
  • 17
  • 99
  • 152
  • Thank you, it seems I have to implement custom key manager. As ip is same for both ports, so to have different certificates for ports, I need to implement custom key manager. Thank you for the solution, really appreciate the help. – user2730259 Jun 06 '18 at 05:41
  • @user2730259 You can accept one answer per question that helped you most. To do so enable the green check mark below the question's vote counter. – Robert Jun 06 '18 at 09:34
1

SSL certificate is related to some domain/hostname+port of a server. So the domain/hostname+port data is present in the certificate. When you would make a connection, the SslConnectionFactory will look if a certificate is present for the particular domain/hostname+port and if it is present it will use that certificate and the private key related to the same for doing handshake.

Remember,by default SSL certificates for domain name know that the port is 443. Similarly, it would work for different ports.

Shubham Kadlag
  • 2,248
  • 1
  • 13
  • 32
  • 1
    I doubt certificate is based on port, its based on the common name (CN), so as both ports have same domain name/IP having two certificate is not possible without the custom implementation of key manager. Thanks for your response – user2730259 Jun 06 '18 at 05:44