title: SSL/TLS error ("no cipher suites in common") with Netty when trying to establish a secure connection between a frontend and a backend
body: <p>I want to secure a TCP connection between a backend and a frontend. We use Netty to establish a TCP connection which works pretty well. Now, we want to secure this connection by using SSL/TLS. For that reason I created a certificate request:</p>
  
  <pre><code>openssl req -newkey rsa:2048 -keyout key.pem -out request.pem -subj '/C=DE/O=XX/ST=XX/L=XX/O=XX/OU=XX/CN=someaddress.de/emailAddress=support@xxx.de'
  </code></pre>
  
  <p>The certificate was then created by the CA.</p>
  
  <p>The keystore was created with:</p>
  
  <pre><code>keytool -import -alias xxx -keystore xxx.keystore -file cert-xxx.pem 
  </code></pre>
  
  <p>Server with Netty at the backend:</p>
  
  <pre><code>public StatefulTcpServer(MessageHandler messageHandler, int port, KeyStore keyStore, String keyStorePassword) {
      this.messageHandler = messageHandler;
      factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
      allChannels = new DefaultChannelGroup("clients");
  
      initTLS(keyStore, keyStorePassword);
  
      ServerBootstrap bootstrap = new ServerBootstrap(factory);
  
      bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
  
          @Override
          public ChannelPipeline getPipeline() {
              ChannelPipeline pipeline = Channels.pipeline();
              if (sslContext != null) {
                  SSLEngine sslEngine = sslContext.createSSLEngine();
                  sslEngine.setUseClientMode(false);
                  sslEngine.setEnabledCipherSuites(new String[] {
                      "TLS_RSA_WITH_AES_128_CBC_SHA"
                  });
                  pipeline.addLast("ssl", new SslHandler(sslEngine));
              }
  
              pipeline.addLast("compressor", new ZlibEncoder());
              pipeline.addLast("decompressor", new ZlibDecoder());
  
              pipeline.addLast("decoder", new JBossSerializationDecoder());
              pipeline.addLast("encoder", new JBossSerializationEncoder());
  
              pipeline.addLast("handler", StatefulTcpServer.this);
              return pipeline;
          }
      });
  
      bootstrap.setOption("child.tcpNoDelay", true);
      bootstrap.setOption("child.keepAlive", true);
  
      bootstrap.bind(new InetSocketAddress(port));
  }
  
  private void initTLS(KeyStore keyStore, String keyStorePassword) {
      try {
          if (keyStore != null) {
              KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
              kmf.init(keyStore, keyStorePassword.toCharArray());
              sslContext = SSLContext.getInstance("TLS");
              sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
          }
      }
      catch (GeneralSecurityException e) {
          logger.error("TLS connection could not be established", e);
          sslContext = null;
      }
  }
  </code></pre>
  
  <p>Server with Netty in the frontend:</p>
  
  <pre><code>public void init(String backendHost, int backendPort, int timeOutSecs, boolean useTLS,
                  boolean acceptOnlyTrustworthyCertsForTLS) throws ConnectionFailedException {
  
      channelFactory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(),
                      Executors.newCachedThreadPool());
  
      if (useTLS) {
          initTLS(acceptOnlyTrustworthyCertsForTLS);
      }
  
      ClientBootstrap bootstrap = new ClientBootstrap(channelFactory);
      bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
  
          @Override
          public ChannelPipeline getPipeline() {
              ChannelPipeline pipeline = Channels.pipeline();
  
              if (sslContext != null) {
                  SSLEngine sslEngine = sslContext.createSSLEngine();
                  sslEngine.setUseClientMode(true);
                  sslEngine.setEnabledCipherSuites(new String[] {
                      "TLS_RSA_WITH_AES_128_CBC_SHA"
                  });
                  pipeline.addLast("ssl", new SslHandler(sslEngine));
              }
  
              pipeline.addLast("compressor", new ZlibEncoder());
              pipeline.addLast("decompressor", new ZlibDecoder());
  
              pipeline.addLast("decoder", new JBossSerializationDecoder());
              pipeline.addLast("encoder", new JBossSerializationEncoder());
  
              pipeline.addLast("handler", StatefulTcpBackendCommunicator.this);
              return pipeline;
          }
      });
      bootstrap.setOption("tcpNoDelay", true);
      bootstrap.setOption("keepAlive", true);
  
      channelFuture = bootstrap.connect(new InetSocketAddress(backendHost, backendPort));
      try {
          boolean connected = channelFuture.await(timeOutSecs * 1000);
          if (!connected || !channelFuture.isSuccess()) {
              throw new ConnectionFailedException();
          }
      }
      catch (InterruptedException e) {
          logger.error(e.getMessage(), e);
      }
  }
  
  
  private void initTLS(boolean acceptOnlyTrustworthyCertsForTLS) {
      try {
          TrustManager[] trustManagers;
          if (acceptOnlyTrustworthyCertsForTLS) {
              TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory
                              .getDefaultAlgorithm());
              trustManagerFactory.init((KeyStore) null);
              trustManagers = trustManagerFactory.getTrustManagers();
          }
          else {
              trustManagers = new TrustManager[] {
                  new X509TrustManager() {
  
                      @Override
                      public X509Certificate[] getAcceptedIssuers() {
                          return null;
                      }
  
  
                      @Override
                      public void checkClientTrusted(X509Certificate[] certs, String authType) {
                          return;
                      }
  
  
                      @Override
                      public void checkServerTrusted(X509Certificate[] certs, String authType) {
                          return;
                      }
                  }
              };
          }
  
          sslContext = SSLContext.getInstance("TLS");
          sslContext.init(null, trustManagers, new SecureRandom());
      }
      catch (GeneralSecurityException e) {
          logger.error("TLS connection could not be established. TLS is not used!", e);
          sslContext = null;
      }
  }
  </code></pre>
  
  <p>When trying to establish the connection between frontend and backend I get an exception: </p>
  
  <pre><code>javax.net.ssl.SSLHandshakeException: no cipher suites in common
  </code></pre>
  
  <p><a href="https://stackoverflow.com/questions/3662837/java-no-cipher-suites-in-common-issue-when-trying-to-securely-connect-to-serve">This post</a> was unfortunately not helpful. Is there something wrong with the configuration of the servers? Or do I use the wrong certificate type?</p>