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-11-17 15:54:45 +0400
committerPeter Dettman <peter.dettman@bouncycastle.org>2013-11-17 15:54:45 +0400
commit6a190004982f1e9456ccc9c1d6f0acdd37bd8dea (patch)
treec229d80233c359b23e3d1dbc91c4a53c3c0f779e /core/src/main/java/org/bouncycastle/crypto/tls
parent3e7f55745c18119e852bd31ce491c28f53c3387b (diff)
Refactoring around DeferredHash so that for (D)TLS 1.2 we can snapshot
any/all hashes that might be needed for CertificateVerify. Defer the actual CertificateVerify hash calculation at the server until after we have seen the DigitallySigned.
Diffstat (limited to 'core/src/main/java/org/bouncycastle/crypto/tls')
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/CombinedHash.java3
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java18
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java7
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java24
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/DeferredHash.java24
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/RecordStream.java30
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java6
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/TlsHandshakeHash.java2
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java22
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java27
10 files changed, 81 insertions, 82 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/CombinedHash.java b/core/src/main/java/org/bouncycastle/crypto/tls/CombinedHash.java
index a433577d..47379117 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/CombinedHash.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/CombinedHash.java
@@ -44,8 +44,9 @@ class CombinedHash
{
}
- public void stopTracking()
+ public TlsHandshakeHash stopTracking()
{
+ return new CombinedHash(this);
}
public Digest forkPRFHash()
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java b/core/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java
index cfde57a1..325db550 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java
@@ -153,13 +153,13 @@ public class DTLSClientProtocol
recordLayer.initPendingEpoch(state.client.getCipher());
// NOTE: Calculated exclusive of the actual Finished message from the server
- byte[] expectedServerVerifyData = TlsUtils.calculateVerifyData(state.clientContext,
- ExporterLabel.server_finished, handshake.getCurrentPRFHash());
+ byte[] expectedServerVerifyData = TlsUtils.calculateVerifyData(state.clientContext, ExporterLabel.server_finished,
+ TlsProtocol.getCurrentPRFHash(state.clientContext, handshake.getHandshakeHash(), null));
processFinished(handshake.receiveMessageBody(HandshakeType.finished), expectedServerVerifyData);
// NOTE: Calculated exclusive of the Finished message itself
byte[] clientVerifyData = TlsUtils.calculateVerifyData(state.clientContext, ExporterLabel.client_finished,
- handshake.getCurrentPRFHash());
+ TlsProtocol.getCurrentPRFHash(state.clientContext, handshake.getHandshakeHash(), null));
handshake.sendMessage(HandshakeType.finished, clientVerifyData);
handshake.finish();
@@ -311,6 +311,8 @@ public class DTLSClientProtocol
TlsProtocol.establishMasterSecret(state.clientContext, state.keyExchange);
recordLayer.initPendingEpoch(state.client.getCipher());
+ TlsHandshakeHash prepareFinishHash = handshake.prepareToFinish();
+
if (state.clientCredentials != null && state.clientCredentials instanceof TlsSignerCredentials)
{
TlsSignerCredentials signerCredentials = (TlsSignerCredentials)state.clientCredentials;
@@ -318,18 +320,16 @@ public class DTLSClientProtocol
* TODO RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
*/
SignatureAndHashAlgorithm algorithm = null;
- byte[] hash = handshake.getCurrentPRFHash();
+ byte[] hash = TlsProtocol.getCurrentPRFHash(state.clientContext, prepareFinishHash, null);
byte[] signature = signerCredentials.generateCertificateSignature(hash);
DigitallySigned certificateVerify = new DigitallySigned(algorithm, signature);
byte[] certificateVerifyBody = generateCertificateVerify(state, certificateVerify);
handshake.sendMessage(HandshakeType.certificate_verify, certificateVerifyBody);
}
- handshake.getHandshakeHash().stopTracking();
-
// NOTE: Calculated exclusive of the Finished message itself
byte[] clientVerifyData = TlsUtils.calculateVerifyData(state.clientContext, ExporterLabel.client_finished,
- handshake.getCurrentPRFHash());
+ TlsProtocol.getCurrentPRFHash(state.clientContext, handshake.getHandshakeHash(), null));
handshake.sendMessage(HandshakeType.finished, clientVerifyData);
if (state.expectSessionTicket)
@@ -346,8 +346,8 @@ public class DTLSClientProtocol
}
// NOTE: Calculated exclusive of the actual Finished message from the server
- byte[] expectedServerVerifyData = TlsUtils.calculateVerifyData(state.clientContext,
- ExporterLabel.server_finished, handshake.getCurrentPRFHash());
+ byte[] expectedServerVerifyData = TlsUtils.calculateVerifyData(state.clientContext, ExporterLabel.server_finished,
+ TlsProtocol.getCurrentPRFHash(state.clientContext, handshake.getHandshakeHash(), null));
processFinished(handshake.receiveMessageBody(HandshakeType.finished), expectedServerVerifyData);
handshake.finish();
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java b/core/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java
index b6bf085b..91ddee60 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java
@@ -41,11 +41,10 @@ class DTLSReliableHandshake
return handshakeHash;
}
- byte[] getCurrentPRFHash()
+ TlsHandshakeHash prepareToFinish()
{
- Digest copyOfHash = handshakeHash.forkPRFHash();
- byte[] result = new byte[copyOfHash.getDigestSize()];
- copyOfHash.doFinal(result, 0);
+ TlsHandshakeHash result = handshakeHash;
+ this.handshakeHash = handshakeHash.stopTracking();
return result;
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java b/core/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java
index b7c3940b..257804d7 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java
@@ -235,11 +235,6 @@ public class DTLSServerProtocol
}
}
- if (!expectCertificateVerifyMessage(state))
- {
- handshake.getHandshakeHash().stopTracking();
- }
-
if (clientMessage.getType() == HandshakeType.client_key_exchange)
{
processClientKeyExchange(state, clientMessage.getBody());
@@ -252,6 +247,8 @@ public class DTLSServerProtocol
TlsProtocol.establishMasterSecret(state.serverContext, state.keyExchange);
recordLayer.initPendingEpoch(state.server.getCipher());
+ TlsHandshakeHash prepareFinishHash = handshake.prepareToFinish();
+
/*
* RFC 5246 7.4.8 This message is only sent following a client certificate that has signing
* capability (i.e., all certificates except those containing fixed Diffie-Hellman
@@ -259,17 +256,13 @@ public class DTLSServerProtocol
*/
if (expectCertificateVerifyMessage(state))
{
- // TODO For TLS 1.2, this can't be calculated until we see what hash algorithm the sender used
- byte[] certificateVerifyHash = handshake.getCurrentPRFHash();
byte[] certificateVerifyBody = handshake.receiveMessageBody(HandshakeType.certificate_verify);
- processCertificateVerify(state, certificateVerifyBody, certificateVerifyHash);
-
- handshake.getHandshakeHash().stopTracking();
+ processCertificateVerify(state, certificateVerifyBody, prepareFinishHash);
}
// NOTE: Calculated exclusive of the actual Finished message from the client
- byte[] expectedClientVerifyData = TlsUtils.calculateVerifyData(state.serverContext,
- ExporterLabel.client_finished, handshake.getCurrentPRFHash());
+ byte[] expectedClientVerifyData = TlsUtils.calculateVerifyData(state.serverContext, ExporterLabel.client_finished,
+ TlsProtocol.getCurrentPRFHash(state.serverContext, handshake.getHandshakeHash(), null));
processFinished(handshake.receiveMessageBody(HandshakeType.finished), expectedClientVerifyData);
if (state.expectSessionTicket)
@@ -281,7 +274,7 @@ public class DTLSServerProtocol
// NOTE: Calculated exclusive of the Finished message itself
byte[] serverVerifyData = TlsUtils.calculateVerifyData(state.serverContext, ExporterLabel.server_finished,
- handshake.getCurrentPRFHash());
+ TlsProtocol.getCurrentPRFHash(state.serverContext, handshake.getHandshakeHash(), null));
handshake.sendMessage(HandshakeType.finished, serverVerifyData);
handshake.finish();
@@ -469,7 +462,7 @@ public class DTLSServerProtocol
notifyClientCertificate(state, clientCertificate);
}
- protected void processCertificateVerify(ServerHandshakeState state, byte[] body, byte[] certificateVerifyHash)
+ protected void processCertificateVerify(ServerHandshakeState state, byte[] body, TlsHandshakeHash prepareFinishHash)
throws IOException
{
ByteArrayInputStream buf = new ByteArrayInputStream(body);
@@ -481,6 +474,9 @@ public class DTLSServerProtocol
// Verify the CertificateVerify message contains a correct signature.
try
{
+ // TODO For TLS 1.2, this needs to be the hash specified in the DigitallySigned
+ byte[] certificateVerifyHash = TlsProtocol.getCurrentPRFHash(state.serverContext, prepareFinishHash, null);
+
org.bouncycastle.asn1.x509.Certificate x509Cert = state.clientCertificate.getCertificateAt(0);
SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
AsymmetricKeyParameter publicKey = PublicKeyFactory.createKey(keyInfo);
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/DeferredHash.java b/core/src/main/java/org/bouncycastle/crypto/tls/DeferredHash.java
index 952e0b59..711172f1 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/DeferredHash.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/DeferredHash.java
@@ -27,6 +27,14 @@ class DeferredHash
this.prfHashAlgorithm = null;
}
+ private DeferredHash(Short prfHashAlgorithm, Digest prfHash)
+ {
+ this.buf = null;
+ this.hashes = new Hashtable();
+ this.prfHashAlgorithm = prfHashAlgorithm;
+ hashes.put(prfHashAlgorithm, prfHash);
+ }
+
public void init(TlsContext context)
{
this.context = context;
@@ -65,20 +73,22 @@ class DeferredHash
checkStopBuffering();
}
- public void stopTracking()
+ public TlsHandshakeHash stopTracking()
{
- if (hashes.size() > 1)
+ Digest prfHash = TlsUtils.cloneHash(prfHashAlgorithm.shortValue(), (Digest)hashes.get(prfHashAlgorithm));
+ if (buf != null)
{
- Digest prfHash = (Digest)hashes.get(prfHashAlgorithm);
- hashes = new Hashtable();
- hashes.put(prfHashAlgorithm, prfHash);
+ buf.updateDigest(prfHash);
}
-
- checkStopBuffering();
+ DeferredHash result = new DeferredHash(prfHashAlgorithm, prfHash);
+ result.init(context);
+ return result;
}
public Digest forkPRFHash()
{
+ checkStopBuffering();
+
if (buf != null)
{
Digest prfHash = TlsUtils.createHash(prfHashAlgorithm.shortValue());
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/RecordStream.java b/core/src/main/java/org/bouncycastle/crypto/tls/RecordStream.java
index c164cf05..cc6640be 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/RecordStream.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/RecordStream.java
@@ -290,27 +290,16 @@ class RecordStream
return handshakeHash;
}
- void updateHandshakeData(byte[] message, int offset, int len)
+ TlsHandshakeHash prepareToFinish()
{
- handshakeHash.update(message, offset, len);
+ TlsHandshakeHash result = handshakeHash;
+ this.handshakeHash = handshakeHash.stopTracking();
+ return result;
}
- /**
- * 'sender' only relevant to SSLv3
- */
- byte[] getCurrentPRFHash(byte[] sslSender)
+ void updateHandshakeData(byte[] message, int offset, int len)
{
- Digest d = handshakeHash.forkPRFHash();
-
- if (TlsUtils.isSSL(context))
- {
- if (sslSender != null)
- {
- d.update(sslSender, 0, sslSender.length);
- }
- }
-
- return doFinal(d);
+ handshakeHash.update(message, offset, len);
}
protected void safeClose()
@@ -345,13 +334,6 @@ class RecordStream
return contents;
}
- private static byte[] doFinal(Digest d)
- {
- byte[] bs = new byte[d.getDigestSize()];
- d.doFinal(bs, 0);
- return bs;
- }
-
private static void checkType(short type, short alertDescription)
throws IOException
{
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 85dd1168..2cea7584 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java
@@ -372,6 +372,8 @@ public class TlsClientProtocol
establishMasterSecret(getContext(), keyExchange);
recordStream.setPendingConnectionState(getPeer().getCompression(), getPeer().getCipher());
+ TlsHandshakeHash prepareFinishHash = recordStream.prepareToFinish();
+
if (clientCreds != null && clientCreds instanceof TlsSignerCredentials)
{
TlsSignerCredentials signerCreds = (TlsSignerCredentials)clientCreds;
@@ -379,7 +381,7 @@ public class TlsClientProtocol
* TODO RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
*/
SignatureAndHashAlgorithm algorithm = null;
- byte[] hash = recordStream.getCurrentPRFHash(null);
+ byte[] hash = getCurrentPRFHash(getContext(), prepareFinishHash, null);
byte[] signature = signerCreds.generateCertificateSignature(hash);
DigitallySigned certificateVerify = new DigitallySigned(algorithm, signature);
sendCertificateVerifyMessage(certificateVerify);
@@ -387,8 +389,6 @@ public class TlsClientProtocol
this.connection_state = CS_CERTIFICATE_VERIFY;
}
- this.recordStream.getHandshakeHash().stopTracking();
-
sendChangeCipherSpecMessage();
sendFinishedMessage();
this.connection_state = CS_CLIENT_FINISHED;
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/TlsHandshakeHash.java b/core/src/main/java/org/bouncycastle/crypto/tls/TlsHandshakeHash.java
index 9c866b1e..51ba28ca 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/TlsHandshakeHash.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsHandshakeHash.java
@@ -13,7 +13,7 @@ interface TlsHandshakeHash
void sealHashAlgorithms();
- void stopTracking();
+ TlsHandshakeHash stopTracking();
Digest forkPRFHash();
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java b/core/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java
index 262e222e..1a97bd14 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java
@@ -11,6 +11,7 @@ import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
+import org.bouncycastle.crypto.Digest;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Integers;
@@ -747,11 +748,11 @@ public abstract class TlsProtocol
if (isServer)
{
return TlsUtils.calculateVerifyData(context, ExporterLabel.server_finished,
- recordStream.getCurrentPRFHash(TlsUtils.SSL_SERVER));
+ getCurrentPRFHash(getContext(), recordStream.getHandshakeHash(), TlsUtils.SSL_SERVER));
}
return TlsUtils.calculateVerifyData(context, ExporterLabel.client_finished,
- recordStream.getCurrentPRFHash(TlsUtils.SSL_CLIENT));
+ getCurrentPRFHash(getContext(), recordStream.getHandshakeHash(), TlsUtils.SSL_CLIENT));
}
/**
@@ -881,6 +882,23 @@ public abstract class TlsProtocol
}
}
+ /**
+ * 'sender' only relevant to SSLv3
+ */
+ protected static byte[] getCurrentPRFHash(TlsContext context, TlsHandshakeHash handshakeHash, byte[] sslSender)
+ {
+ Digest d = handshakeHash.forkPRFHash();
+
+ if (sslSender != null && TlsUtils.isSSL(context))
+ {
+ d.update(sslSender, 0, sslSender.length);
+ }
+
+ byte[] bs = new byte[d.getDigestSize()];
+ d.doFinal(bs, 0);
+ return bs;
+ }
+
protected static Hashtable readExtensions(ByteArrayInputStream input)
throws IOException
{
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java b/core/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java
index 5256d2e4..b2c392c8 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java
@@ -23,7 +23,7 @@ public class TlsServerProtocol
protected CertificateRequest certificateRequest = null;
protected short clientCertificateType = -1;
- protected byte[] certificateVerifyHash = null;
+ protected TlsHandshakeHash prepareFinishHash = null;
public TlsServerProtocol(InputStream input, OutputStream output, SecureRandom secureRandom)
{
@@ -70,7 +70,7 @@ public class TlsServerProtocol
this.keyExchange = null;
this.serverCredentials = null;
this.certificateRequest = null;
- this.certificateVerifyHash = null;
+ this.prepareFinishHash = null;
}
protected AbstractTlsContext getContext()
@@ -282,7 +282,7 @@ public class TlsServerProtocol
* signing capability (i.e., all certificates except those containing fixed
* Diffie-Hellman parameters).
*/
- if (this.certificateVerifyHash == null)
+ if (!expectCertificateVerifyMessage())
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
@@ -290,8 +290,6 @@ public class TlsServerProtocol
receiveCertificateVerifyMessage(buf);
this.connection_state = CS_CERTIFICATE_VERIFY;
- this.recordStream.getHandshakeHash().stopTracking();
-
break;
}
default:
@@ -305,7 +303,7 @@ public class TlsServerProtocol
{
case CS_CLIENT_KEY_EXCHANGE:
{
- if (this.certificateVerifyHash != null)
+ if (expectCertificateVerifyMessage())
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
@@ -434,6 +432,9 @@ public class TlsServerProtocol
// Verify the CertificateVerify message contains a correct signature.
try
{
+ // TODO For TLS 1.2, this needs to be the hash specified in the DigitallySigned
+ byte[] certificateVerifyHash = getCurrentPRFHash(getContext(), prepareFinishHash, null);
+
org.bouncycastle.asn1.x509.Certificate x509Cert = this.peerCertificate.getCertificateAt(0);
SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
AsymmetricKeyParameter publicKey = PublicKeyFactory.createKey(keyInfo);
@@ -441,7 +442,7 @@ public class TlsServerProtocol
TlsSigner tlsSigner = TlsUtils.createTlsSigner(this.clientCertificateType);
tlsSigner.init(getContext());
tlsSigner.verifyRawSignature(clientCertificateVerify.getAlgorithm(),
- clientCertificateVerify.getSignature(), publicKey, this.certificateVerifyHash);
+ clientCertificateVerify.getSignature(), publicKey, certificateVerifyHash);
}
catch (Exception e)
{
@@ -568,20 +569,12 @@ public class TlsServerProtocol
establishMasterSecret(getContext(), keyExchange);
recordStream.setPendingConnectionState(getPeer().getCompression(), getPeer().getCipher());
+ this.prepareFinishHash = recordStream.prepareToFinish();
+
if (!expectSessionTicket)
{
sendChangeCipherSpecMessage();
}
-
- if (expectCertificateVerifyMessage())
- {
- // TODO For TLS 1.2, this can't be calculated until we see what hash algorithm the sender used
- this.certificateVerifyHash = recordStream.getCurrentPRFHash(null);
- }
- else
- {
- this.recordStream.getHandshakeHash().stopTracking();
- }
}
protected void sendCertificateRequestMessage(CertificateRequest certificateRequest)