summary refs log tree commit diff
path: root/crypto/src/tls/TlsClientProtocol.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/tls/TlsClientProtocol.cs')
-rw-r--r--crypto/src/tls/TlsClientProtocol.cs203
1 files changed, 121 insertions, 82 deletions
diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs
index 8e31fa6c8..53cd37123 100644
--- a/crypto/src/tls/TlsClientProtocol.cs
+++ b/crypto/src/tls/TlsClientProtocol.cs
@@ -1112,6 +1112,16 @@ namespace Org.BouncyCastle.Tls
                 m_tlsClient.NotifySessionID(selectedSessionID);
                 securityParameters.m_resumedSession = selectedSessionID.Length > 0 && m_tlsSession != null
                     && Arrays.AreEqual(selectedSessionID, m_tlsSession.SessionID);
+
+                if (securityParameters.IsResumedSession)
+                {
+                    if (serverHello.CipherSuite != m_sessionParameters.CipherSuite ||
+                        !securityParameters.NegotiatedVersion.Equals(m_sessionParameters.NegotiatedVersion))
+                    {
+                        throw new TlsFatalAlert(AlertDescription.illegal_parameter,
+                            "ServerHello parameters do not match resumed session");
+                    }
+                }
             }
 
             /*
@@ -1124,7 +1134,8 @@ namespace Org.BouncyCastle.Tls
                 if (!TlsUtilities.IsValidCipherSuiteSelection(offeredCipherSuites, cipherSuite) ||
                     !TlsUtilities.IsValidVersionForCipherSuite(cipherSuite, securityParameters.NegotiatedVersion))
                 {
-                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter,
+                        "ServerHello selected invalid cipher suite");
                 }
 
                 TlsUtilities.NegotiatedCipherSuite(securityParameters, cipherSuite);
@@ -1139,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
@@ -1178,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
             {
@@ -1218,37 +1229,41 @@ namespace Org.BouncyCastle.Tls
             // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming
             m_tlsClient.NotifySecureRenegotiation(securityParameters.IsSecureRenegotiation);
 
-            /*
-             * 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.
-             */
+            // extended_master_secret
             {
-                bool acceptedExtendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(
-                    m_serverExtensions);
-                bool resumedSession = securityParameters.IsResumedSession;
+                bool negotiatedEms = false;
 
-                if (acceptedExtendedMasterSecret)
+                if (TlsExtensionsUtilities.HasExtendedMasterSecretExtension(m_clientExtensions))
                 {
-                    if (server_version.IsSsl
-                        || (!resumedSession && !m_tlsClient.ShouldUseExtendedMasterSecret()))
+                    negotiatedEms = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(serverHelloExtensions);
+
+                    if (TlsUtilities.IsExtendedMasterSecretOptional(server_version))
                     {
-                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                        if (!negotiatedEms &&
+                            m_tlsClient.RequiresExtendedMasterSecret())
+                        {
+                            throw new TlsFatalAlert(AlertDescription.handshake_failure,
+                                "Extended Master Secret extension is required");
+                        }
                     }
-                }
-                else
-                {
-                    if (m_tlsClient.RequiresExtendedMasterSecret()
-                        || (resumedSession && !m_tlsClient.AllowLegacyResumption()))
+                    else
                     {
-                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                        if (negotiatedEms)
+                        {
+                            throw new TlsFatalAlert(AlertDescription.illegal_parameter,
+                                "Server sent an unexpected extended_master_secret extension negotiating " + server_version);
+                        }
                     }
                 }
 
-                securityParameters.m_extendedMasterSecret = acceptedExtendedMasterSecret;
+                securityParameters.m_extendedMasterSecret = negotiatedEms;
+            }
+
+            if (securityParameters.IsResumedSession &&
+                securityParameters.IsExtendedMasterSecret != m_sessionParameters.IsExtendedMasterSecret)
+            {
+                throw new TlsFatalAlert(AlertDescription.handshake_failure,
+                    "Server resumed session with mismatched extended_master_secret negotiation");
             }
 
             /*
@@ -1257,19 +1272,14 @@ 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
-                    || !server_version.Equals(m_sessionParameters.NegotiatedVersion))
-                {
-                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-                }
-
                 sessionClientExtensions = null;
                 sessionServerExtensions = m_sessionParameters.ReadServerExtensions();
             }
@@ -1291,16 +1301,12 @@ namespace Org.BouncyCastle.Tls
                     securityParameters.m_encryptThenMac = serverSentEncryptThenMAC;
                 }
 
-                securityParameters.m_maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
-                    sessionServerExtensions, AlertDescription.illegal_parameter);
+                securityParameters.m_maxFragmentLength = TlsUtilities.ProcessMaxFragmentLengthExtension(
+                    sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
 
                 securityParameters.m_truncatedHmac = TlsExtensionsUtilities.HasTruncatedHmacExtension(
                     sessionServerExtensions);
 
-                /*
-                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
-                 * a session resumption handshake.
-                 */
                 if (!securityParameters.IsResumedSession)
                 {
                     // TODO[tls13] See RFC 8446 4.4.2.1
@@ -1315,6 +1321,11 @@ namespace Org.BouncyCastle.Tls
                         securityParameters.m_statusRequestVersion = 1;
                     }
 
+                    securityParameters.m_clientCertificateType = TlsUtilities.ProcessClientCertificateTypeExtension(
+                        sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
+                    securityParameters.m_serverCertificateType = TlsUtilities.ProcessServerCertificateTypeExtension(
+                        sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
+
                     this.m_expectSessionTicket = TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions,
                         ExtensionType.session_ticket, AlertDescription.illegal_parameter);
                 }
@@ -1363,10 +1374,6 @@ namespace Org.BouncyCastle.Tls
 
             this.m_certificateRequest = certificateRequest;
 
-            m_tlsClientContext.SecurityParameters.m_clientCertificateType =
-                TlsExtensionsUtilities.GetClientCertificateTypeExtensionServer(m_serverExtensions,
-                    CertificateType.X509);
-
             TlsUtilities.EstablishServerSigAlgs(m_tlsClientContext.SecurityParameters, certificateRequest);
         }
 
@@ -1404,31 +1411,34 @@ namespace Org.BouncyCastle.Tls
 
             var sessionClientExtensions = m_clientExtensions;
             var sessionServerExtensions = m_serverExtensions;
+
             if (securityParameters.IsResumedSession)
             {
-                if (securityParameters.CipherSuite != m_sessionParameters.CipherSuite
-                    || !negotiatedVersion.Equals(m_sessionParameters.NegotiatedVersion))
-                {
-                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-                }
-
                 sessionClientExtensions = null;
                 sessionServerExtensions = m_sessionParameters.ReadServerExtensions();
             }
 
-            securityParameters.m_maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
-                sessionServerExtensions, AlertDescription.illegal_parameter);
+            securityParameters.m_maxFragmentLength = TlsUtilities.ProcessMaxFragmentLengthExtension(
+                sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
 
             securityParameters.m_encryptThenMac = false;
             securityParameters.m_truncatedHmac = false;
 
-            /*
-             * TODO[tls13] RFC 8446 4.4.2.1. OCSP Status and SCT Extensions.
-             * 
-             * OCSP information is carried in an extension for a CertificateEntry.
-             */
-            securityParameters.m_statusRequestVersion =
-                m_clientExtensions.ContainsKey(ExtensionType.status_request) ? 1 : 0;
+            if (!securityParameters.IsResumedSession)
+            {
+                /*
+                 * TODO[tls13] RFC 8446 4.4.2.1. OCSP Status and SCT Extensions.
+                 * 
+                 * OCSP information is carried in an extension for a CertificateEntry.
+                 */
+                securityParameters.m_statusRequestVersion = m_clientExtensions.ContainsKey(ExtensionType.status_request)
+                    ? 1 : 0;
+
+                securityParameters.m_clientCertificateType = TlsUtilities.ProcessClientCertificateTypeExtension13(
+                    sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
+                securityParameters.m_serverCertificateType = TlsUtilities.ProcessServerCertificateTypeExtension13(
+                    sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
+            }
 
             this.m_expectSessionTicket = false;
 
@@ -1514,10 +1524,6 @@ namespace Org.BouncyCastle.Tls
             AssertEmpty(buf);
 
             m_certificateRequest = TlsUtilities.ValidateCertificateRequest(certificateRequest, m_keyExchange);
-
-            m_tlsClientContext.SecurityParameters.m_clientCertificateType =
-                TlsExtensionsUtilities.GetClientCertificateTypeExtensionServer(m_serverExtensions,
-                    CertificateType.X509);
         }
 
         /// <exception cref="IOException"/>
@@ -1659,20 +1665,21 @@ namespace Org.BouncyCastle.Tls
                 securityParameters.m_clientRandom = CreateRandomBlock(useGmtUnixTime, m_tlsClientContext);
             }
 
-            EstablishSession(offeringTlsV12Minus ? m_tlsClient.GetSessionToResume() : null);
-            m_tlsClient.NotifySessionToResume(m_tlsSession);
-
-            /*
-             * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a
-             * Session ID in the TLS ClientHello.
-             */
-            byte[] legacy_session_id = TlsUtilities.GetSessionID(m_tlsSession);
+            TlsSession sessionToResume = offeringTlsV12Minus ? m_tlsClient.GetSessionToResume() : null;
 
             bool fallback = m_tlsClient.IsFallback();
 
             int[] offeredCipherSuites = m_tlsClient.GetCipherSuites();
 
-            if (legacy_session_id.Length > 0 && m_sessionParameters != null)
+            this.m_clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(m_tlsClient.GetClientExtensions());
+
+            bool shouldUseEms = m_tlsClient.ShouldUseExtendedMasterSecret();
+
+            EstablishSession(sessionToResume);
+
+            byte[] legacy_session_id = TlsUtilities.GetSessionID(m_tlsSession);
+
+            if (legacy_session_id.Length > 0)
             {
                 if (!Arrays.Contains(offeredCipherSuites, m_sessionParameters.CipherSuite))
                 {
@@ -1680,8 +1687,42 @@ namespace Org.BouncyCastle.Tls
                 }
             }
 
-            this.m_clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(
-                m_tlsClient.GetClientExtensions());
+            ProtocolVersion sessionVersion = null;
+            if (legacy_session_id.Length > 0)
+            {
+                sessionVersion = m_sessionParameters.NegotiatedVersion;
+
+                if (!ProtocolVersion.Contains(supportedVersions, sessionVersion))
+                {
+                    legacy_session_id = TlsUtilities.EmptyBytes;
+                }
+            }
+
+            if (legacy_session_id.Length > 0 && TlsUtilities.IsExtendedMasterSecretOptional(sessionVersion))
+            {
+                if (shouldUseEms)
+                {
+                    if (!m_sessionParameters.IsExtendedMasterSecret &&
+                        !m_tlsClient.AllowLegacyResumption())
+                    {
+                        legacy_session_id = TlsUtilities.EmptyBytes;
+                    }
+                }
+                else
+                {
+                    if (m_sessionParameters.IsExtendedMasterSecret)
+                    {
+                        legacy_session_id = TlsUtilities.EmptyBytes;
+                    }
+                }
+            }
+
+            if (legacy_session_id.Length < 1)
+            {
+                CancelSession();
+            }
+
+            m_tlsClient.NotifySessionToResume(m_tlsSession);
 
             ProtocolVersion legacy_version = latestVersion;
             if (offeringTlsV13Plus)
@@ -1691,10 +1732,10 @@ namespace Org.BouncyCastle.Tls
                 TlsExtensionsUtilities.AddSupportedVersionsExtensionClient(m_clientExtensions, supportedVersions);
 
                 /*
-                 * RFC 8446 4.2.1. In compatibility mode [..], this field MUST be non-empty, so a client
+                 * RFC 8446 4.1.2. In compatibility mode [..], this field MUST be non-empty, so a client
                  * not offering a pre-TLS 1.3 session MUST generate a new 32-byte value.
                  */
-                if (legacy_session_id.Length < 1)
+                if (legacy_session_id.Length < 1 && TlsUtilities.ShouldUseCompatibilityMode(m_tlsClient))
                 {
                     legacy_session_id = m_tlsClientContext.NonceGenerator.GenerateNonce(32);
                 }
@@ -1720,15 +1761,13 @@ namespace Org.BouncyCastle.Tls
             this.m_clientAgreements = TlsUtilities.AddKeyShareToClientHello(m_tlsClientContext, m_tlsClient,
                 m_clientExtensions);
 
-            if (TlsUtilities.IsExtendedMasterSecretOptionalTls(supportedVersions)
-                && (m_tlsClient.ShouldUseExtendedMasterSecret() ||
-                    (null != m_sessionParameters && m_sessionParameters.IsExtendedMasterSecret)))
+            if (shouldUseEms && TlsUtilities.IsExtendedMasterSecretOptional(supportedVersions))
             {
-                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(m_clientExtensions);
+                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(this.m_clientExtensions);
             }
-            else if (!offeringTlsV13Plus && m_tlsClient.RequiresExtendedMasterSecret())
+            else
             {
-                throw new TlsFatalAlert(AlertDescription.internal_error);
+                this.m_clientExtensions.Remove(ExtensionType.extended_master_secret);
             }
 
             // NOT renegotiating