1 package org.owasp.dependencycheck.utils;
2
3 import java.io.IOException;
4 import java.net.InetAddress;
5 import java.net.Socket;
6 import java.security.KeyManagementException;
7 import java.security.NoSuchAlgorithmException;
8 import java.security.SecureRandom;
9 import java.util.ArrayList;
10 import java.util.Arrays;
11 import java.util.List;
12 import javax.net.ssl.KeyManager;
13 import javax.net.ssl.SSLContext;
14 import javax.net.ssl.SSLSocket;
15 import javax.net.ssl.SSLSocketFactory;
16 import javax.net.ssl.TrustManager;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19
20
21
22
23
24
25
26
27
28
29
30 public class SSLSocketFactoryEx extends SSLSocketFactory {
31
32
33
34
35 private static final Logger LOGGER = LoggerFactory.getLogger(SSLSocketFactoryEx.class);
36
37
38
39
40
41
42
43
44 public SSLSocketFactoryEx() throws NoSuchAlgorithmException, KeyManagementException {
45 initSSLSocketFactoryEx(null, null, null);
46 }
47
48
49
50
51
52
53
54
55
56
57
58 public SSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random) throws NoSuchAlgorithmException, KeyManagementException {
59 initSSLSocketFactoryEx(km, tm, random);
60 }
61
62
63
64
65
66
67
68
69
70 public SSLSocketFactoryEx(SSLContext ctx) throws NoSuchAlgorithmException, KeyManagementException {
71 initSSLSocketFactoryEx(ctx);
72 }
73
74
75
76
77
78
79 @Override
80 public String[] getDefaultCipherSuites() {
81 return Arrays.copyOf(ciphers, ciphers.length);
82 }
83
84
85
86
87
88
89 @Override
90 public String[] getSupportedCipherSuites() {
91 return Arrays.copyOf(ciphers, ciphers.length);
92 }
93
94
95
96
97
98
99 public String[] getDefaultProtocols() {
100 return Arrays.copyOf(protocols, protocols.length);
101 }
102
103
104
105
106
107
108 public String[] getSupportedProtocols() {
109 return Arrays.copyOf(protocols, protocols.length);
110 }
111
112
113
114
115
116
117
118
119
120
121
122 @Override
123 public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
124 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
125 final SSLSocket ss = (SSLSocket) factory.createSocket(s, host, port, autoClose);
126
127 ss.setEnabledProtocols(protocols);
128 ss.setEnabledCipherSuites(ciphers);
129
130 return ss;
131 }
132
133
134
135
136
137
138
139
140
141
142
143 @Override
144 public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
145 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
146 final SSLSocket ss = (SSLSocket) factory.createSocket(address, port, localAddress, localPort);
147
148 ss.setEnabledProtocols(protocols);
149 ss.setEnabledCipherSuites(ciphers);
150
151 return ss;
152 }
153
154
155
156
157
158
159
160
161
162
163
164 @Override
165 public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
166 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
167 final SSLSocket ss = (SSLSocket) factory.createSocket(host, port, localHost, localPort);
168
169 ss.setEnabledProtocols(protocols);
170 ss.setEnabledCipherSuites(ciphers);
171
172 return ss;
173 }
174
175
176
177
178
179
180
181
182
183 @Override
184 public Socket createSocket(InetAddress host, int port) throws IOException {
185 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
186 final SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
187
188 ss.setEnabledProtocols(protocols);
189 ss.setEnabledCipherSuites(ciphers);
190
191 return ss;
192 }
193
194
195
196
197
198
199
200
201
202 @Override
203 public Socket createSocket(String host, int port) throws IOException {
204 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
205 final SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
206
207 ss.setEnabledProtocols(protocols);
208 ss.setEnabledCipherSuites(ciphers);
209
210 return ss;
211 }
212
213
214
215
216
217
218
219
220
221
222
223 private void initSSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random)
224 throws NoSuchAlgorithmException, KeyManagementException {
225 sslCtxt = SSLContext.getInstance("TLS");
226 sslCtxt.init(km, tm, random);
227
228 protocols = getProtocolList();
229 ciphers = getCipherList();
230 }
231
232
233
234
235
236
237
238
239
240 private void initSSLSocketFactoryEx(SSLContext ctx)
241 throws NoSuchAlgorithmException, KeyManagementException {
242 sslCtxt = ctx;
243
244 protocols = getProtocolList();
245 ciphers = getCipherList();
246 }
247
248
249
250
251
252
253 protected String[] getProtocolList() {
254 final String[] preferredProtocols = {"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
255 String[] availableProtocols = null;
256
257 SSLSocket socket = null;
258
259 try {
260 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
261 socket = (SSLSocket) factory.createSocket();
262
263 availableProtocols = socket.getSupportedProtocols();
264 Arrays.sort(availableProtocols);
265 } catch (Exception ex) {
266 LOGGER.debug("Error getting protocol list, using TLSv1", ex);
267 return new String[]{"TLSv1"};
268 } finally {
269 if (socket != null) {
270 try {
271 socket.close();
272 } catch (IOException ex) {
273 LOGGER.trace("Error closing socket", ex);
274 }
275 }
276 }
277
278 final List<String> aa = new ArrayList<String>();
279 for (String preferredProtocol : preferredProtocols) {
280 final int idx = Arrays.binarySearch(availableProtocols, preferredProtocol);
281 if (idx >= 0) {
282 aa.add(preferredProtocol);
283 }
284 }
285
286 return aa.toArray(new String[0]);
287 }
288
289
290
291
292
293
294 protected String[] getCipherList() {
295 final String[] preferredCiphers = {
296
297
298
299
300
301 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
302 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
303 "TLS_ECDHE_ECDSA_WITH_CHACHA20_SHA",
304 "TLS_ECDHE_RSA_WITH_CHACHA20_SHA",
305 "TLS_DHE_RSA_WITH_CHACHA20_POLY1305",
306 "TLS_RSA_WITH_CHACHA20_POLY1305",
307 "TLS_DHE_RSA_WITH_CHACHA20_SHA",
308 "TLS_RSA_WITH_CHACHA20_SHA",
309
310 "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
311 "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
312 "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
313 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
314 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
315 "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
316 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
317 "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
318
319 "TLS_DHE_RSA_WITH_AES_256_CBC_SHA384",
320 "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
321 "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
322 "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
323 "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
324 "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
325 "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",
326 "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA",
327
328
329
330
331
332
333 "TLS_RSA_WITH_AES_256_CBC_SHA256",
334 "TLS_RSA_WITH_AES_256_CBC_SHA",
335 "TLS_RSA_WITH_AES_128_CBC_SHA256",
336 "TLS_RSA_WITH_AES_128_CBC_SHA",
337 };
338
339 String[] availableCiphers;
340
341 try {
342 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
343 availableCiphers = factory.getSupportedCipherSuites();
344 Arrays.sort(availableCiphers);
345 } catch (Exception e) {
346 LOGGER.debug("Error retrieving ciphers", e);
347 return new String[]{
348 "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
349 "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
350 "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
351 "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
352 "TLS_RSA_WITH_AES_256_CBC_SHA256",
353 "TLS_RSA_WITH_AES_256_CBC_SHA",
354 "TLS_RSA_WITH_AES_128_CBC_SHA256",
355 "TLS_RSA_WITH_AES_128_CBC_SHA",
356 "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
357 };
358 }
359
360 final List<String> aa = new ArrayList<String>();
361 for (String preferredCipher : preferredCiphers) {
362 final int idx = Arrays.binarySearch(availableCiphers, preferredCipher);
363 if (idx >= 0) {
364 aa.add(preferredCipher);
365 }
366 }
367
368 aa.add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
369
370 return aa.toArray(new String[0]);
371 }
372
373
374
375
376 private SSLContext sslCtxt;
377
378
379
380 private String[] ciphers;
381
382
383
384 private String[] protocols;
385 }