From ae809eddc05da059ff401787e17fb3e96cd4fe64 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Tue, 6 Nov 2018 16:55:58 +0700 Subject: TLS: Update to RFC 7627 from draft-ietf-tls-session-hash-04 --- crypto/src/crypto/tls/AbstractTlsContext.cs | 20 +++--- crypto/src/crypto/tls/AbstractTlsPeer.cs | 5 ++ crypto/src/crypto/tls/DtlsClientProtocol.cs | 79 ++++++++++++----------- crypto/src/crypto/tls/DtlsServerProtocol.cs | 40 +++++++++--- crypto/src/crypto/tls/ExporterLabel.cs | 2 +- crypto/src/crypto/tls/SecurityParameters.cs | 7 +- crypto/src/crypto/tls/SessionParameters.cs | 21 +++++- crypto/src/crypto/tls/TlsClientProtocol.cs | 45 +++++++------ crypto/src/crypto/tls/TlsPeer.cs | 15 +++++ crypto/src/crypto/tls/TlsProtocol.cs | 1 + crypto/src/crypto/tls/TlsServerProtocol.cs | 26 +++++--- crypto/src/crypto/tls/TlsSessionImpl.cs | 21 +++--- crypto/src/crypto/tls/TlsUtilities.cs | 4 +- crypto/test/src/crypto/tls/test/MockDtlsClient.cs | 1 - crypto/test/src/crypto/tls/test/MockTlsClient.cs | 1 - 15 files changed, 183 insertions(+), 105 deletions(-) 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); @@ -638,6 +641,18 @@ namespace Org.BouncyCastle.Crypto.Tls // 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 @@ -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 @@ -649,6 +649,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 @@ -5,6 +5,21 @@ namespace Org.BouncyCastle.Crypto.Tls { public interface TlsPeer { + /// + /// This implementation supports RFC 7627 and will always negotiate the extended_master_secret + /// extension where possible. + /// + /// + /// 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). + /// + /// + /// true if the handshake should be aborted when the peer does not negotiate the + /// extended_master_secret extension, or false to support legacy interoperability. + /// + bool RequiresExtendedMasterSecret(); + /// /// 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 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. -- cgit 1.4.1