33
33
import java .security .Security ;
34
34
import java .security .cert .PKIXBuilderParameters ;
35
35
import java .security .cert .X509CertSelector ;
36
+ import java .util .ArrayList ;
37
+ import java .util .Arrays ;
38
+ import java .util .List ;
36
39
import java .util .Objects ;
37
40
import java .util .concurrent .atomic .AtomicReference ;
38
41
import java .util .function .Supplier ;
42
+ import java .util .stream .Collectors ;
39
43
import javax .net .ssl .CertPathTrustManagerParameters ;
40
44
import javax .net .ssl .KeyManager ;
41
45
import javax .net .ssl .KeyManagerFactory ;
42
46
import javax .net .ssl .SSLContext ;
43
47
import javax .net .ssl .SSLServerSocket ;
48
+ import javax .net .ssl .SSLServerSocketFactory ;
44
49
import javax .net .ssl .SSLSocket ;
45
50
import javax .net .ssl .TrustManager ;
46
51
import javax .net .ssl .TrustManagerFactory ;
@@ -69,6 +74,9 @@ public abstract class X509Util implements Closeable, AutoCloseable {
69
74
70
75
private static final String REJECT_CLIENT_RENEGOTIATION_PROPERTY = "jdk.tls.rejectClientInitiatedRenegotiation" ;
71
76
private static final String FIPS_MODE_PROPERTY = "zookeeper.fips-mode" ;
77
+ public static final String TLS_1_1 = "TLSv1.1" ;
78
+ public static final String TLS_1_2 = "TLSv1.2" ;
79
+ public static final String TLS_1_3 = "TLSv1.3" ;
72
80
73
81
static {
74
82
// Client-initiated renegotiation in TLS is unsafe and
@@ -82,7 +90,32 @@ public abstract class X509Util implements Closeable, AutoCloseable {
82
90
}
83
91
}
84
92
85
- public static final String DEFAULT_PROTOCOL = "TLSv1.2" ;
93
+ public static final String DEFAULT_PROTOCOL = defaultTlsProtocol ();
94
+
95
+ /**
96
+ * Return TLSv1.3 or TLSv1.2 depending on Java runtime version being used.
97
+ * TLSv1.3 was first introduced in JDK11 and back-ported to OpenJDK 8u272.
98
+ */
99
+ private static String defaultTlsProtocol () {
100
+ String defaultProtocol = TLS_1_2 ;
101
+ List <String > supported = new ArrayList <>();
102
+ try {
103
+ supported = Arrays .asList (SSLContext .getDefault ().getSupportedSSLParameters ().getProtocols ());
104
+ if (supported .contains (TLS_1_3 )) {
105
+ defaultProtocol = TLS_1_3 ;
106
+ }
107
+ } catch (NoSuchAlgorithmException e ) {
108
+ // Ignore.
109
+ }
110
+ LOG .info ("Default TLS protocol is {}, supported TLS protocols are {}" , defaultProtocol , supported );
111
+ return defaultProtocol ;
112
+ }
113
+
114
+ // ChaCha20 was introduced in OpenJDK 11.0.15 and it is not supported by JDK8.
115
+ private static String [] getTLSv13Ciphers () {
116
+ return new String []{"TLS_AES_256_GCM_SHA384" , "TLS_AES_128_GCM_SHA256" , "TLS_CHACHA20_POLY1305_SHA256" };
117
+ }
118
+
86
119
private static String [] getGCMCiphers () {
87
120
return new String []{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" , "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" , "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" , "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" };
88
121
}
@@ -91,18 +124,22 @@ private static String[] getCBCCiphers() {
91
124
return new String []{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" , "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" , "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" , "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" , "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384" , "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" , "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" , "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" };
92
125
}
93
126
94
- private static String [] concatArrays (String [] left , String [] right ) {
95
- String [] result = new String [left .length + right .length ];
96
- System .arraycopy (left , 0 , result , 0 , left .length );
97
- System .arraycopy (right , 0 , result , left .length , right .length );
98
- return result ;
127
+ /**
128
+ * Returns a filtered set of ciphers, where ciphers not supported by the JDK are removed.
129
+ */
130
+ private static String [] getSupportedCiphers (String []... cipherLists ) {
131
+ List <String > supported = Arrays .asList (
132
+ ((SSLServerSocketFactory ) SSLServerSocketFactory .getDefault ()).getSupportedCipherSuites ());
133
+
134
+ return Arrays .stream (cipherLists ).flatMap (Arrays ::stream ).filter (supported ::contains ).collect (Collectors .toList ()).toArray (new String [0 ]);
99
135
}
100
136
101
137
// On Java 8, prefer CBC ciphers since AES-NI support is lacking and GCM is slower than CBC.
102
- private static final String [] DEFAULT_CIPHERS_JAVA8 = concatArrays (getCBCCiphers (), getGCMCiphers ());
138
+ private static final String [] DEFAULT_CIPHERS_JAVA8 = getSupportedCiphers (getCBCCiphers (), getGCMCiphers (), getTLSv13Ciphers ());
103
139
// On Java 9 and later, prefer GCM ciphers due to improved AES-NI support.
104
140
// Note that this performance assumption might not hold true for architectures other than x86_64.
105
- private static final String [] DEFAULT_CIPHERS_JAVA9 = concatArrays (getGCMCiphers (), getCBCCiphers ());
141
+ // TLSv1.3 ciphers can be added at the end of the list without impacting the priority of TLSv1.3 vs TLSv1.2.
142
+ private static final String [] DEFAULT_CIPHERS_JAVA9 = getSupportedCiphers (getGCMCiphers (), getCBCCiphers (), getTLSv13Ciphers ());
106
143
107
144
public static final int DEFAULT_HANDSHAKE_DETECTION_TIMEOUT_MILLIS = 5000 ;
108
145
0 commit comments