jetty / jetty.project

Eclipse Jetty® - Web Container & Clients - supports HTTP/2, HTTP/1.1, HTTP/1.0, websocket, servlets, and more
https://eclipse.dev/jetty
Other
3.86k stars 1.91k forks source link

IBM J9 JVM does not use RFC Cipher Suite Names, making default Excluded Cipher Suite list invalid #2921

Closed ibmmqmet closed 4 years ago

ibmmqmet commented 6 years ago

Issue #2807 added an exclusion for all CipherSuites beginning "SSL_". The IBM security provider still uses that pattern for newer TLS CipherSuites - for historic reasons the ciphersuite names are different than the Oracle/OpenJDK names.

For example, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 is known, like it or not, in the IBM security provider (which may be being used inside a non-IBM JRE) as SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256.

The change has basically removed ALL CipherSuites from being valid. While it's possible to override the default exclusion lists, I don't want to have to maintain that in separate code forever.

Excluding SSLRSA* to match what's done with the TLS_RSA exclusion may be OK.

joakime commented 6 years ago

We support the RFC Cipher Suite names only.

As I recall, IBM had (at one point in the past) a JVM command line option to use the RFC Cipher Suite names for their running JVMs.

joakime commented 6 years ago

The TLS RFCs and the registered names for the Cipher Suites with the IANA are well known.

https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4

When looking at the OpenJDK behaviors specifically, they follow the RFC naming for all TLS Cipher Suites. The presence of Cipher Suites names in OpenJDK that have the "SSL" prefix are not IANA registered RFC Cipher Suites and have historically been present only for older protocols (SSLv3, TLS/1.0, etc) on OpenJDK. Our exclusion of `^SSL.*$` is to comply with our stated goal of being up to date with industry practices of not allowing use of vulnerable Cipher Suites.

Our default exclusion list solves for the overwhelming majority of Jetty users, and can be changed for those users that want other behavior. (such as choosing to make themselves more vulnerable in order to support very old clients).

One technique we've started to see in the wild with users of embedded-jetty is ...

SslContextFactory factory = new SslContextFactory();
String[] excludedCiphersWithoutTlsRsaExclusion = Arrays.stream(factory.getExcludeCipherSuites())
                .filter(cipher -> !cipher.equals("^TLS_RSA_.*$"))
                .toArray(String[]::new);
factory.setExcludeCipherSuites(excludedCiphersWithoutTlsRsaExclusion);

If you are using jetty-home (or the older jetty-distribution) you can use an XML to change the default exclusion list ...

${jetty.base}/etc/tweak-ssl.xml

<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
  "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
  <Call name="setExcludeCipherSuites">
    <Arg>
      <Array type="String">
        <!-- Exclude weak / insecure ciphers -->
        <Item>^.*_(MD5|SHA|SHA1)$</Item>
        <!-- Exclude ciphers that don't support forward secrecy -->
        <Item>^TLS_RSA_.*$</Item>
        <!-- The following exclusions are present to cleanup known bad cipher
         suites that may be accidentally included via include patterns.
         The default enabled cipher list in Java will not include these
         (but they are available in the supported list). -->
        <Item>^SSL_.*$</Item>
        <Item>^.*_NULL_.*$</Item>
        <Item>^.*_anon_.*$</Item>
      </Array>
    </Arg>
  </Call>
</Configure>

You can then use that XML by adding etc/tweak-ssl.xml (that's it, not a fully qualified path, on it's own line) in either your ${jetty.base}/start.ini or ${jetty.base}/start.d/tweakssl.ini.

Since this is subject dear to you, you might also want to be aware of Issue #2889 and more default exclusions to arrive soon.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has been a full year without activit. It will be closed if no further activity occurs. Thank you for your contributions.

joakime commented 4 years ago

See https://www.ibm.com/developerworks/community/forums/html/threadTopic?id=9b5a56a9-fa46-4031-b33b-df91e28d77c2

The IBM J9 JVM only allows interop with the RFC names when declaring the precise list of Cipher Suites to use.

In other words, it wont ever return the RFC names in the supported lists, but will use the RFC names when you declare what you want to use.

This decision by the IBM J9 JVM is incompatible with many projects.

When using the IBM J9 JVM you have to declare the entire list of Cipher Suites you want to use with any product that uses an SSLEngine on the IBM J9 JVM. (HTTP Clients, WebSocket Clients, REST Clients, HTTP Servers, etc...)

On Jetty, you will need to create a custom SslContextFactory to behave in the IBM J9 JVM way, not using RFC Name patterns for inclusion / exclusion.

Override the following method and implement it your IBM J9 JVM way.

public SSLParameters customize(SSLParameters sslParams)
{
    super.customize(sslParams);
    _selectedCipherSuites = // String[] of selected cipher suites on IBM J9
    sslParams.setCipherSuites(_selectedCipherSuites);
}

And alternate approach, that would be more wholesome, is to create a new registered security provider (say "myIbmRFC") that can return a SSLContext which uses the RFC names.

It would have to support ...

String protocol = "TLS";
String provider = "myIbmRFC";
SSLContext context = SSLContext.getInstance(protocol, provider);
context.init(....); // read javadoc about this
SSLParameters enabled = context.getDefaultSSLParameters();
SSLParameters supported = context.getSupportedSSLParameters();
// these two should return RFC names (a mapping between IBM and RFC)
String[] enabledCipherSuites = enabled.getCipherSuites();
String[] supportedCipherSuites = supported.getCipherSuites();

Note: We have reports that you cannot use HTTP/2 on IBM J9 JVM. The TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 Cipher that is mandated by the RFC cannot be discovered to be manually added to the SSLEngine, so it winds up failing the HTTP/2 initialization. If you do manage to get past this, then the list of Blacklisted Cipher Suites from the HTTP/2 RFC use the RFC names as well, and cannot be overridden, so that will increase your likelyhood of generating a INADEQUATE_SECURITY from the remote endpoint to a near certainty as you will be using a blacklisted Cipher suite that wasn't excluded by Jetty's HTTP/2 layer.