Coverage Report - org.owasp.dependencycheck.utils.SSLSocketFactoryEx
 
Classes in this File Line Coverage Branch Coverage Complexity
SSLSocketFactoryEx
0%
0/84
0%
0/10
1.625
 
 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  
  * This class is used to enable additional ciphers used by the SSL Socket. This
 22  
  * is specifically because the NVD stopped supporting TLS 1.0 and Java 6 and 7
 23  
  * clients by default were unable to connect to download the NVD data feeds.
 24  
  *
 25  
  * The following code was copied from
 26  
  * http://stackoverflow.com/questions/1037590/which-cipher-suites-to-enable-for-ssl-socket/23365536#23365536
 27  
  *
 28  
  * @author <a href="http://stackoverflow.com/users/608639/jww">jww</a>
 29  
  */
 30  
 public class SSLSocketFactoryEx extends SSLSocketFactory {
 31  
 
 32  
     /**
 33  
      * The Logger for use throughout the class.
 34  
      */
 35  0
     private static final Logger LOGGER = LoggerFactory.getLogger(SSLSocketFactoryEx.class);
 36  
 
 37  
     /**
 38  
      * Constructs a new SSLSocketFactory.
 39  
      *
 40  
      * @throws NoSuchAlgorithmException thrown when an algorithm is not
 41  
      * supported
 42  
      * @throws KeyManagementException thrown if initialization fails
 43  
      */
 44  0
     public SSLSocketFactoryEx() throws NoSuchAlgorithmException, KeyManagementException {
 45  0
         initSSLSocketFactoryEx(null, null, null);
 46  0
     }
 47  
 
 48  
     /**
 49  
      * Constructs a new SSLSocketFactory.
 50  
      *
 51  
      * @param km the key manager
 52  
      * @param tm the trust manager
 53  
      * @param random secure random
 54  
      * @throws NoSuchAlgorithmException thrown when an algorithm is not
 55  
      * supported
 56  
      * @throws KeyManagementException thrown if initialization fails
 57  
      */
 58  0
     public SSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random) throws NoSuchAlgorithmException, KeyManagementException {
 59  0
         initSSLSocketFactoryEx(km, tm, random);
 60  0
     }
 61  
 
 62  
     /**
 63  
      * Constructs a new SSLSocketFactory.
 64  
      *
 65  
      * @param ctx the SSL context
 66  
      * @throws NoSuchAlgorithmException thrown when an algorithm is not
 67  
      * supported
 68  
      * @throws KeyManagementException thrown if initialization fails
 69  
      */
 70  0
     public SSLSocketFactoryEx(SSLContext ctx) throws NoSuchAlgorithmException, KeyManagementException {
 71  0
         initSSLSocketFactoryEx(ctx);
 72  0
     }
 73  
 
 74  
     /**
 75  
      * Returns the default cipher suites.
 76  
      *
 77  
      * @return the default cipher suites
 78  
      */
 79  
     @Override
 80  
     public String[] getDefaultCipherSuites() {
 81  0
         return Arrays.copyOf(ciphers, ciphers.length);
 82  
     }
 83  
 
 84  
     /**
 85  
      * Returns the supported cipher suites.
 86  
      *
 87  
      * @return the supported cipher suites
 88  
      */
 89  
     @Override
 90  
     public String[] getSupportedCipherSuites() {
 91  0
         return Arrays.copyOf(ciphers, ciphers.length);
 92  
     }
 93  
 
 94  
     /**
 95  
      * Returns the default protocols.
 96  
      *
 97  
      * @return the default protocols
 98  
      */
 99  
     public String[] getDefaultProtocols() {
 100  0
         return Arrays.copyOf(protocols, protocols.length);
 101  
     }
 102  
 
 103  
     /**
 104  
      * Returns the supported protocols.
 105  
      *
 106  
      * @return the supported protocols
 107  
      */
 108  
     public String[] getSupportedProtocols() {
 109  0
         return Arrays.copyOf(protocols, protocols.length);
 110  
     }
 111  
 
 112  
     /**
 113  
      * Creates an SSL Socket.
 114  
      *
 115  
      * @param s the base socket
 116  
      * @param host the host
 117  
      * @param port the port
 118  
      * @param autoClose if the socket should auto-close
 119  
      * @return the SSL Socket
 120  
      * @throws IOException thrown if the creation fails
 121  
      */
 122  
     @Override
 123  
     public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
 124  0
         final SSLSocketFactory factory = sslCtxt.getSocketFactory();
 125  0
         final SSLSocket ss = (SSLSocket) factory.createSocket(s, host, port, autoClose);
 126  
 
 127  0
         ss.setEnabledProtocols(protocols);
 128  0
         ss.setEnabledCipherSuites(ciphers);
 129  
 
 130  0
         return ss;
 131  
     }
 132  
 
 133  
     /**
 134  
      * Creates a new SSL Socket.
 135  
      *
 136  
      * @param address the address to connect to
 137  
      * @param port the port number
 138  
      * @param localAddress the local address
 139  
      * @param localPort the local port
 140  
      * @return the SSL Socket
 141  
      * @throws IOException thrown if the creation fails
 142  
      */
 143  
     @Override
 144  
     public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
 145  0
         final SSLSocketFactory factory = sslCtxt.getSocketFactory();
 146  0
         final SSLSocket ss = (SSLSocket) factory.createSocket(address, port, localAddress, localPort);
 147  
 
 148  0
         ss.setEnabledProtocols(protocols);
 149  0
         ss.setEnabledCipherSuites(ciphers);
 150  
 
 151  0
         return ss;
 152  
     }
 153  
 
 154  
     /**
 155  
      * Creates a new SSL Socket.
 156  
      *
 157  
      * @param host the host to connect to
 158  
      * @param port the port to connect to
 159  
      * @param localHost the local host
 160  
      * @param localPort the local port
 161  
      * @return the SSL Socket
 162  
      * @throws IOException thrown if the creation fails
 163  
      */
 164  
     @Override
 165  
     public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
 166  0
         final SSLSocketFactory factory = sslCtxt.getSocketFactory();
 167  0
         final SSLSocket ss = (SSLSocket) factory.createSocket(host, port, localHost, localPort);
 168  
 
 169  0
         ss.setEnabledProtocols(protocols);
 170  0
         ss.setEnabledCipherSuites(ciphers);
 171  
 
 172  0
         return ss;
 173  
     }
 174  
 
 175  
     /**
 176  
      * Creates a new SSL Socket.
 177  
      *
 178  
      * @param host the host to connect to
 179  
      * @param port the port to connect to
 180  
      * @return the SSL Socket
 181  
      * @throws IOException thrown if the creation fails
 182  
      */
 183  
     @Override
 184  
     public Socket createSocket(InetAddress host, int port) throws IOException {
 185  0
         final SSLSocketFactory factory = sslCtxt.getSocketFactory();
 186  0
         final SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
 187  
 
 188  0
         ss.setEnabledProtocols(protocols);
 189  0
         ss.setEnabledCipherSuites(ciphers);
 190  
 
 191  0
         return ss;
 192  
     }
 193  
 
 194  
     /**
 195  
      * Creates a new SSL Socket.
 196  
      *
 197  
      * @param host the host to connect to
 198  
      * @param port the port to connect to
 199  
      * @return the SSL Socket
 200  
      * @throws IOException thrown if the creation fails
 201  
      */
 202  
     @Override
 203  
     public Socket createSocket(String host, int port) throws IOException {
 204  0
         final SSLSocketFactory factory = sslCtxt.getSocketFactory();
 205  0
         final SSLSocket ss = (SSLSocket) factory.createSocket(host, port);
 206  
 
 207  0
         ss.setEnabledProtocols(protocols);
 208  0
         ss.setEnabledCipherSuites(ciphers);
 209  
 
 210  0
         return ss;
 211  
     }
 212  
 
 213  
     /**
 214  
      * Initializes the SSL Socket Factory Extension.
 215  
      *
 216  
      * @param km the key managers
 217  
      * @param tm the trust managers
 218  
      * @param random the secure random number generator
 219  
      * @throws NoSuchAlgorithmException thrown when an algorithm is not
 220  
      * supported
 221  
      * @throws KeyManagementException thrown if initialization fails
 222  
      */
 223  
     private void initSSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random)
 224  
             throws NoSuchAlgorithmException, KeyManagementException {
 225  0
         sslCtxt = SSLContext.getInstance("TLS");
 226  0
         sslCtxt.init(km, tm, random);
 227  
 
 228  0
         protocols = getProtocolList();
 229  0
         ciphers = getCipherList();
 230  0
     }
 231  
 
 232  
     /**
 233  
      * Initializes the SSL Socket Factory Extension.
 234  
      *
 235  
      * @param ctx the SSL context
 236  
      * @throws NoSuchAlgorithmException thrown when an algorithm is not
 237  
      * supported
 238  
      * @throws KeyManagementException thrown if initialization fails
 239  
      */
 240  
     private void initSSLSocketFactoryEx(SSLContext ctx)
 241  
             throws NoSuchAlgorithmException, KeyManagementException {
 242  0
         sslCtxt = ctx;
 243  
 
 244  0
         protocols = getProtocolList();
 245  0
         ciphers = getCipherList();
 246  0
     }
 247  
 
 248  
     /**
 249  
      * Returns the protocol list.
 250  
      *
 251  
      * @return the protocol list
 252  
      */
 253  
     protected String[] getProtocolList() {
 254  0
         final String[] preferredProtocols = {"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
 255  0
         String[] availableProtocols = null;
 256  
 
 257  0
         SSLSocket socket = null;
 258  
 
 259  
         try {
 260  0
             final SSLSocketFactory factory = sslCtxt.getSocketFactory();
 261  0
             socket = (SSLSocket) factory.createSocket();
 262  
 
 263  0
             availableProtocols = socket.getSupportedProtocols();
 264  0
             Arrays.sort(availableProtocols);
 265  0
         } catch (Exception ex) {
 266  0
             LOGGER.debug("Error getting protocol list, using TLSv1", ex);
 267  0
             return new String[]{"TLSv1"};
 268  
         } finally {
 269  0
             if (socket != null) {
 270  
                 try {
 271  0
                     socket.close();
 272  0
                 } catch (IOException ex) {
 273  0
                     LOGGER.trace("Error closing socket", ex);
 274  0
                 }
 275  
             }
 276  
         }
 277  
 
 278  0
         final List<String> aa = new ArrayList<String>();
 279  0
         for (String preferredProtocol : preferredProtocols) {
 280  0
             final int idx = Arrays.binarySearch(availableProtocols, preferredProtocol);
 281  0
             if (idx >= 0) {
 282  0
                 aa.add(preferredProtocol);
 283  
             }
 284  
         }
 285  
 
 286  0
         return aa.toArray(new String[0]);
 287  
     }
 288  
 
 289  
     /**
 290  
      * Returns the cipher list.
 291  
      *
 292  
      * @return the cipher list
 293  
      */
 294  
     protected String[] getCipherList() {
 295  0
         final String[] preferredCiphers = {
 296  
             // *_CHACHA20_POLY1305 are 3x to 4x faster than existing cipher suites.
 297  
             //   http://googleonlinesecurity.blogspot.com/2014/04/speeding-up-and-strengthening-https.html
 298  
             // Use them if available. Normative names can be found at (TLS spec depends on IPSec spec):
 299  
             //   http://tools.ietf.org/html/draft-nir-ipsecme-chacha20-poly1305-01
 300  
             //   http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-02
 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  
             // Done with bleeding edge, back to TLS v1.2 and below
 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  
             // TLS v1.0 (with some SSLv3 interop)
 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  
             // RSA key transport sucks, but they are needed as a fallback.
 328  
             // For example, microsoft.com fails under all versions of TLS
 329  
             // if they are not included. If only TLS 1.0 is available at
 330  
             // the client, then google.com will fail too. TLS v1.3 is
 331  
             // trying to deprecate them, so it will be interesteng to see
 332  
             // what happens.
 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  0
             final SSLSocketFactory factory = sslCtxt.getSocketFactory();
 343  0
             availableCiphers = factory.getSupportedCipherSuites();
 344  0
             Arrays.sort(availableCiphers);
 345  0
         } catch (Exception e) {
 346  0
             LOGGER.debug("Error retrieving ciphers", e);
 347  0
             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  0
         }
 359  
 
 360  0
         final List<String> aa = new ArrayList<String>();
 361  0
         for (String preferredCipher : preferredCiphers) {
 362  0
             final int idx = Arrays.binarySearch(availableCiphers, preferredCipher);
 363  0
             if (idx >= 0) {
 364  0
                 aa.add(preferredCipher);
 365  
             }
 366  
         }
 367  
 
 368  0
         aa.add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
 369  
 
 370  0
         return aa.toArray(new String[0]);
 371  
     }
 372  
 
 373  
     /**
 374  
      * The SSL context.
 375  
      */
 376  
     private SSLContext sslCtxt;
 377  
     /**
 378  
      * The cipher suites.
 379  
      */
 380  
     private String[] ciphers;
 381  
     /**
 382  
      * The protocols.
 383  
      */
 384  
     private String[] protocols;
 385  
 }