diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-07-08 23:19:24 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-07-08 23:19:24 +0700 |
commit | 2d71de0765cbc92f064a29e03aab8ff88725deb4 (patch) | |
tree | d7ed01c72c460299c04d1cd3517ba676133dbd11 | |
parent | Refactoring in DTLS (diff) | |
download | BouncyCastle.NET-ed25519-2d71de0765cbc92f064a29e03aab8ff88725deb4.tar.xz |
DTLS: refactoring around extended_master_secret
- especially the interaction with session resumption and the methods relating to use of EMS.
-rw-r--r-- | crypto/src/tls/DtlsClientProtocol.cs | 243 | ||||
-rw-r--r-- | crypto/src/tls/DtlsServerProtocol.cs | 286 | ||||
-rw-r--r-- | crypto/src/tls/TlsClientProtocol.cs | 12 | ||||
-rw-r--r-- | crypto/src/tls/TlsServerProtocol.cs | 2 |
4 files changed, 317 insertions, 226 deletions
diff --git a/crypto/src/tls/DtlsClientProtocol.cs b/crypto/src/tls/DtlsClientProtocol.cs index eec920c4a..da39320ea 100644 --- a/crypto/src/tls/DtlsClientProtocol.cs +++ b/crypto/src/tls/DtlsClientProtocol.cs @@ -35,27 +35,6 @@ namespace Org.BouncyCastle.Tls SecurityParameters securityParameters = clientContext.SecurityParameters; securityParameters.m_extendedPadding = client.ShouldUseExtendedPadding(); - TlsSession sessionToResume = client.GetSessionToResume(); - if (sessionToResume != null && sessionToResume.IsResumable) - { - SessionParameters sessionParameters = sessionToResume.ExportSessionParameters(); - - if (sessionParameters != null - && (sessionParameters.IsExtendedMasterSecret - || (!client.RequiresExtendedMasterSecret() && client.AllowLegacyResumption()))) - { - TlsCrypto crypto = clientContext.Crypto; - TlsSecret sessionMasterSecret = TlsUtilities.GetSessionMasterSecret(crypto, - sessionParameters.MasterSecret); - if (sessionMasterSecret != null) - { - state.tlsSession = sessionToResume; - state.sessionParameters = sessionParameters; - state.sessionMasterSecret = sessionMasterSecret; - } - } - } - DtlsRecordLayer recordLayer = new DtlsRecordLayer(clientContext, client, transport); client.NotifyCloseHandle(recordLayer); @@ -129,6 +108,8 @@ namespace Org.BouncyCastle.Tls recordLayer.SetWriteVersion(recordLayerVersion); ProcessServerHello(state, serverMessage.Body); + + ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.MaxFragmentLength); } else { @@ -137,8 +118,6 @@ namespace Org.BouncyCastle.Tls handshake.HandshakeHash.NotifyPrfDetermined(); - ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.MaxFragmentLength); - if (securityParameters.IsResumedSession) { securityParameters.m_masterSecret = state.sessionMasterSecret; @@ -412,7 +391,7 @@ namespace Org.BouncyCastle.Tls ProtocolVersion[] supportedVersions = client.GetProtocolVersions(); - //ProtocolVersion earliestVersion = ProtocolVersion.GetEarliestDtls(supportedVersions); + ProtocolVersion earliestVersion = ProtocolVersion.GetEarliestDtls(supportedVersions); ProtocolVersion latestVersion = ProtocolVersion.GetLatestDtls(supportedVersions); if (!ProtocolVersion.IsSupportedDtlsVersionClient(latestVersion)) @@ -421,7 +400,7 @@ namespace Org.BouncyCastle.Tls clientContext.SetClientVersion(latestVersion); clientContext.SetClientSupportedVersions(supportedVersions); - //bool offeringDtlsV12Minus = ProtocolVersion.DTLSv12.IsEqualOrLaterVersionOf(earliestVersion); + bool offeringDtlsV12Minus = ProtocolVersion.DTLSv12.IsEqualOrLaterVersionOf(earliestVersion); bool offeringDtlsV13Plus = ProtocolVersion.DTLSv13.IsEqualOrEarlierVersionOf(latestVersion); { @@ -430,12 +409,18 @@ namespace Org.BouncyCastle.Tls securityParameters.m_clientRandom = TlsProtocol.CreateRandomBlock(useGmtUnixTime, clientContext); } + TlsSession sessionToResume = offeringDtlsV12Minus ? client.GetSessionToResume() : null; + bool fallback = client.IsFallback(); state.offeredCipherSuites = client.GetCipherSuites(); state.clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(client.GetClientExtensions()); + bool shouldUseEms = client.ShouldUseExtendedMasterSecret(); + + EstablishSession(state, sessionToResume); + byte[] legacy_session_id = TlsUtilities.GetSessionID(state.tlsSession); if (legacy_session_id.Length > 0) @@ -457,7 +442,31 @@ namespace Org.BouncyCastle.Tls } } - client.NotifySessionToResume(legacy_session_id.Length < 1 ? null : state.tlsSession); + if (legacy_session_id.Length > 0 && TlsUtilities.IsExtendedMasterSecretOptional(sessionVersion)) + { + if (shouldUseEms) + { + if (!state.sessionParameters.IsExtendedMasterSecret && + !client.AllowLegacyResumption()) + { + legacy_session_id = TlsUtilities.EmptyBytes; + } + } + else + { + if (state.sessionParameters.IsExtendedMasterSecret) + { + legacy_session_id = TlsUtilities.EmptyBytes; + } + } + } + + if (legacy_session_id.Length < 1) + { + CancelSession(state); + } + + client.NotifySessionToResume(state.tlsSession); ProtocolVersion legacy_version = latestVersion; if (offeringDtlsV13Plus) @@ -493,15 +502,13 @@ namespace Org.BouncyCastle.Tls state.clientAgreements = TlsUtilities.AddKeyShareToClientHello(clientContext, client, state.clientExtensions); - if (TlsUtilities.IsExtendedMasterSecretOptional(supportedVersions) - && client.ShouldUseExtendedMasterSecret()) + if (shouldUseEms && TlsUtilities.IsExtendedMasterSecretOptional(supportedVersions)) { TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.clientExtensions); } - else if (!offeringDtlsV13Plus - && client.RequiresExtendedMasterSecret()) + else { - throw new TlsFatalAlert(AlertDescription.internal_error); + state.clientExtensions.Remove(ExtensionType.extended_master_secret); } // Cipher Suites (and SCSV) @@ -572,7 +579,7 @@ namespace Org.BouncyCastle.Tls return buf.ToArray(); } - protected virtual void InvalidateSession(ClientHandshakeState state) + protected virtual void CancelSession(ClientHandshakeState state) { if (state.sessionMasterSecret != null) { @@ -586,11 +593,53 @@ namespace Org.BouncyCastle.Tls state.sessionParameters = null; } + state.tlsSession = null; + } + + protected virtual bool EstablishSession(ClientHandshakeState state, TlsSession sessionToResume) + { + state.tlsSession = null; + state.sessionParameters = null; + state.sessionMasterSecret = null; + + if (null == sessionToResume || !sessionToResume.IsResumable) + return false; + + SessionParameters sessionParameters = sessionToResume.ExportSessionParameters(); + if (null == sessionParameters) + return false; + + ProtocolVersion sessionVersion = sessionParameters.NegotiatedVersion; + if (null == sessionVersion || !sessionVersion.IsDtls) + return false; + + bool isEms = sessionParameters.IsExtendedMasterSecret; + if (!TlsUtilities.IsExtendedMasterSecretOptional(sessionVersion)) + { + if (!isEms) + return false; + } + + TlsCrypto crypto = state.clientContext.Crypto; + TlsSecret sessionMasterSecret = TlsUtilities.GetSessionMasterSecret(crypto, sessionParameters.MasterSecret); + if (null == sessionMasterSecret) + return false; + + state.tlsSession = sessionToResume; + state.sessionParameters = sessionParameters; + state.sessionMasterSecret = sessionMasterSecret; + + return true; + } + + protected virtual void InvalidateSession(ClientHandshakeState state) + { if (state.tlsSession != null) { state.tlsSession.Invalidate(); - state.tlsSession = null; } + + CancelSession(state); } /// <exception cref="IOException"/> @@ -685,11 +734,11 @@ namespace Org.BouncyCastle.Tls MemoryStream buf = new MemoryStream(body, false); ServerHello serverHello = ServerHello.Parse(buf); - state.serverExtensions = serverHello.Extensions; + var serverHelloExtensions = serverHello.Extensions; ProtocolVersion legacy_version = serverHello.Version; ProtocolVersion supported_version = TlsExtensionsUtilities.GetSupportedVersionsExtensionServer( - state.serverExtensions); + serverHelloExtensions); ProtocolVersion server_version; if (null == supported_version) @@ -774,63 +823,15 @@ namespace Org.BouncyCastle.Tls } /* - * RFC3546 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 - * possibility that the extended server hello message could "break" existing TLS 1.0 - * clients. - */ - - /* - * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore - * extensions appearing in the client hello, and send a server hello containing no - * extensions. - */ - - /* - * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended - * master secret [..]. (and see 5.2, 5.3) - * - * RFC 8446 Appendix D. Because TLS 1.3 always hashes in the transcript up to the server - * Finished, implementations which support both TLS 1.3 and earlier versions SHOULD indicate - * the use of the Extended Master Secret extension in their APIs whenever TLS 1.3 is used. - */ - if (TlsUtilities.IsTlsV13(server_version)) - { - securityParameters.m_extendedMasterSecret = true; - } - else - { - bool acceptedExtendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension( - state.serverExtensions); - - if (acceptedExtendedMasterSecret) - { - if (!securityParameters.IsResumedSession && !client.ShouldUseExtendedMasterSecret()) - throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - else - { - if (client.RequiresExtendedMasterSecret() - || (securityParameters.IsResumedSession && !client.AllowLegacyResumption())) - { - throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - } - - securityParameters.m_extendedMasterSecret = acceptedExtendedMasterSecret; - } - - /* * * 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. */ - if (state.serverExtensions != null) + state.serverExtensions = serverHelloExtensions; + if (serverHelloExtensions != null) { - foreach (int extType in state.serverExtensions.Keys) + foreach (int extType in serverHelloExtensions.Keys) { /* * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a @@ -867,17 +868,30 @@ namespace Org.BouncyCastle.Tls } } - /* - * RFC 5746 3.4. Client Behavior: Initial Handshake - */ + byte[] renegExtData = TlsUtilities.GetExtensionData(serverHelloExtensions, + ExtensionType.renegotiation_info); + + // NOT renegotiating { /* + * RFC 5746 3.4. Client Behavior: Initial Handshake (both full and session-resumption) + */ + + /* * When a ServerHello is received, the client MUST check if it includes the * "renegotiation_info" extension: */ - byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, - ExtensionType.renegotiation_info); - if (renegExtData != null) + if (renegExtData == null) + { + /* + * If the extension is not present, the server does not support secure + * renegotiation; set secure_renegotiation flag to FALSE. In this case, some clients + * may want to terminate the handshake instead of continuing; see Section 4.1 for + * discussion. + */ + securityParameters.m_secureRenegotiation = false; + } + else { /* * If the extension is present, set the secure_renegotiation flag to TRUE. The @@ -898,13 +912,50 @@ namespace Org.BouncyCastle.Tls // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming client.NotifySecureRenegotiation(securityParameters.IsSecureRenegotiation); + // extended_master_secret + { + bool negotiatedEms = false; + + if (TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions)) + { + negotiatedEms = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(serverHelloExtensions); + + if (TlsUtilities.IsExtendedMasterSecretOptional(server_version)) + { + if (!negotiatedEms && + client.RequiresExtendedMasterSecret()) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure, + "Extended Master Secret extension is required"); + } + } + else + { + if (negotiatedEms) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, + "Server sent an unexpected extended_master_secret extension negotiating " + server_version); + } + } + } + + securityParameters.m_extendedMasterSecret = negotiatedEms; + } + + if (securityParameters.IsResumedSession && + securityParameters.IsExtendedMasterSecret != state.sessionParameters.IsExtendedMasterSecret) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure, + "Server resumed session with mismatched extended_master_secret negotiation"); + } + /* * RFC 7301 3.1. When session resumption or session tickets [...] are used, the previous * contents of this extension are irrelevant, and only the values in the new handshake * messages are considered. */ securityParameters.m_applicationProtocol = TlsExtensionsUtilities.GetAlpnExtensionServer( - state.serverExtensions); + serverHelloExtensions); securityParameters.m_applicationProtocolSet = true; // Connection ID @@ -914,7 +965,7 @@ namespace Org.BouncyCastle.Tls * RFC 9146 3. When a DTLS session is resumed or renegotiated, the "connection_id" extension is * negotiated afresh. */ - var serverConnectionID = TlsExtensionsUtilities.GetConnectionIDExtension(state.serverExtensions); + var serverConnectionID = TlsExtensionsUtilities.GetConnectionIDExtension(serverHelloExtensions); if (serverConnectionID != null) { var clientConnectionID = TlsExtensionsUtilities.GetConnectionIDExtension(state.clientExtensions) @@ -928,7 +979,7 @@ namespace Org.BouncyCastle.Tls // Heartbeats { HeartbeatExtension heartbeatExtension = TlsExtensionsUtilities.GetHeartbeatExtension( - state.serverExtensions); + serverHelloExtensions); if (null == heartbeatExtension) { state.heartbeat = null; @@ -941,7 +992,7 @@ namespace Org.BouncyCastle.Tls } var sessionClientExtensions = state.clientExtensions; - var sessionServerExtensions = state.serverExtensions; + var sessionServerExtensions = serverHelloExtensions; if (securityParameters.IsResumedSession) { diff --git a/crypto/src/tls/DtlsServerProtocol.cs b/crypto/src/tls/DtlsServerProtocol.cs index e3f2d7564..0116bb9e6 100644 --- a/crypto/src/tls/DtlsServerProtocol.cs +++ b/crypto/src/tls/DtlsServerProtocol.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.IO; @@ -119,25 +120,6 @@ namespace Org.BouncyCastle.Tls ProcessClientHello(state, request.ClientHello); } - /* - * NOTE: Currently no server support for session resumption - * - * If adding support, ensure securityParameters.tlsUnique is set to the localVerifyData, but - * ONLY when extended_master_secret has been negotiated (otherwise NULL). - */ - { - // TODO[resumption] - - state.tlsSession = TlsUtilities.ImportSession(TlsUtilities.EmptyBytes, null); - state.sessionParameters = null; - state.sessionMasterSecret = null; - } - - securityParameters.m_resumedSession = false; - securityParameters.m_sessionID = state.tlsSession.SessionID; - - server.NotifySession(state.tlsSession); - { byte[] serverHelloBody = GenerateServerHello(state, recordLayer); @@ -379,7 +361,7 @@ namespace Org.BouncyCastle.Tls .SetServerExtensions(state.serverExtensions) .Build(); - state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters); + state.tlsSession = TlsUtilities.ImportSession(securityParameters.SessionID, state.sessionParameters); securityParameters.m_tlsUnique = securityParameters.PeerVerifyData; @@ -425,9 +407,14 @@ namespace Org.BouncyCastle.Tls TlsServerContextImpl serverContext = state.serverContext; SecurityParameters securityParameters = serverContext.SecurityParameters; - ProtocolVersion server_version = server.GetServerVersion(); + // TODO[dtls13] Negotiate cipher suite first? + + ProtocolVersion serverVersion; + + // NOT renegotiating { - if (!ProtocolVersion.Contains(serverContext.ClientSupportedVersions, server_version)) + serverVersion = server.GetServerVersion(); + if (!ProtocolVersion.Contains(serverContext.ClientSupportedVersions, serverVersion)) throw new TlsFatalAlert(AlertDescription.internal_error); // TODO[dtls13] Read draft/RFC for guidance on the legacy_record_version field @@ -436,24 +423,116 @@ namespace Org.BouncyCastle.Tls // : server_version; //recordLayer.SetWriteVersion(legacy_record_version); - securityParameters.m_negotiatedVersion = server_version; - - TlsUtilities.NegotiatedVersionDtlsServer(serverContext); + securityParameters.m_negotiatedVersion = serverVersion; } + // TODO[dtls13] + //if (ProtocolVersion.DTLSv13.IsEqualOrEarlierVersionOf(serverVersion)) + //{ + // // See RFC 8446 D.4. + // recordStream.SetIgnoreChangeCipherSpec(true); + + // recordStream.SetWriteVersion(ProtocolVersion.DTLSv12); + + // return Generate13ServerHello(clientHello, clientHelloMessage, false); + //} + + //recordStream.setWriteVersion(serverVersion); + { - bool useGmtUnixTime = ProtocolVersion.DTLSv12.IsEqualOrLaterVersionOf(server_version) - && server.ShouldUseGmtUnixTime(); + bool useGmtUnixTime = server.ShouldUseGmtUnixTime(); securityParameters.m_serverRandom = TlsProtocol.CreateRandomBlock(useGmtUnixTime, serverContext); - if (!server_version.Equals(ProtocolVersion.GetLatestDtls(server.GetProtocolVersions()))) + if (!serverVersion.Equals(ProtocolVersion.GetLatestDtls(server.GetProtocolVersions()))) + { + TlsUtilities.WriteDowngradeMarker(serverVersion, securityParameters.ServerRandom); + } + } + + /* + * NOTE: Currently no server support for session resumption + * + * If adding support, ensure securityParameters.tlsUnique is set to the localVerifyData, but + * ONLY when extended_master_secret has been negotiated (otherwise NULL). + */ + // TODO[resumption] + { + state.tlsSession = null; + state.sessionParameters = null; + state.sessionMasterSecret = null; + } + + bool resumedSession = false; + + if (resumedSession && !serverVersion.Equals(state.sessionParameters.NegotiatedVersion)) + { + resumedSession = false; + } + + // TODO Check the session cipher suite is selectable by the same rules that GetSelectedCipherSuite uses + + // TODO Check the resumed session has a peer certificate if we NEED client-auth + + // extended_master_secret + { + bool negotiateEms = false; + + if (TlsUtilities.IsExtendedMasterSecretOptional(serverVersion) && + server.ShouldUseExtendedMasterSecret()) + { + if (TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions)) + { + negotiateEms = true; + } + else if (server.RequiresExtendedMasterSecret()) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure, + "Extended Master Secret extension is required"); + } + else if (resumedSession) + { + if (state.sessionParameters.IsExtendedMasterSecret) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure, + "Extended Master Secret extension is required for EMS session resumption"); + } + + if (!server.AllowLegacyResumption()) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure, + "Extended Master Secret extension is required for legacy session resumption"); + } + } + } + + if (resumedSession && negotiateEms != state.sessionParameters.IsExtendedMasterSecret) + { + resumedSession = false; + } + + securityParameters.m_extendedMasterSecret = negotiateEms; + } + + if (!resumedSession) + { + CancelSession(state); + + byte[] newSessionID = server.GetNewSessionID(); + if (null == newSessionID) { - TlsUtilities.WriteDowngradeMarker(server_version, securityParameters.ServerRandom); + newSessionID = TlsUtilities.EmptyBytes; } + + state.tlsSession = TlsUtilities.ImportSession(newSessionID, null); } - bool resumedSession = securityParameters.IsResumedSession; + securityParameters.m_resumedSession = resumedSession; + securityParameters.m_sessionID = state.tlsSession.SessionID; + + server.NotifySession(state.tlsSession); + + TlsUtilities.NegotiatedVersionDtlsServer(serverContext); { int cipherSuite = ValidateSelectedCipherSuite(server.GetSelectedCipherSuite(), @@ -468,76 +547,54 @@ namespace Org.BouncyCastle.Tls TlsUtilities.NegotiatedCipherSuite(securityParameters, cipherSuite); } - state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised( - server.GetServerExtensions()); - - server.GetServerExtensionsForConnection(state.serverExtensions); - - ProtocolVersion legacy_version = server_version; - if (server_version.IsLaterVersionOf(ProtocolVersion.DTLSv12)) { - legacy_version = ProtocolVersion.DTLSv12; + IDictionary<int, byte[]> sessionServerExtensions = resumedSession + ? state.sessionParameters.ReadServerExtensions() + : server.GetServerExtensions(); - TlsExtensionsUtilities.AddSupportedVersionsExtensionServer(state.serverExtensions, server_version); + state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(sessionServerExtensions); } - /* - * RFC 5746 3.6. Server Behavior: Initial Handshake - */ - if (securityParameters.IsSecureRenegotiation) - { - byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, - ExtensionType.renegotiation_info); - bool noRenegExt = (null == renegExtData); + server.GetServerExtensionsForConnection(state.serverExtensions); - if (noRenegExt) + // NOT renegotiating + { + /* + * RFC 5746 3.6. Server Behavior: Initial Handshake (both full and session-resumption) + */ + if (securityParameters.IsSecureRenegotiation) { - /* - * Note that sending a "renegotiation_info" extension in response to a ClientHello - * containing only the SCSV is an explicit exception to the prohibition in RFC 5246, - * Section 7.4.1.4, on the server sending unsolicited extensions and is only allowed - * because the client is signaling its willingness to receive the extension via the - * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. - */ + byte[] serverRenegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, + ExtensionType.renegotiation_info); + bool noRenegExt = (null == serverRenegExtData); - /* - * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty - * "renegotiation_info" extension in the ServerHello message. - */ - state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo( - TlsUtilities.EmptyBytes); + if (noRenegExt) + { + /* + * Note that sending a "renegotiation_info" extension in response to a ClientHello + * containing only the SCSV is an explicit exception to the prohibition in RFC 5246, + * Section 7.4.1.4, on the server sending unsolicited extensions and is only allowed + * because the client is signaling its willingness to receive the extension via the + * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. + */ + + /* + * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty + * "renegotiation_info" extension in the ServerHello message. + */ + state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo( + TlsUtilities.EmptyBytes); + } } } - /* - * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended - * master secret [..]. (and see 5.2, 5.3) - * - * RFC 8446 Appendix D. Because TLS 1.3 always hashes in the transcript up to the server - * Finished, implementations which support both TLS 1.3 and earlier versions SHOULD indicate - * the use of the Extended Master Secret extension in their APIs whenever TLS 1.3 is used. - */ - if (TlsUtilities.IsTlsV13(server_version)) + if (securityParameters.IsExtendedMasterSecret) { - securityParameters.m_extendedMasterSecret = true; + TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions); } else { - securityParameters.m_extendedMasterSecret = state.offeredExtendedMasterSecret - && server.ShouldUseExtendedMasterSecret(); - - if (securityParameters.IsExtendedMasterSecret) - { - TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions); - } - else if (server.RequiresExtendedMasterSecret()) - { - throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - else if (resumedSession && !server.AllowLegacyResumption()) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } + state.serverExtensions.Remove(ExtensionType.extended_master_secret); } // Heartbeats @@ -547,13 +604,6 @@ namespace Org.BouncyCastle.Tls new HeartbeatExtension(state.heartbeatPolicy)); } - - - /* - * RFC 7301 3.1. When session resumption or session tickets [...] are used, the previous - * contents of this extension are irrelevant, and only the values in the new handshake - * messages are considered. - */ securityParameters.m_applicationProtocol = TlsExtensionsUtilities.GetAlpnExtensionServer( state.serverExtensions); securityParameters.m_applicationProtocolSet = true; @@ -576,11 +626,6 @@ namespace Org.BouncyCastle.Tls } } - /* - * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore - * extensions appearing in the client hello, and send a server hello containing no - * extensions. - */ if (state.serverExtensions.Count > 0) { securityParameters.m_encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension( @@ -593,10 +638,6 @@ namespace Org.BouncyCastle.Tls securityParameters.m_truncatedHmac = TlsExtensionsUtilities.HasTruncatedHmacExtension( state.serverExtensions); - /* - * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in - * a session resumption handshake. - */ if (!resumedSession) { // TODO[tls13] See RFC 8446 4.4.2.1 @@ -618,17 +659,15 @@ namespace Org.BouncyCastle.Tls ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.MaxFragmentLength); - - - ServerHello serverHello = new ServerHello(legacy_version, securityParameters.ServerRandom, - state.tlsSession.SessionID, securityParameters.CipherSuite, state.serverExtensions); + ServerHello serverHello = new ServerHello(serverVersion, securityParameters.ServerRandom, + securityParameters.SessionID, securityParameters.CipherSuite, state.serverExtensions); MemoryStream buf = new MemoryStream(); serverHello.Encode(serverContext, buf); return buf.ToArray(); } - protected virtual void InvalidateSession(ServerHandshakeState state) + protected virtual void CancelSession(ServerHandshakeState state) { if (state.sessionMasterSecret != null) { @@ -642,11 +681,17 @@ namespace Org.BouncyCastle.Tls state.sessionParameters = null; } + state.tlsSession = null; + } + + protected virtual void InvalidateSession(ServerHandshakeState state) + { if (state.tlsSession != null) { state.tlsSession.Invalidate(); - state.tlsSession = null; } + + CancelSession(state); } /// <exception cref="IOException"/> @@ -764,11 +809,16 @@ namespace Org.BouncyCastle.Tls * TODO[resumption] Check RFC 7627 5.4. for required behaviour */ - /* - * RFC 5746 3.6. Server Behavior: Initial Handshake - */ + byte[] clientRenegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, + ExtensionType.renegotiation_info); + + // NOT renegotiatiing { /* + * RFC 5746 3.6. Server Behavior: Initial Handshake (both full and session-resumption) + */ + + /* * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension, * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the * ClientHello. Including both is NOT RECOMMENDED. @@ -784,13 +834,7 @@ namespace Org.BouncyCastle.Tls securityParameters.m_secureRenegotiation = true; } - /* - * The server MUST check if the "renegotiation_info" extension is included in the - * ClientHello. - */ - byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, - ExtensionType.renegotiation_info); - if (renegExtData != null) + if (clientRenegExtData != null) { /* * If the extension is present, set secure_renegotiation flag to TRUE. The @@ -799,7 +843,7 @@ namespace Org.BouncyCastle.Tls */ securityParameters.m_secureRenegotiation = true; - if (!Arrays.FixedTimeEquals(renegExtData, + if (!Arrays.FixedTimeEquals(clientRenegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes))) { throw new TlsFatalAlert(AlertDescription.handshake_failure); @@ -809,9 +853,6 @@ namespace Org.BouncyCastle.Tls server.NotifySecureRenegotiation(securityParameters.IsSecureRenegotiation); - state.offeredExtendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension( - state.clientExtensions); - if (state.clientExtensions != null) { // NOTE: Validates the padding extension data, if present @@ -889,7 +930,6 @@ namespace Org.BouncyCastle.Tls internal int[] offeredCipherSuites = null; internal IDictionary<int, byte[]> clientExtensions = null; internal IDictionary<int, byte[]> serverExtensions = null; - internal bool offeredExtendedMasterSecret = false; internal bool expectSessionTicket = false; internal TlsKeyExchange keyExchange = null; internal TlsCredentials serverCredentials = null; diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs index b117a4025..30ad67fbe 100644 --- a/crypto/src/tls/TlsClientProtocol.cs +++ b/crypto/src/tls/TlsClientProtocol.cs @@ -1150,9 +1150,9 @@ namespace Org.BouncyCastle.Tls * Hello is always allowed. */ this.m_serverExtensions = serverHelloExtensions; - if (m_serverExtensions != null) + if (serverHelloExtensions != null) { - foreach (int extType in m_serverExtensions.Keys) + foreach (int extType in serverHelloExtensions.Keys) { /* * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a @@ -1189,7 +1189,7 @@ namespace Org.BouncyCastle.Tls } } - byte[] renegExtData = TlsUtilities.GetExtensionData(m_serverExtensions, ExtensionType.renegotiation_info); + byte[] renegExtData = TlsUtilities.GetExtensionData(serverHelloExtensions, ExtensionType.renegotiation_info); // NOT renegotiating { @@ -1235,7 +1235,7 @@ namespace Org.BouncyCastle.Tls if (TlsExtensionsUtilities.HasExtendedMasterSecretExtension(m_clientExtensions)) { - negotiatedEms = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(m_serverExtensions); + negotiatedEms = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(serverHelloExtensions); if (TlsUtilities.IsExtendedMasterSecretOptional(server_version)) { @@ -1272,11 +1272,11 @@ namespace Org.BouncyCastle.Tls * messages are considered. */ securityParameters.m_applicationProtocol = TlsExtensionsUtilities.GetAlpnExtensionServer( - m_serverExtensions); + serverHelloExtensions); securityParameters.m_applicationProtocolSet = true; var sessionClientExtensions = m_clientExtensions; - var sessionServerExtensions = m_serverExtensions; + var sessionServerExtensions = serverHelloExtensions; if (securityParameters.IsResumedSession) { if (securityParameters.CipherSuite != m_sessionParameters.CipherSuite diff --git a/crypto/src/tls/TlsServerProtocol.cs b/crypto/src/tls/TlsServerProtocol.cs index def8ae49b..efe055f1b 100644 --- a/crypto/src/tls/TlsServerProtocol.cs +++ b/crypto/src/tls/TlsServerProtocol.cs @@ -718,7 +718,7 @@ namespace Org.BouncyCastle.Tls ApplyMaxFragmentLengthExtension(securityParameters.MaxFragmentLength); - return new ServerHello(serverVersion, securityParameters.ServerRandom, m_tlsSession.SessionID, + return new ServerHello(serverVersion, securityParameters.ServerRandom, securityParameters.SessionID, securityParameters.CipherSuite, m_serverExtensions); } |