summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/src/tls/DtlsClientProtocol.cs2
-rw-r--r--crypto/src/tls/OfferedPsks.cs15
-rw-r--r--crypto/src/tls/SecurityParameters.cs7
-rw-r--r--crypto/src/tls/TlsClientProtocol.cs76
-rw-r--r--crypto/src/tls/TlsServerProtocol.cs14
-rw-r--r--crypto/src/tls/TlsUtilities.cs55
6 files changed, 119 insertions, 50 deletions
diff --git a/crypto/src/tls/DtlsClientProtocol.cs b/crypto/src/tls/DtlsClientProtocol.cs
index cd2fff709..a4810b983 100644
--- a/crypto/src/tls/DtlsClientProtocol.cs
+++ b/crypto/src/tls/DtlsClientProtocol.cs
@@ -446,7 +446,7 @@ namespace Org.BouncyCastle.Tls
             securityParameters.m_clientSupportedGroups = TlsExtensionsUtilities.GetSupportedGroupsExtension(
                 state.clientExtensions);
 
-            state.clientAgreements = TlsUtilities.AddEarlyKeySharesToClientHello(state.clientContext, state.client,
+            state.clientAgreements = TlsUtilities.AddKeyShareToClientHello(state.clientContext, state.client,
                 state.clientExtensions);
 
             if (TlsUtilities.IsExtendedMasterSecretOptionalDtls(context.ClientSupportedVersions)
diff --git a/crypto/src/tls/OfferedPsks.cs b/crypto/src/tls/OfferedPsks.cs
index dfa2be034..14b6448b4 100644
--- a/crypto/src/tls/OfferedPsks.cs
+++ b/crypto/src/tls/OfferedPsks.cs
@@ -9,15 +9,18 @@ namespace Org.BouncyCastle.Tls
 {
     public sealed class OfferedPsks
     {
-        internal class Config
+        internal class BindersConfig
         {
             internal readonly TlsPsk[] m_psks;
+            internal readonly short[] m_pskKeyExchangeModes;
             internal readonly TlsSecret[] m_earlySecrets;
             internal int m_bindersSize;
 
-            internal Config(TlsPsk[] psks, TlsSecret[] earlySecrets, int bindersSize)
+            internal BindersConfig(TlsPsk[] psks, short[] pskKeyExchangeModes, TlsSecret[] earlySecrets,
+                int bindersSize)
             {
                 this.m_psks = psks;
+                this.m_pskKeyExchangeModes = pskKeyExchangeModes;
                 this.m_earlySecrets = earlySecrets;
                 this.m_bindersSize = bindersSize;
             }
@@ -93,11 +96,11 @@ namespace Org.BouncyCastle.Tls
 
         /// <exception cref="IOException"/>
         internal static void EncodeBinders(Stream output, TlsCrypto crypto, TlsHandshakeHash handshakeHash,
-            Config config)
+            BindersConfig bindersConfig)
         {
-            TlsPsk[] psks = config.m_psks;
-            TlsSecret[] earlySecrets = config.m_earlySecrets;
-            int expectedLengthOfBindersList = config.m_bindersSize - 2;
+            TlsPsk[] psks = bindersConfig.m_psks;
+            TlsSecret[] earlySecrets = bindersConfig.m_earlySecrets;
+            int expectedLengthOfBindersList = bindersConfig.m_bindersSize - 2;
 
             TlsUtilities.CheckUint16(expectedLengthOfBindersList);
             TlsUtilities.WriteUint16(expectedLengthOfBindersList, output);
diff --git a/crypto/src/tls/SecurityParameters.cs b/crypto/src/tls/SecurityParameters.cs
index 23a83a65f..548e4a4ca 100644
--- a/crypto/src/tls/SecurityParameters.cs
+++ b/crypto/src/tls/SecurityParameters.cs
@@ -22,7 +22,6 @@ namespace Org.BouncyCastle.Tls
         internal TlsSecret m_exporterMasterSecret = null;
         internal TlsSecret m_handshakeSecret = null;
         internal TlsSecret m_masterSecret = null;
-        internal TlsSecret m_sharedSecret = null;
         internal TlsSecret m_trafficSecretClient = null;
         internal TlsSecret m_trafficSecretServer = null;
         internal byte[] m_clientRandom = null;
@@ -78,7 +77,6 @@ namespace Org.BouncyCastle.Tls
             this.m_exporterMasterSecret = ClearSecret(m_exporterMasterSecret);
             this.m_handshakeSecret = ClearSecret(m_handshakeSecret);
             this.m_masterSecret = ClearSecret(m_masterSecret);
-            this.m_sharedSecret = ClearSecret(m_sharedSecret);
         }
 
         public ProtocolName ApplicationProtocol
@@ -276,11 +274,6 @@ namespace Org.BouncyCastle.Tls
             get { return m_sessionID; }
         }
 
-        public TlsSecret SharedSecret
-        {
-            get { return m_sharedSecret; }
-        }
-
         public byte[] SrpIdentity
         {
             get { return m_srpIdentity; }
diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs
index 190a1927f..5356880ff 100644
--- a/crypto/src/tls/TlsClientProtocol.cs
+++ b/crypto/src/tls/TlsClientProtocol.cs
@@ -14,6 +14,7 @@ namespace Org.BouncyCastle.Tls
         internal TlsClientContextImpl m_tlsClientContext = null;
 
         protected IDictionary m_clientAgreements = null;
+        internal OfferedPsks.BindersConfig m_clientBinders = null;
         protected ClientHello m_clientHello = null;
         protected TlsKeyExchange m_keyExchange = null;
         protected TlsAuthentication m_authentication = null;
@@ -90,6 +91,7 @@ namespace Org.BouncyCastle.Tls
             base.CleanupHandshake();
 
             this.m_clientAgreements = null;
+            this.m_clientBinders = null;
             this.m_clientHello = null;
             this.m_keyExchange = null;
             this.m_authentication = null;
@@ -832,6 +834,15 @@ namespace Org.BouncyCastle.Tls
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
             }
 
+            if (null != m_clientBinders)
+            {
+                if (!Arrays.Contains(m_clientBinders.m_pskKeyExchangeModes, PskKeyExchangeMode.psk_dhe_ke))
+                {
+                    // TODO[tls13-psk] Notify client that no PSK was selected.
+                    this.m_clientBinders = null;
+                }
+            }
+
             /*
              * RFC 8446 4.2.8. Upon receipt of this [Key Share] extension in a HelloRetryRequest, the
              * client MUST verify that (1) the selected_group field corresponds to a group which was
@@ -939,10 +950,29 @@ namespace Org.BouncyCastle.Tls
              */
             securityParameters.m_statusRequestVersion = m_clientExtensions.Contains(ExtensionType.status_request) ? 1 : 0;
 
+            // TODO[tls13-psk] Use PSK early secret if negotiated
+            TlsSecret pskEarlySecret = null;
+
+            if (null != m_clientBinders)
+            {
+                // TODO[tls13-psk] Process the server's pre_shared_key response, if any
+                //int selected_identity = TlsExtensionsUtilities.GetPreSharedKeyServerHello(extensions);
+
+                // TODO[tls13-psk] Notify client of selected PSK
+                // pskEarlySecret = ...;
+
+                this.m_clientBinders = null;
+            }
+
+            TlsSecret sharedSecret = null;
+
             {
                 KeyShareEntry keyShareEntry = TlsExtensionsUtilities.GetKeyShareServerHello(extensions);
                 if (null == keyShareEntry)
+                {
+                    // TODO[tls13-psk] This would be OK for PskKeyExchangeMode.psk_ke (and not after HRR)
                     throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
 
                 if (!m_clientAgreements.Contains(keyShareEntry.NamedGroup))
                     throw new TlsFatalAlert(AlertDescription.illegal_parameter);
@@ -952,14 +982,11 @@ namespace Org.BouncyCastle.Tls
                 this.m_clientAgreements = null;
 
                 agreement.ReceivePeerValue(keyShareEntry.KeyExchange);
-                securityParameters.m_sharedSecret = agreement.CalculateSecret();
-
-                // TODO[tls13-psk] Use PSK early secret if negotiated
-                TlsSecret pskEarlySecret = null;
-
-                TlsUtilities.Establish13PhaseSecrets(m_tlsClientContext, pskEarlySecret);
+                sharedSecret = agreement.CalculateSecret();
             }
 
+            TlsUtilities.Establish13PhaseSecrets(m_tlsClientContext, pskEarlySecret, sharedSecret);
+
             {
                 InvalidateSession();
 
@@ -1477,13 +1504,12 @@ namespace Org.BouncyCastle.Tls
         /// <exception cref="IOException"/>
         protected virtual void Send13ClientHelloRetry()
         {
-            // TODO[tls13-psk] Create a new ClientHello object and handle any changes to the bindersSize
-
             IDictionary clientHelloExtensions = m_clientHello.Extensions;
 
             clientHelloExtensions.Remove(ExtensionType.cookie);
             clientHelloExtensions.Remove(ExtensionType.early_data);
             clientHelloExtensions.Remove(ExtensionType.key_share);
+            clientHelloExtensions.Remove(ExtensionType.pre_shared_key);
 
             /*
              * RFC 4.2.2. When sending the new ClientHello, the client MUST copy the contents of the
@@ -1492,6 +1518,9 @@ namespace Org.BouncyCastle.Tls
              */
             if (null != m_retryCookie)
             {
+                /*
+                 * - Including a "cookie" extension if one was provided in the HelloRetryRequest.
+                 */
                 TlsExtensionsUtilities.AddCookieExtension(clientHelloExtensions, m_retryCookie);
                 this.m_retryCookie = null;
             }
@@ -1504,14 +1533,24 @@ namespace Org.BouncyCastle.Tls
             if (m_retryGroup < 0)
                 throw new TlsFatalAlert(AlertDescription.internal_error);
 
+            /*
+             * - If a "key_share" extension was supplied in the HelloRetryRequest, replacing the list of shares
+             * with a list containing a single KeyShareEntry from the indicated group
+             */
             this.m_clientAgreements = TlsUtilities.AddKeyShareToClientHelloRetry(m_tlsClientContext,
                 clientHelloExtensions, m_retryGroup);
 
             /*
-             * TODO[tls13] Updating the "pre_shared_key" extension if present by recomputing the
-             * "obfuscated_ticket_age" and binder values and (optionally) removing any PSKs which are
-             * incompatible with the server's indicated cipher suite.
+             * - Updating the "pre_shared_key" extension if present by recomputing the "obfuscated_ticket_age"
+             * and binder values and (optionally) removing any PSKs which are incompatible with the server's
+             * indicated cipher suite.
              */
+            if (null != m_clientBinders)
+            {
+                // TODO[tls13-psk]
+                //this.m_clientBinders = TlsUtilities.AddPreSharedKeyToClientHelloRetry(m_tlsClientContext,
+                //    m_clientBinders, clientHelloExtensions);
+            }
 
             /*
              * TODO[tls13] Optionally adding, removing, or changing the length of the "padding"
@@ -1627,7 +1666,11 @@ namespace Org.BouncyCastle.Tls
             securityParameters.m_clientSupportedGroups = TlsExtensionsUtilities.GetSupportedGroupsExtension(
                 m_clientExtensions);
 
-            this.m_clientAgreements = TlsUtilities.AddEarlyKeySharesToClientHello(m_tlsClientContext, m_tlsClient,
+            this.m_clientBinders = TlsUtilities.AddPreSharedKeyToClientHello(m_tlsClientContext, m_tlsClient,
+                m_clientExtensions, offeredCipherSuites);
+
+            // TODO[tls13-psk] Perhaps don't add key_share if external PSK(s) offered and 'psk_dhe_ke' not offered  
+            this.m_clientAgreements = TlsUtilities.AddKeyShareToClientHello(m_tlsClientContext, m_tlsClient,
                 m_clientExtensions);
 
             if (TlsUtilities.IsExtendedMasterSecretOptionalTls(supportedVersions)
@@ -1684,9 +1727,7 @@ namespace Org.BouncyCastle.Tls
 
 
 
-            // TODO[tls13-psk] Calculate the total length of the binders that will be added.
-            int bindersSize = 0;
-            //int bindersSize = 2 + lengthOfBindersList;
+            int bindersSize = null == m_clientBinders ? 0 : m_clientBinders.m_bindersSize;
 
             this.m_clientHello = new ClientHello(legacy_version, securityParameters.ClientRandom, legacy_session_id,
                 null, offeredCipherSuites, m_clientExtensions, bindersSize);
@@ -1702,7 +1743,10 @@ namespace Org.BouncyCastle.Tls
 
             message.PrepareClientHello(m_handshakeHash, m_clientHello.BindersSize);
 
-            // TODO[tls13-psk] Calculate any PSK binders and write them to 'message' here. 
+            if (null != m_clientBinders)
+            {
+                OfferedPsks.EncodeBinders(message, Context.Crypto, m_handshakeHash, m_clientBinders);
+            }
 
             message.SendClientHello(this, m_handshakeHash, m_clientHello.BindersSize);
         }
diff --git a/crypto/src/tls/TlsServerProtocol.cs b/crypto/src/tls/TlsServerProtocol.cs
index 2afb625a8..89365afad 100644
--- a/crypto/src/tls/TlsServerProtocol.cs
+++ b/crypto/src/tls/TlsServerProtocol.cs
@@ -309,6 +309,11 @@ namespace Org.BouncyCastle.Tls
 
             this.m_expectSessionTicket = false;
 
+            // TODO[tls13-psk] Use PSK early secret if negotiated
+            TlsSecret pskEarlySecret = null;
+
+            TlsSecret sharedSecret = null;
+
             {
                 int namedGroup = clientShare.NamedGroup;
 
@@ -331,14 +336,11 @@ namespace Org.BouncyCastle.Tls
                 TlsExtensionsUtilities.AddKeyShareServerHello(serverHelloExtensions, serverShare);
 
                 agreement.ReceivePeerValue(clientShare.KeyExchange);
-                securityParameters.m_sharedSecret = agreement.CalculateSecret();
-
-                // TODO[tls13-psk] Use PSK early secret if negotiated
-                TlsSecret pskEarlySecret = null;
-
-                TlsUtilities.Establish13PhaseSecrets(m_tlsServerContext, pskEarlySecret);
+                sharedSecret = agreement.CalculateSecret();
             }
 
+            TlsUtilities.Establish13PhaseSecrets(m_tlsServerContext, pskEarlySecret, sharedSecret);
+
             this.m_serverExtensions = serverEncryptedExtensions;
 
             ApplyMaxFragmentLengthExtension(securityParameters.MaxFragmentLength);
diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs
index a80e6da32..7f529d8c5 100644
--- a/crypto/src/tls/TlsUtilities.cs
+++ b/crypto/src/tls/TlsUtilities.cs
@@ -1559,7 +1559,8 @@ namespace Org.BouncyCastle.Tls
             return Prf(securityParameters, master_secret, asciiLabel, prfHash, verify_data_length).Extract();
         }
 
-        internal static void Establish13PhaseSecrets(TlsContext context, TlsSecret pskEarlySecret)
+        internal static void Establish13PhaseSecrets(TlsContext context, TlsSecret pskEarlySecret,
+            TlsSecret sharedSecret)
         {
             TlsCrypto crypto = context.Crypto;
             SecurityParameters securityParameters = context.SecurityParameters;
@@ -1575,7 +1576,6 @@ namespace Org.BouncyCastle.Tls
                     .HkdfExtract(cryptoHashAlgorithm, zeros);
             }
 
-            TlsSecret sharedSecret = securityParameters.SharedSecret;
             if (null == sharedSecret)
             {
                 sharedSecret = zeros;
@@ -1595,7 +1595,6 @@ namespace Org.BouncyCastle.Tls
             securityParameters.m_earlySecret = earlySecret;
             securityParameters.m_handshakeSecret = handshakeSecret;
             securityParameters.m_masterSecret = masterSecret;
-            securityParameters.m_sharedSecret = null;
         }
 
         private static void Establish13TrafficSecrets(TlsContext context, byte[] transcriptHash, TlsSecret phaseSecret,
@@ -4844,7 +4843,7 @@ namespace Org.BouncyCastle.Tls
             return false;
         }
 
-        internal static IDictionary AddEarlyKeySharesToClientHello(TlsClientContext clientContext, TlsClient client,
+        internal static IDictionary AddKeyShareToClientHello(TlsClientContext clientContext, TlsClient client,
             IDictionary clientExtensions)
         {
             /*
@@ -5435,17 +5434,40 @@ namespace Org.BouncyCastle.Tls
 #endif
 
         /// <exception cref="IOException"/>
-        internal static OfferedPsks.Config GetOfferedPsksConfig(TlsClientContext clientContext, TlsClient client)
+        internal static OfferedPsks.BindersConfig AddPreSharedKeyToClientHello(TlsClientContext clientContext,
+            TlsClient client, IDictionary clientExtensions, int[] offeredCipherSuites)
         {
-            TlsPskExternal[] pskExternals = GetPskExternalsClient(client);
+            if (!IsTlsV13(clientContext.ClientVersion))
+                return null;
+
+            TlsPskExternal[] pskExternals = GetPskExternalsClient(client, offeredCipherSuites);
             if (null == pskExternals)
                 return null;
 
+            short[] pskKeyExchangeModes = client.GetPskKeyExchangeModes();
+            if (IsNullOrEmpty(pskKeyExchangeModes))
+                throw new TlsFatalAlert(AlertDescription.internal_error,
+                    "External PSKs configured but no PskKeyExchangeMode available");
+
+            // Add the pre_shared_key extension
+            {
+                IList identities = Platform.CreateArrayList(pskExternals.Length);
+                for (int i = 0; i < pskExternals.Length; ++i)
+                {
+                    TlsPskExternal pskExternal = pskExternals[i];
+
+                    // TODO[tls13-psk] Handle obfuscated_ticket_age for resumption PSKs
+                    identities.Add(new PskIdentity(pskExternal.Identity, 0L));
+                }
+
+                TlsExtensionsUtilities.AddPreSharedKeyClientHello(clientExtensions, new OfferedPsks(identities));
+            }
+
             TlsSecret[] pskEarlySecrets = GetPskEarlySecrets(clientContext.Crypto, pskExternals);
 
             int bindersSize = OfferedPsks.GetBindersSize(pskExternals);
 
-            return new OfferedPsks.Config(pskExternals, pskEarlySecrets, bindersSize);
+            return new OfferedPsks.BindersConfig(pskExternals, pskKeyExchangeModes, pskEarlySecrets, bindersSize);
         }
 
         internal static TlsSecret GetPskEarlySecret(TlsCrypto crypto, TlsPsk psk)
@@ -5469,24 +5491,29 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
-        internal static TlsPskExternal[] GetPskExternalsClient(TlsClient client)
+        internal static TlsPskExternal[] GetPskExternalsClient(TlsClient client, int[] offeredCipherSuites)
         {
-            // TODO[tl13-psk] Ensure PSK hash algorithms are supported by cipher suites
-
             IList externalPsks = client.GetExternalPsks();
             if (IsNullOrEmpty(externalPsks))
                 return null;
 
+            int[] prfAlgorithms = GetPrfAlgorithms13(offeredCipherSuites);
+
             int count = externalPsks.Count;
             TlsPskExternal[] result = new TlsPskExternal[count];
 
             for (int i = 0; i < count; ++i)
             {
-                TlsPskExternal element = externalPsks[i] as TlsPskExternal;
-                if (null == element)
-                    throw new TlsFatalAlert(AlertDescription.internal_error);
+                TlsPskExternal pskExternal = externalPsks[i] as TlsPskExternal;
+                if (null == pskExternal)
+                    throw new TlsFatalAlert(AlertDescription.internal_error,
+                        "External PSKs element is not a TlsPSKExternal");
+
+                if (!Arrays.Contains(prfAlgorithms, pskExternal.PrfAlgorithm))
+                    throw new TlsFatalAlert(AlertDescription.internal_error,
+                        "External PSK incompatible with offered cipher suites");
 
-                result[i] = element;
+                result[i] = pskExternal;
             }
 
             return result;