Skip to content

Commit

Permalink
TLS: Update to RFC 7627 from draft-ietf-tls-session-hash-04
Browse files Browse the repository at this point in the history
  • Loading branch information
peterdettman committed Nov 6, 2018
1 parent aeb4be5 commit ae809ed
Show file tree
Hide file tree
Showing 15 changed files with 183 additions and 105 deletions.
20 changes: 11 additions & 9 deletions crypto/src/crypto/tls/AbstractTlsContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,21 @@ public virtual object UserObject

public virtual byte[] ExportKeyingMaterial(string asciiLabel, byte[] context_value, int length)
{
/*
* TODO[session-hash]
*
* draft-ietf-tls-session-hash-04 5.4. If a client or server chooses to continue with a full
* handshake without the extended master secret extension, [..] the client or server MUST
* NOT export any key material based on the new master secret for any subsequent
* application-level authentication. In particular, it MUST disable [RFC5705] [..].
*/

if (context_value != null && !TlsUtilities.IsValidUint16(context_value.Length))
throw new ArgumentException("must have length less than 2^16 (or be null)", "context_value");

SecurityParameters sp = SecurityParameters;
if (!sp.IsExtendedMasterSecret)
{
/*
* RFC 7627 5.4. If a client or server chooses to continue with a full handshake without
* the extended master secret extension, [..] the client or server MUST NOT export any
* key material based on the new master secret for any subsequent application-level
* authentication. In particular, it MUST disable [RFC5705] [..].
*/
throw new InvalidOperationException("cannot export keying material without extended_master_secret");
}

byte[] cr = sp.ClientRandom, sr = sp.ServerRandom;

int seedLength = cr.Length + sr.Length;
Expand Down
5 changes: 5 additions & 0 deletions crypto/src/crypto/tls/AbstractTlsPeer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ namespace Org.BouncyCastle.Crypto.Tls
public abstract class AbstractTlsPeer
: TlsPeer
{
public virtual bool RequiresExtendedMasterSecret()
{
return false;
}

public virtual bool ShouldUseGmtUnixTime()
{
/*
Expand Down
79 changes: 42 additions & 37 deletions crypto/src/crypto/tls/DtlsClientProtocol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transpo
if (sessionToResume != null && sessionToResume.IsResumable)
{
SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
if (sessionParameters != null)
if (sessionParameters != null && sessionParameters.IsExtendedMasterSecret)
{
state.tlsSession = sessionToResume;
state.sessionParameters = sessionParameters;
Expand Down Expand Up @@ -356,6 +356,7 @@ internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsR
state.sessionParameters = new SessionParameters.Builder()
.SetCipherSuite(securityParameters.CipherSuite)
.SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
.SetExtendedMasterSecret(securityParameters.IsExtendedMasterSecret)
.SetMasterSecret(securityParameters.MasterSecret)
.SetPeerCertificate(serverCertificate)
.SetPskIdentity(securityParameters.PskIdentity)
Expand Down Expand Up @@ -383,19 +384,15 @@ protected virtual byte[] GenerateCertificateVerify(ClientHandshakeState state, D

protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
{
MemoryStream buf = new MemoryStream();

ProtocolVersion client_version = client.ClientVersion;
if (!client_version.IsDtls)
throw new TlsFatalAlert(AlertDescription.internal_error);

TlsClientContextImpl context = state.clientContext;

context.SetClientVersion(client_version);
TlsUtilities.WriteVersion(client_version, buf);

SecurityParameters securityParameters = context.SecurityParameters;
buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);

// Session ID
byte[] session_id = TlsUtilities.EmptyBytes;
Expand All @@ -407,20 +404,35 @@ protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClie
session_id = TlsUtilities.EmptyBytes;
}
}
TlsUtilities.WriteOpaque8(session_id, buf);

// Cookie
TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

bool fallback = client.IsFallback;

/*
* Cipher suites
*/
state.offeredCipherSuites = client.GetCipherSuites();

// Integer -> byte[]
state.clientExtensions = client.GetClientExtensions();
if (session_id.Length > 0 && state.sessionParameters != null)
{
if (!state.sessionParameters.IsExtendedMasterSecret
|| !Arrays.Contains(state.offeredCipherSuites, state.sessionParameters.CipherSuite)
|| CompressionMethod.cls_null != state.sessionParameters.CompressionAlgorithm)
{
session_id = TlsUtilities.EmptyBytes;
}
}

state.clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(client.GetClientExtensions());

TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.clientExtensions);

MemoryStream buf = new MemoryStream();

TlsUtilities.WriteVersion(client_version, buf);

buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);

TlsUtilities.WriteOpaque8(session_id, buf);

// Cookie
TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

// Cipher Suites (and SCSV)
{
Expand Down Expand Up @@ -455,18 +467,9 @@ protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClie
TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf);
}

// TODO Add support for compression
// Compression methods
// state.offeredCompressionMethods = client.getCompressionMethods();
state.offeredCompressionMethods = new byte[]{ CompressionMethod.cls_null };
TlsUtilities.WriteUint8ArrayWithUint8Length(new byte[]{ CompressionMethod.cls_null }, buf);

TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf);

// Extensions
if (state.clientExtensions != null)
{
TlsProtocol.WriteExtensions(buf, state.clientExtensions);
}
TlsProtocol.WriteExtensions(buf, state.clientExtensions);

return buf.ToArray();
}
Expand Down Expand Up @@ -616,7 +619,7 @@ protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] bod
state.client.NotifySelectedCipherSuite(selectedCipherSuite);

byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
if (CompressionMethod.cls_null != selectedCompressionMethod)
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
state.client.NotifySelectedCompressionMethod(selectedCompressionMethod);

Expand All @@ -638,6 +641,18 @@ protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] bod
// Integer -> byte[]
state.serverExtensions = TlsProtocol.ReadExtensions(buf);

/*
* RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended
* master secret [..]. (and see 5.2, 5.3)
*/
securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.serverExtensions);

if (!securityParameters.IsExtendedMasterSecret
&& (state.resumedSession || state.client.RequiresExtendedMasterSecret()))
{
throw new TlsFatalAlert(AlertDescription.handshake_failure);
}

/*
* RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
* extended client hello message. However, see RFC 5746 exception below. We always include
Expand Down Expand Up @@ -725,7 +740,7 @@ protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] bod
securityParameters.cipherSuite = selectedCipherSuite;
securityParameters.compressionAlgorithm = selectedCompressionMethod;

if (sessionServerExtensions != null)
if (sessionServerExtensions != null && sessionServerExtensions.Count > 0)
{
{
/*
Expand All @@ -740,8 +755,6 @@ protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] bod
securityParameters.encryptThenMac = serverSentEncryptThenMAC;
}

securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);

securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);

Expand All @@ -760,13 +773,6 @@ protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] bod
AlertDescription.illegal_parameter);
}

/*
* TODO[session-hash]
*
* draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
* that do not use the extended master secret [..]. (and see 5.2, 5.3)
*/

if (sessionClientExtensions != null)
{
state.client.ProcessServerExtensions(sessionServerExtensions);
Expand Down Expand Up @@ -839,7 +845,6 @@ protected internal class ClientHandshakeState
internal SessionParameters sessionParameters = null;
internal SessionParameters.Builder sessionParametersBuilder = null;
internal int[] offeredCipherSuites = null;
internal byte[] offeredCompressionMethods = null;
internal IDictionary clientExtensions = null;
internal IDictionary serverExtensions = null;
internal byte[] selectedSessionID = null;
Expand Down
40 changes: 31 additions & 9 deletions crypto/src/crypto/tls/DtlsServerProtocol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,24 @@ internal virtual DtlsTransport ServerHandshake(ServerHandshakeState state, DtlsR

handshake.Finish();

//{
// state.sessionParameters = new SessionParameters.Builder()
// .SetCipherSuite(securityParameters.CipherSuite)
// .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
// .SetExtendedMasterSecret(securityParameters.IsExtendedMasterSecret)
// .SetMasterSecret(securityParameters.MasterSecret)
// .SetPeerCertificate(state.clientCertificate)
// .SetPskIdentity(securityParameters.PskIdentity)
// .SetSrpIdentity(securityParameters.SrpIdentity)
// // TODO Consider filtering extensions that aren't relevant to resumed sessions
// .SetServerExtensions(state.serverExtensions)
// .Build();

// state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters);

// state.serverContext.SetResumableSession(state.tlsSession);
//}

state.server.NotifyHandshakeComplete();

return new DtlsTransport(recordLayer);
Expand Down Expand Up @@ -356,7 +374,7 @@ protected virtual byte[] GenerateServerHello(ServerHandshakeState state)
TlsUtilities.WriteUint16(selectedCipherSuite, buf);
TlsUtilities.WriteUint8(selectedCompressionMethod, buf);

state.serverExtensions = state.server.GetServerExtensions();
state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.server.GetServerExtensions());

/*
* RFC 5746 3.6. Server Behavior: Initial Handshake
Expand All @@ -380,14 +398,12 @@ protected virtual byte[] GenerateServerHello(ServerHandshakeState state)
* If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
* "renegotiation_info" extension in the ServerHello message.
*/
state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
}
}

if (securityParameters.extendedMasterSecret)
if (securityParameters.IsExtendedMasterSecret)
{
state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions);
}

Expand All @@ -397,7 +413,7 @@ protected virtual byte[] GenerateServerHello(ServerHandshakeState state)
* extensions.
*/

if (state.serverExtensions != null)
if (state.serverExtensions.Count > 0)
{
securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions);

Expand Down Expand Up @@ -583,12 +599,18 @@ protected virtual void ProcessClientHello(ServerHandshakeState state, byte[] bod
SecurityParameters securityParameters = context.SecurityParameters;

/*
* TODO[session-hash]
*
* draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
* that do not use the extended master secret [..]. (and see 5.2, 5.3)
* TODO[resumption] Check RFC 7627 5.4. for required behaviour
*/

/*
* RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended
* master secret [..]. (and see 5.2, 5.3)
*/
securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions);
if (!securityParameters.IsExtendedMasterSecret && state.server.RequiresExtendedMasterSecret())
{
throw new TlsFatalAlert(AlertDescription.handshake_failure);
}

context.SetClientVersion(client_version);

Expand Down
2 changes: 1 addition & 1 deletion crypto/src/crypto/tls/ExporterLabel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public abstract class ExporterLabel
public const string dtls_srtp = "EXTRACTOR-dtls_srtp";

/*
* draft-ietf-tls-session-hash-04
* RFC 7627
*/
public static readonly string extended_master_secret = "extended master secret";
}
Expand Down
7 changes: 6 additions & 1 deletion crypto/src/crypto/tls/SecurityParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public virtual int CipherSuite
/**
* @return {@link CompressionMethod}
*/
public byte CompressionAlgorithm
public virtual byte CompressionAlgorithm
{
get { return compressionAlgorithm; }
}
Expand Down Expand Up @@ -99,5 +99,10 @@ public virtual byte[] SrpIdentity
{
get { return srpIdentity; }
}

public virtual bool IsExtendedMasterSecret
{
get { return extendedMasterSecret; }
}
}
}
21 changes: 18 additions & 3 deletions crypto/src/crypto/tls/SessionParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public sealed class Builder
private byte[] mPskIdentity = null;
private byte[] mSrpIdentity = null;
private byte[] mEncodedServerExtensions = null;
private bool mExtendedMasterSecret = false;

public Builder()
{
Expand All @@ -28,7 +29,7 @@ public SessionParameters Build()
Validate(this.mCompressionAlgorithm >= 0, "compressionAlgorithm");
Validate(this.mMasterSecret != null, "masterSecret");
return new SessionParameters(mCipherSuite, (byte)mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
mPskIdentity, mSrpIdentity, mEncodedServerExtensions);
mPskIdentity, mSrpIdentity, mEncodedServerExtensions, mExtendedMasterSecret);
}

public Builder SetCipherSuite(int cipherSuite)
Expand All @@ -43,6 +44,12 @@ public Builder SetCompressionAlgorithm(byte compressionAlgorithm)
return this;
}

public Builder SetExtendedMasterSecret(bool extendedMasterSecret)
{
this.mExtendedMasterSecret = extendedMasterSecret;
return this;
}

public Builder SetMasterSecret(byte[] masterSecret)
{
this.mMasterSecret = masterSecret;
Expand Down Expand Up @@ -96,9 +103,11 @@ private void Validate(bool condition, string parameter)
private byte[] mPskIdentity;
private byte[] mSrpIdentity;
private byte[] mEncodedServerExtensions;
private bool mExtendedMasterSecret;

private SessionParameters(int cipherSuite, byte compressionAlgorithm, byte[] masterSecret,
Certificate peerCertificate, byte[] pskIdentity, byte[] srpIdentity, byte[] encodedServerExtensions)
Certificate peerCertificate, byte[] pskIdentity, byte[] srpIdentity, byte[] encodedServerExtensions,
bool extendedMasterSecret)
{
this.mCipherSuite = cipherSuite;
this.mCompressionAlgorithm = compressionAlgorithm;
Expand All @@ -107,6 +116,7 @@ private SessionParameters(int cipherSuite, byte compressionAlgorithm, byte[] mas
this.mPskIdentity = Arrays.Clone(pskIdentity);
this.mSrpIdentity = Arrays.Clone(srpIdentity);
this.mEncodedServerExtensions = encodedServerExtensions;
this.mExtendedMasterSecret = extendedMasterSecret;
}

public void Clear()
Expand All @@ -120,7 +130,7 @@ public void Clear()
public SessionParameters Copy()
{
return new SessionParameters(mCipherSuite, mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
mPskIdentity, mSrpIdentity, mEncodedServerExtensions);
mPskIdentity, mSrpIdentity, mEncodedServerExtensions, mExtendedMasterSecret);
}

public int CipherSuite
Expand All @@ -133,6 +143,11 @@ public byte CompressionAlgorithm
get { return mCompressionAlgorithm; }
}

public bool IsExtendedMasterSecret
{
get { return mExtendedMasterSecret; }
}

public byte[] MasterSecret
{
get { return mMasterSecret; }
Expand Down
Loading

0 comments on commit ae809ed

Please sign in to comment.