From 739bef8b6390a8b75f9a6f9909ee325da5e878cc Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Tue, 27 Jul 2021 23:13:49 +0700 Subject: Filter PSK set for ClientHello retry --- crypto/src/tls/AbstractTlsClient.cs | 4 ++ crypto/src/tls/TlsClient.cs | 2 + crypto/src/tls/TlsClientProtocol.cs | 35 +++++++++-------- crypto/src/tls/TlsUtilities.cs | 77 +++++++++++++++++++++++++++++++------ 4 files changed, 91 insertions(+), 27 deletions(-) diff --git a/crypto/src/tls/AbstractTlsClient.cs b/crypto/src/tls/AbstractTlsClient.cs index 8d9d9de3d..fc62765c8 100644 --- a/crypto/src/tls/AbstractTlsClient.cs +++ b/crypto/src/tls/AbstractTlsClient.cs @@ -373,6 +373,10 @@ namespace Org.BouncyCastle.Tls { } + public virtual void NotifySelectedPsk(TlsPsk selectedPsk) + { + } + /// public virtual void ProcessServerExtensions(IDictionary serverExtensions) { diff --git a/crypto/src/tls/TlsClient.cs b/crypto/src/tls/TlsClient.cs index a9356aa4b..ef4586574 100644 --- a/crypto/src/tls/TlsClient.cs +++ b/crypto/src/tls/TlsClient.cs @@ -61,6 +61,8 @@ namespace Org.BouncyCastle.Tls void NotifySelectedCipherSuite(int selectedCipherSuite); + void NotifySelectedPsk(TlsPsk selectedPsk); + /// The protocol implementation validates that any server extensions received correspond to client /// extensions sent. /// diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs index daa5664b0..870a898f8 100644 --- a/crypto/src/tls/TlsClientProtocol.cs +++ b/crypto/src/tls/TlsClientProtocol.cs @@ -840,8 +840,9 @@ namespace Org.BouncyCastle.Tls { 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; + + m_tlsClient.NotifySelectedPsk(null); } } @@ -1511,8 +1512,7 @@ namespace Org.BouncyCastle.Tls clientHelloExtensions.Remove(ExtensionType.cookie); clientHelloExtensions.Remove(ExtensionType.early_data); clientHelloExtensions.Remove(ExtensionType.key_share); - // TODO[tls13-psk] - //clientHelloExtensions.Remove(ExtensionType.pre_shared_key); + clientHelloExtensions.Remove(ExtensionType.pre_shared_key); /* * RFC 4.2.2. When sending the new ClientHello, the client MUST copy the contents of the @@ -1528,6 +1528,21 @@ namespace Org.BouncyCastle.Tls this.m_retryCookie = null; } + /* + * - 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) + { + this.m_clientBinders = TlsUtilities.AddPreSharedKeyToClientHelloRetry(m_tlsClientContext, + m_clientBinders, clientHelloExtensions); + if (null == m_clientBinders) + { + m_tlsClient.NotifySelectedPsk(null); + } + } + /* * RFC 8446 4.2.8. [..] when sending the new ClientHello, the client MUST replace the * original "key_share" extension with one containing only a new KeyShareEntry for the group @@ -1543,18 +1558,6 @@ namespace Org.BouncyCastle.Tls this.m_clientAgreements = TlsUtilities.AddKeyShareToClientHelloRetry(m_tlsClientContext, clientHelloExtensions, m_retryGroup); - /* - * - 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" * extension [RFC7685]. @@ -1748,7 +1751,7 @@ namespace Org.BouncyCastle.Tls if (null != m_clientBinders) { - OfferedPsks.EncodeBinders(message, Context.Crypto, m_handshakeHash, m_clientBinders); + OfferedPsks.EncodeBinders(message, m_tlsClientContext.Crypto, m_handshakeHash, m_clientBinders); } message.SendClientHello(this, m_handshakeHash, m_clientHello.BindersSize); diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs index 7f529d8c5..9dea576f5 100644 --- a/crypto/src/tls/TlsUtilities.cs +++ b/crypto/src/tls/TlsUtilities.cs @@ -5433,6 +5433,21 @@ namespace Org.BouncyCastle.Tls } #endif + /// + internal static void AddPreSharedKeyToClientExtensions(TlsPsk[] psks, IDictionary clientExtensions) + { + IList identities = Platform.CreateArrayList(psks.Length); + for (int i = 0; i < psks.Length; ++i) + { + TlsPsk psk = psks[i]; + + // TODO[tls13-psk] Handle obfuscated_ticket_age for resumption PSKs + identities.Add(new PskIdentity(psk.Identity, 0L)); + } + + TlsExtensionsUtilities.AddPreSharedKeyClientHello(clientExtensions, new OfferedPsks(identities)); + } + /// internal static OfferedPsks.BindersConfig AddPreSharedKeyToClientHello(TlsClientContext clientContext, TlsClient client, IDictionary clientExtensions, int[] offeredCipherSuites) @@ -5449,25 +5464,52 @@ namespace Org.BouncyCastle.Tls throw new TlsFatalAlert(AlertDescription.internal_error, "External PSKs configured but no PskKeyExchangeMode available"); - // Add the pre_shared_key extension + TlsSecret[] pskEarlySecrets = GetPskEarlySecrets(clientContext.Crypto, pskExternals); + + int bindersSize = OfferedPsks.GetBindersSize(pskExternals); + + AddPreSharedKeyToClientExtensions(pskExternals, clientExtensions); + + return new OfferedPsks.BindersConfig(pskExternals, pskKeyExchangeModes, pskEarlySecrets, bindersSize); + } + + /// + internal static OfferedPsks.BindersConfig AddPreSharedKeyToClientHelloRetry(TlsClientContext clientContext, + OfferedPsks.BindersConfig clientBinders, IDictionary clientExtensions) + { + SecurityParameters securityParameters = clientContext.SecurityParameters; + + int prfAlgorithm = GetPrfAlgorithm13(securityParameters.CipherSuite); + + IList pskIndices = GetPskIndices(clientBinders.m_psks, prfAlgorithm); + if (pskIndices.Count < 1) + return null; + + OfferedPsks.BindersConfig result = clientBinders; + + int count = pskIndices.Count; + if (count < clientBinders.m_psks.Length) { - IList identities = Platform.CreateArrayList(pskExternals.Length); - for (int i = 0; i < pskExternals.Length; ++i) + TlsPsk[] psks = new TlsPsk[count]; + TlsSecret[] earlySecrets = new TlsSecret[count]; + + for (int i = 0; i < count; ++i) { - TlsPskExternal pskExternal = pskExternals[i]; + int j = (int)pskIndices[i]; - // TODO[tls13-psk] Handle obfuscated_ticket_age for resumption PSKs - identities.Add(new PskIdentity(pskExternal.Identity, 0L)); + psks[i] = clientBinders.m_psks[j]; + earlySecrets[i] = clientBinders.m_earlySecrets[j]; } - TlsExtensionsUtilities.AddPreSharedKeyClientHello(clientExtensions, new OfferedPsks(identities)); + int bindersSize = OfferedPsks.GetBindersSize(psks); + + result = new OfferedPsks.BindersConfig(psks, clientBinders.m_pskKeyExchangeModes, earlySecrets, + bindersSize); } - TlsSecret[] pskEarlySecrets = GetPskEarlySecrets(clientContext.Crypto, pskExternals); + AddPreSharedKeyToClientExtensions(result.m_psks, clientExtensions); - int bindersSize = OfferedPsks.GetBindersSize(pskExternals); - - return new OfferedPsks.BindersConfig(pskExternals, pskKeyExchangeModes, pskEarlySecrets, bindersSize); + return result; } internal static TlsSecret GetPskEarlySecret(TlsCrypto crypto, TlsPsk psk) @@ -5518,5 +5560,18 @@ namespace Org.BouncyCastle.Tls return result; } + + internal static IList GetPskIndices(TlsPsk[] psks, int prfAlgorithm) + { + IList v = Platform.CreateArrayList(psks.Length); + for (int i = 0; i < psks.Length; ++i) + { + if (psks[i].PrfAlgorithm == prfAlgorithm) + { + v.Add(i); + } + } + return v; + } } } -- cgit 1.4.1