summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-07-10 21:11:02 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-07-10 21:11:02 +0700
commit0af4be8e434b6c31949a9a948a6a493877f97e0f (patch)
tree3bb21945d3d021c1dd76bc7e86b29fffc0263c4b /crypto/src
parentDTLS: Fixed server support for client_certificate_type extension. (diff)
downloadBouncyCastle.NET-ed25519-0af4be8e434b6c31949a9a948a6a493877f97e0f.tar.xz
DTLS: server support for session resumption
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/tls/DtlsClientProtocol.cs3
-rw-r--r--crypto/src/tls/DtlsServerProtocol.cs147
2 files changed, 107 insertions, 43 deletions
diff --git a/crypto/src/tls/DtlsClientProtocol.cs b/crypto/src/tls/DtlsClientProtocol.cs
index da39320ea..5c5686bbb 100644
--- a/crypto/src/tls/DtlsClientProtocol.cs
+++ b/crypto/src/tls/DtlsClientProtocol.cs
@@ -148,8 +148,7 @@ namespace Org.BouncyCastle.Tls
 
                 clientContext.HandshakeComplete(client, state.tlsSession);
 
-                recordLayer.InitHeartbeat(state.heartbeat,
-                    HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy);
+                recordLayer.InitHeartbeat(state.heartbeat, HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy);
 
                 return new DtlsTransport(recordLayer, client.IgnoreCorruptDtlsRecords);
             }
diff --git a/crypto/src/tls/DtlsServerProtocol.cs b/crypto/src/tls/DtlsServerProtocol.cs
index 8b2d9db2c..30d491990 100644
--- a/crypto/src/tls/DtlsServerProtocol.cs
+++ b/crypto/src/tls/DtlsServerProtocol.cs
@@ -114,10 +114,14 @@ namespace Org.BouncyCastle.Tls
                 {
                     throw new TlsFatalAlert(AlertDescription.unexpected_message);
                 }
+
+                clientMessage = null;
             }
             else
             {
                 ProcessClientHello(state, request.ClientHello);
+
+                request = null;
             }
 
             {
@@ -135,6 +139,41 @@ namespace Org.BouncyCastle.Tls
 
             handshake.HandshakeHash.NotifyPrfDetermined();
 
+            if (securityParameters.IsResumedSession)
+            {
+                securityParameters.m_masterSecret = state.sessionMasterSecret;
+                recordLayer.InitPendingEpoch(TlsUtilities.InitCipher(serverContext));
+
+                // NOTE: Calculated exclusive of the Finished message itself
+                securityParameters.m_localVerifyData = TlsUtilities.CalculateVerifyData(serverContext,
+                    handshake.HandshakeHash, true);
+                handshake.SendMessage(HandshakeType.finished, securityParameters.LocalVerifyData);
+
+                // NOTE: Calculated exclusive of the actual Finished message from the client
+                securityParameters.m_peerVerifyData = TlsUtilities.CalculateVerifyData(serverContext,
+                    handshake.HandshakeHash, false);
+                ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished),
+                    securityParameters.PeerVerifyData);
+
+                handshake.Finish();
+
+                if (securityParameters.IsExtendedMasterSecret)
+                {
+                    securityParameters.m_tlsUnique = securityParameters.LocalVerifyData;
+                }
+
+                securityParameters.m_localCertificate = state.sessionParameters.LocalCertificate;
+                securityParameters.m_peerCertificate = state.sessionParameters.PeerCertificate;
+                securityParameters.m_pskIdentity = state.sessionParameters.PskIdentity;
+                securityParameters.m_srpIdentity = state.sessionParameters.SrpIdentity;
+
+                serverContext.HandshakeComplete(server, state.tlsSession);
+
+                recordLayer.InitHeartbeat(state.heartbeat, HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy);
+
+                return new DtlsTransport(recordLayer, server.IgnoreCorruptDtlsRecords);
+            }
+
             var serverSupplementalData = server.GetServerSupplementalData();
             if (serverSupplementalData != null)
             {
@@ -322,6 +361,8 @@ namespace Org.BouncyCastle.Tls
                 }
             }
 
+            clientMessage = null;
+
             // NOTE: Calculated exclusive of the actual Finished message from the client
             securityParameters.m_peerVerifyData = TlsUtilities.CalculateVerifyData(serverContext,
                 handshake.HandshakeHash, false);
@@ -450,20 +491,11 @@ namespace Org.BouncyCastle.Tls
                 }
             }
 
-            /*
-             * 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;
-            }
+            var clientHelloExtensions = state.clientHello.Extensions;
 
-            bool resumedSession = false;
+            TlsSession sessionToResume = server.GetSessionToResume(state.clientHello.SessionID);
+
+            bool resumedSession = EstablishSession(state, sessionToResume);
 
             if (resumedSession && !serverVersion.Equals(state.sessionParameters.NegotiatedVersion))
             {
@@ -481,7 +513,7 @@ namespace Org.BouncyCastle.Tls
                 if (TlsUtilities.IsExtendedMasterSecretOptional(serverVersion) &&
                     server.ShouldUseExtendedMasterSecret())
                 {
-                    if (TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions))
+                    if (TlsExtensionsUtilities.HasExtendedMasterSecretExtension(clientHelloExtensions))
                     {
                         negotiateEms = true;
                     }
@@ -538,7 +570,7 @@ namespace Org.BouncyCastle.Tls
                 int cipherSuite = ValidateSelectedCipherSuite(server.GetSelectedCipherSuite(),
                     AlertDescription.internal_error);
 
-                if (!TlsUtilities.IsValidCipherSuiteSelection(state.offeredCipherSuites, cipherSuite) ||
+                if (!TlsUtilities.IsValidCipherSuiteSelection(state.clientHello.CipherSuites, cipherSuite) ||
                     !TlsUtilities.IsValidVersionForCipherSuite(cipherSuite, securityParameters.NegotiatedVersion))
                 {
                     throw new TlsFatalAlert(AlertDescription.internal_error);
@@ -618,7 +650,7 @@ namespace Org.BouncyCastle.Tls
                 var serverConnectionID = TlsExtensionsUtilities.GetConnectionIDExtension(state.serverExtensions);
                 if (serverConnectionID != null)
                 {
-                    var clientConnectionID = TlsExtensionsUtilities.GetConnectionIDExtension(state.clientExtensions)
+                    var clientConnectionID = TlsExtensionsUtilities.GetConnectionIDExtension(clientHelloExtensions)
                         ?? throw new TlsFatalAlert(AlertDescription.internal_error);
 
                     securityParameters.m_connectionIDLocal = clientConnectionID;
@@ -632,7 +664,7 @@ namespace Org.BouncyCastle.Tls
                     state.serverExtensions);
 
                 securityParameters.m_maxFragmentLength = TlsUtilities.ProcessMaxFragmentLengthExtension(
-                    resumedSession ? null : state.clientExtensions, state.serverExtensions,
+                    resumedSession ? null : clientHelloExtensions, state.serverExtensions,
                     AlertDescription.internal_error);
 
                 securityParameters.m_truncatedHmac = TlsExtensionsUtilities.HasTruncatedHmacExtension(
@@ -657,11 +689,13 @@ namespace Org.BouncyCastle.Tls
                 }
             }
 
-            ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.MaxFragmentLength);
-
             ServerHello serverHello = new ServerHello(serverVersion, securityParameters.ServerRandom,
                 securityParameters.SessionID, securityParameters.CipherSuite, state.serverExtensions);
 
+            state.clientHello = null;
+
+            ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.MaxFragmentLength);
+
             MemoryStream buf = new MemoryStream();
             serverHello.Encode(serverContext, buf);
             return buf.ToArray();
@@ -684,6 +718,42 @@ namespace Org.BouncyCastle.Tls
             state.tlsSession = null;
         }
 
+        protected virtual bool EstablishSession(ServerHandshakeState 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.serverContext.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(ServerHandshakeState state)
         {
             if (state.tlsSession != null)
@@ -752,16 +822,12 @@ namespace Org.BouncyCastle.Tls
         /// <exception cref="IOException"/>
         protected virtual void ProcessClientHello(ServerHandshakeState state, ClientHello clientHello)
         {
+            state.clientHello = clientHello;
+
             // TODO Read RFCs for guidance on the expected record layer version number
             ProtocolVersion legacy_version = clientHello.Version;
-            state.offeredCipherSuites = clientHello.CipherSuites;
-
-            /*
-             * 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.
-             */
-            state.clientExtensions = clientHello.Extensions;
+            int[] offeredCipherSuites = clientHello.CipherSuites;
+            var clientHelloExtensions = clientHello.Extensions;
 
 
 
@@ -775,7 +841,7 @@ namespace Org.BouncyCastle.Tls
             serverContext.SetRsaPreMasterSecretVersion(legacy_version);
 
             serverContext.SetClientSupportedVersions(
-                TlsExtensionsUtilities.GetSupportedVersionsExtensionClient(state.clientExtensions));
+                TlsExtensionsUtilities.GetSupportedVersionsExtensionClient(clientHelloExtensions));
 
             ProtocolVersion client_version = legacy_version;
             if (null == serverContext.ClientSupportedVersions)
@@ -801,15 +867,15 @@ namespace Org.BouncyCastle.Tls
 
             securityParameters.m_clientRandom = clientHello.Random;
 
-            server.NotifyFallback(Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));
+            server.NotifyFallback(Arrays.Contains(offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));
 
-            server.NotifyOfferedCipherSuites(state.offeredCipherSuites);
+            server.NotifyOfferedCipherSuites(offeredCipherSuites);
 
             /*
              * TODO[resumption] Check RFC 7627 5.4. for required behaviour 
              */
 
-            byte[] clientRenegExtData = TlsUtilities.GetExtensionData(state.clientExtensions,
+            byte[] clientRenegExtData = TlsUtilities.GetExtensionData(clientHelloExtensions,
                 ExtensionType.renegotiation_info);
 
             // NOT renegotiatiing
@@ -829,7 +895,7 @@ namespace Org.BouncyCastle.Tls
                  * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
                  * to TRUE.
                  */
-                if (Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
+                if (Arrays.Contains(offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
                 {
                     securityParameters.m_secureRenegotiation = true;
                 }
@@ -853,13 +919,13 @@ namespace Org.BouncyCastle.Tls
 
             server.NotifySecureRenegotiation(securityParameters.IsSecureRenegotiation);
 
-            if (state.clientExtensions != null)
+            if (clientHelloExtensions != null)
             {
                 // NOTE: Validates the padding extension data, if present
-                TlsExtensionsUtilities.GetPaddingExtension(state.clientExtensions);
+                TlsExtensionsUtilities.GetPaddingExtension(clientHelloExtensions);
 
                 securityParameters.m_clientServerNames = TlsExtensionsUtilities.GetServerNameExtensionClient(
-                    state.clientExtensions);
+                    clientHelloExtensions);
 
                 /*
                  * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior
@@ -867,16 +933,16 @@ namespace Org.BouncyCastle.Tls
                  */
                 if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(client_version))
                 {
-                    TlsUtilities.EstablishClientSigAlgs(securityParameters, state.clientExtensions);
+                    TlsUtilities.EstablishClientSigAlgs(securityParameters, clientHelloExtensions);
                 }
 
                 securityParameters.m_clientSupportedGroups = TlsExtensionsUtilities.GetSupportedGroupsExtension(
-                    state.clientExtensions);
+                    clientHelloExtensions);
 
                 // Heartbeats
                 {
                     HeartbeatExtension heartbeatExtension = TlsExtensionsUtilities.GetHeartbeatExtension(
-                        state.clientExtensions);
+                        clientHelloExtensions);
                     if (null != heartbeatExtension)
                     {
                         if (HeartbeatMode.peer_allowed_to_send == heartbeatExtension.Mode)
@@ -888,7 +954,7 @@ namespace Org.BouncyCastle.Tls
                     }
                 }
 
-                server.ProcessClientExtensions(state.clientExtensions);
+                server.ProcessClientExtensions(clientHelloExtensions);
             }
         }
 
@@ -927,8 +993,7 @@ namespace Org.BouncyCastle.Tls
             internal SessionParameters sessionParameters = null;
             internal TlsSecret sessionMasterSecret = null;
             internal SessionParameters.Builder sessionParametersBuilder = null;
-            internal int[] offeredCipherSuites = null;
-            internal IDictionary<int, byte[]> clientExtensions = null;
+            internal ClientHello clientHello = null;
             internal IDictionary<int, byte[]> serverExtensions = null;
             internal bool expectSessionTicket = false;
             internal TlsKeyExchange keyExchange = null;