1 package org.owasp.dependencycheck.utils;
2
3 import java.io.FileInputStream;
4 import java.io.IOException;
5 import java.net.InetAddress;
6 import java.net.Socket;
7 import java.security.KeyManagementException;
8 import java.security.KeyStore;
9 import java.security.KeyStoreException;
10 import java.security.NoSuchAlgorithmException;
11 import java.security.SecureRandom;
12 import java.security.UnrecoverableKeyException;
13 import java.security.cert.CertificateException;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.List;
17 import javax.net.ssl.KeyManager;
18 import javax.net.ssl.KeyManagerFactory;
19 import javax.net.ssl.SSLContext;
20 import javax.net.ssl.SSLSocket;
21 import javax.net.ssl.SSLSocketFactory;
22 import javax.net.ssl.TrustManager;
23 import javax.net.ssl.TrustManagerFactory;
24 import org.apache.commons.lang3.StringUtils;
25
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public class SSLSocketFactoryEx extends SSLSocketFactory {
43
44
45
46
47 private static final Logger LOGGER = LoggerFactory.getLogger(SSLSocketFactoryEx.class);
48
49
50
51
52 private SSLContext sslCtxt;
53
54
55
56 private String[] protocols;
57
58
59
60 private final Settings settings;
61
62
63
64
65 private static boolean protocolsLogged = false;
66
67
68
69
70
71
72
73
74
75
76 public SSLSocketFactoryEx(Settings settings) throws NoSuchAlgorithmException, KeyManagementException {
77 this.settings = settings;
78 final KeyManager[] km = getKeyManagers();
79 final TrustManager[] tm = getTrustManagers();
80
81 initSSLSocketFactoryEx(km, tm, null);
82 }
83
84
85
86
87
88
89
90
91
92
93
94
95
96 public SSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random, Settings settings)
97 throws NoSuchAlgorithmException, KeyManagementException {
98 this.settings = settings;
99 initSSLSocketFactoryEx(km, tm, random);
100 }
101
102
103
104
105
106
107
108
109
110
111
112 public SSLSocketFactoryEx(SSLContext ctx, Settings settings) throws NoSuchAlgorithmException, KeyManagementException {
113 this.settings = settings;
114 initSSLSocketFactoryEx(ctx);
115 }
116
117
118
119
120
121
122 @Override
123 public String[] getDefaultCipherSuites() {
124 return sslCtxt.getSocketFactory().getDefaultCipherSuites();
125 }
126
127
128
129
130
131
132 @Override
133 public String[] getSupportedCipherSuites() {
134 return sslCtxt.getSocketFactory().getSupportedCipherSuites();
135 }
136
137
138
139
140
141
142 public String[] getDefaultProtocols() {
143 return Arrays.copyOf(protocols, protocols.length);
144 }
145
146
147
148
149
150
151 public String[] getSupportedProtocols() {
152 return Arrays.copyOf(protocols, protocols.length);
153 }
154
155
156
157
158
159
160 @Override
161 public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
162 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
163 final SSLSocket ss = (SSLSocket) factory.createSocket(s, host, port, autoClose);
164
165 ss.setEnabledProtocols(protocols);
166
167 return ss;
168 }
169
170
171
172
173
174
175 @Override
176 public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
177 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
178 final SSLSocket ss = (SSLSocket) factory.createSocket(address, port, localAddress, localPort);
179
180 ss.setEnabledProtocols(protocols);
181
182 return ss;
183 }
184
185
186
187
188
189
190 @Override
191 public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
192 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
193 final SSLSocket ss = (SSLSocket) factory.createSocket(host, port, localHost, localPort);
194
195 ss.setEnabledProtocols(protocols);
196
197 return ss;
198 }
199
200
201
202
203
204
205 @Override
206 public Socket createSocket(InetAddress host, int port) throws IOException {
207 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
208 final SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
209
210 ss.setEnabledProtocols(protocols);
211
212 return ss;
213 }
214
215
216
217
218
219
220 @Override
221 public Socket createSocket(String host, int port) throws IOException {
222 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
223 final SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
224
225 ss.setEnabledProtocols(protocols);
226
227 return ss;
228 }
229
230
231
232
233
234
235
236
237
238
239
240 private void initSSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random)
241 throws NoSuchAlgorithmException, KeyManagementException {
242 sslCtxt = SSLContext.getInstance("TLS");
243 sslCtxt.init(km, tm, random);
244
245 protocols = getProtocolList();
246 }
247
248
249
250
251
252
253
254
255
256 private void initSSLSocketFactoryEx(SSLContext ctx)
257 throws NoSuchAlgorithmException, KeyManagementException {
258 sslCtxt = ctx;
259 protocols = getProtocolList();
260 }
261
262
263
264
265
266
267 @SuppressWarnings("StringSplitter")
268 protected String[] getProtocolList() {
269 SSLSocket socket = null;
270 final String[] availableProtocols;
271 final String[] preferredProtocols = settings.getString(
272 Settings.KEYS.DOWNLOADER_TLS_PROTOCOL_LIST,
273 "TLSv1.1,TLSv1.2,TLSv1.3")
274 .split(",");
275 try {
276 final SSLSocketFactory factory = sslCtxt.getSocketFactory();
277 socket = (SSLSocket) factory.createSocket();
278
279 availableProtocols = socket.getSupportedProtocols();
280 Arrays.sort(availableProtocols);
281 if (LOGGER.isDebugEnabled() && !protocolsLogged) {
282 protocolsLogged = true;
283 LOGGER.debug("Available Protocols:");
284 for (String p : availableProtocols) {
285 LOGGER.debug(p);
286 }
287 }
288 } catch (Exception ex) {
289 LOGGER.debug("Error getting protocol list, using TLSv1.1-1.3", ex);
290 return new String[]{"TLSv1.1", "TLSv1.2", "TLSv1.3"};
291 } finally {
292 if (socket != null) {
293 try {
294 socket.close();
295 } catch (IOException ex) {
296 LOGGER.trace("Error closing socket", ex);
297 }
298 }
299 }
300
301 final List<String> aa = new ArrayList<>();
302 for (String preferredProtocol : preferredProtocols) {
303 final int idx = Arrays.binarySearch(availableProtocols, preferredProtocol);
304 if (idx >= 0) {
305 aa.add(preferredProtocol);
306 }
307 }
308
309 return aa.toArray(new String[0]);
310 }
311
312 private KeyManager[] getKeyManagers() {
313 KeyManager[] km = null;
314 final String ksPath = System.getProperty("javax.net.ssl.keyStore");
315 final String ksType = System.getProperty("javax.net.ssl.keyStoreType");
316 final String ksPass = System.getProperty("javax.net.ssl.keyStorePassword");
317
318 if (!StringUtils.isAnyEmpty(ksPath, ksType, ksPass)) {
319 try (FileInputStream fis = new FileInputStream(ksPath)) {
320 final KeyStore ks = KeyStore.getInstance(ksType);
321 ks.load(fis, ksPass.toCharArray());
322 final KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
323 kmf.init(ks, ksPass.toCharArray());
324 km = kmf.getKeyManagers();
325 } catch (KeyStoreException | IOException | CertificateException | UnrecoverableKeyException | NoSuchAlgorithmException ex) {
326 throw new RuntimeException(ex);
327 }
328 }
329 return km;
330 }
331
332 private TrustManager[] getTrustManagers() {
333 TrustManager[] tm = null;
334 final String ksType = System.getProperty("javax.net.ssl.keyStoreType");
335 final String tsPath = System.getProperty("javax.net.ssl.trustStore");
336 final String tsPass = System.getProperty("javax.net.ssl.trustStorePassword");
337
338 if (!StringUtils.isAnyEmpty(tsPath, ksType, tsPass)) {
339 try (FileInputStream fis = new FileInputStream(tsPath)) {
340 final KeyStore ts = KeyStore.getInstance(ksType);
341 ts.load(fis, tsPass.toCharArray());
342 final TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
343 tmf.init(ts);
344 tm = tmf.getTrustManagers();
345 } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException ex) {
346 throw new RuntimeException(ex);
347 }
348 }
349 return tm;
350 }
351 }