Token Binding over HTTP [I-D.ietf-tokbind-https] provides a mechanism that enables HTTP servers to cryptographically bind cookies and other security tokens to a key generated by the client. When Token Binding is negotiated in the TLS handshake [I-D.ietf-tokbind-negotiation] the client sends an encoded Token Binding Message [I-D.ietf-tokbind-protocol] as a header in each HTTP request, which proves possession of one or more private keys held by the client. The public portion of the keys are represented in the Token Binding IDs of the Token Binding Message and for each one there is a signature over some data, which includes the exported keying material [RFC 5705] of the TLS connection. An HTTP server issuing cookies or other security tokens can associate them with the Token Binding ID, which ensures those tokens cannot be used successfully over a different TLS connection or by a different client than the one to which they were issued.
This project provides an implementation of the TLS Extension for Token Binding Protocol Negotiation as well as TLS Keying Material Exporters (also TLS Extended Master Secret Extension [RFC 7627] in some older versions) for Java 9. An an open source library for consuming or producing Token Binding message structures, which applications do after negotiation, can be found with the token-binding-java project.
This implementation relies on modifications of a few JDK classes in the sun.security.ssl
package. The JVM needs to be told to use those modified classes in place of those in the base modul of the JRE. And your application needs to interact with the API of some of those classes, likely through reflection and dynamic method invocation.
To use the functionality of this project, the JVM needs to be started using the --patch-module
option as follows:
java --patch-module java.base=<path-to-java9-token-binding-negotiation-jar> --add-exports java.base/sun.security.ssl=ALL-UNNAMED ...
Where path-to-java9-token-binding-negotiation-jar is the path on the file system for this project's jar file. This tells the JVM to use the jar file and its classes in preference to the default JRE classes. Be certain to use the jar version which corresponds to the version of the JRE being used (see Versions below).
A few new methods have been added to the OpenJDK implementations of SSLEngine
and SSLSocket
to facilitate an application doing Token Binding using the functionality provided by this project.
In order to negotiate the use of Token Binding, before handshaking begins, the list of identifiers of the supported key parameters needs to be indicated for the connection. For a client, this is the list that will be offered in the Client Hello Extension. For a server, this is the list of key parameter types that it is willing to successfully negotiate. In all cases the list indicates the Token Binding key parameters supported in descending order of preference. This can be accomplished by calling the following method on SSLEngine
or SSLSocket
before the handshaking process begins.
public void setSupportedTokenBindingKeyParams(byte[] supportedTokenBindingKeyParams)
The supportedTokenBindingKeyParams
byte array argument is the list of supported key parameters type identifiers (i.e. from I-D.ietf-tokbind-protocol rsa2048_pkcs1.5(0), rsa2048_pss(1), ecdsap256(2)
). So, for example, the following would set up an SSLEngine
to accept or offer ecdsap256
and rsa2048_pkcs1.5
(in that order of preference) during the handshake.
Class<? extends SSLEngine> engineClass = engine.getClass();
Method supportedKeyParamsMethod = engineClass.getMethod("setSupportedTokenBindingKeyParams", byte[].class);
Object supported = new byte[] {2, 0};
supportedKeyParamsMethod.invoke(engine, supported);
Alternately, the system properties unbearable.server.defaultSupportedKeyParams
and unbearable.client.defaultSupportedKeyParams
may be used to indicate the supported key parameters type identifiers for all connections when acting as the server or client respectively. The value is a comma seperated list of key parameters type identifiers. For example, adding the following argument when starting the JVM would say that TLS connections as the server will successfully negotiate Token Binding with ecdsap256(2)
or rsa2048_pkcs1.5(0)
when offered by the client.
-Dunbearable.server.defaultSupportedKeyParams=2,0
If the use of the Token Binding is successfully negotiated with HTTP, the client includes an encoded token binding message in each request via the Sec-Token-Binding
header and the server validates the message. In order to produce or consume a Token Binding message, an application needs to know what key parameters type was negotiated and get the exported keying material (EKM) from the TLS connection. That data can be obtained using the following methods on SSLEngine
or SSLSocket
where getNegotiatedTokenBindingKeyParams()
will give the the identifier of the negotiated key parameters (or null
, if Token Binding was not negotiated) and exportKeyingMaterial("EXPORTER-Token-Binding", 32)
will return the appropriate EKM.
public Byte getNegotiatedTokenBindingKeyParams()
public byte[] exportKeyingMaterial(String label, int length)
The following, for example, could be used to access the negotiated key parameters type and the EKM from an SSLEngine
.
Class<? extends SSLEngine> engineClass = engine.getClass();
Method tbKeyParamsMethod = engineClass.getMethod("getNegotiatedTokenBindingKeyParams");
Method ekmMethod = engineClass.getMethod("exportKeyingMaterial", String.class, int.class);
Byte negotiatedKeyParamsId = (Byte) tbKeyParamsMethod.invoke(object);
byte[] ekm = (byte[]) ekmMethod.invoke(object, "EXPORTER-Token-Binding", 32);
With the EKM and the negotiated key parameters type, a library like token-binding-java can be used to consume or create Token Binding messages.
The Token Binding negotiation implementation relies on modifications to a few OpenJDK classes so needs to be updated to stay in sync when there are changes to those OpenJDK classes in a Java update. As such, the java9-token-binding-negotiation jar version matching the JRE version needs to be used. The following provides the version mappings.
Java 9 Version | java9-token-binding-negotiation Version |
---|---|
9.0.4 | 1.0.0.v2 |
9.0.1 | 1.0.0.v1 |
9 | unsupported |
See java8-token-binding-negotiation or java10-token-binding-negotiation for Token Binding Protocol Negotiation support with Java 8 and Java 10 respectively.
The modified OpenJDK classes are released under the same GPLv2 + Classpath Exception license as the OpenJDK.