Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions tls/src/main/java/org/bouncycastle/tls/AbstractTlsClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ public Hashtable getClientExtensions()
TlsExtensionsUtils.addSupportedGroupsExtension(clientExtensions, supportedGroups);
}

//add TokenBinding Extension
TokenBindingExtension tokenBindingExtension = new TokenBindingExtension();
TlsExtensionsUtils.addTokenBindingExtension(clientExtensions, tokenBindingExtension);

return clientExtensions;
}

Expand Down
5 changes: 5 additions & 0 deletions tls/src/main/java/org/bouncycastle/tls/ExporterLabel.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,9 @@ public class ExporterLabel
* draft-ietf-tls-session-hash-04
*/
public static final String extended_master_secret = "extended master secret";

/*
* draft-ietf-tokbind-protocol-16
*/
public static final String token_binding = "EXPORTER-Token-Binding";
}
68 changes: 68 additions & 0 deletions tls/src/main/java/org/bouncycastle/tls/NegotiatedTokenBinding.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.bouncycastle.tls;

/**
* This class captures the negotiated parameters from the TLS handshake
*/
public class NegotiatedTokenBinding {

private String selectedKeyParameter;
protected String RSA2048_PCKS15 = "rsa2048_pcks15";
protected String RSA2048_PSS = "rsa2048_pss";
protected String RSA2048_ECDSAP256 = "rsa2048_ecdsap256";

public byte[] exportKeyingMaterial;

public byte[] getExportKeyingMaterial() {
return exportKeyingMaterial;
}

public void setExportKeyingMaterial(byte[] exportKeyingMaterial) {
this.exportKeyingMaterial = exportKeyingMaterial;
}

public int MajorProtocolVerison = 0;
public int MinorProtocolVerison = 13;

public String getSelectedKeyParameter() {
return selectedKeyParameter;
}

public void setSelectedKeyParameter(String selectedKeyParameter) {
this.selectedKeyParameter = selectedKeyParameter;
}

public int getMajorProtocolVerison() {
return MajorProtocolVerison;
}

public void setMajorProtocolVerison(int majorProtocolVerison) {
MajorProtocolVerison = majorProtocolVerison;
}

public int getMinorProtocolVerison() {
return MinorProtocolVerison;
}

public void setMinorProtocolVerison(int minorProtocolVerison) {
MinorProtocolVerison = minorProtocolVerison;
}

public NegotiatedTokenBinding decode(int[] serverdata) throws TlsFatalAlert {

if (serverdata.length != 4) {
throw new TlsFatalAlert(AlertDescription.unsupported_extension);
}
this.setMajorProtocolVerison(serverdata[0]);
this.setMinorProtocolVerison(serverdata[1]);
if (serverdata[3] == 0) {
this.setSelectedKeyParameter(RSA2048_PCKS15);
} else if (serverdata[3] == 1) {
this.setSelectedKeyParameter(RSA2048_PSS);
} else if (serverdata[3] == 2) {
this.setSelectedKeyParameter(RSA2048_ECDSAP256);
} else {
throw new TlsFatalAlert(AlertDescription.unsupported_extension);
}
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class SecurityParameters
boolean encryptThenMAC = false;
boolean extendedMasterSecret = false;
boolean truncatedHMac = false;
NegotiatedTokenBinding negotiatedTokenBinding =null;

void clear()
{
Expand Down Expand Up @@ -132,4 +133,12 @@ public boolean isTruncatedHMac()
{
return truncatedHMac;
}

public NegotiatedTokenBinding getNegotiatedTokenBinding() {
return negotiatedTokenBinding;
}

public void setNegotiatedTokenBinding(NegotiatedTokenBinding negotiatedTokenBinding) {
this.negotiatedTokenBinding = negotiatedTokenBinding;
}
}
7 changes: 7 additions & 0 deletions tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,12 @@ protected void handleHandshakeMessage(short type, ByteArrayInputStream buf)

establishMasterSecret(getContext(), keyExchange);

if (this.securityParameters.negotiatedTokenBinding != null && this.securityParameters.masterSecret !=
null ){
this.securityParameters.negotiatedTokenBinding.setExportKeyingMaterial(this.tlsClientContext
.exportKeyingMaterial(ExporterLabel.token_binding,null,32));
}

recordStream.setPendingConnectionState(getPeer().getCompression(), getPeer().getCipher());

if (credentialedSigner != null)
Expand Down Expand Up @@ -776,6 +782,7 @@ protected void receiveServerHelloMessage(ByteArrayInputStream buf)
sessionServerExtensions, AlertDescription.illegal_parameter);

this.securityParameters.truncatedHMac = TlsExtensionsUtils.hasTruncatedHMacExtension(sessionServerExtensions);
this.securityParameters.negotiatedTokenBinding=processTokenBindingExtension(sessionServerExtensions);

/*
* TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
Expand Down
31 changes: 31 additions & 0 deletions tls/src/main/java/org/bouncycastle/tls/TlsExtensionsUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class TlsExtensionsUtils
public static final Integer EXT_supported_groups = Integers.valueOf(ExtensionType.supported_groups);
public static final Integer EXT_truncated_hmac = Integers.valueOf(ExtensionType.truncated_hmac);
public static final Integer EXT_trusted_ca_keys = Integers.valueOf(ExtensionType.trusted_ca_keys);
public static final Integer EXT_token_binding = Integers.valueOf(ExtensionType.DRAFT_token_binding);

public static Hashtable ensureExtensionsInitialised(Hashtable extensions)
{
Expand Down Expand Up @@ -119,6 +120,12 @@ public static void addTrustedCAKeysExtensionServer(Hashtable extensions)
extensions.put(EXT_trusted_ca_keys, createTrustedCAKeysExtensionServer());
}

public static void addTokenBindingExtension(Hashtable extensions, TokenBindingExtension tokenBindingExtension)
throws IOException {
extensions.put(EXT_token_binding, createTokenBindingExtension(tokenBindingExtension));
}


public static short[] getClientCertificateTypeExtensionClient(Hashtable extensions)
throws IOException
{
Expand Down Expand Up @@ -195,6 +202,13 @@ public static Vector getTrustedCAKeysExtensionClient(Hashtable extensions)
return extensionData == null ? null : readTrustedCAKeysExtensionClient(extensionData);
}

public static NegotiatedTokenBinding getTokenBindingExtension(Hashtable extensions)
throws IOException
{
byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_token_binding);
return extensionData == null ? null : readTokenBindingExtension(extensionData);
}

public static boolean hasClientCertificateURLExtension(Hashtable extensions) throws IOException
{
byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_client_certificate_url);
Expand Down Expand Up @@ -225,6 +239,15 @@ public static boolean hasTrustedCAKeysExtensionServer(Hashtable extensions) thro
return extensionData == null ? false : readTrustedCAKeysExtensionServer(extensionData);
}

private static byte[] createTokenBindingExtension(TokenBindingExtension tokenBindingExtension) throws IOException {
if (tokenBindingExtension == null) {
throw new TlsFatalAlert(AlertDescription.internal_error);
}
ByteArrayOutputStream buf = new ByteArrayOutputStream();
tokenBindingExtension.encode(buf);
return buf.toByteArray();
}

public static byte[] createCertificateTypeExtensionClient(short[] certificateTypes) throws IOException
{
if (certificateTypes == null || certificateTypes.length < 1 || certificateTypes.length > 255)
Expand Down Expand Up @@ -366,6 +389,14 @@ public static byte[] createTrustedCAKeysExtensionServer()
return createEmptyExtensionData();
}

public static NegotiatedTokenBinding readTokenBindingExtension(byte[] extensionData)
throws IOException {
int[] serverData = TlsUtils.decodeUint8ArrayWithUint16Length(extensionData);
NegotiatedTokenBinding tokenBinding = new NegotiatedTokenBinding();
tokenBinding.decode(serverData);
return tokenBinding;
}

private static boolean readEmptyExtensionData(byte[] extensionData) throws IOException
{
if (extensionData == null)
Expand Down
20 changes: 20 additions & 0 deletions tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,26 @@ protected void refuseRenegotiation() throws IOException
raiseAlertWarning(AlertDescription.no_renegotiation, "Renegotiation not supported");
}

/**
* This method creates NegotiatedTokenBindingClass and checks the negotiated parameters.
*
* @param serverExtensions
* @return
* @throws IOException
*/
protected NegotiatedTokenBinding processTokenBindingExtension(Hashtable serverExtensions) throws IOException {
NegotiatedTokenBinding tokenBinding = TlsExtensionsUtils.getTokenBindingExtension(serverExtensions);
if (tokenBinding != null) {
if (tokenBinding.getMajorProtocolVerison() > TokenBindingExtension.getMajorProtocolVerison()) {
throw new TlsFatalAlert(AlertDescription.unsupported_extension);
}
if (tokenBinding.getMinorProtocolVerison() > TokenBindingExtension.getMinorProtocolVerison()) {
throw new TlsFatalAlert(AlertDescription.unsupported_extension);
}
}
return tokenBinding;
}

/**
* Make sure the InputStream 'buf' now empty. Fail otherwise.
*
Expand Down
15 changes: 15 additions & 0 deletions tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,21 @@ public static short[] decodeUint8ArrayWithUint8Length(byte[] buf) throws IOExcep
return uints;
}

public static int[] decodeUint8ArrayWithUint16Length(byte[] buf) throws IOException
{
if (buf == null)
{
throw new IllegalArgumentException("'buf' cannot be null");
}

int[] uints = new int[buf.length];
for (int i = 0; i < buf.length; ++i)
{
uints[i] = readUint8(buf, i );
}
return uints;
}

public static byte[] encodeOpaque8(byte[] buf)
throws IOException
{
Expand Down
74 changes: 74 additions & 0 deletions tls/src/main/java/org/bouncycastle/tls/TokenBindingExtension.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.bouncycastle.tls;

import org.bouncycastle.util.io.Streams;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* Token binding (draft) extension to TLS
*/
public class TokenBindingExtension {

public static final Integer rsa2048_pcks15 = 0;
public static final Integer rsa2048_pss = 1;
public static final Integer rsa2048_ecdsap256 = 2;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these be in upper case since these are constants? Do contrast with the token binding spec as well.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spec always denote them in the simple letters


List<Integer> TokenBindingKeyParameters = new ArrayList<Integer>();

private static int MajorProtocolVerison = 0;

public static int getMajorProtocolVerison() {
return MajorProtocolVerison;
}

public static int getMinorProtocolVerison() {
return MinorProtocolVerison;
}

private static int MinorProtocolVerison = 13;

public static void setMajorProtocolVerison(int majorProtocolVerison) {
MajorProtocolVerison = majorProtocolVerison;
}

public static void setMinorProtocolVerison(int minorProtocolVerison) {
MinorProtocolVerison = minorProtocolVerison;
}

public void addTokenbindingKeyParameters(int parameter) {
TokenBindingKeyParameters.add(parameter);
}

public List<Integer> getTokenBindingKeyParameters() {
if (TokenBindingKeyParameters.size() < 1) {
TokenBindingKeyParameters.add(rsa2048_pcks15);
}
Collections.sort(TokenBindingKeyParameters, Collections.reverseOrder());
return TokenBindingKeyParameters;
}

public void encode(OutputStream output) throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream();

TlsUtils.checkUint8(MajorProtocolVerison);
TlsUtils.checkUint8(MinorProtocolVerison);
TlsUtils.writeUint8(MajorProtocolVerison, output);
TlsUtils.writeUint8(MinorProtocolVerison, output);

for (Integer param : this.getTokenBindingKeyParameters()) {
TlsUtils.checkUint8(param);
TlsUtils.writeUint8(param, buf);
}

TlsUtils.checkUint8(buf.size());
TlsUtils.writeUint8(buf.size(), output);
Streams.writeBufTo(buf, output);

}

}