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);
}
|