Bug 63650

Summary: Unable to use own JSSE cipher implementation
Product: Tomcat 9 Reporter: Arne Stahlbock <arne.stahlbock>
Component: ConnectorsAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: normal    
Priority: P2    
Version: 9.0.21   
Target Milestone: -----   
Hardware: PC   
OS: All   

Description Arne Stahlbock 2019-08-08 10:56:19 UTC
Due to our need to use certain TLS cipher suites which are not supported by the SunJSSE provider by Oracle, we have created an own implementation of a JSSE provider.
In Tomcat 7, we are able to use it easily by registering our provider in the JRE and configuring

<Connector port="..." protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" keystoreFile="..." keystorePass="..." sslProtocol="TLSPSK" ciphers="TLS_RSA_PSK_WITH_AES_256_GCM_SHA384" clientAuth="false" />

where "TLSPSK" is the name of our SSLContext implementation.

However we are unable to use it in Tomcat 9 (or 8.5).
Startup of Tomcat 9 (with same connector configuration) results in following exception:

Caused by: java.lang.IllegalArgumentException: Keine der spezifizierten [ciphers] wird von der SSL Engine unterst├╝tzt: [[TLS_RSA_PSK_WITH_AES_256_GCM_SHA384]]
at org.apache.tomcat.util.net.SSLUtilBase.getEnabled(SSLUtilBase.java:151)
at org.apache.tomcat.util.net.SSLUtilBase.<init>(SSLUtilBase.java:125)
at org.apache.tomcat.util.net.jsse.JSSEUtil.<init>(JSSEUtil.java:113)
at org.apache.tomcat.util.net.jsse.JSSEUtil.<init>(JSSEUtil.java:108)
at org.apache.tomcat.util.net.jsse.JSSEImplementation.getSSLUtil(JSSEImplementation.java:50)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:88)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.initialiseSsl(AbstractJsseEndpoint.java:71)
at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:218)
at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1124)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:1137)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:574)
at org.apache.coyote.http11.AbstractHttp11Protocol.init(AbstractHttp11Protocol.java:74)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:980)

meaning given ciphers not supported.
An investigation showed us that SSLUtilBase.getEnabled always produces an empty list with operations

enabled.addAll(configured);
enabled.retainAll(implemented);

where "configured" holds exactly the ciphers we give in the config, and "implemented" holds a number of ciphers but not ours.
Tracking down where "implemented" comes from led us to JSSEUtil static initializer

SSLContext context;
try {
    context = new JSSESSLContext(Constants.SSL_PROTO_TLS);

... and later

    String[] implementedCipherSuiteArray = context.getSupportedSSLParameters().getCipherSuites();

So, the "implemented" ciphers are always taken from the SSLContext one receives from SSLContext.getInstance("TLS") which is usually the SunJSSE implementation, essentially locking out all other ciphers.
A workaround by naming our SSLContext "TLS" and assigning it higher priority than SunJSSE, so JSSEUtil would then always use ours, is not feasible as we also need SunJSSE (on other connectors).
Comment 1 Mark Thomas 2019-08-08 13:40:37 UTC
Fixed in:
- master for 9.0.23 onwards
- 8.5.x for 8.5.44 onwards

I have refactored the initialisation so it uses the sslProtocol value from the SSLHostContext.