Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2013-06-22 17:22:41 +0400
committerPeter Dettman <peter.dettman@bouncycastle.org>2013-06-22 17:22:41 +0400
commit93033823c8dfdcf0ded8a3fff6ec5a75de84a921 (patch)
tree103dd234c50f82ef4caa7ce45edef24ba80ef7ac /core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java
parentf658c6ca808b7a14986cd122beae2188b85686e4 (diff)
Initial implementation of session resumption (client-side TLS)
Diffstat (limited to 'core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java')
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java127
1 files changed, 107 insertions, 20 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java b/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java
index 2308ee08..84f74612 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java
@@ -22,6 +22,7 @@ public class TlsClientProtocol
protected short[] offeredCompressionMethods = null;
protected Hashtable clientExtensions = null;
+ protected byte[] selectedSessionID = null;
protected int selectedCipherSuite;
protected short selectedCompressionMethod;
@@ -62,11 +63,22 @@ public class TlsClientProtocol
/**
* Initiates a TLS handshake in the role of client
*
- * @param tlsClient
+ * @param tlsClient The {@link TlsClient} to use for the handshake.
* @throws IOException If handshake was not successful.
*/
- public void connect(TlsClient tlsClient)
- throws IOException
+ public void connect(TlsClient tlsClient) throws IOException
+ {
+ connect(tlsClient, null);
+ }
+
+ /**
+ * Initiates a TLS handshake in the role of client, resuming the provided session if possible.
+ *
+ * @param tlsClient The {@link TlsClient} to use for the handshake.
+ * @param tlsSession The {@link TlsSession} to try to resume, or null.
+ * @throws IOException If handshake was not successful.
+ */
+ public void connect(TlsClient tlsClient, TlsSession tlsSession) throws IOException
{
if (tlsClient == null)
{
@@ -74,10 +86,11 @@ public class TlsClientProtocol
}
if (this.tlsClient != null)
{
- throw new IllegalStateException("connect can only be called once");
+ throw new IllegalStateException("'connect' can only be called once");
}
this.tlsClient = tlsClient;
+ this.tlsSession = tlsSession;
this.securityParameters = new SecurityParameters();
this.securityParameters.entity = ConnectionEnd.client;
@@ -100,6 +113,7 @@ public class TlsClientProtocol
this.offeredCipherSuites = null;
this.offeredCompressionMethods = null;
this.clientExtensions = null;
+ this.selectedSessionID = null;
this.keyExchange = null;
this.authentication = null;
this.serverCertificate = null;
@@ -122,6 +136,23 @@ public class TlsClientProtocol
{
ByteArrayInputStream buf = new ByteArrayInputStream(data);
+ if (this.resumedSession)
+ {
+ if (type != HandshakeType.finished || this.connection_state != CS_SERVER_HELLO)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ processFinishedMessage(buf);
+ this.connection_state = CS_SERVER_FINISHED;
+
+ sendFinishedMessage();
+ this.connection_state = CS_CLIENT_FINISHED;
+ this.connection_state = CS_END;
+
+ return;
+ }
+
switch (type)
{
case HandshakeType.certificate:
@@ -193,6 +224,7 @@ public class TlsClientProtocol
case CS_CLIENT_FINISHED:
processFinishedMessage(buf);
this.connection_state = CS_SERVER_FINISHED;
+ this.connection_state = CS_END;
break;
default:
this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
@@ -205,8 +237,9 @@ public class TlsClientProtocol
receiveServerHelloMessage(buf);
this.connection_state = CS_SERVER_HELLO;
- securityParameters.prfAlgorithm = getPRFAlgorithm(getContext(), selectedCipherSuite);
+ securityParameters.cipherSuite = this.selectedCipherSuite;
securityParameters.compressionAlgorithm = this.selectedCompressionMethod;
+ securityParameters.prfAlgorithm = getPRFAlgorithm(getContext(), selectedCipherSuite);
/*
* RFC 5264 7.4.9. Any cipher suite which does not explicitly specify
@@ -217,6 +250,38 @@ public class TlsClientProtocol
recordStream.notifyHelloComplete();
+ this.resumedSession = this.selectedSessionID.length > 0 && this.tlsSession != null
+ && Arrays.areEqual(this.selectedSessionID, this.tlsSession.getSessionID());
+
+ if (this.resumedSession)
+ {
+ SecurityParameters sessionParameters = this.tlsSession.getSecurityParameters();
+
+ if (securityParameters.getCipherSuite() != sessionParameters.getCipherSuite()
+ || securityParameters.getCompressionAlgorithm() != sessionParameters.getCompressionAlgorithm())
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ securityParameters.masterSecret = Arrays.clone(sessionParameters.masterSecret);
+ recordStream.setPendingConnectionState(getPeer().getCompression(), getPeer().getCipher());
+
+ sendChangeCipherSpecMessage();
+ }
+ else
+ {
+ if (this.tlsSession != null)
+ {
+ this.tlsSession.close();
+ this.tlsSession = null;
+ }
+
+ if (this.selectedSessionID.length > 0)
+ {
+ this.tlsSession = new TlsSessionImpl(this.selectedSessionID, null);
+ }
+ }
+
break;
default:
this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
@@ -437,7 +502,7 @@ public class TlsClientProtocol
* if it does not wish to renegotiate a session, or the client may, if it wishes,
* respond with a no_renegotiation alert.
*/
- if (this.connection_state == CS_SERVER_FINISHED)
+ if (this.connection_state == CS_END)
{
String message = "Renegotiation not supported";
raiseWarning(AlertDescription.no_renegotiation, message);
@@ -504,13 +569,13 @@ public class TlsClientProtocol
*/
securityParameters.serverRandom = TlsUtils.readFully(32, buf);
- byte[] sessionID = TlsUtils.readOpaque8(buf);
- if (sessionID.length > 32)
+ this.selectedSessionID = TlsUtils.readOpaque8(buf);
+ if (this.selectedSessionID.length > 32)
{
this.failWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
}
- this.tlsClient.notifySessionID(sessionID);
+ this.tlsClient.notifySessionID(this.selectedSessionID);
/*
* Find out which CipherSuite the server has chosen and check that it was one of the offered
@@ -649,9 +714,7 @@ public class TlsClientProtocol
protected void sendClientHelloMessage()
throws IOException
{
- recordStream.setWriteVersion(this.tlsClient.getClientHelloRecordLayerVersion());
-
- HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);
+ this.recordStream.setWriteVersion(this.tlsClient.getClientHelloRecordLayerVersion());
ProtocolVersion client_version = this.tlsClient.getClientVersion();
if (client_version.isDTLS())
@@ -660,21 +723,48 @@ public class TlsClientProtocol
}
getContext().setClientVersion(client_version);
- TlsUtils.writeVersion(client_version, message);
-
- message.write(securityParameters.clientRandom);
- // Session id
- TlsUtils.writeOpaque8(TlsUtils.EMPTY_BYTES, message);
+ // Session ID
+ byte[] session_id = TlsUtils.EMPTY_BYTES;
+ if (this.tlsSession != null)
+ {
+ session_id = this.tlsSession.getSessionID();
+ if (session_id == null || session_id.length > 32)
+ {
+ session_id = TlsUtils.EMPTY_BYTES;
+ }
+ }
/*
* Cipher suites
*/
this.offeredCipherSuites = this.tlsClient.getCipherSuites();
+ // Compression methods
+ this.offeredCompressionMethods = this.tlsClient.getCompressionMethods();
+
+ if (session_id.length > 0)
+ {
+ SecurityParameters sessionParameters = this.tlsSession.getSecurityParameters();
+
+ if (!arrayContains(this.offeredCipherSuites, sessionParameters.getCipherSuite())
+ || !arrayContains(this.offeredCompressionMethods, sessionParameters.getCompressionAlgorithm()))
+ {
+ session_id = TlsUtils.EMPTY_BYTES;
+ }
+ }
+
// Integer -> byte[]
this.clientExtensions = this.tlsClient.getClientExtensions();
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);
+
+ TlsUtils.writeVersion(client_version, message);
+
+ message.write(this.securityParameters.getClientRandom());
+
+ TlsUtils.writeOpaque8(session_id, message);
+
// Cipher Suites (and SCSV)
{
/*
@@ -703,9 +793,6 @@ public class TlsClientProtocol
}
}
- // Compression methods
- this.offeredCompressionMethods = this.tlsClient.getCompressionMethods();
-
TlsUtils.checkUint8(offeredCompressionMethods.length);
TlsUtils.writeUint8(offeredCompressionMethods.length, message);
TlsUtils.writeUint8Array(offeredCompressionMethods, message);