Skip to content

Commit

Permalink
Ban all Diffie-Hellman ciphers in Java 1.7.0_6 and higher
Browse files Browse the repository at this point in the history
Addresses an issue in SSL/TLS/GSI sessions that approximately one
out of 256 connections fail with an 'invalid padding' error. This
affects gridftp, webdav with https, httpd with https, SRM and gsidcap.
It should be noted that this significantly reduces the number of
available ciphers.

It appears that Diffie-Hellman is broken in Java 1.7.0_6 and higher. This
patch bans those ciphers if a broken version of Java is used.

The patch adds new configuration properties for configuring whether
certain cipher families are banned:

dcache.security.ciphers
webdav.security.ciphers
httpd.security.ciphers
gsidcap.security.ciphers
srm.security.ciphers
gridftp.security.ciphers

The latter are defined in terms of the first. The property names follow
the schema agreed upon at the 2013 developers workshop. The patch
introduces a new configuration property group called security. It is
intended for general security related properties like authentication,
authorization, cryptography, etc.

Target: trunk
Request: 2.6
Request: 2.2-sha2
Require-notes: yes
Require-book: no
Acked-by: Dmitry Litvintsev <litvinse@gnal.gov>
Patch: http://rb.dcache.org/r/5616/
(cherry picked from commit 4cc7e3e)
  • Loading branch information
gbehrmann committed Jun 13, 2013
1 parent a570346 commit c35a52e
Show file tree
Hide file tree
Showing 18 changed files with 323 additions and 45 deletions.
259 changes: 230 additions & 29 deletions modules/common/src/main/java/org/dcache/util/Crypto.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package org.dcache.util;

import com.google.common.primitives.Ints;

import java.util.HashSet;
import java.util.Set;

import static java.util.Arrays.asList;

/**
* Various useful cryptographic utility method
*/
public class Crypto
{
public enum CipherFlag
{
DISABLE_BROKEN_DH,
DISABLE_EC
}

/* The following is a list of cipher suites that are problematic
* with currently suported versions of Java.
*
Expand Down Expand Up @@ -64,36 +77,224 @@ public class Crypto
* The following list was generated from OpenJDK source code using
* the command:
*/

// sed -n '/add.*TLS_ECDHE/s/.*add(\([^,]*\).*/ \1,/p'
// sun/security/ssl/CipherSuite.java | sort
public static final String[] EC_CIPHERS = new String[] {
"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",
"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_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_NULL_SHA",
"TLS_ECDHE_RSA_WITH_NULL_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_PSK_WITH_RC4_128_SHA",
"TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_PSK_WITH_NULL_SHA",
"TLS_ECDHE_PSK_WITH_NULL_SHA256",
"TLS_ECDHE_PSK_WITH_NULL_SHA384"
};

/* The following is a list of cipher suites that are problematic
* with currently available Java versions from 1.7u6 and up.
*
* The problem is described here:
*
* https://forums.oracle.com/forums/thread.jspa?messageID=10875177&tstart=0
*
* The problem seems to be caused by a bug in how leading zeros are interpreted
* in Diffie-Hellman ciphers.
*
* The following list was generated from OpenJDK source code using the command:
*/
// sed -n '/add.*DH/s/.*add(\([^,]*\).*/ \1,/p' ~/Downloads/CipherSuite.java | sort
//
public static final String[] DH_CIPHERS = new String[] {
"SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_RC4_128_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA",
"SSL_DH_DSS_WITH_DES_CBC_SHA",
"SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DH_RSA_WITH_DES_CBC_SHA",
"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
"SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
"SSL_DH_anon_WITH_DES_CBC_SHA",
"SSL_DH_anon_WITH_RC4_128_MD5",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_SEED_CBC_SHA",
"TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",
"TLS_DHE_PSK_WITH_AES_128_GCM_SHA256",
"TLS_DHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",
"TLS_DHE_PSK_WITH_AES_256_GCM_SHA384",
"TLS_DHE_PSK_WITH_NULL_SHA",
"TLS_DHE_PSK_WITH_NULL_SHA256",
"TLS_DHE_PSK_WITH_NULL_SHA384",
"TLS_DHE_PSK_WITH_RC4_128_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DHE_RSA_WITH_SEED_CBC_SHA",
"TLS_DH_DSS_WITH_AES_128_CBC_SHA",
"TLS_DH_DSS_WITH_AES_128_CBC_SHA256",
"TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
"TLS_DH_DSS_WITH_AES_256_CBC_SHA",
"TLS_DH_DSS_WITH_AES_256_CBC_SHA256",
"TLS_DH_DSS_WITH_AES_256_GCM_SHA384",
"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DH_DSS_WITH_SEED_CBC_SHA",
"TLS_DH_RSA_WITH_AES_128_CBC_SHA",
"TLS_DH_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DH_RSA_WITH_AES_256_CBC_SHA",
"TLS_DH_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DH_RSA_WITH_SEED_CBC_SHA",
"TLS_DH_anon_WITH_AES_128_CBC_SHA",
"TLS_DH_anon_WITH_AES_128_CBC_SHA256",
"TLS_DH_anon_WITH_AES_128_GCM_SHA256",
"TLS_DH_anon_WITH_AES_256_CBC_SHA",
"TLS_DH_anon_WITH_AES_256_CBC_SHA256",
"TLS_DH_anon_WITH_AES_256_GCM_SHA384",
"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DH_anon_WITH_SEED_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_NULL_SHA",
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_PSK_WITH_NULL_SHA",
"TLS_ECDHE_PSK_WITH_NULL_SHA256",
"TLS_ECDHE_PSK_WITH_NULL_SHA384",
"TLS_ECDHE_PSK_WITH_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_NULL_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDH_ECDSA_WITH_NULL_SHA",
"TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDH_RSA_WITH_NULL_SHA",
"TLS_ECDH_RSA_WITH_RC4_128_SHA",
"TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
"TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
"TLS_ECDH_anon_WITH_NULL_SHA",
"TLS_ECDH_anon_WITH_RC4_128_SHA"
};

/**
* @throws IllegalArgumentException if the value could not be parsed
*/
public static String[] getBannedCipherSuitesFromConfigurationValue(String value)
{
String[] values = value.split(",");
CipherFlag[] flags = new CipherFlag[values.length];
for (int i = 0; i < values.length; i++) {
flags[i] = CipherFlag.valueOf(values[i]);
}
return getBannedCipherSuites(flags);
}

public static String[] getBannedCipherSuites(CipherFlag[] flags)
{
String version = System.getProperty("java.version");
Set<String> banned = new HashSet<>();
for (CipherFlag flag : flags) {
switch (flag) {
case DISABLE_BROKEN_DH:
if (version.startsWith("1.7.0_")) {
Integer update = Ints.tryParse(version.substring(6));
if (update != null && update > 5) {
banned.addAll(asList(DH_CIPHERS));
}
}
break;
case DISABLE_EC:
banned.addAll(asList(EC_CIPHERS));
break;
}
}
return banned.toArray(new String[banned.size()]);
}

public static final String[] BANNED_CIPHERS = {
"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",
"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_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_NULL_SHA",
"TLS_ECDHE_RSA_WITH_NULL_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_PSK_WITH_RC4_128_SHA",
"TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_PSK_WITH_NULL_SHA",
"TLS_ECDHE_PSK_WITH_NULL_SHA256",
"TLS_ECDHE_PSK_WITH_NULL_SHA384"};
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ public class GsiFtpDoorV1 extends GssFtpDoorV1
)
protected String service_trusted_certs;

@Option(
name="gridftp.security.ciphers",
required=true
)
protected String cipherFlags;

private String _user;

/** Creates a new instance of GsiFtpDoorV1 */
Expand Down Expand Up @@ -118,7 +124,7 @@ protected GSSContext getServiceContext() throws GSSException {
(ExtendedGSSContext)manager.createContext(cred);

context.setOption(GSSConstants.GSS_MODE, GSIConstants.MODE_GSI);
context.setBannedCiphers(Crypto.BANNED_CIPHERS);
context.setBannedCiphers(Crypto.getBannedCipherSuitesFromConfigurationValue(cipherFlags));

return context;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,12 @@
</property>
</bean>

<beans profile="connector-http">
<bean id="banned-ciphers" class="org.dcache.util.Crypto"
factory-method="getBannedCipherSuitesFromConfigurationValue">
<constructor-arg value="${webdav.security.ciphers}"/>
</bean>

<beans profile="connector-http">
<bean id="protocol-family" class="java.lang.String">
<description>http</description>
<constructor-arg type="String" value="http"/>
Expand Down Expand Up @@ -248,7 +253,6 @@
</beans>



<beans profile="connector-https">
<bean id="https-connector"
class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector">
Expand All @@ -263,9 +267,7 @@
<property name="trustPassword" value="${webdavTrustStorePassword}"/>
<property name="wantClientAuth" value="${webdavWantClientAuth}"/>
<property name="needClientAuth" value="${webdavNeedClientAuth}"/>
<property name="excludeCipherSuites">
<util:constant static-field="org.dcache.util.Crypto.BANNED_CIPHERS"/>
</property>
<property name="excludeCipherSuites" ref="banned-ciphers"/>
</bean>
</beans>

Expand All @@ -290,6 +292,7 @@
value="#{ ${hostCertificateRefreshPeriod} * 1000 }"/>
<property name="millisecBetweenTrustAnchorRefresh"
value="#{ ${trustAnchorRefreshPeriod} * 1000 }"/>
<property name="excludeCipherSuites" ref="banned-ciphers"/>
</bean>
</beans>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ public class HttpServiceCell extends AbstractCell implements EnvironmentAware {
description = "Password for accessing trusted CA certs")
protected String trustPassword;

@Option(name = "httpd.security.ciphers",
description = "Cipher flags")
protected String cipherFlags;

private Server server;
private String defaultWebappsXml;
private volatile Map<String, Object> environment = Collections.emptyMap();
Expand Down Expand Up @@ -251,7 +255,7 @@ private Connector createSslConnector() {
final SslSelectChannelConnector connector = new SslSelectChannelConnector();
connector.setPort(httpsPort);
connector.setHost(IPV4_INETADDR_ANY);
connector.setExcludeCipherSuites(Crypto.BANNED_CIPHERS);
connector.setExcludeCipherSuites(Crypto.getBannedCipherSuitesFromConfigurationValue(cipherFlags));
final SslContextFactory factory = connector.getSslContextFactory();
factory.setKeyStorePath(keystore);
factory.setKeyStoreType(keystoreType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

import org.dcache.commons.util.NDC;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.dcache.util.Files.checkDirectory;
import static org.dcache.util.Files.checkFile;
import static org.globus.axis.gsi.GSIConstants.*;
Expand Down Expand Up @@ -92,6 +93,7 @@ public class JettyGSIConnector
private volatile boolean _rejectLimitedProxy = false;
private volatile Integer _mode = GSIConstants.MODE_SSL;
private volatile int _handshakeTimeout = 0; // 0 means use maxIdleTime
private String[] _excludedCipherSuites = {};

/**
* Assing default values to the certificate refresh intervals
Expand Down Expand Up @@ -289,6 +291,11 @@ public void setHandshakeTimeout (int msec)
_handshakeTimeout = msec;
}

public void setExcludeCipherSuites(String[] cipherSuites)
{
_excludedCipherSuites = checkNotNull(cipherSuites);
}

protected ExtendedGSSContext createGSSContext()
throws GSSException
{
Expand All @@ -309,7 +316,7 @@ protected ExtendedGSSContext createGSSContext()
// _trustedCerts);
// }

context.setBannedCiphers(Crypto.BANNED_CIPHERS);
context.setBannedCiphers(_excludedCipherSuites);
context.requestConf(_encrypt);
return context;
}
Expand Down
Loading

0 comments on commit c35a52e

Please sign in to comment.