diff --git a/crypto/src/crypto/tls/AbstractTlsContext.cs b/crypto/src/crypto/tls/AbstractTlsContext.cs
index ae7efc64d..4c484fe64 100644
--- a/crypto/src/crypto/tls/AbstractTlsContext.cs
+++ b/crypto/src/crypto/tls/AbstractTlsContext.cs
@@ -107,19 +107,21 @@ namespace Org.BouncyCastle.Crypto.Tls
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;
diff --git a/crypto/src/crypto/tls/AbstractTlsPeer.cs b/crypto/src/crypto/tls/AbstractTlsPeer.cs
index 81a53386c..1bbea68c8 100644
--- a/crypto/src/crypto/tls/AbstractTlsPeer.cs
+++ b/crypto/src/crypto/tls/AbstractTlsPeer.cs
@@ -6,6 +6,11 @@ namespace Org.BouncyCastle.Crypto.Tls
public abstract class AbstractTlsPeer
: TlsPeer
{
+ public virtual bool RequiresExtendedMasterSecret()
+ {
+ return false;
+ }
+
public virtual bool ShouldUseGmtUnixTime()
{
/*
diff --git a/crypto/src/crypto/tls/DtlsClientProtocol.cs b/crypto/src/crypto/tls/DtlsClientProtocol.cs
index ae6e6a573..ce0c4c767 100644
--- a/crypto/src/crypto/tls/DtlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsClientProtocol.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Crypto.Tls
if (sessionToResume != null && sessionToResume.IsResumable)
{
SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
- if (sessionParameters != null)
+ if (sessionParameters != null && sessionParameters.IsExtendedMasterSecret)
{
state.tlsSession = sessionToResume;
state.sessionParameters = sessionParameters;
@@ -356,6 +356,7 @@ namespace Org.BouncyCastle.Crypto.Tls
state.sessionParameters = new SessionParameters.Builder()
.SetCipherSuite(securityParameters.CipherSuite)
.SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
+ .SetExtendedMasterSecret(securityParameters.IsExtendedMasterSecret)
.SetMasterSecret(securityParameters.MasterSecret)
.SetPeerCertificate(serverCertificate)
.SetPskIdentity(securityParameters.PskIdentity)
@@ -383,8 +384,6 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
@@ -392,10 +391,8 @@ namespace Org.BouncyCastle.Crypto.Tls
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;
@@ -407,20 +404,35 @@ namespace Org.BouncyCastle.Crypto.Tls
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)
{
@@ -455,18 +467,9 @@ namespace Org.BouncyCastle.Crypto.Tls
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();
}
@@ -616,7 +619,7 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
@@ -639,6 +642,18 @@ namespace Org.BouncyCastle.Crypto.Tls
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
* the SCSV, so an Extended Server Hello is always allowed.
@@ -725,7 +740,7 @@ namespace Org.BouncyCastle.Crypto.Tls
securityParameters.cipherSuite = selectedCipherSuite;
securityParameters.compressionAlgorithm = selectedCompressionMethod;
- if (sessionServerExtensions != null)
+ if (sessionServerExtensions != null && sessionServerExtensions.Count > 0)
{
{
/*
@@ -740,8 +755,6 @@ namespace Org.BouncyCastle.Crypto.Tls
securityParameters.encryptThenMac = serverSentEncryptThenMAC;
}
- securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
-
securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
@@ -760,13 +773,6 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
@@ -839,7 +845,6 @@ namespace Org.BouncyCastle.Crypto.Tls
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;
diff --git a/crypto/src/crypto/tls/DtlsServerProtocol.cs b/crypto/src/crypto/tls/DtlsServerProtocol.cs
index 3032269d1..1095014cd 100644
--- a/crypto/src/crypto/tls/DtlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsServerProtocol.cs
@@ -268,6 +268,24 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
@@ -356,7 +374,7 @@ namespace Org.BouncyCastle.Crypto.Tls
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
@@ -380,14 +398,12 @@ namespace Org.BouncyCastle.Crypto.Tls
* 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);
}
@@ -397,7 +413,7 @@ namespace Org.BouncyCastle.Crypto.Tls
* extensions.
*/
- if (state.serverExtensions != null)
+ if (state.serverExtensions.Count > 0)
{
securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions);
@@ -583,12 +599,18 @@ namespace Org.BouncyCastle.Crypto.Tls
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);
diff --git a/crypto/src/crypto/tls/ExporterLabel.cs b/crypto/src/crypto/tls/ExporterLabel.cs
index 5970769d7..12603f3ff 100644
--- a/crypto/src/crypto/tls/ExporterLabel.cs
+++ b/crypto/src/crypto/tls/ExporterLabel.cs
@@ -30,7 +30,7 @@ namespace Org.BouncyCastle.Crypto.Tls
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";
}
diff --git a/crypto/src/crypto/tls/SecurityParameters.cs b/crypto/src/crypto/tls/SecurityParameters.cs
index 3b851587d..f3ec7011e 100644
--- a/crypto/src/crypto/tls/SecurityParameters.cs
+++ b/crypto/src/crypto/tls/SecurityParameters.cs
@@ -52,7 +52,7 @@ namespace Org.BouncyCastle.Crypto.Tls
/**
* @return {@link CompressionMethod}
*/
- public byte CompressionAlgorithm
+ public virtual byte CompressionAlgorithm
{
get { return compressionAlgorithm; }
}
@@ -99,5 +99,10 @@ namespace Org.BouncyCastle.Crypto.Tls
{
get { return srpIdentity; }
}
+
+ public virtual bool IsExtendedMasterSecret
+ {
+ get { return extendedMasterSecret; }
+ }
}
}
diff --git a/crypto/src/crypto/tls/SessionParameters.cs b/crypto/src/crypto/tls/SessionParameters.cs
index a1eb5f27c..e827172ea 100644
--- a/crypto/src/crypto/tls/SessionParameters.cs
+++ b/crypto/src/crypto/tls/SessionParameters.cs
@@ -17,6 +17,7 @@ namespace Org.BouncyCastle.Crypto.Tls
private byte[] mPskIdentity = null;
private byte[] mSrpIdentity = null;
private byte[] mEncodedServerExtensions = null;
+ private bool mExtendedMasterSecret = false;
public Builder()
{
@@ -28,7 +29,7 @@ namespace Org.BouncyCastle.Crypto.Tls
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)
@@ -43,6 +44,12 @@ namespace Org.BouncyCastle.Crypto.Tls
return this;
}
+ public Builder SetExtendedMasterSecret(bool extendedMasterSecret)
+ {
+ this.mExtendedMasterSecret = extendedMasterSecret;
+ return this;
+ }
+
public Builder SetMasterSecret(byte[] masterSecret)
{
this.mMasterSecret = masterSecret;
@@ -96,9 +103,11 @@ namespace Org.BouncyCastle.Crypto.Tls
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;
@@ -107,6 +116,7 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mPskIdentity = Arrays.Clone(pskIdentity);
this.mSrpIdentity = Arrays.Clone(srpIdentity);
this.mEncodedServerExtensions = encodedServerExtensions;
+ this.mExtendedMasterSecret = extendedMasterSecret;
}
public void Clear()
@@ -120,7 +130,7 @@ namespace Org.BouncyCastle.Crypto.Tls
public SessionParameters Copy()
{
return new SessionParameters(mCipherSuite, mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
- mPskIdentity, mSrpIdentity, mEncodedServerExtensions);
+ mPskIdentity, mSrpIdentity, mEncodedServerExtensions, mExtendedMasterSecret);
}
public int CipherSuite
@@ -133,6 +143,11 @@ namespace Org.BouncyCastle.Crypto.Tls
get { return mCompressionAlgorithm; }
}
+ public bool IsExtendedMasterSecret
+ {
+ get { return mExtendedMasterSecret; }
+ }
+
public byte[] MasterSecret
{
get { return mMasterSecret; }
diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs
index 8de76c2f8..17b756693 100644
--- a/crypto/src/crypto/tls/TlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/TlsClientProtocol.cs
@@ -96,7 +96,7 @@ namespace Org.BouncyCastle.Crypto.Tls
if (sessionToResume != null && sessionToResume.IsResumable)
{
SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
- if (sessionParameters != null)
+ if (sessionParameters != null && sessionParameters.IsExtendedMasterSecret)
{
this.mTlsSession = sessionToResume;
this.mSessionParameters = sessionParameters;
@@ -640,7 +640,7 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
/*
- * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
+ * RFC 3546 2.2 The extended server hello message format MAY be sent in place of the server
* hello message when the client has requested extended functionality via the extended
* client hello message specified in Section 2.1. ... Note that the extended server hello
* message is only sent in response to an extended client hello message. This prevents the
@@ -650,6 +650,19 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mServerExtensions = 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)
+ */
+ this.mSecurityParameters.extendedMasterSecret = !TlsUtilities.IsSsl(mTlsClientContext)
+ && TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mServerExtensions);
+
+ if (!mSecurityParameters.IsExtendedMasterSecret
+ && (mResumedSession || mTlsClient.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.
*
@@ -738,7 +751,7 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mSecurityParameters.cipherSuite = selectedCipherSuite;
this.mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
- if (sessionServerExtensions != null)
+ if (sessionServerExtensions != null && sessionServerExtensions.Count > 0)
{
{
/*
@@ -754,8 +767,6 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
}
- this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
-
this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
sessionServerExtensions, AlertDescription.illegal_parameter);
@@ -774,13 +785,6 @@ namespace Org.BouncyCastle.Crypto.Tls
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)
{
this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
@@ -837,14 +841,20 @@ namespace Org.BouncyCastle.Crypto.Tls
if (session_id.Length > 0 && this.mSessionParameters != null)
{
- if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite)
+ if (!mSessionParameters.IsExtendedMasterSecret
+ || !Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite)
|| !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm))
{
session_id = TlsUtilities.EmptyBytes;
}
}
- this.mClientExtensions = this.mTlsClient.GetClientExtensions();
+ this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mTlsClient.GetClientExtensions());
+
+ if (!client_version.IsSsl)
+ {
+ TlsExtensionsUtilities.AddExtendedMasterSecretExtension(this.mClientExtensions);
+ }
HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);
@@ -869,8 +879,6 @@ namespace Org.BouncyCastle.Crypto.Tls
if (noRenegExt && noRenegScsv)
{
// TODO Consider whether to default to a client extension instead
- // this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions);
- // this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
}
@@ -891,10 +899,7 @@ namespace Org.BouncyCastle.Crypto.Tls
TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message);
- if (mClientExtensions != null)
- {
- WriteExtensions(message, mClientExtensions);
- }
+ WriteExtensions(message, mClientExtensions);
message.WriteToRecordStream(this);
}
diff --git a/crypto/src/crypto/tls/TlsPeer.cs b/crypto/src/crypto/tls/TlsPeer.cs
index 1ae41a41a..993fdf93f 100644
--- a/crypto/src/crypto/tls/TlsPeer.cs
+++ b/crypto/src/crypto/tls/TlsPeer.cs
@@ -6,6 +6,21 @@ namespace Org.BouncyCastle.Crypto.Tls
public interface TlsPeer
{
/// <summary>
+ /// This implementation supports RFC 7627 and will always negotiate the extended_master_secret
+ /// extension where possible.
+ /// </summary>
+ /// <remarks>
+ /// When connecting to a peer that does not offer/accept this extension, it is recommended to
+ /// abort the handshake. This option is provided for interoperability with legacy peers,
+ /// although some TLS features will be disabled in that case (see RFC 7627 5.4).
+ /// </remarks>
+ /// <returns>
+ /// <code>true</code> if the handshake should be aborted when the peer does not negotiate the
+ /// extended_master_secret extension, or <code>false</code> to support legacy interoperability.
+ /// </returns>
+ bool RequiresExtendedMasterSecret();
+
+ /// <summary>
/// draft-mathewson-no-gmtunixtime-00 2. "If existing users of a TLS implementation may rely on
/// gmt_unix_time containing the current time, we recommend that implementors MAY provide the
/// ability to set gmt_unix_time as an option only, off by default."
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
index bbb76d53c..394967c37 100644
--- a/crypto/src/crypto/tls/TlsProtocol.cs
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -288,6 +288,7 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mSessionParameters = new SessionParameters.Builder()
.SetCipherSuite(this.mSecurityParameters.CipherSuite)
.SetCompressionAlgorithm(this.mSecurityParameters.CompressionAlgorithm)
+ .SetExtendedMasterSecret(this.mSecurityParameters.IsExtendedMasterSecret)
.SetMasterSecret(this.mSecurityParameters.MasterSecret)
.SetPeerCertificate(this.mPeerCertificate)
.SetPskIdentity(this.mSecurityParameters.PskIdentity)
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
index f5285d80b..e610b5950 100644
--- a/crypto/src/crypto/tls/TlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -560,12 +560,18 @@ namespace Org.BouncyCastle.Crypto.Tls
this.mClientExtensions = ReadExtensions(buf);
/*
- * 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)
*/
this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mClientExtensions);
+ if (!mSecurityParameters.IsExtendedMasterSecret && mTlsServer.RequiresExtendedMasterSecret())
+ {
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
ContextAdmin.SetClientVersion(client_version);
@@ -724,7 +730,7 @@ namespace Org.BouncyCastle.Crypto.Tls
TlsUtilities.WriteUint16(selectedCipherSuite, message);
TlsUtilities.WriteUint8(selectedCompressionMethod, message);
- this.mServerExtensions = mTlsServer.GetServerExtensions();
+ this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mTlsServer.GetServerExtensions());
/*
* RFC 5746 3.6. Server Behavior: Initial Handshake
@@ -748,14 +754,16 @@ namespace Org.BouncyCastle.Crypto.Tls
* If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
* "renegotiation_info" extension in the ServerHello message.
*/
- this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions);
this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
}
}
- if (mSecurityParameters.extendedMasterSecret)
+ if (TlsUtilities.IsSsl(mTlsServerContext))
+ {
+ mSecurityParameters.extendedMasterSecret = false;
+ }
+ else if (mSecurityParameters.IsExtendedMasterSecret)
{
- this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions);
TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions);
}
@@ -765,7 +773,7 @@ namespace Org.BouncyCastle.Crypto.Tls
* extensions.
*/
- if (this.mServerExtensions != null)
+ if (this.mServerExtensions.Count > 0)
{
this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);
diff --git a/crypto/src/crypto/tls/TlsSessionImpl.cs b/crypto/src/crypto/tls/TlsSessionImpl.cs
index 866392623..4f0ff819e 100644
--- a/crypto/src/crypto/tls/TlsSessionImpl.cs
+++ b/crypto/src/crypto/tls/TlsSessionImpl.cs
@@ -8,17 +8,21 @@ namespace Org.BouncyCastle.Crypto.Tls
: TlsSession
{
internal readonly byte[] mSessionID;
- internal SessionParameters mSessionParameters;
+ internal readonly SessionParameters mSessionParameters;
+ internal bool mResumable;
internal TlsSessionImpl(byte[] sessionID, SessionParameters sessionParameters)
{
if (sessionID == null)
throw new ArgumentNullException("sessionID");
- if (sessionID.Length < 1 || sessionID.Length > 32)
- throw new ArgumentException("must have length between 1 and 32 bytes, inclusive", "sessionID");
+ if (sessionID.Length > 32)
+ throw new ArgumentException("cannot be longer than 32 bytes", "sessionID");
this.mSessionID = Arrays.Clone(sessionID);
this.mSessionParameters = sessionParameters;
+ this.mResumable = sessionID.Length > 0
+ && null != sessionParameters
+ && sessionParameters.IsExtendedMasterSecret;
}
public virtual SessionParameters ExportSessionParameters()
@@ -36,19 +40,12 @@ namespace Org.BouncyCastle.Crypto.Tls
public virtual void Invalidate()
{
- lock (this)
- {
- if (this.mSessionParameters != null)
- {
- this.mSessionParameters.Clear();
- this.mSessionParameters = null;
- }
- }
+ lock (this) this.mResumable = false;
}
public virtual bool IsResumable
{
- get { lock (this) return this.mSessionParameters != null; }
+ get { lock (this) return mResumable; }
}
}
}
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index 698bf6da6..e6bd253aa 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -963,14 +963,14 @@ namespace Org.BouncyCastle.Crypto.Tls
{
SecurityParameters securityParameters = context.SecurityParameters;
- byte[] seed = securityParameters.extendedMasterSecret
+ byte[] seed = securityParameters.IsExtendedMasterSecret
? securityParameters.SessionHash
: Concat(securityParameters.ClientRandom, securityParameters.ServerRandom);
if (IsSsl(context))
return CalculateMasterSecret_Ssl(pre_master_secret, seed);
- string asciiLabel = securityParameters.extendedMasterSecret
+ string asciiLabel = securityParameters.IsExtendedMasterSecret
? ExporterLabel.extended_master_secret
: ExporterLabel.master_secret;
diff --git a/crypto/test/src/crypto/tls/test/MockDtlsClient.cs b/crypto/test/src/crypto/tls/test/MockDtlsClient.cs
index 8d76c97b2..51493fae1 100644
--- a/crypto/test/src/crypto/tls/test/MockDtlsClient.cs
+++ b/crypto/test/src/crypto/tls/test/MockDtlsClient.cs
@@ -68,7 +68,6 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
{
IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions());
TlsExtensionsUtilities.AddEncryptThenMacExtension(clientExtensions);
- TlsExtensionsUtilities.AddExtendedMasterSecretExtension(clientExtensions);
{
/*
* NOTE: If you are copying test code, do not blindly set these extensions in your own client.
diff --git a/crypto/test/src/crypto/tls/test/MockTlsClient.cs b/crypto/test/src/crypto/tls/test/MockTlsClient.cs
index d8deabf96..f28236f0b 100644
--- a/crypto/test/src/crypto/tls/test/MockTlsClient.cs
+++ b/crypto/test/src/crypto/tls/test/MockTlsClient.cs
@@ -58,7 +58,6 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
{
IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions());
TlsExtensionsUtilities.AddEncryptThenMacExtension(clientExtensions);
- TlsExtensionsUtilities.AddExtendedMasterSecretExtension(clientExtensions);
{
/*
* NOTE: If you are copying test code, do not blindly set these extensions in your own client.
|