2727import java .security .Security ;
2828import java .security .cert .PKIXBuilderParameters ;
2929import java .security .cert .X509CertSelector ;
30+ import java .util .ArrayList ;
3031import java .util .Arrays ;
32+ import java .util .List ;
3133import java .util .Objects ;
34+ import java .util .Set ;
3235import java .util .concurrent .atomic .AtomicReference ;
3336import javax .net .ssl .CertPathTrustManagerParameters ;
3437import javax .net .ssl .KeyManager ;
4952import org .slf4j .LoggerFactory ;
5053
5154import org .apache .hbase .thirdparty .com .google .common .collect .ObjectArrays ;
55+ import org .apache .hbase .thirdparty .io .netty .handler .ssl .OpenSsl ;
5256import org .apache .hbase .thirdparty .io .netty .handler .ssl .SslContext ;
5357import org .apache .hbase .thirdparty .io .netty .handler .ssl .SslContextBuilder ;
58+ import org .apache .hbase .thirdparty .io .netty .handler .ssl .SslProvider ;
5459
5560/**
5661 * Utility code for X509 handling Default cipher suites: Performance testing done by Facebook
@@ -83,9 +88,10 @@ public final class X509Util {
8388 public static final String TLS_CONFIG_OCSP = CONFIG_PREFIX + "ocsp" ;
8489 public static final String TLS_CONFIG_REVERSE_DNS_LOOKUP_ENABLED =
8590 CONFIG_PREFIX + "host-verification.reverse-dns.enabled" ;
86- private static final String TLS_ENABLED_PROTOCOLS = CONFIG_PREFIX + "enabledProtocols" ;
87- private static final String TLS_CIPHER_SUITES = CONFIG_PREFIX + "ciphersuites" ;
91+ public static final String TLS_ENABLED_PROTOCOLS = CONFIG_PREFIX + "enabledProtocols" ;
92+ public static final String TLS_CIPHER_SUITES = CONFIG_PREFIX + "ciphersuites" ;
8893 public static final String TLS_CERT_RELOAD = CONFIG_PREFIX + "certReload" ;
94+ public static final String TLS_USE_OPENSSL = CONFIG_PREFIX + "useOpenSsl" ;
8995 public static final String DEFAULT_PROTOCOL = "TLSv1.2" ;
9096
9197 //
@@ -131,6 +137,34 @@ private static String[] getCBCCiphers() {
131137 private static final String [] DEFAULT_CIPHERS_JAVA9 =
132138 ObjectArrays .concat (getGCMCiphers (), getCBCCiphers (), String .class );
133139
140+ private static final String [] DEFAULT_CIPHERS_OPENSSL = getOpenSslFilteredDefaultCiphers ();
141+
142+ /**
143+ * Not all of our default ciphers are available in OpenSSL. Takes our default cipher lists and
144+ * filters them to only those available in OpenSsl. Does GCM first, then CBC because GCM tends to
145+ * be better and faster, and we don't need to worry about the java8 vs 9 performance issue if
146+ * OpenSSL is handling it.
147+ */
148+ private static String [] getOpenSslFilteredDefaultCiphers () {
149+ if (!OpenSsl .isAvailable ()) {
150+ return new String [0 ];
151+ }
152+
153+ Set <String > openSslSuites = OpenSsl .availableJavaCipherSuites ();
154+ List <String > defaultSuites = new ArrayList <>();
155+ for (String cipher : getGCMCiphers ()) {
156+ if (openSslSuites .contains (cipher )) {
157+ defaultSuites .add (cipher );
158+ }
159+ }
160+ for (String cipher : getCBCCiphers ()) {
161+ if (openSslSuites .contains (cipher )) {
162+ defaultSuites .add (cipher );
163+ }
164+ }
165+ return defaultSuites .toArray (new String [0 ]);
166+ }
167+
134168 /**
135169 * Enum specifying the client auth requirement of server-side TLS sockets created by this
136170 * X509Util.
@@ -176,7 +210,10 @@ private X509Util() {
176210 // disabled
177211 }
178212
179- static String [] getDefaultCipherSuites () {
213+ static String [] getDefaultCipherSuites (boolean useOpenSsl ) {
214+ if (useOpenSsl ) {
215+ return DEFAULT_CIPHERS_OPENSSL ;
216+ }
180217 return getDefaultCipherSuitesForJavaVersion (System .getProperty ("java.specification.version" ));
181218 }
182219
@@ -202,6 +239,7 @@ public static SslContext createSslContextForClient(Configuration config)
202239
203240 SslContextBuilder sslContextBuilder = SslContextBuilder .forClient ();
204241
242+ boolean useOpenSsl = configureOpenSslIfAvailable (sslContextBuilder , config );
205243 String keyStoreLocation = config .get (TLS_CONFIG_KEYSTORE_LOCATION , "" );
206244 char [] keyStorePassword = config .getPassword (TLS_CONFIG_KEYSTORE_PASSWORD );
207245 String keyStoreType = config .get (TLS_CONFIG_KEYSTORE_TYPE , "" );
@@ -234,11 +272,21 @@ public static SslContext createSslContextForClient(Configuration config)
234272
235273 sslContextBuilder .enableOcsp (sslOcspEnabled );
236274 sslContextBuilder .protocols (getEnabledProtocols (config ));
237- sslContextBuilder .ciphers (Arrays .asList (getCipherSuites (config )));
275+ sslContextBuilder .ciphers (Arrays .asList (getCipherSuites (config , useOpenSsl )));
238276
239277 return sslContextBuilder .build ();
240278 }
241279
280+ private static boolean configureOpenSslIfAvailable (SslContextBuilder sslContextBuilder ,
281+ Configuration conf ) {
282+ if (OpenSsl .isAvailable () && conf .getBoolean (TLS_USE_OPENSSL , true )) {
283+ LOG .debug ("Using netty-tcnative to accelerate TLS handling" );
284+ sslContextBuilder .sslProvider (SslProvider .OPENSSL );
285+ return true ;
286+ }
287+ return false ;
288+ }
289+
242290 public static SslContext createSslContextForServer (Configuration config )
243291 throws X509Exception , IOException {
244292 String keyStoreLocation = config .get (TLS_CONFIG_KEYSTORE_LOCATION , "" );
@@ -254,6 +302,7 @@ public static SslContext createSslContextForServer(Configuration config)
254302 sslContextBuilder = SslContextBuilder
255303 .forServer (createKeyManager (keyStoreLocation , keyStorePassword , keyStoreType ));
256304
305+ boolean useOpenSsl = configureOpenSslIfAvailable (sslContextBuilder , config );
257306 String trustStoreLocation = config .get (TLS_CONFIG_TRUSTSTORE_LOCATION , "" );
258307 char [] trustStorePassword = config .getPassword (TLS_CONFIG_TRUSTSTORE_PASSWORD );
259308 String trustStoreType = config .get (TLS_CONFIG_TRUSTSTORE_TYPE , "" );
@@ -277,7 +326,7 @@ public static SslContext createSslContextForServer(Configuration config)
277326
278327 sslContextBuilder .enableOcsp (sslOcspEnabled );
279328 sslContextBuilder .protocols (getEnabledProtocols (config ));
280- sslContextBuilder .ciphers (Arrays .asList (getCipherSuites (config )));
329+ sslContextBuilder .ciphers (Arrays .asList (getCipherSuites (config , useOpenSsl )));
281330 sslContextBuilder .clientAuth (clientAuth .toNettyClientAuth ());
282331
283332 return sslContextBuilder .build ();
@@ -393,10 +442,10 @@ private static String[] getEnabledProtocols(Configuration config) {
393442 return enabledProtocolsInput .split ("," );
394443 }
395444
396- private static String [] getCipherSuites (Configuration config ) {
445+ private static String [] getCipherSuites (Configuration config , boolean useOpenSsl ) {
397446 String cipherSuitesInput = config .get (TLS_CIPHER_SUITES );
398447 if (cipherSuitesInput == null ) {
399- return getDefaultCipherSuites ();
448+ return getDefaultCipherSuites (useOpenSsl );
400449 } else {
401450 return cipherSuitesInput .split ("," );
402451 }
0 commit comments