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)
+ {
+ }
+
/// <exception cref="IOException"/>
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);
+
/// <summary>The protocol implementation validates that any server extensions received correspond to client
/// extensions sent.</summary>
/// <remarks>
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
@@ -1529,6 +1529,21 @@ namespace Org.BouncyCastle.Tls
}
/*
+ * - 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
* indicated in the selected_group field of the triggering HelloRetryRequest.
@@ -1544,18 +1559,6 @@ namespace Org.BouncyCastle.Tls
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
@@ -5434,6 +5434,21 @@ namespace Org.BouncyCastle.Tls
#endif
/// <exception cref="IOException"/>
+ 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));
+ }
+
+ /// <exception cref="IOException"/>
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);
+ }
+
+ /// <exception cref="IOException"/>
+ 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;
+ }
}
}
|