private CipherTest(PeerFactory peerFactory) throws IOException { THREADS = Integer.parseInt(System.getProperty("numThreads", "4")); factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket socket = (SSLSocket) factory.createSocket(); String[] cipherSuites = socket.getSupportedCipherSuites(); String[] protocols = socket.getSupportedProtocols(); // String[] clientAuths = {null, "RSA", "DSA"}; String[] clientAuths = {null}; tests = new ArrayList<TestParameters>(cipherSuites.length * protocols.length * clientAuths.length); for (int i = 0; i < cipherSuites.length; i++) { String cipherSuite = cipherSuites[i]; for (int j = 0; j < protocols.length; j++) { String protocol = protocols[j]; if (!peerFactory.isSupported(cipherSuite, protocol)) { continue; } for (int k = 0; k < clientAuths.length; k++) { String clientAuth = clientAuths[k]; if ((clientAuth != null) && (cipherSuite.indexOf("DH_anon") != -1)) { // no client with anonymous ciphersuites continue; } tests.add(new TestParameters(cipherSuite, protocol, clientAuth)); } } } testIterator = tests.iterator(); }
@Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0); SSLSocket ssl = (SSLSocket) sslSocketFactory.createSocket(InetAddress.getByName(host), port); // enable TLSv1.1/1.2 if available // (see https://github.com/rfc2822/davdroid/issues/229) ssl.setEnabledProtocols(ssl.getSupportedProtocols()); // set up SNI before the handshake if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { Log.i("SNISocketFactory", "Setting SNI hostname"); sslSocketFactory.setHostname(ssl, host); } else { Log.d( "SNISocketFactory", "No documented SNI support on Android <4.2, trying with reflection"); try { java.lang.reflect.Method setHostnameMethod = ssl.getClass().getMethod("setHostname", String.class); setHostnameMethod.invoke(ssl, host); } catch (Exception e) { Log.w("SNISocketFactory", "SNI not useable", e); } } return ssl; }
/** * Updates the provided socket to apply the appropriate set of enabled SSL protocols. This will * only have any effect for sockets that are instances of {@code javax.net.ssl.SSLSocket}, but it * is safe to call for any kind of {@code java.net.Socket}. This should be called before * attempting any communication over the socket, as * * @param socket The socket on which to apply the configured set of enabled SSL protocols. * @param protocols The set of protocols that should be enabled for the socket, if available. * @throws IOException If {@link #getEnabledSSLProtocols} returns a non-empty set but none of the * values in that set are supported by the socket. */ static void applyEnabledSSLProtocols(final Socket socket, final Set<String> protocols) throws IOException { if ((socket == null) || (!(socket instanceof SSLSocket)) || protocols.isEmpty()) { return; } final Set<String> lowerProtocols = new HashSet<String>(protocols.size()); for (final String s : protocols) { lowerProtocols.add(StaticUtils.toLowerCase(s)); } final SSLSocket sslSocket = (SSLSocket) socket; final String[] supportedProtocols = sslSocket.getSupportedProtocols(); final ArrayList<String> enabledList = new ArrayList<String>(supportedProtocols.length); for (final String supportedProtocol : supportedProtocols) { if (lowerProtocols.contains(StaticUtils.toLowerCase(supportedProtocol))) { enabledList.add(supportedProtocol); } } if (enabledList.isEmpty()) { final StringBuilder enabledBuffer = new StringBuilder(); final Iterator<String> enabledIterator = protocols.iterator(); while (enabledIterator.hasNext()) { enabledBuffer.append('\''); enabledBuffer.append(enabledIterator.next()); enabledBuffer.append('\''); if (enabledIterator.hasNext()) { enabledBuffer.append(", "); } } final StringBuilder supportedBuffer = new StringBuilder(); for (int i = 0; i < supportedProtocols.length; i++) { if (i > 0) { supportedBuffer.append(", "); } supportedBuffer.append('\''); supportedBuffer.append(supportedProtocols[i]); supportedBuffer.append('\''); } throw new IOException( ERR_NO_ENABLED_SSL_PROTOCOLS_AVAILABLE_FOR_SOCKET.get( enabledBuffer.toString(), supportedBuffer.toString(), PROPERTY_ENABLED_SSL_PROTOCOLS, SSLUtil.class.getName() + ".setEnabledSSLProtocols")); } else { final String[] enabledArray = new String[enabledList.size()]; sslSocket.setEnabledProtocols(enabledList.toArray(enabledArray)); } }
/** Inits supported and enabled protocol versions. */ private void initSupportedProtocols() { try { SSLSocket ssl_socket = (SSLSocket) ssl_factory.createSocket(); if (supported_protocols == null) supported_protocols = ssl_socket.getSupportedProtocols(); if (enabled_protocols == null) enabled_protocols = ssl_socket.getEnabledProtocols(); ssl_socket.close(); } catch (Exception e) { e.printStackTrace(); } }
protected CamelContext createPropertiesPlaceholderAwareContext() throws Exception { Properties supplementalProperties = new Properties(); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); SecureRandom sr = null; try { sr = SecureRandom.getInstance("SHA1PRNG"); } catch (NoSuchAlgorithmException e) { // Ignore } SSLContext sslc = SSLContext.getInstance("TLS"); sslc.init(null, null, null); SSLSocket socket = (SSLSocket) sslc.getSocketFactory().createSocket(); supplementalProperties.setProperty("keyStoreParameters.type", KeyStore.getDefaultType()); supplementalProperties.setProperty("keyStoreParameters.provider", ks.getProvider().getName()); supplementalProperties.setProperty( "keyManagersParameters.algorithm", KeyManagerFactory.getDefaultAlgorithm()); supplementalProperties.setProperty( "keyManagersParameters.provider", kmf.getProvider().getName()); supplementalProperties.setProperty( "trustManagersParameters.algorithm", TrustManagerFactory.getDefaultAlgorithm()); supplementalProperties.setProperty( "trustManagersParameters.provider", tmf.getProvider().getName()); if (sr != null) { supplementalProperties.setProperty("secureRandomParameters.algorithm", "SHA1PRNG"); supplementalProperties.setProperty( "secureRandomParameters.provider", sr.getProvider().getName()); } supplementalProperties.setProperty( "sslContextParameters.provider", sslc.getProvider().getName()); supplementalProperties.setProperty("cipherSuite.0", socket.getSupportedCipherSuites()[0]); // Have to skip this guy because he doesn't work with TLS as the SSLContext protocol String ssp = ""; for (String protocol : socket.getSupportedProtocols()) { if (!"SSLv2Hello".equals(protocol)) { ssp = protocol; break; } } supplementalProperties.setProperty("secureSocketProtocol.0", ssp); return this.createPropertiesPlaceholderAwareContext(supplementalProperties); }
@Override public Socket createSocket(Socket plainSocket, String host, int port, boolean autoClose) throws IOException { String peerHost = this.conn.getRequestProperty("Host"); if (peerHost == null) peerHost = host; Log.i(TAG, "customized createSocket. host: " + peerHost); InetAddress address = plainSocket.getInetAddress(); if (autoClose) { // we don't need the plainSocket plainSocket.close(); } // create and connect SSL socket, but don't do hostname/certificate verification yet SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0); SSLSocket ssl = (SSLSocket) sslSocketFactory.createSocket(address, port); // enable TLSv1.1/1.2 if available ssl.setEnabledProtocols(ssl.getSupportedProtocols()); // set up SNI before the handshake if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { Log.i(TAG, "Setting SNI hostname"); sslSocketFactory.setHostname(ssl, peerHost); } else { Log.d(TAG, "No documented SNI support on Android <4.2, trying with reflection"); try { java.lang.reflect.Method setHostnameMethod = ssl.getClass().getMethod("setHostname", String.class); setHostnameMethod.invoke(ssl, peerHost); } catch (Exception e) { Log.w(TAG, "SNI not useable", e); } } // verify hostname and certificate SSLSession session = ssl.getSession(); if (!hostnameVerifier.verify(peerHost, session)) throw new SSLPeerUnverifiedException("Cannot verify hostname: " + peerHost); Log.i( TAG, "Established " + session.getProtocol() + " connection with " + session.getPeerHost() + " using " + session.getCipherSuite()); return ssl; }
/** {@inheritDoc} Used to enforce the preferred TLS protocol during SSL handshake. */ @Override protected final void prepareSocket(final SSLSocket socket) { String[] supported = socket.getSupportedProtocols(); String[] enabled = socket.getEnabledProtocols(); if (LOG.isDebugEnabled()) { LOG.debug( "socket.getSupportedProtocols(): " + Arrays.toString(supported) + ", socket.getEnabledProtocols(): " + Arrays.toString(enabled)); } List<String> target = new ArrayList<String>(); if (supported != null) { // Append the preferred protocols in descending order of preference // but only do so if the protocols are supported TLSProtocol[] values = TLSProtocol.values(); for (int i = 0; i < values.length; i++) { final String pname = values[i].getProtocolName(); if (existsIn(pname, supported)) { target.add(pname); } } } if (enabled != null) { // Append the rest of the already enabled protocols to the end // if not already included in the list for (String pname : enabled) { if (!target.contains(pname)) { target.add(pname); } } } if (target.size() > 0) { String[] enabling = target.toArray(new String[target.size()]); socket.setEnabledProtocols(enabling); if (LOG.isDebugEnabled()) { LOG.debug("TLS protocol enabled for SSL handshake: " + Arrays.toString(enabling)); } } }
@SuppressLint("NewApi") private Socket enableSNI(SSLSocket ssl, String host) throws SSLPeerUnverifiedException { // enable TLSv1.1/1.2 if available // (see https://github.com/rfc2822/davdroid/issues/229) ssl.setEnabledProtocols(ssl.getSupportedProtocols()); // set up SNI before the handshake if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { AppLog.i(T.API, "Setting SNI hostname"); mFactory.setHostname(ssl, host); } else { AppLog.i(T.API, "No documented SNI support on Android <4.2, trying with reflection"); try { java.lang.reflect.Method setHostnameMethod = ssl.getClass().getMethod("setHostname", String.class); setHostnameMethod.invoke(ssl, host); } catch (Exception e) { AppLog.e(T.API, "SNI not useable", e); } } // verify hostname and certificate SSLSession session = ssl.getSession(); if (!mHostnameVerifier.verify(host, session)) { throw new SSLPeerUnverifiedException("Cannot verify hostname: " + host); } AppLog.i( T.API, "Established " + session.getProtocol() + " connection with " + session.getPeerHost() + " using " + session.getCipherSuite()); return ssl; }
/** * Prepares a TLS/SSL connection socket by: - setting reasonable TLS protocol versions - setting * reasonable cipher suites (if required) * * @param socket unconnected SSLSocket to prepare */ private void setTlsParameters(SSLSocket socket) { // Android 5.0+ (API level21) provides reasonable default settings // but it still allows SSLv3 // https://developer.android.com/about/versions/android-5.0-changes.html#ssl /* set reasonable protocol versions */ // - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0) // - remove all SSL versions (especially SSLv3) because they're insecure now final List<String> protocols = new LinkedList<String>(); for (String protocol : socket.getSupportedProtocols()) { if (!protocol.toUpperCase().contains("SSL")) { protocols.add(protocol); } } Log.v(TAG, "Setting allowed TLS protocols: " + TextUtils.join(", ", protocols)); socket.setEnabledProtocols(protocols.toArray(new String[protocols.size()])); /* set reasonable cipher suites */ if (Build.VERSION.SDK_INT < VERSION_CODES_LOLLIPOP) { // choose secure cipher suites final List<String> availableCiphers = Arrays.asList(socket.getSupportedCipherSuites()); // preferred ciphers = allowed Ciphers \ availableCiphers final Set<String> preferredCiphers = new HashSet<String>(ALLOWED_CIPHERS); preferredCiphers.retainAll(availableCiphers); // add enabled ciphers to preferred ciphers // for maximum security, preferred ciphers should *replace* enabled ciphers, // but for the security level of ACRA, disabling of insecure // ciphers should be a server-side task preferredCiphers.addAll(Arrays.asList(socket.getEnabledCipherSuites())); Log.v(TAG, "Setting allowed TLS ciphers: " + TextUtils.join(", ", preferredCiphers)); socket.setEnabledCipherSuites(preferredCiphers.toArray(new String[preferredCiphers.size()])); } }
public String[] getSupportedProtocols() { return delegate.getSupportedProtocols(); }