summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2021-07-28 16:00:23 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2021-07-28 16:00:23 +0700
commit2b15619e62a09da46a0b2c0f5279c86394a14eb5 (patch)
tree4163c0412c125e05bc664cda37263e997c499d14
parentFix test class name (diff)
downloadBouncyCastle.NET-ed25519-2b15619e62a09da46a0b2c0f5279c86394a14eb5.tar.xz
Client message flow for PSK handshake
-rw-r--r--crypto/src/tls/TlsClientProtocol.cs56
-rw-r--r--crypto/src/tls/TlsProtocol.cs4
-rw-r--r--crypto/src/tls/TlsUtilities.cs12
3 files changed, 45 insertions, 27 deletions
diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs
index 021e8da1b..4616580f0 100644
--- a/crypto/src/tls/TlsClientProtocol.cs
+++ b/crypto/src/tls/TlsClientProtocol.cs
@@ -118,20 +118,9 @@ namespace Org.BouncyCastle.Tls
         /// <exception cref="IOException"/>
         protected virtual void Handle13HandshakeMessage(short type, HandshakeMessageInput buf)
         {
-            if (!IsTlsV13ConnectionState())
+            if (!IsTlsV13ConnectionState() || m_resumedSession)
                 throw new TlsFatalAlert(AlertDescription.internal_error);
 
-            if (m_resumedSession)
-            {
-                /*
-                 * TODO[tls13] Resumption/PSK
-                 * 
-                 * NOTE: No CertificateRequest, Certificate, CertificateVerify messages, but client
-                 * might now send EndOfEarlyData after receiving server Finished message.
-                 */
-                throw new TlsFatalAlert(AlertDescription.internal_error);
-            }
-
             switch (type)
             {
             case HandshakeType.certificate:
@@ -146,9 +135,6 @@ namespace Org.BouncyCastle.Tls
                         Skip13CertificateRequest();
                     }
 
-                    /*
-                     * TODO[tls13] For PSK-only key exchange, there's no Certificate message.
-                     */
                     Receive13ServerCertificate(buf);
                     this.m_connectionState = CS_SERVER_CERTIFICATE;
                     break;
@@ -235,6 +221,12 @@ namespace Org.BouncyCastle.Tls
                     // See RFC 8446 D.4.
                     m_recordStream.SetIgnoreChangeCipherSpec(false);
 
+                    /*
+                     * TODO[tls13] After receiving the server's Finished message, if the server has accepted early
+                     * data, an EndOfEarlyData message will be sent to indicate the key change. This message will
+                     * be encrypted with the 0-RTT traffic keys.
+                     */
+
                     if (null != m_certificateRequest)
                     {
                         TlsCredentialedSigner clientCredentials = TlsUtilities.Establish13ClientCredentials(
@@ -968,6 +960,8 @@ namespace Org.BouncyCastle.Tls
                         throw new TlsFatalAlert(AlertDescription.illegal_parameter);
 
                     pskEarlySecret = m_clientBinders.m_earlySecrets[selected_identity];
+
+                    this.m_selectedPsk13 = true;
                 }
 
                 m_tlsClient.NotifySelectedPsk(selectedPsk);
@@ -1028,7 +1022,10 @@ namespace Org.BouncyCastle.Tls
             {
                 m_recordStream.SetIgnoreChangeCipherSpec(true);
 
-                // TODO[tls13] If offering early data, the record is placed immediately after the first ClientHello.
+                /*
+                 * TODO[tls13] If offering early_data, the record is placed immediately after the first
+                 * ClientHello.
+                 */
                 /*
                  * TODO[tls13] Ideally wait until just after Server Finished received, but then we'd need to defer
                  * the enabling of the pending write cipher
@@ -1338,23 +1335,22 @@ namespace Org.BouncyCastle.Tls
         /// <exception cref="IOException"/>
         protected virtual void Receive13CertificateRequest(MemoryStream buf, bool postHandshakeAuth)
         {
+            // TODO[tls13] Support for post_handshake_auth
+            if (postHandshakeAuth)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
             /* 
              * RFC 8446 4.3.2. A server which is authenticating with a certificate MAY optionally
              * request a certificate from the client.
              */
 
-            /*
-             * TODO[tls13] Currently all handshakes are certificate-authenticated. When PSK-only becomes an option,
-             * then check here that a certificate message is expected (else fatal unexpected_message alert).
-             */
+            if (m_selectedPsk13)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
 
             CertificateRequest certificateRequest = CertificateRequest.Parse(m_tlsClientContext, buf);
 
             AssertEmpty(buf);
 
-            if (postHandshakeAuth)
-                throw new TlsFatalAlert(AlertDescription.internal_error);
-
             if (!certificateRequest.HasCertificateRequestContext(TlsUtilities.EmptyBytes))
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
 
@@ -1459,6 +1455,9 @@ namespace Org.BouncyCastle.Tls
         /// <exception cref="IOException"/>
         protected virtual void Receive13ServerCertificate(MemoryStream buf)
         {
+            if (m_selectedPsk13)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
             this.m_authentication = TlsUtilities.Receive13ServerCertificate(m_tlsClientContext, m_tlsClient, buf);
 
             // NOTE: In TLS 1.3 we don't have to wait for a possible CertificateStatus message.
@@ -1584,7 +1583,10 @@ namespace Org.BouncyCastle.Tls
             {
                 m_recordStream.SetIgnoreChangeCipherSpec(true);
 
-                // TODO[tls13] If offering early data, the record is placed immediately after the first ClientHello.
+                /*
+                 * TODO[tls13] If offering early_data, the record is placed immediately after the first
+                 * ClientHello.
+                 */
                 SendChangeCipherSpecMessage();
             }
 
@@ -1791,10 +1793,10 @@ namespace Org.BouncyCastle.Tls
         /// <exception cref="IOException"/>
         protected virtual void Skip13ServerCertificate()
         {
-            this.m_authentication = null;
+            if (!m_selectedPsk13)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
 
-            // TODO[tls13] May be skipped for PSK handshakes?
-            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            this.m_authentication = TlsUtilities.Skip13ServerCertificate(m_tlsClientContext);
         }
     }
 }
diff --git a/crypto/src/tls/TlsProtocol.cs b/crypto/src/tls/TlsProtocol.cs
index f05c09a1b..8d0e3fc0d 100644
--- a/crypto/src/tls/TlsProtocol.cs
+++ b/crypto/src/tls/TlsProtocol.cs
@@ -150,6 +150,7 @@ namespace Org.BouncyCastle.Tls
 
         protected short m_connectionState = CS_START;
         protected bool m_resumedSession = false;
+        protected bool m_selectedPsk13 = false;
         protected bool m_receivedChangeCipherSpec = false;
         protected bool m_expectSessionTicket = false;
 
@@ -359,6 +360,8 @@ namespace Org.BouncyCastle.Tls
 
             this.m_handshakeHash = new DeferredHash(context);
             this.m_connectionState = CS_START;
+            this.m_resumedSession = false;
+            this.m_selectedPsk13 = false;
 
             context.HandshakeBeginning(peer);
 
@@ -389,6 +392,7 @@ namespace Org.BouncyCastle.Tls
             this.m_serverExtensions = null;
 
             this.m_resumedSession = false;
+            this.m_selectedPsk13 = false;
             this.m_receivedChangeCipherSpec = false;
             this.m_expectSessionTicket = false;
         }
diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs
index 9dea576f5..8df787b6f 100644
--- a/crypto/src/tls/TlsUtilities.cs
+++ b/crypto/src/tls/TlsUtilities.cs
@@ -4821,6 +4821,18 @@ namespace Org.BouncyCastle.Tls
             return authentication;
         }
 
+        internal static TlsAuthentication Skip13ServerCertificate(TlsClientContext clientContext)
+        {
+            SecurityParameters securityParameters = clientContext.SecurityParameters;
+            if (null != securityParameters.PeerCertificate)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            securityParameters.m_peerCertificate = null;
+            securityParameters.m_tlsServerEndPoint = null;
+
+            return null;
+        }
+
         public static bool ContainsNonAscii(byte[] bs)
         {
             for (int i = 0; i < bs.Length; ++i)