java: provide our own preferred cipher suite list

This updates the Java client to use a cipher suite list which matches
the server side. This has a very big performance benefit since it
prioritizes GCM-based ciphers which are significantly faster than those
that use SHA256 or SHA384 HMAC for integrity.

In particular, a YCSB in-memory random-read workload I was running got
~60% faster. The CPU profile on the server previously showed most of its
time in SHA hash calculation, and now shows only relatively little CPU
in GCM-related calls.

Change-Id: I4b2853dfd8d330bdf003924a5574fde865f54249
Reviewed-on: http://gerrit.cloudera.org:8080/9398
Reviewed-by: Dan Burkert <d...@cloudera.com>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/8ea955d7
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/8ea955d7
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/8ea955d7

Branch: refs/heads/master
Commit: 8ea955d7645ae9a1ef6a816b2f28b2661f2f87d2
Parents: f92f65c
Author: Todd Lipcon <t...@apache.org>
Authored: Thu Feb 22 10:04:35 2018 -0800
Committer: Todd Lipcon <t...@apache.org>
Committed: Thu Feb 22 21:02:34 2018 +0000

----------------------------------------------------------------------
 .../java/org/apache/kudu/client/Negotiator.java | 39 ++++++++++++++++++++
 1 file changed, 39 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/8ea955d7/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java
----------------------------------------------------------------------
diff --git 
a/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java 
b/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java
index 466f265..c58ffe6 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java
@@ -111,6 +111,30 @@ public class Negotiator extends 
SimpleChannelUpstreamHandler {
   static final int CONNECTION_CTX_CALL_ID = -3;
   static final int SASL_CALL_ID = -33;
 
+  /**
+   * The cipher suites, in order of our preference.
+   * This list is based on the kDefaultTlsCiphers list in security_flags.cc,
+   * See that file for details on how it was derived.
+   */
+  static final String[] PREFERRED_CIPHER_SUITES = new String[] {
+      "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", // Java 8
+      "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",   // Java 8
+      "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // Java 8
+      "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",   // Java 8
+      "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", // Java 7 (TLS 1.2+ only)
+      "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",   // Java 7 (TLS 1.2+ only)
+      "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", // Java 7 (TLS 1.2+ only)
+      "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",   // Java 7 (TLS 1.2+ only)
+      "TLS_RSA_WITH_AES_256_GCM_SHA384",         // Java 8
+      "TLS_RSA_WITH_AES_128_GCM_SHA256",         // Java 8
+      "TLS_RSA_WITH_AES_256_CBC_SHA256",         // Java 7 (TLS 1.2+ only)
+      "TLS_RSA_WITH_AES_128_CBC_SHA256",         // Java 7 (TLS 1.2+ only)
+      // The following two are critical to allow the client to connect to
+      // servers running versions of OpenSSL that don't support TLS 1.2.
+      "TLS_RSA_WITH_AES_256_CBC_SHA",            // All Java versions
+      "TLS_RSA_WITH_AES_128_CBC_SHA"             // All Java versions
+  };
+
   private enum State {
     INITIAL,
     AWAIT_NEGOTIATE,
@@ -486,6 +510,21 @@ public class Negotiator extends 
SimpleChannelUpstreamHandler {
         throw new AssertionError("unreachable");
     }
     engine.setUseClientMode(true);
+    Set<String> supported = Sets.newHashSet(engine.getSupportedCipherSuites());
+    List<String> toEnable = Lists.newArrayList();
+    for (String cipher : PREFERRED_CIPHER_SUITES) {
+      if (supported.contains(cipher)) {
+        toEnable.add(cipher);
+      }
+    }
+    if (toEnable.isEmpty()) {
+      // This should never be the case given the cipher suites we picked are
+      // supported by the standard JDK, but just in case, better to have a 
clear
+      // exception.
+      throw new RuntimeException("No preferred cipher suites were supported. " 
+
+          "Supported suites: " + Joiner.on(',').join(supported));
+    }
+    engine.setEnabledCipherSuites(toEnable.toArray(new String[0]));
     SslHandler handler = new SslHandler(engine);
     handler.setEnableRenegotiation(false);
     sslEmbedder = new DecoderEmbedder<>(handler);

Reply via email to