title: Handling multiple certificates in Netty's SSL Handler used in Play Framework 1.2.7
body: <p>I have a Java Key Store where I store certificates for each of my customer's sub-domain. I am planning to use the server alias to differentiate between multiple customers in the key store as suggested <a href="https://stackoverflow.com/questions/6370745/can-we-load-multiple-certificates-keys-in-a-key-store">here</a>. Play framework 1.2.7 uses Netty's SslHandler to support SSL on the server-side. I tried implementing a custom SslHttpServerContextFactory that uses this <a href="https://stackoverflow.com/a/9217941/794988">solution</a>.</p>
  
  <pre><code>import play.Play;
  
  import javax.net.ssl.*;
  import java.io.FileInputStream;
  import java.net.InetAddress;
  import java.net.Socket;
  import java.security.KeyStore;
  import java.security.Principal;
  import java.security.PrivateKey;
  import java.security.Security;
  import java.security.cert.X509Certificate;
  import java.util.Properties;
  
  public class CustomSslHttpServerContextFactory {
  
    private static final String PROTOCOL = "SSL";
    private static final SSLContext SERVER_CONTEXT;
  
    static {
  
      String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
      if (algorithm == null) {
        algorithm = "SunX509";
      }
  
      SSLContext serverContext = null;
      KeyStore ks = null;
      try {
        final Properties p = Play.configuration;
  
        // Try to load it from the keystore
        ks = KeyStore.getInstance(p.getProperty("keystore.algorithm", "JKS"));
        // Load the file from the conf
        char[] certificatePassword = p.getProperty("keystore.password", "secret").toCharArray();
        ks.load(new FileInputStream(Play.getFile(p.getProperty("keystore.file", "conf/certificate.jks"))),
            certificatePassword);
  
        // Set up key manager factory to use our key store
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
        kmf.init(ks, certificatePassword);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
        tmf.init(ks);
  
        final X509KeyManager origKm = (X509KeyManager) kmf.getKeyManagers()[0];
        X509KeyManager km = new X509KeyManagerWrapper(origKm);
  
        // Initialize the SSLContext to work with our key managers.
        serverContext = SSLContext.getInstance(PROTOCOL);
        serverContext.init(new KeyManager[]{km}, tmf.getTrustManagers(), null);
      } catch (Exception e) {
        throw new Error("Failed to initialize the server-side SSLContext", e);
      }
  
      SERVER_CONTEXT = serverContext;
    }
  
    public static SSLContext getServerContext() {
      return SERVER_CONTEXT;
    }
  
    public static class X509KeyManagerWrapper implements X509KeyManager {
      final X509KeyManager origKm;
  
      public X509KeyManagerWrapper(X509KeyManager origKm) {
        this.origKm = origKm;
      }
  
      public String chooseServerAlias(String keyType,
                                      Principal[] issuers, Socket socket) {
        InetAddress remoteAddress = socket.getInetAddress();
        //TODO: Implement alias selection based on remoteAddress
  
        return origKm.chooseServerAlias(keyType, issuers, socket);
      }
  
      @Override
      public String chooseClientAlias(String[] keyType,
                                      Principal[] issuers, Socket socket) {
        return origKm.chooseClientAlias(keyType, issuers, socket);
      }
  
      @Override
      public String[] getClientAliases(String s, Principal[] principals) {
        return origKm.getClientAliases(s, principals);
      }
  
      @Override
      public String[] getServerAliases(String s, Principal[] principals) {
        return origKm.getServerAliases(s, principals);
      }
  
      @Override
      public X509Certificate[] getCertificateChain(String s) {
        return origKm.getCertificateChain(s);
      }
  
      @Override
      public PrivateKey getPrivateKey(String s) {
        return origKm.getPrivateKey(s);
      }
  
    }
  
  }
  </code></pre>
  
  <p>But, this approach did not work for some reason. I get this message in my SSL debug log.</p>
  
  <pre><code>X509KeyManager passed to SSLContext.init():  need an X509ExtendedKeyManager for SSLEngine use
  </code></pre>
  
  <p>This is the SSL <a href="https://gist.github.com/aruld/8152111" rel="nofollow noreferrer">trace</a>, which fails with "no cipher suites in common". Now, I switched the wrapper to:</p>
  
  <pre><code>public static class X509KeyManagerWrapper extends X509ExtendedKeyManager
  </code></pre>
  
  <p>With this change, I got rid of the warning, but I still see the same error as before "no cipher suites in common" and here is the SSL <a href="https://gist.github.com/aruld/8152172" rel="nofollow noreferrer">trace</a>. I am not sure why the delegation of key manager won't work.</p>
  
  <p>Some more information that may be useful in this context.</p>
  
  <ul>
  <li><a href="http://netty.io/3.8/guide/#architecture.8.4" rel="nofollow noreferrer">Netty</a> uses javax.net.ssl.SSLEngine to support SSL in NIO server.</li>
  <li>As per the recommendation in this bug <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6448723" rel="nofollow noreferrer">report</a>, it is intentional that X509ExtendedKeyManager must be used with an SSLEngine. So, the wrapper must extend X509ExtendedKeyManager.</li>
  </ul>
  
  <p>This is hindering me to move further with the custom alias selection logic in X509KeyManagerWrapper. Any clues on what might be happening here? Is there any other way to implement this in Netty/Play? Appreciate any suggestions. </p>